Skip to content

feat: add initial A2A runtime integration#1

Merged
rdobrik merged 24 commits intomasterfrom
codex/add-a2a-support
Mar 18, 2026
Merged

feat: add initial A2A runtime integration#1
rdobrik merged 24 commits intomasterfrom
codex/add-a2a-support

Conversation

@rdobrik
Copy link
Copy Markdown
Contributor

@rdobrik rdobrik commented Mar 12, 2026

Summary

This PR adds the first end-to-end Camel Agent A2A integration slice: it exposes local plans over the existing camel-a2a-component runtime surface and lets agent tools call remote A2A runtimes through a2a: endpoints while preserving correlation and audit metadata.

Scope

  • add A2A runtime configuration and bootstrap wiring
  • expose POST /a2a/rpc, GET /a2a/sse/{taskId}, and GET /.well-known/agent-card.json
  • load a separate exposed-agent catalog that maps public A2A identities to local {planName, planVersion}
  • create linked local conversations/tasks for inbound A2A work and persist A2A task snapshots
  • add outbound a2a: tool execution over JSON-RPC HTTP with correlation reuse for follow-up task calls
  • surface A2A agent/task/conversation identifiers through correlation and audit views

Implementation notes

  • agents.yaml remains the internal local plan catalog
  • public A2A exposure is configured separately through the exposed-agent catalog
  • inbound routing is explicit: only configured exposed agents are published and routable
  • outbound tool calls intercept a2a: targets in the Camel tool executor, call the remote runtime over JSON-RPC, and bind returned remote task identifiers back into the local conversation correlation state

Verification

  • ./mvnw -q -pl camel-agent-core -Dtest=A2AExposedAgentCatalogLoaderTest,AgentA2ATaskRepositoryTest,A2AToolClientTest test
  • ./mvnw -q -pl camel-agent-core,camel-agent-starter -am -DskipTests compile
  • ./mvnw -q -pl camel-agent-core,camel-agent-persistence-dscope -am -DskipTests compile

Known gaps

  • sample/runtime wiring for demonstrating A2A in the support sample is still pending
  • full reactor compile still fails in samples/agent-support-service because of pre-existing missing sample classes in src/main/java/io/dscope/camel/agent/samples/Main.java

Copilot AI review requested due to automatic review settings March 12, 2026 20:30
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds initial inbound A2A runtime integration to Camel Agent, including runtime routes, exposed-agent publishing, and persistence/audit correlation of A2A task & conversation metadata.

Changes:

  • Introduces A2A runtime bootstrap/binding and Undertow routes for /a2a/rpc, /a2a/sse/{taskId}, and /.well-known/agent-card.json.
  • Adds an exposed-agent catalog (YAML loader + agent-card generation) mapping public A2A agent cards to local plan name/version.
  • Persists and surfaces A2A correlation metadata in persistence/audit views, with focused unit tests.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pom.xml Adds ${a2a.version} property for the new A2A component dependency.
camel-agent-core/pom.xml Adds camel-a2a-component dependency to core runtime.
docs/roadmap.md Adds roadmap entry referencing the A2A integration work.
docs/pr-drafts/a2a-runtime-integration.md Adds PR draft/design notes for the A2A runtime integration.
camel-agent-persistence-dscope/.../DscopePersistenceFacade.java Extends stored correlation metadata to include A2A identifiers.
camel-agent-core/.../runtime/RuntimeResourceBootstrapper.java Stages remote exposed-agent config when configured via HTTP URL.
camel-agent-core/.../runtime/AgentRuntimeBootstrap.java Wires A2A protocol beans + A2A runtime route builder when enabled.
camel-agent-core/.../runtime/AgentA2ARuntimeRouteBuilder.java Adds Undertow routes that dispatch to A2A component processors via beans.
camel-agent-core/.../runtime/A2ARuntimeProperties.java Adds A2A runtime configuration parsing and URL/path helpers.
camel-agent-core/.../config/CorrelationKeys.java Adds A2A correlation key constants.
camel-agent-core/.../config/AgentHeaders.java Adds A2A header constants for propagating correlation into the agent component.
camel-agent-core/.../component/AgentProducer.java Binds incoming A2A correlation headers into the correlation registry.
camel-agent-core/.../audit/AuditMetadataSupport.java Derives A2A correlation from events and surfaces it in conversation metadata.
camel-agent-core/.../audit/AuditConversationViewProcessor.java Adds a2a metadata block to conversation view responses.
camel-agent-core/.../a2a/AgentA2ATaskRepository.java Adds in-memory + persisted A2A task storage and conversation event appends.
camel-agent-core/.../a2a/AgentA2AProtocolSupport.java Binds A2A processors/services/agent-card catalog into Camel Main when enabled.
camel-agent-core/.../a2a/AgentA2AAgentCardCatalog.java Generates discovery/extended agent cards from exposed-agent catalog.
camel-agent-core/.../a2a/A2AExposedAgentSpec.java Defines exposed-agent spec model for YAML config.
camel-agent-core/.../a2a/A2AExposedAgentCatalogLoader.java Loads exposed-agent YAML config from classpath/file/http(s).
camel-agent-core/.../a2a/A2AExposedAgentCatalog.java Validates and provides lookup/default behavior for exposed agents.
camel-agent-core/src/test/.../A2AExposedAgentCatalogLoaderTest.java Tests exposed-agent catalog loading and validation.
camel-agent-core/src/test/.../AgentA2ATaskRepositoryTest.java Tests task create/cancel + persisted conversation audit event behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +178 to +191
bind(main, A2AComponentApplicationSupport.BEAN_TASK_EVENT_SERVICE, taskEventService);
bind(main, A2AComponentApplicationSupport.BEAN_PUSH_CONFIG_SERVICE, pushConfigService);
bind(main, A2AComponentApplicationSupport.BEAN_TASK_SERVICE, taskRepository);
bind(main, A2AComponentApplicationSupport.BEAN_AGENT_CARD_CATALOG, agentCardCatalog);
bind(main, A2AComponentApplicationSupport.BEAN_CREATE_PUSH_CONFIG_PROCESSOR, createPushConfigProcessor);
bind(main, A2AComponentApplicationSupport.BEAN_GET_PUSH_CONFIG_PROCESSOR, getPushConfigProcessor);
bind(main, A2AComponentApplicationSupport.BEAN_LIST_PUSH_CONFIGS_PROCESSOR, listPushConfigsProcessor);
bind(main, A2AComponentApplicationSupport.BEAN_DELETE_PUSH_CONFIG_PROCESSOR, deletePushConfigProcessor);
bind(main, A2AComponentApplicationSupport.BEAN_ENVELOPE_PROCESSOR, new A2AJsonRpcEnvelopeProcessor(A2AProtocolMethods.CORE_METHODS));
bind(main, A2AComponentApplicationSupport.BEAN_ERROR_PROCESSOR, new A2AErrorProcessor());
bind(main, A2AComponentApplicationSupport.BEAN_METHOD_PROCESSOR, new A2AMethodDispatchProcessor(methods));
bind(main, A2AComponentApplicationSupport.BEAN_SSE_PROCESSOR, new A2ATaskSseProcessor(taskEventService));
bind(main, A2AComponentApplicationSupport.BEAN_AGENT_CARD_DISCOVERY_PROCESSOR, new AgentCardDiscoveryProcessor(agentCardCatalog));
bind(main, A2AComponentApplicationSupport.BEAN_GET_EXTENDED_AGENT_CARD_PROCESSOR, getExtendedAgentCardProcessor);
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

