Skip to content

LCORE-2914: A2A client support: enable LCS to discover and call external A2A agents#2162

Open
are-ces wants to merge 2 commits into
lightspeed-core:mainfrom
are-ces:lcore-2914-a2a-client-discovery
Open

LCORE-2914: A2A client support: enable LCS to discover and call external A2A agents#2162
are-ces wants to merge 2 commits into
lightspeed-core:mainfrom
are-ces:lcore-2914-a2a-client-discovery

Conversation

@are-ces

@are-ces are-ces commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Description

Enable LCS to act as an A2A client — discovering and delegating tasks to external A2A-compliant agents during inference. Previously LCS only supported the A2A protocol as a server. This PR adds both the client-side infrastructure and refactors the A2A server to use pydantic-ai agents.

A2A Server Refactor

  • Refactor A2AAgentExecutor to use build_agent() + agent.run_stream_events() instead of raw client.responses.create(), aligning the A2A path with query/streaming endpoints
  • Add _build_a2a_parts_from_agent_result() and _dispatch_agent_event() for pydantic-ai → A2A event mapping

A2A Client

  • A2AAgentsConfiguration: YAML config for remote agent endpoints with timeout, max_retries, and optional auth_token
  • A2AClientManager: singleton that resolves agent cards at startup, holds Client instances with httpx timeout/retry transport
  • A2ADelegationCapability: pydantic-ai capability with list_agents and delegate_to_agent tools, auto-injected into build_agent() when agents are configured
  • Startup/shutdown lifecycle wired into FastAPI lifespan
  • Graceful degradation: unavailable agents are skipped at startup; delegation failures return error strings to the LLM

Docs & Config

  • docs/a2a_protocol.md updated with A2A client documentation
  • examples/lightspeed-stack-a2a-agents.yaml example config
  • OpenAPI schema regenerated

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement
  • Benchmarks improvement

Tools used to create PR

  • Assisted-by: Claude Opus 4.6
  • Generated by: Claude Opus 4.6

Related Tickets & Documents

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • uv run make verify — all linters pass
  • uv run make test-unit — 2992 tests pass, 0 failures
  • Manual testing with 4-instance demo (orchestrator + 3 A2A server agents): delegation, parallel tool calls, error handling verified

Summary by CodeRabbit

  • New Features
    • Added configuration for external A2A agents to enable task delegation.
    • Added remote agent discovery and delegation tools during inference.
    • Implemented streaming delegation with handling for unknown agents, failures, timeouts, and retry behavior.
    • Added a Lightspeed orchestrator example wiring up three remote A2A agents.
  • Documentation
    • Updated the A2A protocol docs to describe client-side delegation and configuration.
  • Tests
    • Added/expanded unit tests for delegation behavior, response parsing, manager initialization, and authentication header injection.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds configurable external A2A agent discovery and delegation, including client lifecycle management, Pydantic-AI tools, startup/shutdown integration, configuration schemas, tests, an example deployment, and protocol documentation.

Changes

A2A delegation

Layer / File(s) Summary
A2A configuration contracts
src/models/config.py, src/configuration.py, docs/devel_doc/openapi.json, examples/..., tests/unit/models/config/test_dump_configuration.py
Adds typed external-agent configuration, application accessors, OpenAPI schemas, an example configuration, and updated configuration dump expectations.
Remote-agent connection lifecycle
src/a2a_client/manager.py, src/app/main.py, tests/unit/a2a_client/test_manager.py
Connects configured agents with streaming clients, bearer authentication, timeouts, and retries; caches agent cards; and manages startup and shutdown cleanup.
Delegation capability and agent wiring
src/a2a_client/capability.py, src/a2a_client/__init__.py, src/utils/pydantic_ai_helpers.py, tests/unit/a2a_client/*
Adds agent discovery and delegation tools, streamed response collection and failure handling, conditional capability registration, public exports, and unit tests.
A2A protocol documentation
docs/user_doc/a2a_protocol.md
Documents LCS client/server roles, executor behavior, remote delegation configuration, runtime flow, authentication, and references.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant FastAPI_lifespan
  participant A2AClientManager
  participant RemoteA2AAgent
  participant PydanticAI_Agent
  FastAPI_lifespan->>A2AClientManager: initialize configured agents
  A2AClientManager->>RemoteA2AAgent: connect and fetch AgentCard
  PydanticAI_Agent->>A2AClientManager: list_agents or delegate_to_agent
  A2AClientManager->>RemoteA2AAgent: send delegated user message
  RemoteA2AAgent-->>PydanticAI_Agent: streamed response events
Loading

Possibly related PRs

Suggested reviewers: tisnik


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Security And Secret Handling ❌ Error FAIL: src/models/config.py:2041-2049 allows auth_token on AnyHttpUrl, and src/a2a_client/manager.py:98-112 sends Authorization: Bearer ... without HTTPS, so tokens can leak in plaintext. Require https:// for any endpoint with auth_token (or a narrowly scoped insecure-dev opt-in) and add validation/tests to reject plaintext bearer-token transport.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding A2A client support for discovering and delegating to external agents.
Docstring Coverage ✅ Passed Docstring coverage is 86.57% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Performance And Algorithmic Complexity ✅ Passed manager.py:83-180 and capability.py:60-184 are linear over configured agents/events; caches are bounded by config and cleared on close. No O(n^2), N+1, or unbounded growth.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
examples/lightspeed-stack-a2a-agents.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

docs/devel_doc/openapi.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@are-ces
are-ces force-pushed the lcore-2914-a2a-client-discovery branch from 71f1074 to 60029d6 Compare July 17, 2026 14:37
Comment thread src/a2a_client/manager.py Dismissed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/main.py (1)

145-153: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guarantee A2A cleanup when another shutdown step fails.

If either preceding cleanup raises, Line 149 is skipped and remote connections remain open. Put A2AClientManager().close() in an independent finally block.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/main.py` around lines 145 - 153, Update the shutdown cleanup sequence
around shutdown_background_topic_summary_tasks, A2AStorageFactory.cleanup, and
A2AClientManager().close so the client close operation runs in its own finally
block even when an earlier cleanup step raises. Preserve the outer Sentry flush
behavior after all cleanup attempts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/a2a_client/__init__.py`:
- Around line 3-9: Update the package initializer by removing the
A2ADelegationCapability and A2AClientManager imports and deleting __all__; move
those imports into each consuming module so this __init__.py contains only a
brief package description.

In `@src/a2a_client/capability.py`:
- Around line 87-89: Update the documentation section header in the affected
function docstring from “Args:” to “Parameters:”, while preserving the existing
agent_name and task descriptions.
- Around line 130-142: Update the agent-list prompt construction in the
capability method around self._manager.list_agents() so remote card.description
and skill names are not inserted as trusted system-instruction prose. Restrict
displayed metadata to validated identifiers, or clearly encode the description
and skills as untrusted data while preserving the delegation list and agent
names.
- Around line 51-52: Replace the Any annotation on the _manager field with
A2AClientManager, and update _send_and_collect.client to use the concrete Client
interface. Add or reuse the appropriate imports, preserving the existing runtime
behavior while ensuring both class attributes and parameters are statically
checked against the SDK contracts.
- Around line 101-103: Update the delegation debug log in the try block around
create_text_message_object to remove the user-provided task from logger.debug,
retaining only the target agent name and non-sensitive diagnostic context.
- Around line 170-181: Update the terminal-state handling in the capability
delegation logic around the existing failed-state branch to treat
TaskState.failed, TaskState.rejected, and TaskState.canceled uniformly,
preserving the existing failure-message extraction and delegation error
response. In tests/unit/a2a_client/test_capability.py, extend the relevant unit
test coverage to verify all three terminal states produce the delegation failure
result.

In `@src/a2a_client/manager.py`:
- Around line 128-148: Update get_client and get_card in
src/a2a_client/manager.py to use modern union return annotations with | None
instead of Optional. Apply the same annotation change to the helper at
src/utils/pydantic_ai.py line 193; preserve each function’s existing return
behavior.
- Around line 97-113: Update the exception path surrounding
ClientFactory.connect and client.get_card in the connection manager to close any
partially initialized client and its httpx_client before handling or logging the
error. Ensure cleanup is conditional and safe when either resource was never
created, while preserving caching only after successful card retrieval.
- Around line 55-58: Update the request-kwargs preparation around the headers
assignment to copy the incoming mapping and its headers mapping before adding
the Bearer Authorization value. Preserve all existing request options while
ensuring the original input and caller-owned headers remain unchanged, and
assign the copied headers back to the copied kwargs before returning.

In `@src/configuration.py`:
- Around line 431-437: Update the a2a_agents property docstring to use the
Google-style format, adding a Returns section for its A2AAgentsConfiguration |
None result and a Raises section documenting LogicError when _configuration is
not loaded.

---

Outside diff comments:
In `@src/app/main.py`:
- Around line 145-153: Update the shutdown cleanup sequence around
shutdown_background_topic_summary_tasks, A2AStorageFactory.cleanup, and
A2AClientManager().close so the client close operation runs in its own finally
block even when an earlier cleanup step raises. Preserve the outer Sentry flush
behavior after all cleanup attempts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e733f60c-2ce1-4f05-898b-ecf8346ba5f3

📥 Commits

Reviewing files that changed from the base of the PR and between 938dcac and 71f1074.

📒 Files selected for processing (14)
  • docs/a2a_protocol.md
  • docs/openapi.json
  • examples/lightspeed-stack-a2a-agents.yaml
  • src/a2a_client/__init__.py
  • src/a2a_client/capability.py
  • src/a2a_client/manager.py
  • src/app/main.py
  • src/configuration.py
  • src/models/config.py
  • src/utils/pydantic_ai.py
  • tests/unit/a2a_client/__init__.py
  • tests/unit/a2a_client/test_capability.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/models/config/test_dump_configuration.py
📜 Review details
⏰ Context from checks skipped due to timeout. (7)
  • GitHub Check: E2E Tests for Lightspeed Evaluation job
  • GitHub Check: E2E: server mode / ci / group 2
  • GitHub Check: E2E: library mode / ci / group 2
  • GitHub Check: E2E: library mode / ci / group 1
  • GitHub Check: E2E: server mode / ci / group 1
  • GitHub Check: E2E: server mode / ci / group 3
  • GitHub Check: E2E: library mode / ci / group 3
🧰 Additional context used
📓 Path-based instructions (8)
**/*

