Replace the Substrate turn transport with a kagent A2A client - #74
Merged
Merged
Conversation
Native Claude and Codex turns now go through kagent: A2A JSON-RPC for messages (SendStreamingMessage, SubscribeToTask, GetTask, ListTasks, CancelTask) and SessionService over grpc-web for Session lifecycle. There is no feature flag and no compatibility path. - Add runtime/kagent_client.py. A task snapshot replaces the projection because kagent has no event cursor. "Send not accepted" is read from ErrorInfo.metadata.reason and retried with the identical message within a 30s wall-clock budget (KAGENT_SEND_RETRY_BUDGET_SECONDS). Every other failure after a send is resolved by messageId lookup, never by replaying the prompt. The lookup follows ListTasks pages and re-reads the match with GetTask so the reply is mirrored. - Rewrite runtime/native_sessions.py on that client, keeping the delivery ledger (queued, recorded, sending, delivered, completed, uncertain, failed), the per-session lock, queued reports and deterministic assistant-message ids. A delivery is sent only by the pass that claims it from recorded, so a cancel or a second pass cannot send it again. Reconciliation sends recorded deliveries left by a restart once, and expires a sending delivery whose lookup keeps failing to uncertain. - Replace a kagent Session that was deleted (for example by idle expiry) once, under a fresh persisted request id, and resend standing context to it. Open turns on the old Session become uncertain. Changing KAGENT_USER_ID is a migration: every Session is replaced. - Create the main session and child sessions with their bindings in one transaction; the main session is created under an advisory lock. - POST /workspaces returns 409 until workspaces move to kagent. - Add the SSE event turn:updated without reply text, with deterministic ids. Fix SSEEvent to encode enum members by value. - Delete the journal, projection, contract and per-provider stream modules, their fixtures and tests, the native_events and native_lineage tables, main-thread rotation and its settings, and the two native-agent architecture documents that described them. Trim substrate_workspace to read-only access. native_bindings and native_deliveries now carry the kagent Session, request and task identity. - Add kagent_* settings and reshape NativeSessionInfo and NativeDeliveryInfo in the shared models. Update the frontend types, the SSE client and chat components, the specs, architecture notes and README, including the known gap that agents cannot yet call Mainloop tools from kagent. - Add a fake kagent gateway that serves kagent's paged, artifact-free ListTasks shape, sanitized fixtures, and tests for the client, the native session flow, the SSE encoding and the Postgres ledger (opt-in via MAINLOOP_TEST_DATABASE_URL). Verified live against kind-kagent-spike with claude-subscription and codex-subscription-https through the Mainloop API: create, send and stream, restart reconciliation without a duplicate send, suspend and resume with context, delete, and a clear failure status when kagent is unreachable. The send retry and Session replacement paths are covered by fixtures, not live runs. Backend suite passes against PostgreSQL 18; make lint and svelte-check are clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Native Claude Code and Codex turns now run on kagent harness agents, from the
oldsj/kagentfork. Mainloop is an A2A client of the kagent gateway. There is no feature flag and no compatibility path.This is slice (a) of the kagent migration. Workspaces, previews and agent-to-Mainloop tools follow in later PRs (see Known gaps).
What's in it
runtime/kagent_client.py): A2A JSON-RPC for turns (SendStreamingMessage, SubscribeToTask, GetTask, ListTasks, CancelTask) and SessionService over grpc-web for Session lifecycle.messageIdacross all ListTasks pages, then re-reading the task so the reply is kept.runtime/native_sessions.py):POST /workspacesreturns 409 until workspaces move to kagent.turn:updated(no reply text yet). Fixes enum encoding inSSEEvent.native_eventsandnative_lineagetables, main-thread rotation and its settings, and the docs describing them.AGENTS.md/ROADMAP.mdnow name kagent as the workspace runtime.Verification
make lintandsvelte-checkclean.Known gaps