Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d1ca753
feat(engine): adapt to latest A2A-T SDK content APIs and negotiation …
Zhoujie628 Aug 23, 2026
4436fb6
feat(samples): SDK negotiation content integration for SPN scenario
Zhoujie628 Aug 23, 2026
d5db86d
chore(samples): remove orphan demo superseded by SpringSpnDemo
Zhoujie628 Aug 23, 2026
b14d21d
docs: sync API reference and guides with the SDK negotiation contract
Zhoujie628 Aug 23, 2026
3a9939e
refactor(samples): reorganize package structure, keep only generic de…
Zhoujie628 Aug 23, 2026
324c35c
docs: sync workbench integration guide generic improvements from dev
Zhoujie628 Aug 23, 2026
ed17eec
refactor(samples): remove redundant demo code and deduplicate shared …
Zhoujie628 Aug 23, 2026
0b2eea8
refactor(samples): move SpringWorkbenchExecutor to the workbench package
Zhoujie628 Aug 23, 2026
53ec6f0
feat(engine): full A2A-T SDK integration — fromData dual track and th…
Zhoujie628 Aug 23, 2026
cdb2801
docs: document the fromData dual track and the stateful negotiation loop
Zhoujie628 Aug 23, 2026
bc36988
feat(samples): southbound fromData dispatch, fromData pre-positioning…
Zhoujie628 Aug 23, 2026
2d56c27
refactor(engine): migrate off the SDK's deprecated negotiation state …
Zhoujie628 Aug 24, 2026
aa4dae1
chore: pin unreleased A2A-T SDK revision
Zhoujie628 Aug 25, 2026
e85746d
docs: document pinned A2A-T SDK setup
Zhoujie628 Aug 25, 2026
a4c3de6
feat(engine): align protocol clients with current A2A-T SDK
Zhoujie628 Aug 25, 2026
4485b58
fix(engine): enforce workflow execution invariants
Zhoujie628 Aug 25, 2026
c9faa81
test(engine): cover protocol and workflow lifecycle behavior
Zhoujie628 Aug 25, 2026
ff20c42
fix(starter): close streaming responses deterministically
Zhoujie628 Aug 25, 2026
f32766b
feat(samples): model SPN workflow protocol operations
Zhoujie628 Aug 25, 2026
617dcb4
test(samples): cover SPN protocol orchestration
Zhoujie628 Aug 25, 2026
b52676d
fix(samples): validate SPN completion and shutdown lifecycles
Zhoujie628 Aug 25, 2026
161f259
docs: align engine guidance with current protocol behavior
Zhoujie628 Aug 25, 2026
ce83a06
docs(main): keep direct transport guidance vendor-neutral
Zhoujie628 Aug 25, 2026
e19769c
chore(a2at): pin latest SDK resources
Zhoujie628 Aug 26, 2026
b82755c
fix(a2at): align protocol flows with latest SDK
Zhoujie628 Aug 26, 2026
caaf569
test(a2at): cover current protocol contracts
Zhoujie628 Aug 26, 2026
5958861
docs(a2at): document latest-only protocol behavior
Zhoujie628 Aug 26, 2026
b063899
fix(samples): restore protocol diagnostics
Zhoujie628 Aug 26, 2026
c3c8ef4
docs(api): complete extension lifecycle signatures
Zhoujie628 Aug 26, 2026
cdbd764
docs: remove superseded review artifacts
Zhoujie628 Aug 26, 2026
8744836
docs: clarify host integration architecture
Zhoujie628 Aug 27, 2026
1dcb86e
feat(a2at): adopt SDK 1.0.0-841c575 typed negotiation and task dispatch
Zhoujie628 Aug 27, 2026
b78cdf5
docs(en): sync integration guide generic sections with current protocol
Zhoujie628 Aug 27, 2026
5b155cf
docs: remove vendor SDK references from main
Zhoujie628 Aug 27, 2026
638049c
chore(a2a): upgrade Java SDK to 1.2.0.Final
Zhoujie628 Aug 28, 2026
26eeaa2
feat(engine): expose current A2A-T business inputs
Zhoujie628 Aug 28, 2026
9aafcee
fix(samples): align SPN protocol business lifecycle
Zhoujie628 Aug 28, 2026
c15f632
docs: refresh current protocol integration guidance
Zhoujie628 Aug 28, 2026
620266e
feat(auth): support reusable credential profiles
Zhoujie628 Aug 29, 2026
5393eca
fix(samples): isolate pre-workflow protocol failures
Zhoujie628 Aug 29, 2026
8e26838
docs(samples): clarify independent pre-workflow operations
Zhoujie628 Aug 29, 2026
25b0ec5
feat(samples): support external AgentCard configuration
Zhoujie628 Aug 29, 2026
639b7f7
docs(samples): document external AgentCard loading
Zhoujie628 Aug 29, 2026
377973d
chore(deps): use A2A-T SDK 1.1.0 from Maven Central
Zhoujie628 Aug 31, 2026
f8acfc0
feat(logging): observe real protocol traffic with pretty redacted output
Zhoujie628 Aug 31, 2026
47005e9
refactor(engine): separate protocol scheduling from host business cal…
Zhoujie628 Aug 31, 2026
c34d8d3
fix(samples): align authorization and negotiation with SDK 1.1.0
Zhoujie628 Aug 31, 2026
ad205f4
docs: refresh callback contracts and SPN integration guidance
Zhoujie628 Aug 31, 2026
e8794f4
docs: use the canonical Negotiation-T extension URI in the zh guide
Zhoujie628 Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 7 additions & 20 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# A2A-T SDK Configuration
# Copy this file to .env and fill in your values