📄 CodeRabbit inference engine (Custom checks)

**/*: Flag meaningful O(n^2)+ algorithms on non-trivial inputs, including handlers and Kubernetes list operations.
Flag N+1 patterns that list items and then query once per item, including Kubernetes API and database access.
Flag expensive work inside loops, including API calls, JSON parsing, and regex compilation.
Flag unbounded growth in caches, watchers, or buffers when eviction or limits are missing.
Flag missing pagination or limits on list operations and API endpoints.
Flag secrets or tokens logged in plaintext or hardcoded in source.
Flag API endpoints missing authentication or authorization.
Flag injection vulnerabilities, including SQL injection, command injection, and path traversal.
Flag sensitive data leaked in API responses, WebSocket messages, or logs.
Flag Kubernetes Secrets and Red Hat secrets missing OwnerReferences.

Files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
  • examples/lightspeed-stack-a2a-agents.yaml
  • src/a2a_client/capability.py
  • docs/openapi.json
  • src/configuration.py
  • src/a2a_client/manager.py
  • src/app/main.py
  • src/utils/pydantic_ai.py
  • src/models/config.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
  • docs/a2a_protocol.md
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use absolute imports for internal Python modules.
Start every module with a descriptive docstring and use logger = get_logger(__name__) for module logging.
Define shared constants in the central constants.py module, use descriptive comments, and annotate constants with Final[type].
Use complete type annotations for function parameters and return values, modern union syntax, and typing_extensions.Self for model validators.
Document all modules, classes, and functions using Google-style Python docstrings, including applicable Parameters, Returns, Raises, and Attributes sections.
Use descriptive snake_case, action-oriented function names such as get_, validate_, and check_.
Avoid modifying input parameters in place; return a newly created data structure instead.
Use async def for I/O operations and external API calls.
Use standard logger levels appropriately: debug for diagnostics, info for normal execution, warning for unexpected conditions, and error for serious failures.
Name classes with PascalCase and use descriptive suffixes such as Configuration, Error/Exception, Resolver, and Interface where applicable.
Use ABC and @abstractmethod for abstract interfaces; provide complete, specific type annotations for class attributes and avoid Any.

Files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
  • src/a2a_client/capability.py
  • src/configuration.py
  • src/a2a_client/manager.py
  • src/app/main.py
  • src/utils/pydantic_ai.py
  • src/models/config.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
**/__init__.py

📄 CodeRabbit inference engine (AGENTS.md)

Keep package __init__.py files limited to brief package descriptions.

Files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
tests/unit/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use pytest for unit tests, shared fixtures in conftest.py, pytest-mock for mocks, and pytest.mark.asyncio for asynchronous tests; do not use unittest.

Files:

  • tests/unit/a2a_client/__init__.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain at least 60% unit-test coverage and 10% integration-test coverage.

Files:

  • tests/unit/a2a_client/__init__.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
