Spec C1 of the A2A inventory in docs/core-functionality/a2a/a2a-coverage-scope.md — planned in #1195, never written. Closes the first [ ] bullet of QA-CHECKLIST.md §16.2 (line 650).
Problem
A2A has two halves: serving an agent and consuming one. #1349 promoted 7 specs covering the server; the A2AAgent component — the entire client half — has zero coverage.
mode=Internal is the half that is reachable today: it lists locally published agents in a dropdown and calls one over the same /jsonrpc endpoint the server specs already prove. It does not depend on the loopback-SSRF question that blocks C2/External (LE-1904 class) — that constraint applies only to pointing the component at an external URL, including this instance's own.
What to prove
Two flows in one test:
- Flow A — the published passthrough (
createRunnableChatFlowViaApi → PATCH flow_type=agent, a2a_enabled=true). Same shape the server specs publish.
- Flow B — a second flow carrying an
A2AAgent node with mode=Internal.
| Observable |
Expected |
agent_name_selected dropdown in Flow B |
lists Flow A's published agent (refreshable input, populated from local published agents) |
| Running Flow B |
the Response output contains the per-run sentinel Flow A echoes verbatim |
No LLM on either side — the passthrough echoes Chat Input to Chat Output, so the sentinel is causal evidence the remote call actually executed the other flow's graph, not a "something came back" check.
Component facts from the surface map (measured)
lfx/components/models_and_agents/a2a_agent.py — display_name = "A2A Agent", name = "A2AAgent", icon = "bot".
Inputs: mode (TabInput Internal | External), agent_name_selected (Dropdown, refreshable, populated from local published agents), agent_url (External only), agent_card (DataDisplayInput), message (Multiline, tool_mode=True), api_key (SecretStr), timeout (Int, seconds). One output: Response.
Two things to watch:
- The dropdown is refreshable — it may need an explicit refresh after Flow A is published, since the node was added before. Assert the option is present rather than assuming the initial render has it.
agent_name_selected is a name, not an id. Two flows with the same name would make the assertion ambiguous — give Flow A a per-run unique name.
Preconditions already available
createRunnableChatFlowViaApi — the LLM-free passthrough plus id-scoped teardown.
requireA2aEnabled() — first call, as in every spec of the area.
- The server specs already prove the endpoint Flow B will call, so a failure here isolates to the component, not the transport.
Deliverables
tests/tests-automations/regression/core-functionality/a2a/a2a-client-agent-internal.spec.ts
docs/core-functionality/a2a/a2a-client-agent-internal.md (spec doc first — SDD)
QA-CHECKLIST.md §16.2 line 650 → [x] with the spec reference
- Tags:
@stable @components @a2a (plus @workspace if the spec drives the canvas to build Flow B). LLM-free, so no provider dependency.
- Both flows deleted id-scoped in
finally.
Decision to make during PLAN
Whether Flow B is built through the canvas (drag the A2AAgent in, set the dropdown) or via API from a fixture JSON. The canvas route also covers the dropdown population — which is half the observable — so it is the stronger option, but it is slower and pulls in the sidebar-add primitive. Scout it live before committing.
Out of scope
- C2 / External mode (
LE-1845) — blocked until the loopback-SSRF question is answered; tracked separately.
- C3 / as a Tool (
LE-1963) — the only LLM-dependent row of the area; tracked separately.
Spec C1 of the A2A inventory in
docs/core-functionality/a2a/a2a-coverage-scope.md— planned in #1195, never written. Closes the first[ ]bullet ofQA-CHECKLIST.md§16.2 (line 650).Problem
A2A has two halves: serving an agent and consuming one. #1349 promoted 7 specs covering the server; the
A2AAgentcomponent — the entire client half — has zero coverage.mode=Internalis the half that is reachable today: it lists locally published agents in a dropdown and calls one over the same/jsonrpcendpoint the server specs already prove. It does not depend on the loopback-SSRF question that blocks C2/External (LE-1904class) — that constraint applies only to pointing the component at an external URL, including this instance's own.What to prove
Two flows in one test:
createRunnableChatFlowViaApi→PATCH flow_type=agent, a2a_enabled=true). Same shape the server specs publish.A2AAgentnode withmode=Internal.agent_name_selecteddropdown in Flow BResponseoutput contains the per-run sentinel Flow A echoes verbatimNo LLM on either side — the passthrough echoes Chat Input to Chat Output, so the sentinel is causal evidence the remote call actually executed the other flow's graph, not a "something came back" check.
Component facts from the surface map (measured)
lfx/components/models_and_agents/a2a_agent.py—display_name = "A2A Agent",name = "A2AAgent",icon = "bot".Inputs:
mode(TabInputInternal|External),agent_name_selected(Dropdown, refreshable, populated from local published agents),agent_url(External only),agent_card(DataDisplayInput),message(Multiline,tool_mode=True),api_key(SecretStr),timeout(Int, seconds). One output:Response.Two things to watch:
agent_name_selectedis a name, not an id. Two flows with the same name would make the assertion ambiguous — give Flow A a per-run unique name.Preconditions already available
createRunnableChatFlowViaApi— the LLM-free passthrough plus id-scoped teardown.requireA2aEnabled()— first call, as in every spec of the area.Deliverables
tests/tests-automations/regression/core-functionality/a2a/a2a-client-agent-internal.spec.tsdocs/core-functionality/a2a/a2a-client-agent-internal.md(spec doc first — SDD)QA-CHECKLIST.md§16.2 line 650 →[x]with the spec reference@stable@components@a2a(plus@workspaceif the spec drives the canvas to build Flow B). LLM-free, so no provider dependency.finally.Decision to make during PLAN
Whether Flow B is built through the canvas (drag the
A2AAgentin, set the dropdown) or via API from a fixture JSON. The canvas route also covers the dropdown population — which is half the observable — so it is the stronger option, but it is slower and pulls in the sidebar-add primitive. Scout it live before committing.Out of scope
LE-1845) — blocked until the loopback-SSRF question is answered; tracked separately.LE-1963) — the only LLM-dependent row of the area; tracked separately.