# Full A2A/Order protocol messages are emitted by the dedicated PROTOCOL DEBUG logger.
# Full A2A protocol messages are emitted by the dedicated PROTOCOL DEBUG logger.
# Keep sensitive values hidden by default; set true only during controlled local debugging.
WORKFLOW_ENGINE_PROTOCOL_INCLUDE_SENSITIVE_HEADERS=false
# Set false to omit request/response bodies; large bodies are truncated at this character count.
Expand All @@ -41,7 +41,7 @@ A2AT_LLM_PROVIDER=openai
A2AT_LLM_MODEL=deepseek-chat
A2AT_LLM_API_KEY=your-api-key-here
A2AT_LLM_BASE_URL=https://api.deepseek.com
A2AT_LLM_MAX_TOKENS=2000
A2AT_LLM_MAX_TOKENS=4000
A2AT_LLM_TEMPERATURE=0
A2AT_LLM_TIMEOUT_SECONDS=60
A2AT_LLM_HISTORY_WINDOW=10
Expand All @@ -55,21 +55,8 @@ A2AT_NEGOTIATION_STATE_STORE_TYPE=in_memory
# Generate with: openssl rand -hex 32
A2AT_CRED_KEY=your-32-byte-hex-key-here

# Workbench outbound transport: order (Eastcom SDK), mock, or direct
A2A_TRANSPORT_MODE=order
A2A_MOCK_GATEWAY_URL=http://127.0.0.1:26400

# Eastcom instruction platform. Configure either a default NE or per-agent NE routes.
# true starts the local RSocket-RPC protocol simulator; never enable it in production.
EASTCOM_ORDER_SIMULATOR_ENABLED=false
EASTCOM_ORDER_HOST=10.x.x.x
EASTCOM_ORDER_PORT=0
EASTCOM_ORDER_USERNAME=your-username
EASTCOM_ORDER_PASSWORD=your-password
EASTCOM_ORDER_CLIENT_ID=
EASTCOM_ORDER_CLIENT_SECRET=
EASTCOM_ORDER_DEFAULT_NE=
EASTCOM_ORDER_CITY1_NE=city1-omc
EASTCOM_ORDER_CITY2_NE=city2-omc
EASTCOM_ORDER_LOGIN_TIMEOUT_SECONDS=15
EASTCOM_ORDER_TIMEOUT_SECONDS=600
# Keep true for production HTTPS. Set false only for local/self-signed integration testing.
A2A_SSL_VERIFY=false
# Comma-separated classpath:, file: URI, or absolute file locations. Leave empty for bundled cards.
# For a live OMC, point the city AgentCards at files exported by the registry center.
A2A_AGENT_CARD_LOCATIONS=
12 changes: 5 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
build-and-test:
runs-on: ubuntu-latest
name: Build and Test (workflow-engine, spring-boot-starter)

steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -39,11 +39,11 @@ jobs:
spring-boot-starter/target/surefire-reports/
retention-days: 7

samples-compileilation-check:
samples-compilation-check:
runs-on: ubuntu-latest
name: Samples Compilation Check (optional)
continue-on-error: true

steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -55,7 +55,5 @@ jobs:
distribution: 'temurin'
cache: 'maven'

- name: Check samples compilation
run: |
echo "::notice::Samples module depends on Eastcom SDK (not on Maven Central). Skipping compilation check in CI."
echo "::notice::Local verification: mvn -pl samples -am compile"
- name: Build and test samples
run: mvn -B -pl samples -am verify
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
# Changelog

## Unreleased — business callback boundary

- Use published A2A-T 1.1.0 from Maven Central; remove SDK source checkout/install from CI; move content generation, validation, templates and SDK initialization to the host.
- onTask returns final MessageContent; onNegotiation returns Send/Stop. Remove engine profiles and content handlers.
- Preserve complete ReceivedMessage and metadata layers alongside deterministic convenience outputs; keep local nested multi-output values.
- Deduplicate negotiation rounds, separate resource budgets from protocol rounds, and suppress late sends after timeout/cancellation.
- Separate authorization/notification lifecycle from workflow outcomes; never synthesize a subscription ACK.
- Observe serialized HTTP/JSON-RPC, real gRPC metadata/protobuf and dev vendor SDK traffic with mandatory redaction and bounded SSE.
- Add local missing-port SpringSpnDemo negotiation tests for direct and dev Order; real LLM/platform/OMC validation remains separate.
- Refresh bilingual callback, architecture and integration contracts. No older SDK compatibility layer.

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

> Entries below older release headings describe those releases and are not current API contracts.

### Added

- Client TLS options for custom CA, mTLS client certificate/private key, encrypted PKCS#8 keys, and CRL checking
- Configurable bounded executors for client sends and Spring Boot server request handling
- Configurable Notification-T acknowledgement timeout and protocol-log body controls
- Pinned, unreleased A2A-T SDK revision with real offline SDK end-to-end coverage
- Explicit `NotificationSubscription` lifecycle/heartbeat handle and stable SDK-event mapper
- Structured Authorization-T and Notification-T generation, server validation, and whitelist/recovery sample callbacks
- WAIMO Task-T parsing plus two-city parallel diagnosis and exact-once merged workbench result

### Changed

Expand All @@ -24,6 +41,11 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Workflow execution validates graph targets and cycles up front and waits only for activated predecessors at joins
- Protocol headers are redacted by default; sensitive values require an explicit diagnostic opt-in
- Agent clients and transport executors are reused and closed through their owning runtime
- Task-T, Authorization-T, and Notification-T use independent transport/runtime/context instances
- Negotiation-T uses the latest stateless content APIs and canonical `negotiationContext`; removed SDK state-machine APIs are not used
- SDK `.env` paths remain instance-local instead of being copied into JVM-wide system properties
- Extension subscription and task-control capabilities are explicit interface contracts instead of
default methods that fail at runtime

### Fixed

Expand All @@ -32,6 +54,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Extension URI matching now uses exact URI path segments instead of substring matching
- Notification callback implementations can no longer silently discard the supplied callback
- Header construction is split into isolated auth, credential, and extension contributors with conflict detection
- Protocol generation/validation failures now fail closed instead of sending raw text under an A2A-T URI
- Authorization-T rejection stops the independent authorization operation; add/modify/delete/query operations follow the SDK template contract
- Notification-T failed/canceled/rejected acknowledgements fail the subscription and callback failures cannot prevent cleanup
- Workflow joins merge all predecessor outputs deterministically and execute exactly once after active predecessors complete

## [1.0.0] - 2026-07-28

Expand Down
74 changes: 52 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,40 @@

A standalone SDK for executing multi-agent workflows over the [A2A protocol](https://a2aproject.github.io/a2a-java/) with [A2A-T](https://projects.tmforum.org/a2aproject/telecommunication/extensions/) telecom extensions.

The engine handles all protocol mechanics: A2A message transport, SSE streaming, Task-T prompt generation, Negotiation-T auto-loop, authentication, and TLS. You implement only business decisions.
The engine handles workflow scheduling, A2A envelopes, transport, task waiting, authentication and TLS. Host callbacks return final message content and own any A2A-T generation, schema, validation or LLM calls.

## Features

- **A2A-T Extension Support**: Task-T (structured task prompts), Negotiation-T (auto negotiation loop), Authorization-T (pre-positioned whitelist), Notification-T (long-lived SSE subscription)
- **A2A-T Extension Support**: Task-T (structured task prompts), Negotiation-T (stateless auto negotiation loop), Authorization-T (independent whitelist operation), Notification-T (independent long-lived SSE subscription)
- **Content-neutral callbacks**: final MessageContent, complete ReceivedMessage, local multi-output TaskResult and explicit NegotiationReply.Send/Stop
- **Minimal A2A-T dependency**: a2a-t-core only in the engine; content generation and template queries use the host's explicit a2a-t-client dependency
- **DAG Workflow Execution**: Parallel dispatch, self-loop steps, conditional routing
- **Multi-Protocol Transport**: REST, JSON-RPC, and gRPC auto-selected from AgentCard
- **Authentication**: Bearer token login with TTL cache, AES-256-GCM encrypted credentials, custom `AuthProvider`
- **HTTPS/TLS**: Configurable trust store, self-signed cert support for development
- **Protocol Logging**: Full request/response header and body dumps for debugging
- **Protocol Logging**: actual HTTP/JSON-RPC boundaries, gRPC metadata/protobuf views and dev Order SDK observations; bodies default on at DEBUG with mandatory secret-field redaction

The SPN sample treats the protocol document as an input, not as executable truth. The pinned A2A-T
SDK templates, slot schemas, canonical URIs, and validation results are authoritative. Protocol
generation and validation fail closed; raw text is never sent under an A2A-T URI as a fallback.

In `SpringSpnDemo`, WAIMO sends a Task-T complaint to the workbench. The workbench loads the PSOP,
dispatches two city-specific OMC diagnoses in parallel, joins both branches exactly once, and
returns the real merged result over direct HTTP+JSON transport. Task-T, Authorization-T, and
Notification-T each use an independent transport/runtime/context. Authorization and Notification
are independently triggered workbench operations rather than DAG nodes; Notification keeps an
explicit long-lived subscription until the recovery result, cancellation, or shutdown.

## Quick Start

### 1. Add Maven dependency

A2A-T SDK `1.1.0` is published to Maven Central. Maven resolves it automatically;
no SDK source checkout or local SDK build is required. The engine depends only on
`a2a-t-core`; hosts using content generation explicitly add `a2a-t-client:1.1.0`
(and `a2a-t-server:1.1.0` for receiving-side validation).
See the [A2A-T SDK dependency guide](docs/zh/A2AT-SDK-DEPENDENCY.md) for IDEA setup and upgrade checks.

```xml
<dependency>
<groupId>dev.openan.workflow.sdk</groupId>
Expand Down Expand Up @@ -56,24 +75,17 @@ List<AgentCard> agentCards = registry.fetchAgentCards();
A2ATransport transport = new A2ATransport(agentCards, null,
WorkflowEngineClientConfig.builder()
.sslVerify(true)
.a2atEnvPath(".env")
.credentialsConfigPath("credentials.json")
.build());
WorkflowEngineClient client = new DefaultWorkflowEngineClient(transport);

// 4. Implement ControlPoint (business decisions only)
ControlPoint controlPoint = new DefaultControlPoint() {
@Override
public CompletableFuture<TaskResponse> onTask(
TaskRequest request, WorkflowEngineClient engineClient) {
return engineClient
.sendMessage(request.getAgentName(), request.getMessage())
.thenApply(r -> TaskResponse.builder()
.success(true)
.output(r.getText())
.build());
}
};
// 4. Plain A2A example; use host A2A-T SDK generation for Task-T.
ControlPoint controlPoint = ControlPoint.builder()
.onTask(request -> CompletableFuture.completedFuture(
MessageContent.text(request.getInstruction())))
.build();
// Implement local, conditional-route and negotiation callbacks as needed.
// Complete contract: docs/en/BUSINESS_CALLBACKS.md

// 5. Execute
ExecutionResult result = ExecutePsop.builder()
Expand All @@ -90,6 +102,8 @@ System.out.println("Success: " + result.isSuccess());
```


Final content callbacks, complete dependency inputs and negotiation Send/Stop: [English](docs/en/BUSINESS_CALLBACKS.md) / [中文](docs/zh/BUSINESS_CALLBACKS.md).

## Architecture

```mermaid
Expand Down Expand Up @@ -135,7 +149,7 @@ graph TD
| `client` | `WorkflowEngineClient`, `DefaultWorkflowEngineClient`, `ExtensionSender`, `A2ATransport`, `AuthProvider`, `AgentAuthManager`, `WorkflowEngineClientConfig`, `CredentialCrypto`, `AgentCardJacksonModule` | A2A transport, auth, extensions (package-private internals) |
| `control` | `ControlPoint`, `DefaultControlPoint`, `EventCallback`, `EventType`, `NegotiationStrategy` | User-facing decision interfaces |
| `core` | `WorkflowExecutor`, `ContextBuilder` | DAG traversal, context assembly |
| `model` | `Workflow`, `WorkflowStep`, `Task`, `TaskRequest`, `TaskResponse`, `StepType`, `JumpCondition`, `RouteDecision`, `ExecutionResult`, `SendMessageResult`, `TaskStatus`, `WorkflowSearchResult` | Data models |
| `model` | `Workflow`, `WorkflowStep`, `Task`, `TaskRequest`, `MessageContent`, `TaskResult`, `NegotiationRequest`, `NegotiationReply`, `ExecutionResult` | Data models |
| `registry` | `LoadPsop`, `RegistryClient` | PSOP loading and AgentCard registry |
| `runner` | `ExecutePsop` | Entry point for workflow execution |

Expand All @@ -149,17 +163,13 @@ graph TD
- [API Reference](docs/en/API_REFERENCE.md) - Public interface and class documentation
- [Design Document](docs/en/DESIGN.md) - Architecture, module structure, design decisions
- [Developer Guide](docs/en/DEVELOPER_GUIDE.md) - Internal architecture, contribution, debugging
- [Notification-T Design Analysis](docs/en/notification-t-design-analysis.md) - Long-lived SSE design

### 中文

- [集成指南](docs/zh/INTEGRATION_GUIDE.md) - 安装、配置、二次开发
- [API 参考](docs/zh/API_REFERENCE.md) - 公共接口和类文档
- [架构设计](docs/zh/DESIGN.md) - 架构、模块结构、设计决策
- [开发者指南](docs/zh/DEVELOPER_GUIDE.md) - 内部架构、贡献、调试
- [Notification-T 设计分析](docs/zh/notification-t-design-analysis.md) - 长连接 SSE 设计选型
- [业务流](docs/zh/业务流.md) - SPN 跨城诊断业务流程
- [调用过程](docs/zh/调用过程.md) - 端到端报文交互示例
- [工作台集成指南](docs/zh/工作台集成指南.md) - 工作台 Spring Boot 集成完整指南

## Modules
Expand All @@ -173,3 +183,23 @@ graph TD
## License

[Apache License 2.0](LICENSE)

### Inspect negotiation in the local Demo

Running the local SpringSpnDemo without VM options now negotiates missing City1 input; City2 diagnoses directly.
This is a local sample scenario, not an engine default. To use complete inputs in both cities, add this IDEA **VM option**:

```text
-Da2at.samples.negotiation=false
```

By default only City1 loses its Task-T task object. Add `-Da2at.samples.negotiation.city=city2` or `both`
to exercise City2 or both cities. The host retains city-scoped authoritative input and the complaint context is preserved.
Expect DEMO_NEGOTIATION → INPUT_REQUIRED/PROPOSE → onNegotiation → ACCEPT → both diagnoses → one aggregate.
External-OMC mode defaults to no injection and rejects an explicit true switch.
The Demo passes its setting into the current Spring application context without modifying JVM-wide properties.
Protocol observations are in the console and `logs/spn-demo.log` relative to the run directory.

Run `SpringSpnDemoE2ETest` (direct) and, on dev, `SpringSpnDemoOrderE2ETest` sequentially.
Each tests the no-VM-option single-city default, explicit disable/enable and both-city negotiation with current SDK resources and an offline LLM provider.
This is local protocol E2E evidence, not real model/platform/OMC validation.
56 changes: 56 additions & 0 deletions docs/diagrams/workflow-engine-surrounding-systems.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
%%{init: {"flowchart": {"curve": "basis", "nodeSpacing": 55, "rankSpacing": 75}}}%%
flowchart TB
classDef external fill:#EEF4FF,stroke:#2563EB,color:#172554,stroke-width:1.5px
classDef host fill:#FFF7ED,stroke:#EA580C,color:#431407,stroke-width:1.5px
classDef sdk fill:#ECFDF5,stroke:#059669,color:#052E16,stroke-width:1.5px
classDef local fill:#F8FAFC,stroke:#64748B,color:#0F172A,stroke-dasharray:5 3
classDef agent fill:#F5F3FF,stroke:#7C3AED,color:#2E1065,stroke-width:1.5px

subgraph CONTROL["周边控制面与上游系统"]
direction LR
WAIMO["WAIMO<br/>上游任务发起方"]:::external
REG["注册中心 / Registry Center<br/>AgentCard 发布与查询"]:::external
ORCH["编排中心 / Orchestration Center<br/>工作流检索与 PSOP 加载"]:::external
end

subgraph HOST["宿主智能体:传输工作台 / Workbench Agent"]
direction TB
ENTRY["A2A 服务端入口<br/>接收 Task-T,解析诊断意图"]:::host
ADAPTER["宿主集成层<br/>准备 AgentCard、Workflow、配置和业务上下文"]:::host

subgraph ENGINE["嵌入式 Workflow Execution Engine SDK"]
direction TB
LOAD["发现辅助 API<br/>RegistryClient / LoadPsop"]:::sdk
RUN["工作流协议调度<br/>ExecutePsop → WorkflowExecutor<br/>Task-T + Negotiation-T"]:::sdk
CALLBACK["宿主回调接口<br/>ControlPoint / EventCallback / onFinish"]:::sdk
EXT["流程外协议操作<br/>ExtensionSender<br/>Authorization-T / Notification-T"]:::sdk
end

BIZ["工作台业务实现<br/>业务接管、路由、汇总、持久化、通知处理"]:::host
end

subgraph SAMPLE["Demo 本地替代路径(非生产数据源)"]
direction LR
LOCALCARD["本地 AgentCard JSON<br/>WorkbenchAgentCatalog"]:::local
LOCALPSOP["本地 PSOP fallback<br/>仅用于离线演示"]:::local
end

subgraph DOWNSTREAM["下游业务智能体"]
OMCS["地市 OMC 智能体群<br/>地市 1 OMC | 地市 2 OMC"]:::agent
end

WAIMO <-->|"Task-T 诊断任务 / 汇总 artifact"| ENTRY
ENTRY -->|"运行意图"| ADAPTER
REG -->|"生产:查询 AgentCard"| LOAD
ORCH -->|"search / load PSOP"| LOAD
LOCALCARD -.->|"Demo 替代注册中心"| ADAPTER
LOCALPSOP -.->|"Demo 检索失败时"| ADAPTER
LOAD -->|"发现结果交给宿主"| ADAPTER
ADAPTER -->|"Workflow + AgentCards"| RUN
RUN <-->|"业务决策与执行结果"| CALLBACK
CALLBACK <-->|"回调"| BIZ
ADAPTER -->|"独立业务时机"| EXT

RUN <-->|"向两地市并行 Task-T<br/>必要时 Negotiation-T / 返回诊断结果"| OMCS
EXT <-->|"Authorization-T 一次性授权<br/>Notification-T 长连接订阅与结果 SSE"| OMCS
BIZ -->|"汇总结果"| ENTRY
Loading
Loading