**/*.{py,yaml,yml,json,toml}

📄 CodeRabbit inference engine (AGENTS.md)

Never commit secrets or keys; use environment variables for sensitive data.

Files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
  • examples/lightspeed-stack-a2a-agents.yaml
  • src/a2a_client/capability.py
  • docs/openapi.json
  • src/configuration.py
  • src/a2a_client/manager.py
  • src/app/main.py
  • src/utils/pydantic_ai.py
  • src/models/config.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Configuration models must extend ConfigurationBase, whose extra="forbid" behavior rejects unknown fields; use types such as Optional[FilePath], PositiveInt, and SecretStr where appropriate.

Files:

  • src/a2a_client/__init__.py
  • src/a2a_client/capability.py
  • src/configuration.py
  • src/a2a_client/manager.py
  • src/app/main.py
  • src/utils/pydantic_ai.py
  • src/models/config.py
src/models/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use ConfigurationBase for configuration Pydantic models and BaseModel for data models; use @model_validator and @field_validator for validation.

Files:

  • src/models/config.py
🧠 Learnings (5)
📚 Learning: 2026-06-24T13:45:37.249Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 1971
File: src/utils/markdown_repair.py:31-36
Timestamp: 2026-06-24T13:45:37.249Z
Learning: In the lightspeed-stack repository, docstrings must use the section header name "Parameters:" (not "Args:") for function arguments, even if the project references Google Python docstring conventions. Ensure docstrings follow the project’s established "Parameters:" header format for any documented function parameters.

Applied to files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
  • src/a2a_client/capability.py
  • src/configuration.py
  • src/a2a_client/manager.py
  • src/app/main.py
  • src/utils/pydantic_ai.py
  • src/models/config.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
📚 Learning: 2026-07-06T15:26:18.398Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2071
File: src/models/config.py:2416-2422
Timestamp: 2026-07-06T15:26:18.398Z
Learning: In this repo’s Python code under src/**, don’t treat differences in string concatenation style as a style inconsistency when Black has effectively forced (or made clearer) use of explicit `+` string concatenation in multi-line logger/string expressions. If adjacent-literal implicit concatenation is avoided/changed specifically to accommodate Black’s formatting in these call sites, accept the `+` usage and don’t recommend converting it solely for consistency with nearby blocks that use implicit concatenation.

Applied to files:

  • src/a2a_client/__init__.py
  • src/a2a_client/capability.py
  • src/configuration.py
  • src/a2a_client/manager.py
  • src/app/main.py
  • src/utils/pydantic_ai.py
  • src/models/config.py
📚 Learning: 2026-05-20T08:09:30.641Z
Learnt from: max-svistunov
Repo: lightspeed-core/lightspeed-stack PR: 1580
File: docs/design/llama-stack-config-merge/poc-results/library-mode/synthesized-run.yaml:107-110
Timestamp: 2026-05-20T08:09:30.641Z
Learning: In Llama-stack config YAMLs, when defining a Llama Guard safety shield entry, set `provider_shield_id` to the *guard model identifier* (e.g., `meta-llama/Llama-Guard-3-8B`). Do not use a chat/generative model id (e.g., `openai/gpt-4o-mini`): a chat-model id (or `native_override`) indicates only an override landed and does **not** mean the safety shield is actually gating queries. Ensure any E2E coverage for the related implementation (JIRA/E2E tests) exercises a real Llama Guard model to verify that the shield is effective.

Applied to files:

  • examples/lightspeed-stack-a2a-agents.yaml
📚 Learning: 2026-01-12T10:58:40.230Z
Learnt from: blublinsky
Repo: lightspeed-core/lightspeed-stack PR: 972
File: src/models/config.py:459-513
Timestamp: 2026-01-12T10:58:40.230Z
Learning: In lightspeed-core/lightspeed-stack, for Python files under src/models, when a user claims a fix is done but the issue persists, verify the current code state before accepting the fix. Steps: review the diff, fetch the latest changes, run relevant tests, reproduce the issue, search the codebase for lingering references to the original problem, confirm the fix is applied and not undone by subsequent commits, and validate with local checks to ensure the issue is resolved.

Applied to files:

  • src/models/config.py
📚 Learning: 2026-02-25T07:46:33.545Z
Learnt from: asimurka
Repo: lightspeed-core/lightspeed-stack PR: 1211
File: src/models/responses.py:8-16
Timestamp: 2026-02-25T07:46:33.545Z
Learning: In the Python codebase, requests.py should use OpenAIResponseInputTool as Tool while responses.py uses OpenAIResponseTool as Tool. This difference is intentional due to differing schemas for input vs output tools in llama-stack-api. Apply this distinction consistently to other models under src/models (e.g., ensure request-related tools use the InputTool variant and response-related tools use the ResponseTool variant). If adding new tools, choose the corresponding InputTool or Tool class based on whether the tool represents input or output, and document the rationale in code comments.

Applied to files:

  • src/models/config.py
🪛 Checkov (3.3.8)
docs/openapi.json

[medium] 10768-10775: Ensure that arrays have a maximum number of items

(CKV_OPENAPI_21)

🔇 Additional comments (11)
tests/unit/a2a_client/__init__.py (1)

1-1: LGTM!

src/models/config.py (1)

1981-2034: LGTM!

Also applies to: 2727-2732

docs/openapi.json (2)

10714-10781: LGTM!


12230-12241: LGTM!

examples/lightspeed-stack-a2a-agents.yaml (1)

1-42: LGTM!

tests/unit/models/config/test_dump_configuration.py (1)

212-212: LGTM!

Also applies to: 436-436, 811-811, 1070-1070, 1309-1309, 1528-1528, 1907-1907, 2132-2132, 2357-2357, 2589-2589

docs/a2a_protocol.md (1)

7-10: LGTM!

Also applies to: 316-317, 792-819

src/app/main.py (1)

17-17: LGTM!

Also applies to: 132-136

src/utils/pydantic_ai.py (1)

15-16: LGTM!

Also applies to: 199-202, 219-222

src/a2a_client/manager.py (1)

102-108: 🎯 Functional Correctness

ClientFactory.connect is part of the supported a2a-sdk API.

			> Likely an incorrect or invalid review comment.
tests/unit/a2a_client/test_manager.py (1)

72-75: 🎯 Functional Correctness

No change needed for ClientFactory.connect This test matches src/a2a_client/manager.py's use of ClientFactory.connect, so the API mismatch is not present.

			> Likely an incorrect or invalid review comment.

Comment thread src/a2a_client/__init__.py
Comment thread src/a2a_client/capability.py Outdated
Comment thread src/a2a_client/capability.py
Comment thread src/a2a_client/capability.py
Comment on lines +130 to +142
agents = self._manager.list_agents()
if not agents:
return None
lines = ["You can delegate tasks to these external agents when appropriate:"]
for name, card in agents.items():
skills_text = ""
if card.skills:
skill_names = [s.name for s in card.skills if s.name]
if skill_names:
skills_text = f" (skills: {', '.join(skill_names)})"
lines.append(
f"- {name}: {card.description or 'No description'}{skills_text}"
)

@coderabbitai coderabbitai Bot Jul 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Do not place untrusted agent-card prose directly in system instructions.

A remote agent controls its description and skill names, allowing a compromised endpoint to inject model instructions. Restrict this prompt to validated identifiers or encode remote metadata as explicitly untrusted data.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/a2a_client/capability.py` around lines 130 - 142, Update the agent-list
prompt construction in the capability method around self._manager.list_agents()
so remote card.description and skill names are not inserted as trusted
system-instruction prose. Restrict displayed metadata to validated identifiers,
or clearly encode the description and skills as untrusted data while preserving
the delegation list and agent names.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not relevant, the agent card is needed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@are-ces, agreed that the agent card is needed for agent discovery and selection. The concern is not fetching or using it—it is interpolating endpoint-controlled descriptions and skill names as trusted system-prompt prose.

The card can still be exposed to the model while marking that content as untrusted data (or limiting prompt content to agent identifiers). That preserves delegation functionality while preventing a remote endpoint from injecting instructions into the orchestrator’s system context.

🐇💭

Comment thread src/a2a_client/capability.py
Comment thread src/a2a_client/manager.py Outdated
Comment thread src/a2a_client/manager.py
Comment on lines +97 to +113
transport = httpx.AsyncHTTPTransport(retries=agent_config.max_retries)
httpx_client = httpx.AsyncClient(
timeout=httpx.Timeout(agent_config.timeout),
transport=transport,
)
client = await ClientFactory.connect(
url,
client_config=ClientConfig(
streaming=True, httpx_client=httpx_client
),
interceptors=interceptors or None,
)
card = await client.get_card()
self._clients[name] = client
self._cards[name] = card
logger.info("Connected to A2A agent '%s' at %s", name, url)
except (A2AClientError, httpx.HTTPError, OSError) as e:

@coderabbitai coderabbitai Bot Jul 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Close partially created connections when discovery fails.

If connection or card retrieval raises, httpx_client and possibly client are neither cached nor closed. Explicitly close the partially initialized resource in the exception path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/a2a_client/manager.py` around lines 97 - 113, Update the exception path
surrounding ClientFactory.connect and client.get_card in the connection manager
to close any partially initialized client and its httpx_client before handling
or logging the error. Ensure cleanup is conditional and safe when either
resource was never created, while preserving caching only after successful card
retrieval.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressing in new commit

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@are-ces, thanks — I’ll verify the cleanup path once the new commit is available.

Comment thread src/a2a_client/manager.py
Comment thread src/configuration.py
Comment on lines +431 to +437
@property
def a2a_agents(self) -> A2AAgentsConfiguration | None:
"""Return A2A clients configuration."""
if self._configuration is None:
raise LogicError("logic error: configuration is not loaded")
return self._configuration.a2a_agents

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Include Returns: and Raises: in the property docstring.

As per coding guidelines, all functions and properties must be documented using Google-style Python docstrings, including applicable Returns: and Raises: sections. Since this property dynamically raises a LogicError and returns a specific type, these details should be explicitly documented to match the surrounding properties (like database_configuration).

📝 Proposed docstring fix
     `@property`
     def a2a_agents(self) -> A2AAgentsConfiguration | None:
-        """Return A2A clients configuration."""
+        """Return A2A clients configuration.
+
+        Returns:
+            A2AAgentsConfiguration | None: The configured A2A agents or None if not set.
+
+        Raises:
+            LogicError: If the configuration has not been loaded.
+        """
         if self._configuration is None:
             raise LogicError("logic error: configuration is not loaded")
         return self._configuration.a2a_agents
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@property
def a2a_agents(self) -> A2AAgentsConfiguration | None:
"""Return A2A clients configuration."""
if self._configuration is None:
raise LogicError("logic error: configuration is not loaded")
return self._configuration.a2a_agents
`@property`
def a2a_agents(self) -> A2AAgentsConfiguration | None:
"""Return A2A clients configuration.
Returns:
A2AAgentsConfiguration | None: The configured A2A agents or None if not set.
Raises:
LogicError: If the configuration has not been loaded.
"""
if self._configuration is None:
raise LogicError("logic error: configuration is not loaded")
return self._configuration.a2a_agents
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/configuration.py` around lines 431 - 437, Update the a2a_agents property
docstring to use the Google-style format, adding a Returns section for its
A2AAgentsConfiguration | None result and a Raises section documenting LogicError
when _configuration is not loaded.

Source: Coding guidelines

@are-ces
are-ces force-pushed the lcore-2914-a2a-client-discovery branch from 60029d6 to 6afc62d Compare July 20, 2026 08:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/user_doc/a2a_protocol.md (1)

1-1: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Align environment variable interpolation syntax with the working example.

The documentation examples omit the env. prefix for environment variable interpolation, which is inconsistent with the working configuration in examples/lightspeed-stack-a2a-agents.yaml. Using the incorrect syntax may cause configuration parsing errors for users copying these snippets.

  • docs/user_doc/a2a_protocol.md#L834-834: Update the token example to use ${env.ANSIBLE_AGENT_TOKEN}.
  • docs/user_doc/a2a_protocol.md#L872-872: Update the token example to use ${env.MY_AGENT_TOKEN}.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/user_doc/a2a_protocol.md` at line 1, Update the token interpolation
examples in the A2A protocol documentation to include the env. prefix: use
${env.ANSIBLE_AGENT_TOKEN} and ${env.MY_AGENT_TOKEN} in the examples identified
by their respective token names. Leave all other documentation unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unit/a2a_client/test_capability.py`:
- Around line 56-84: Add unit tests in TestA2ADelegationCapability that retrieve
and invoke the delegate_to_agent tool from capability.get_toolset(), covering
both wrapper branches: assert ModelRetry when manager.get_client() returns None,
and assert the expected delegation-failure string when the client raises
A2AClientError. Ensure these tests exercise the closure itself rather than
bypassing it through _send_and_collect.

---

Outside diff comments:
In `@docs/user_doc/a2a_protocol.md`:
- Line 1: Update the token interpolation examples in the A2A protocol
documentation to include the env. prefix: use ${env.ANSIBLE_AGENT_TOKEN} and
${env.MY_AGENT_TOKEN} in the examples identified by their respective token
names. Leave all other documentation unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 62038b57-59c7-4faa-ac61-0c6742c5d2fb

📥 Commits

Reviewing files that changed from the base of the PR and between 71f1074 and 6afc62d.

📒 Files selected for processing (14)
  • docs/devel_doc/openapi.json
  • docs/user_doc/a2a_protocol.md
  • examples/lightspeed-stack-a2a-agents.yaml
  • src/a2a_client/__init__.py
  • src/a2a_client/capability.py
  • src/a2a_client/manager.py
  • src/app/main.py
  • src/configuration.py
  • src/models/config.py
  • src/utils/pydantic_ai_helpers.py
  • tests/unit/a2a_client/__init__.py
  • tests/unit/a2a_client/test_capability.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/models/config/test_dump_configuration.py
📜 Review details
⏰ Context from checks skipped due to timeout. (10)
  • GitHub Check: integration_tests (3.13)
  • GitHub Check: integration_tests (3.12)
  • GitHub Check: build-pr
  • GitHub Check: E2E: library mode / ci / group 1
  • GitHub Check: E2E: server mode / ci / group 2
  • GitHub Check: E2E: library mode / ci / group 2
  • GitHub Check: E2E: server mode / ci / group 1
  • GitHub Check: E2E: server mode / ci / group 3
  • GitHub Check: E2E: library mode / ci / group 3
  • GitHub Check: E2E Tests for Lightspeed Evaluation job
🧰 Additional context used
📓 Path-based instructions (4)
**/*

📄 CodeRabbit inference engine (Custom checks)

**/*: Flag meaningful O(n^2)+ algorithms on non-trivial inputs, including handlers and Kubernetes list operations.
Flag N+1 patterns that list items and then query once per item, including Kubernetes API and database access.
Flag expensive work inside loops, including API calls, JSON parsing, and regex compilation.
Flag unbounded growth in caches, watchers, or buffers when eviction or limits are missing.
Flag missing pagination or limits on list operations and API endpoints.
Flag secrets or tokens logged in plaintext or hardcoded in source.
Flag API endpoints missing authentication or authorization.
Flag injection vulnerabilities, including SQL injection, command injection, and path traversal.
Flag sensitive data leaked in API responses, WebSocket messages, or logs.
Flag Kubernetes Secrets and Red Hat secrets missing OwnerReferences.

Never commit secrets or keys; use environment variables for sensitive data.

Files:

  • src/a2a_client/__init__.py
  • examples/lightspeed-stack-a2a-agents.yaml
  • tests/unit/a2a_client/__init__.py
  • src/configuration.py
  • docs/devel_doc/openapi.json
  • docs/user_doc/a2a_protocol.md
  • src/a2a_client/manager.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
  • src/utils/pydantic_ai_helpers.py
  • src/models/config.py
  • src/app/main.py
  • src/a2a_client/capability.py
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.py: Use absolute imports for internal Python modules, complete type annotations, descriptive snake_case names, and module docstrings.
Every module, class, and function must have a descriptive Google-style docstring; document parameters, returns, raises, and class attributes where applicable.
Use logger = get_logger(__name__) from log.py for module logging and apply debug, info, warning, and error levels appropriately.
Use Final[type] annotations for constants and define shared constants in constants.py with descriptive comments.
Use async def for I/O operations and external API calls, and avoid modifying mutable parameters in place; return newly constructed data instead.
Use modern union syntax such as str | int, Optional[Type] for optional values, and typing_extensions.Self for model validators.
All configuration must use Pydantic models extending ConfigurationBase; configuration must reject unknown fields with extra="forbid".
Use @field_validator and @model_validator for custom Pydantic validation; use specific types such as Optional[FilePath], PositiveInt, and SecretStr.
Classes require descriptive docstrings, PascalCase names, complete typed attributes, and specific types instead of Any.
Use ABC and @abstractmethod for abstract interfaces; use standard suffixes such as Configuration, Error/Exception, Resolver, and Interface where applicable.

Files:

  • src/a2a_client/__init__.py
  • src/configuration.py
  • src/a2a_client/manager.py
  • src/utils/pydantic_ai_helpers.py
  • src/models/config.py
  • src/app/main.py
  • src/a2a_client/capability.py
tests/unit/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

tests/unit/**/*.py: Use pytest for unit tests, shared fixtures in conftest.py, pytest-mock for mocks, and pytest.mark.asyncio for async tests.
Maintain at least 60% unit-test coverage; add unit tests for new functionality.

Files:

  • tests/unit/a2a_client/__init__.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
src/models/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Pydantic configuration models extend ConfigurationBase, while data models extend BaseModel; use Pydantic validators for validation.

Files:

  • src/models/config.py
🧠 Learnings (6)
📚 Learning: 2026-06-24T13:45:37.249Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 1971
File: src/utils/markdown_repair.py:31-36
Timestamp: 2026-06-24T13:45:37.249Z
Learning: In the lightspeed-stack repository, docstrings must use the section header name "Parameters:" (not "Args:") for function arguments, even if the project references Google Python docstring conventions. Ensure docstrings follow the project’s established "Parameters:" header format for any documented function parameters.

Applied to files:

  • src/a2a_client/__init__.py
  • tests/unit/a2a_client/__init__.py
  • src/configuration.py
  • src/a2a_client/manager.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
  • src/utils/pydantic_ai_helpers.py
  • src/models/config.py
  • src/app/main.py
  • src/a2a_client/capability.py
📚 Learning: 2026-07-06T15:26:18.398Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2071
File: src/models/config.py:2416-2422
Timestamp: 2026-07-06T15:26:18.398Z
Learning: In this repo’s Python code under src/**, don’t treat differences in string concatenation style as a style inconsistency when Black has effectively forced (or made clearer) use of explicit `+` string concatenation in multi-line logger/string expressions. If adjacent-literal implicit concatenation is avoided/changed specifically to accommodate Black’s formatting in these call sites, accept the `+` usage and don’t recommend converting it solely for consistency with nearby blocks that use implicit concatenation.

Applied to files:

  • src/a2a_client/__init__.py
  • src/configuration.py
  • src/a2a_client/manager.py
  • src/utils/pydantic_ai_helpers.py
  • src/models/config.py
  • src/app/main.py
  • src/a2a_client/capability.py
📚 Learning: 2026-07-17T19:25:05.325Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2166
File: src/utils/saved_prompts.py:129-157
Timestamp: 2026-07-17T19:25:05.325Z
Learning: For any endpoint that handles saved prompts and calls `src/utils/saved_prompts.py::create_saved_prompt`, treat the endpoint as the validation boundary. Before calling `create_saved_prompt`, validate the incoming saved-prompt name and content, specifically using `validate_saved_prompt_name` and then persist (store) the normalized value it returns. Do not call `create_saved_prompt` with unvalidated/raw name/content.

Applied to files:

  • src/a2a_client/__init__.py
  • src/configuration.py
  • src/a2a_client/manager.py
  • src/utils/pydantic_ai_helpers.py
  • src/models/config.py
  • src/app/main.py
  • src/a2a_client/capability.py
📚 Learning: 2026-05-20T08:09:30.641Z
Learnt from: max-svistunov
Repo: lightspeed-core/lightspeed-stack PR: 1580
File: docs/design/llama-stack-config-merge/poc-results/library-mode/synthesized-run.yaml:107-110
Timestamp: 2026-05-20T08:09:30.641Z
Learning: In Llama-stack config YAMLs, when defining a Llama Guard safety shield entry, set `provider_shield_id` to the *guard model identifier* (e.g., `meta-llama/Llama-Guard-3-8B`). Do not use a chat/generative model id (e.g., `openai/gpt-4o-mini`): a chat-model id (or `native_override`) indicates only an override landed and does **not** mean the safety shield is actually gating queries. Ensure any E2E coverage for the related implementation (JIRA/E2E tests) exercises a real Llama Guard model to verify that the shield is effective.

Applied to files:

  • examples/lightspeed-stack-a2a-agents.yaml
📚 Learning: 2026-01-12T10:58:40.230Z
Learnt from: blublinsky
Repo: lightspeed-core/lightspeed-stack PR: 972
File: src/models/config.py:459-513
Timestamp: 2026-01-12T10:58:40.230Z
Learning: In lightspeed-core/lightspeed-stack, for Python files under src/models, when a user claims a fix is done but the issue persists, verify the current code state before accepting the fix. Steps: review the diff, fetch the latest changes, run relevant tests, reproduce the issue, search the codebase for lingering references to the original problem, confirm the fix is applied and not undone by subsequent commits, and validate with local checks to ensure the issue is resolved.

Applied to files:

  • src/models/config.py
📚 Learning: 2026-02-25T07:46:33.545Z
Learnt from: asimurka
Repo: lightspeed-core/lightspeed-stack PR: 1211
File: src/models/responses.py:8-16
Timestamp: 2026-02-25T07:46:33.545Z
Learning: In the Python codebase, requests.py should use OpenAIResponseInputTool as Tool while responses.py uses OpenAIResponseTool as Tool. This difference is intentional due to differing schemas for input vs output tools in llama-stack-api. Apply this distinction consistently to other models under src/models (e.g., ensure request-related tools use the InputTool variant and response-related tools use the ResponseTool variant). If adding new tools, choose the corresponding InputTool or Tool class based on whether the tool represents input or output, and document the rationale in code comments.

Applied to files:

  • src/models/config.py
🪛 Checkov (3.3.8)
docs/devel_doc/openapi.json

[medium] 10931-10938: Ensure that arrays have a maximum number of items

(CKV_OPENAPI_21)

🪛 GitHub Check: Bandit
src/a2a_client/manager.py

[warning] 98-99:
Call to httpx without timeout

🔇 Additional comments (24)
src/configuration.py (2)

431-437: Include Returns: and Raises: in the property docstring.

As per coding guidelines, all functions and properties must be documented using Google-style Python docstrings, including applicable Returns: and Raises: sections. Since this property dynamically raises a LogicError and returns a specific type, these details should be explicitly documented.

📝 Proposed docstring fix
     `@property`
     def a2a_agents(self) -> A2AAgentsConfiguration | None:
-        """Return A2A clients configuration."""
+        """Return A2A clients configuration.
+
+        Returns:
+            A2AAgentsConfiguration | None: The configured A2A agents or None if not set.
+
+        Raises:
+            LogicError: If the configuration has not been loaded.
+        """
         if self._configuration is None:
             raise LogicError("logic error: configuration is not loaded")
         return self._configuration.a2a_agents

Source: Coding guidelines


16-16: LGTM!

src/models/config.py (1)

670-761: LGTM!

Also applies to: 2025-2078, 2771-2776

docs/devel_doc/openapi.json (1)

6934-7096: LGTM!

Also applies to: 10877-10944, 12393-12404, 19517-19560, 20438-20450, 21387-21390

examples/lightspeed-stack-a2a-agents.yaml (1)

1-42: LGTM!

tests/unit/models/config/test_dump_configuration.py (1)

212-212: LGTM!

Also applies to: 436-436, 811-811, 1070-1070, 1309-1309, 1528-1528, 1907-1907, 2132-2132, 2357-2357, 2589-2589

tests/unit/a2a_client/__init__.py (1)

1-2: LGTM!

docs/user_doc/a2a_protocol.md (1)

7-10: LGTM!

Also applies to: 316-317

src/a2a_client/manager.py (4)

55-58: 🔒 Security & Privacy

Mutates caller-owned headers/http_kwargs.

headers = http_kwargs.get("headers", {}) mutates the caller's dict in place and writes it back; copy both before injecting the Authorization header.


79-126: 🩺 Stability & Availability

Partial httpx_client/client not closed on connection failure.

If ClientFactory.connect or client.get_card() raises, the created httpx_client (and possibly client) is neither cached nor closed, leaking the connection. Close it in the exception path.

The Bandit hint on L98-99 ("httpx without timeout") is a false positive — timeout=httpx.Timeout(agent_config.timeout) is passed explicitly at L99.


128-148: 📐 Maintainability & Code Quality

Use ... | None instead of Optional[...] for consistency with the rest of this A2A surface.

intercept's agent_card: AgentCard | None param already uses modern syntax; get_client/get_card should match.


61-78: LGTM!

Also applies to: 150-173

src/a2a_client/__init__.py (1)

3-9: 📐 Maintainability & Code Quality

Package initializer should stay description-only.

Move the A2ADelegationCapability/A2AClientManager imports to their consumers and drop __all__.

src/a2a_client/capability.py (6)

51-52: 📐 Maintainability & Code Quality

Replace Any with concrete A2AClientManager type.


87-93: 📐 Maintainability & Code Quality

Use Parameters: instead of Args: in the docstring.

Based on learnings, this repository requires the Parameters: header for documented function arguments.


101-103: 🔒 Security & Privacy

Don't log the raw delegated task content.

task may contain user prompts or sensitive data; log only the target agent name.


124-147: 🔒 Security & Privacy

Untrusted remote agent-card text is embedded directly into system instructions.

card.description/skill names are attacker-controlled if the remote agent is compromised, allowing prompt injection via get_instructions().


150-182: 🎯 Functional Correctness

Only TaskState.failed is handled as terminal; rejected/canceled are not.

Those states currently fall through to the generic "Agent returned no response." instead of surfacing a delegation failure to the LLM.


1-49: LGTM!

Also applies to: 59-75, 94-100, 116-123

tests/unit/a2a_client/test_capability.py (2)

178-210: 🎯 Functional Correctness

Extend terminal-state coverage to rejected/canceled, matching the capability.py fix.


1-53: LGTM!

Also applies to: 85-176, 211-232

src/app/main.py (1)

17-17: LGTM!

Also applies to: 136-143, 155-155

tests/unit/a2a_client/test_manager.py (1)

1-193: LGTM!

src/utils/pydantic_ai_helpers.py (1)

14-15: LGTM!

Also applies to: 133-144, 161-162

Comment thread tests/unit/a2a_client/test_capability.py

@are-ces are-ces left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressing Coderabbit's comments in next commit

are-ces and others added 2 commits July 21, 2026 14:08
Enable LCS to discover and delegate tasks to external A2A-compliant
agents. The delegation is exposed as a pydantic-ai capability, so any
agent-powered endpoint (query, streaming, A2A) can use it.

- A2AAgentsConfiguration: YAML config for remote agent endpoints
  with timeout, max_retries, and optional auth_token
- A2AClientManager: singleton that resolves agent cards at startup
  and holds Client instances with httpx timeout/retry transport
- A2ADelegationCapability: pydantic-ai tools (list_agents,
  delegate_to_agent) auto-injected into build_agent()
- Startup/shutdown lifecycle wired into FastAPI lifespan
- A2A protocol docs updated with client documentation
- OpenAPI schema regenerated
- Example config: examples/lightspeed-stack-a2a-agents.yaml

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace Any with concrete types (A2AClientManager, Client) in capability.py
- Remove task content from debug log to avoid logging sensitive data
- Handle all terminal task states (failed, rejected, canceled) in _send_and_collect
- Copy request kwargs before injecting credentials in BearerTokenInterceptor
- Close httpx_client on connection failure in A2AClientManager.initialize
- Add tests for delegate_to_agent tool closure and terminal task states

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@are-ces
are-ces force-pushed the lcore-2914-a2a-client-discovery branch from 2ffd483 to 72dc26f Compare July 21, 2026 12:08
@are-ces
are-ces requested review from asimurka and tisnik July 21, 2026 13:24
@are-ces are-ces added the hold label Jul 22, 2026

@asimurka asimurka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@are-ces

are-ces commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/main.py (1)

151-155: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guarantee A2A cleanup when earlier shutdown work fails.

If shutdown_background_topic_summary_tasks() or A2AStorageFactory.cleanup() raises, line 155 is skipped and remote client resources remain open. Put A2AClientManager().close() in a finally block before flushing Sentry.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/main.py` around lines 151 - 155, Update the shutdown cleanup flow
around shutdown_background_topic_summary_tasks and A2AStorageFactory.cleanup so
A2AClientManager().close() runs from a finally block even when either earlier
cleanup step raises; keep it before the existing Sentry flush.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/user_doc/a2a_protocol.md`:
- Around line 316-317: Update the adjacent Event Flow diagram to represent the
Pydantic-AI path: show the executor invoking build_agent(), then
agent.run_stream_events(), and converting Pydantic-AI events into A2A events
instead of calling the Llama Stack Responses API or streaming response chunks
directly. Align all related actor and event labels with this flow.

In `@src/models/config.py`:
- Around line 2036-2040: Validate the agent name fields around the `name`
declarations at lines 2036 and 2072 during model validation: reject empty or
whitespace-only identifiers and detect duplicate names across the agent
collection. Perform these checks before the manager constructs its client/card
mappings, while preserving valid unique names.
- Around line 2041-2049: Update the configuration model containing url and
auth_token to validate that any configured auth_token requires an HTTPS URL;
reject HTTP endpoints during model validation, while preserving unauthenticated
HTTP configurations unless an existing explicitly scoped insecure-development
opt-in is used.

In `@tests/unit/a2a_client/test_manager.py`:
- Around line 27-50: Update the a2a_config and a2a_config_with_token fixtures to
return A2AAgentsConfiguration instead of Any, constructing the configuration or
using a typed cast as appropriate. Update dependent test parameters to use the
same concrete configuration type while preserving the existing mock agent values
and authentication behavior.

In `@tests/unit/models/config/test_dump_configuration.py`:
- Line 212: Update the dump tests in test_dump_configuration.py to construct at
least one Configuration with a populated a2a_agents entry containing
representative fields such as name, url, and auth_token. Assert the serialized
output preserves the expected a2a_agents shape while replacing auth_token with
the existing redaction value, matching the api_key/password redaction behavior
used elsewhere in the tests.

---

Outside diff comments:
In `@src/app/main.py`:
- Around line 151-155: Update the shutdown cleanup flow around
shutdown_background_topic_summary_tasks and A2AStorageFactory.cleanup so
A2AClientManager().close() runs from a finally block even when either earlier
cleanup step raises; keep it before the existing Sentry flush.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f2edeb98-3be9-4c3e-b072-b11beacf8e80

📥 Commits

Reviewing files that changed from the base of the PR and between 6afc62d and 72dc26f.

📒 Files selected for processing (14)
  • docs/devel_doc/openapi.json
  • docs/user_doc/a2a_protocol.md
  • examples/lightspeed-stack-a2a-agents.yaml
  • src/a2a_client/__init__.py
  • src/a2a_client/capability.py
  • src/a2a_client/manager.py
  • src/app/main.py
  • src/configuration.py
  • src/models/config.py
  • src/utils/pydantic_ai_helpers.py
  • tests/unit/a2a_client/__init__.py
  • tests/unit/a2a_client/test_capability.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/models/config/test_dump_configuration.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*

📄 CodeRabbit inference engine (Custom checks)

**/*: Flag meaningful O(n^2)+ algorithms on non-trivial inputs, including handlers and Kubernetes list operations.
Flag N+1 patterns that list items and then query once per item, including Kubernetes API and database access.
Flag expensive work inside loops, including API calls, JSON parsing, and regex compilation.
Flag unbounded growth in caches, watchers, or buffers when eviction or limits are missing.
Flag missing pagination or limits on list operations and API endpoints.
Flag secrets or tokens logged in plaintext or hardcoded in source.
Flag API endpoints missing authentication or authorization.
Flag injection vulnerabilities, including SQL injection, command injection, and path traversal.
Flag sensitive data leaked in API responses, WebSocket messages, or logs.
Flag Kubernetes Secrets and Red Hat secrets missing OwnerReferences.

Files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
  • examples/lightspeed-stack-a2a-agents.yaml
  • docs/devel_doc/openapi.json
  • src/utils/pydantic_ai_helpers.py
  • src/configuration.py
  • src/app/main.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
  • src/a2a_client/capability.py
  • tests/unit/models/config/test_dump_configuration.py
  • src/models/config.py
  • docs/user_doc/a2a_protocol.md
  • src/a2a_client/manager.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use absolute imports for internal Python modules.
All modules must begin with descriptive docstrings explaining their purpose.
Use logger = get_logger(__name__) from log.py for module logging.
Use complete type annotations for function parameters and return types.
Use modern union syntax such as str | int; use Optional[Type] for optional values.
Use typing_extensions.Self for model validators.
Functions must use descriptive, action-oriented snake_case names such as get_, validate_, and check_.
Avoid modifying mutable parameters in place; return a new data structure instead.
Use async def for I/O operations and external API calls.
Handle APIConnectionError from Llama Stack.
All classes must have descriptive docstrings and complete type annotations for class attributes; use specific types instead of Any.
Use PascalCase for classes and descriptive standard suffixes such as Configuration, Error/Exception, Resolver, and Interface.
Use ABC and @abstractmethod for abstract interfaces.
Follow Google Python docstring conventions; document all modules, classes, and functions, including Parameters, Returns, Raises, and Attributes sections as applicable.
Never commit secrets or keys; use environment variables for sensitive data.

Files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
  • src/utils/pydantic_ai_helpers.py
  • src/configuration.py
  • src/app/main.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
  • src/a2a_client/capability.py
  • tests/unit/models/config/test_dump_configuration.py
  • src/models/config.py
  • src/a2a_client/manager.py
**/__init__.py

📄 CodeRabbit inference engine (AGENTS.md)

Package __init__.py files must contain brief package descriptions.

Files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
tests/unit/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

tests/unit/**/*.py: Use pytest for all unit tests; do not use unittest.
Use conftest.py for shared fixtures, pytest-mock for AsyncMock objects, and pytest.mark.asyncio for asynchronous tests.

Files:

  • tests/unit/a2a_client/__init__.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
  • tests/unit/models/config/test_dump_configuration.py
src/models/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/models/**/*.py: Extend ConfigurationBase for configuration models and BaseModel for data models.
Use @model_validator and @field_validator for Pydantic model validation.

Files:

  • src/models/config.py
🧠 Learnings (7)
📚 Learning: 2026-06-24T13:45:37.249Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 1971
File: src/utils/markdown_repair.py:31-36
Timestamp: 2026-06-24T13:45:37.249Z
Learning: In the lightspeed-stack repository, docstrings must use the section header name "Parameters:" (not "Args:") for function arguments, even if the project references Google Python docstring conventions. Ensure docstrings follow the project’s established "Parameters:" header format for any documented function parameters.

Applied to files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
  • src/utils/pydantic_ai_helpers.py
  • src/configuration.py
  • src/app/main.py
  • tests/unit/a2a_client/test_manager.py
  • tests/unit/a2a_client/test_capability.py
  • src/a2a_client/capability.py
  • tests/unit/models/config/test_dump_configuration.py
  • src/models/config.py
  • src/a2a_client/manager.py
📚 Learning: 2026-07-21T11:10:05.060Z
Learnt from: are-ces
Repo: lightspeed-core/lightspeed-stack PR: 2162
File: src/a2a_client/__init__.py:3-9
Timestamp: 2026-07-21T11:10:05.060Z
Learning: In this repository, it is acceptable for Python package `__init__.py` files to contain functional code (not only docstrings/metadata) and to perform package-level re-exports. Do not flag `__init__.py` solely for containing imports or other logic used to re-export symbols; this is allowed when it’s implemented via imports and `__all__` (or otherwise clearly intended to define the package’s public API).

Applied to files:

  • tests/unit/a2a_client/__init__.py
  • src/a2a_client/__init__.py