The A2A beans are only bound if missing, but this method still constructs new taskEventService, taskRepository, agentCardCatalog, and processors that are wired together. If any of the A2AComponentApplicationSupport.BEAN_* names are already present in the Main registry, you can end up with routes using the pre-existing beans while other newly-created processors/services are used elsewhere, causing inconsistent state (e.g., SSE processor using a different event service than the task repository publishes to). Consider either (1) treating these beans as an atomic set (fail fast if any already exist), (2) always overriding them when A2A is enabled, or (3) looking up and reusing existing beans instead of creating new ones.

Copilot uses AI. Check for mistakes.
Comment on lines +123 to +126
current.setUpdatedAt(Instant.now().toString());
tasks.put(taskId, current);
historyByTaskId.computeIfAbsent(taskId, ignored -> new ArrayList<>()).add(copyStatus(canceled));
eventService.publishTaskUpdate(current);
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

historyByTaskId stores mutable ArrayList instances inside a ConcurrentMap and later mutates them (e.g., .add(...)). This is not thread-safe and can lead to lost updates or ConcurrentModificationException when history is read while another thread updates it. Use a thread-safe list (e.g., CopyOnWriteArrayList) or update the map with a new immutable list on each change.

Copilot uses AI. Check for mistakes.
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.

@copilot open a new pull request to apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 64 out of 65 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rdobrik
Copy link
Copy Markdown
Contributor Author

rdobrik commented Mar 17, 2026

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 17, 2026

@rdobrik I've opened a new pull request, #2, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 3 commits March 17, 2026 19:17
… issues

Co-authored-by: rdobrik <8812511+rdobrik@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 17, 2026

@rdobrik I've opened a new pull request, #3, to work on those changes. Once the pull request is ready, I'll request review from you.

rdobrik and others added 8 commits March 17, 2026 12:36
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
… InMemoryPersistenceFacade

Co-authored-by: rdobrik <8812511+rdobrik@users.noreply.github.com>
… InMemoryPersistenceFacade

Co-authored-by: rdobrik <8812511+rdobrik@users.noreply.github.com>
Co-authored-by: rdobrik <8812511+rdobrik@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 17, 2026

@rdobrik I've opened a new pull request, #4, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 17, 2026

@rdobrik I've opened a new pull request, #5, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 17, 2026

@rdobrik I've opened a new pull request, #6, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 7 commits March 17, 2026 20:45
Co-authored-by: rdobrik <8812511+rdobrik@users.noreply.github.com>
Normalize whitespace for all required fields in A2AExposedAgentCatalog
Fix broken absolute filesystem path in roadmap.md
fix: use CopyOnWriteArrayList for thread-safe conversation history in InMemoryPersistenceFacade
fix: address A2A runtime review feedback — interface types, port fallback, reflection, and field normalization
@rdobrik rdobrik merged commit 4dcf00b into master Mar 18, 2026
@rdobrik rdobrik deleted the codex/add-a2a-support branch March 18, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants