Skip to content

fix: preserve A2A transcript order - #2591

Open
EItanya wants to merge 4 commits into
mainfrom
fix/task-transcript-order
Open

fix: preserve A2A transcript order#2591
EItanya wants to merge 4 commits into
mainfrom
fix/task-transcript-order

Conversation

@EItanya

@EItanya EItanya commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • archive input-required status messages before user replies
  • publish tool calls and results as A2A status messages instead of artifacts
  • remove the UI transcript-order inference and replay protocol history directly

Testing

  • go test ./core/v2/a2agateway ./adk/pkg/a2a
  • yarn test src/api/chat/a2aGrpcChatClient.test.ts
  • yarn typecheck
  • yarn eslint src/api/chat/a2aGrpcChatClient.ts src/api/chat/a2aGrpcChatClient.test.ts

Closes #2584

Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
@github-actions github-actions Bot added the bug Something isn't working label Aug 26, 2026
@EItanya

EItanya commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Design context: why conversion happens in KAgentExecutor

We traced the exact ADK Go v2.2.0 path and audited its callback/plugin surfaces before settling on the executor decorator.

The upstream path is:

session.Event -> part conversion -> private eventToArtifactTransform -> TaskArtifactUpdateEvent

Except for long-running calls that become input-required, every content-bearing ADK event is passed through the artifact transform. Both supported output modes produce artifacts.

The available hooks do not provide a persistence-safe event-type replacement:

Hook Limitation
Model callbacks Modify model requests/responses, not A2A event types
Tool callbacks Modify tool arguments/results only
Agent callbacks Add or replace agent content, which is still converted to an artifact
Plugin OnEventCallback Can replace a session.Event, but artifact conversion happens afterwards
GenAIPartConverter Converts individual parts only
A2A AfterEventCallback Receives an already-created TaskArtifactUpdateEvent and cannot replace it
Custom runner/provider Still feeds session events into the same artifact-only processor
A2A call interceptor Can replace the outbound streamed event, but runs after the task store processed the original artifact, so replay would remain wrong

Marking a tool as long-running is only correct when execution must enter input-required; using it for ordinary tool calls/results would change task semantics.

Therefore the AgentExecutor decorator is the earliest public seam where kagent can replace the concrete A2A event before the A2A SDK persists it. The cleaner long-term solution is upstream support for an event converter that returns a general a2a.Event (or an artifact/message/status transform), at which point this local conversion can be removed.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ListTasks returns a task's messages and artifacts as two unordered lists, so a transcript cannot be replayed in order

1 participant