📚 Learning: 2026-07-06T15:26:18.398Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2071
File: src/models/config.py:2416-2422
Timestamp: 2026-07-06T15:26:18.398Z
Learning: In this repo’s Python code under src/**, don’t treat differences in string concatenation style as a style inconsistency when Black has effectively forced (or made clearer) use of explicit `+` string concatenation in multi-line logger/string expressions. If adjacent-literal implicit concatenation is avoided/changed specifically to accommodate Black’s formatting in these call sites, accept the `+` usage and don’t recommend converting it solely for consistency with nearby blocks that use implicit concatenation.

Applied to files:

  • src/a2a_client/__init__.py
  • src/utils/pydantic_ai_helpers.py
  • src/configuration.py
  • src/app/main.py
  • src/a2a_client/capability.py
  • src/models/config.py
  • src/a2a_client/manager.py
📚 Learning: 2026-07-17T19:25:05.325Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2166
File: src/utils/saved_prompts.py:129-157
Timestamp: 2026-07-17T19:25:05.325Z
Learning: For any endpoint that handles saved prompts and calls `src/utils/saved_prompts.py::create_saved_prompt`, treat the endpoint as the validation boundary. Before calling `create_saved_prompt`, validate the incoming saved-prompt name and content, specifically using `validate_saved_prompt_name` and then persist (store) the normalized value it returns. Do not call `create_saved_prompt` with unvalidated/raw name/content.

Applied to files:

  • src/a2a_client/__init__.py
  • src/utils/pydantic_ai_helpers.py
  • src/configuration.py
  • src/app/main.py
  • src/a2a_client/capability.py
  • src/models/config.py
  • src/a2a_client/manager.py
📚 Learning: 2026-05-20T08:09:30.641Z
Learnt from: max-svistunov
Repo: lightspeed-core/lightspeed-stack PR: 1580
File: docs/design/llama-stack-config-merge/poc-results/library-mode/synthesized-run.yaml:107-110
Timestamp: 2026-05-20T08:09:30.641Z
Learning: In Llama-stack config YAMLs, when defining a Llama Guard safety shield entry, set `provider_shield_id` to the *guard model identifier* (e.g., `meta-llama/Llama-Guard-3-8B`). Do not use a chat/generative model id (e.g., `openai/gpt-4o-mini`): a chat-model id (or `native_override`) indicates only an override landed and does **not** mean the safety shield is actually gating queries. Ensure any E2E coverage for the related implementation (JIRA/E2E tests) exercises a real Llama Guard model to verify that the shield is effective.

Applied to files:

  • examples/lightspeed-stack-a2a-agents.yaml
📚 Learning: 2026-01-12T10:58:40.230Z
Learnt from: blublinsky
Repo: lightspeed-core/lightspeed-stack PR: 972
File: src/models/config.py:459-513
Timestamp: 2026-01-12T10:58:40.230Z
Learning: In lightspeed-core/lightspeed-stack, for Python files under src/models, when a user claims a fix is done but the issue persists, verify the current code state before accepting the fix. Steps: review the diff, fetch the latest changes, run relevant tests, reproduce the issue, search the codebase for lingering references to the original problem, confirm the fix is applied and not undone by subsequent commits, and validate with local checks to ensure the issue is resolved.

Applied to files:

  • src/models/config.py
📚 Learning: 2026-02-25T07:46:33.545Z
Learnt from: asimurka
Repo: lightspeed-core/lightspeed-stack PR: 1211
File: src/models/responses.py:8-16
Timestamp: 2026-02-25T07:46:33.545Z
Learning: In the Python codebase, requests.py should use OpenAIResponseInputTool as Tool while responses.py uses OpenAIResponseTool as Tool. This difference is intentional due to differing schemas for input vs output tools in llama-stack-api. Apply this distinction consistently to other models under src/models (e.g., ensure request-related tools use the InputTool variant and response-related tools use the ResponseTool variant). If adding new tools, choose the corresponding InputTool or Tool class based on whether the tool represents input or output, and document the rationale in code comments.

Applied to files:

  • src/models/config.py
🔇 Additional comments (11)
src/configuration.py (2)

431-436: Previously reported: complete the property docstring.

Add Returns: for A2AAgentsConfiguration | None and Raises: for LogicError, as already requested in the previous review.

Source: Coding guidelines


16-16: LGTM!

docs/devel_doc/openapi.json (1)

10877-10944: LGTM!

Also applies to: 12393-12404

examples/lightspeed-stack-a2a-agents.yaml (1)

1-42: LGTM!

src/utils/pydantic_ai_helpers.py (1)

14-15: LGTM!

Also applies to: 133-144, 161-162

tests/unit/a2a_client/test_capability.py (1)

1-393: LGTM! The previously requested coverage for the delegate_to_agent closure (ModelRetry on missing agent, A2AClientError → failure string) is now present in TestDelegateToAgent (lines 89-151), resolving the earlier review comment.

src/a2a_client/manager.py (1)

107-120: Close the partially initialized A2A client when card discovery fails.

This remains covered by the existing review finding for this range.

src/a2a_client/capability.py (2)

88-90: Use Parameters: in this tool docstring.

This remains covered by the existing review finding for this range.


131-143: Treat remote agent-card text as untrusted prompt data.

This remains covered by the existing review finding for this range.

src/a2a_client/__init__.py (1)

1-9: LGTM!

tests/unit/a2a_client/__init__.py (1)

1-1: LGTM!

Comment on lines +316 to +317
3. **Builds Pydantic-AI Agent**: Uses `build_agent()` with the same capabilities as the query/streaming endpoints (skills, A2A delegation)
4. **Streams via Agent**: Runs `agent.run_stream_events()` and converts pydantic-ai events to A2A events

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the adjacent Event Flow diagram for the Pydantic-AI execution path.

The diagram below still says the executor calls the Llama Stack Responses API and streams response chunks directly, contradicting the new build_agent() / run_stream_events() flow. Align that diagram and its event labels with the implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/user_doc/a2a_protocol.md` around lines 316 - 317, Update the adjacent
Event Flow diagram to represent the Pydantic-AI path: show the executor invoking
build_agent(), then agent.run_stream_events(), and converting Pydantic-AI events
into A2A events instead of calling the Llama Stack Responses API or streaming
response chunks directly. Align all related actor and event labels with this
flow.

Comment thread src/models/config.py
Comment on lines +2036 to +2040
name: str = Field(
...,
title="Agent name",
description="Unique identifier for this agent, used by the delegation tool.",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate A2A agent identifiers.

The field documentation promises a unique agent identifier, but empty/whitespace names and duplicate names are currently accepted. Reject invalid names and duplicate entries during model validation before the manager constructs its client/card mappings.

Also applies to: 2072-2076

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/models/config.py` around lines 2036 - 2040, Validate the agent name
fields around the `name` declarations at lines 2036 and 2072 during model
validation: reject empty or whitespace-only identifiers and detect duplicate
names across the agent collection. Perform these checks before the manager
constructs its client/card mappings, while preserving valid unique names.

Comment thread src/models/config.py
Comment on lines +2041 to +2049
url: AnyHttpUrl = Field(
...,
title="Agent URL",
description="Base URL of the external A2A agent.",
)
auth_token: Optional[SecretStr] = Field(
default=None,
title="Auth token",
description="Static bearer token for authenticating with this agent.",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
git ls-files | grep -x 'src/models/config.py' || true

echo "== relevant definitions around A2A endpoint =="
sed -n '2010,2075p' src/models/config.py

echo "== model validators/usages =="
rg -n "A2AAgentEndpointConfiguration|validate|validator|Field|any_url|HttpUrl|AnyHttpUrl|allow_http|auth_token" src/models/config.py

echo "== pydantic/url model version in requirements =="
for f in pyproject.toml requirements.txt requirements-dev.txt Pipfile poetry.lock uv.lock; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    grep -iE "pydantic|pydantic-settings|pydantic-core|httpx|requests" "$f" || true
  fi
done

Repository: lightspeed-core/lightspeed-stack

Length of output: 38910


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from typing import Optional
try:
    from pydantic import BaseModel, Field, ValidationError
    from pydantic.networks import AnyHttpUrl
except ImportError as e:
    print("IMPORT_ERROR", repr(e))
    raise SystemExit(0)

class Model(BaseModel):
    url: AnyHttpUrl
    auth_token: Optional[str] = Field(default=None)

for value in ("http://example.test", "https://example.test"):
    try:
        m = Model(url=value)
        print(value, "OK", m.url, f"http={m.url.is_http()}")
    except Exception as e:
        print(value, "ERROR", repr(type(e).__name__), str(e))
PY

Repository: lightspeed-core/lightspeed-stack

Length of output: 233


🌐 Web query:

Pydantic AnyHttpUrl permits http URL or sanitizes HttpUrl HTTPS documentation

💡 Result:

Pydantic provides the AnyHttpUrl and HttpUrl types to validate that a given input is a correctly formatted HTTP or HTTPS URL [1][2]. Both types ensure the input follows the URL structure, but they are not intended as general-purpose security sanitizers [3]. Key points regarding these types: 1. Purpose of AnyHttpUrl and HttpUrl: These types validate that the input string conforms to valid URL syntax and restricted schemes (http or https) [1][2]. Pydantic performs validation, such as ensuring the scheme is correct [2][4], and will automatically handle the conversion of Internationalized Domain Names (IDNs) into their punycode representation [1][5]. 2. Sanitization vs. Validation: Pydantic's validation is focused on data integrity and type enforcement rather than security sanitization [3]. While Pydantic ensures the URL is syntactically valid according to RFC standards, it does not sanitize the content to protect against vulnerabilities such as Cross-Site Scripting (XSS), Server-Side Request Forgery (SSRF), or malicious path injection [3]. If you need to protect against such threats, you must apply appropriate security-focused sanitization and output encoding techniques beyond what Pydantic provides. 3. Differences between the types: - AnyHttpUrl: Accepts any HTTP or HTTPS URL [1][2]. - HttpUrl: Performs the same validation as AnyHttpUrl but includes an additional constraint: a maximum length of 2083 characters [1][2]. If you are using these types for application logic (such as saving to a database or making external requests), you should continue to use specialized security libraries to sanitize or validate the URLs according to your specific security requirements [3].

Citations:


Reject bearer tokens on insecure HTTP endpoints.

AnyHttpUrl accepts http://, so configuring auth_token with HTTP can transmit the bearer token in plaintext. Require HTTPS whenever auth_token is set, or add an explicit, tightly scoped insecure-development opt-in.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/models/config.py` around lines 2041 - 2049, Update the configuration
model containing url and auth_token to validate that any configured auth_token
requires an HTTPS URL; reject HTTP endpoints during model validation, while
preserving unauthenticated HTTP configurations unless an existing explicitly
scoped insecure-development opt-in is used.

Comment on lines +27 to +50
@pytest.fixture
def a2a_config(mocker: MockerFixture) -> Any:
"""Create a mock A2AAgentsConfiguration."""
agent1 = mocker.MagicMock()
agent1.name = "test-agent"
agent1.url = "https://agent.example.com"
agent1.auth_token = None

config = mocker.MagicMock()
config.agents = [agent1]
return config


@pytest.fixture
def a2a_config_with_token(mocker: MockerFixture) -> Any:
"""Create a mock config with auth token."""
agent1 = mocker.MagicMock()
agent1.name = "secure-agent"
agent1.url = "https://secure.example.com"
agent1.auth_token.get_secret_value.return_value = "test-token-123"

config = mocker.MagicMock()
config.agents = [agent1]
return config

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Type the configuration fixtures concretely.

Replace the Any fixture return types with A2AAgentsConfiguration (construct it or use a typed cast) and update dependent test parameters accordingly. This keeps the manager/configuration contract statically checked.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/a2a_client/test_manager.py` around lines 27 - 50, Update the
a2a_config and a2a_config_with_token fixtures to return A2AAgentsConfiguration
instead of Any, constructing the configuration or using a typed cast as
appropriate. Update dependent test parameters to use the same concrete
configuration type while preserving the existing mock agent values and
authentication behavior.

Source: Coding guidelines

"sqlite": None,
"postgres": None,
},
"a2a_agents": None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

All 10 additions correctly reflect the default (a2a_agents=None), but no test exercises a populated a2a_agents config.

Every Configuration(...) in this file omits a2a_agents, so all 10 additions are trivially correct. However, none of the existing dump tests construct a real a2a_agents value (with name/url/auth_token/etc., mirroring examples/lightspeed-stack-a2a-agents.yaml). Given auth_token is a secret similar to api_key/password (which are redacted to "**********" elsewhere in this file), it'd be valuable to add one dump test with a populated a2a_agents list to confirm the serialized shape and, importantly, that auth_token is redacted rather than leaked in plaintext.

Also applies to: 436-436, 811-811, 1070-1070, 1309-1309, 1528-1528, 1907-1907, 2132-2132, 2357-2357, 2589-2589

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/models/config/test_dump_configuration.py` at line 212, Update the
dump tests in test_dump_configuration.py to construct at least one Configuration
with a populated a2a_agents entry containing representative fields such as name,
url, and auth_token. Assert the serialized output preserves the expected
a2a_agents shape while replacing auth_token with the existing redaction value,
matching the api_key/password redaction behavior used elsewhere in the tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants