Skip to content

feat(kap-server): add v3 message streaming and transcript APIs - #3532

Open
sailist wants to merge 4 commits into
MoonshotAI:mainfrom
sailist:feat-148-09-03-message-api-v3
Open

feat(kap-server): add v3 message streaming and transcript APIs#3532
sailist wants to merge 4 commits into
MoonshotAI:mainfrom
sailist:feat-148-09-03-message-api-v3

Conversation

@sailist

@sailist sailist commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

Internal task (feat-148); no linked issue.

Problem

Session consumers that want a message-level view of a session must either run the transcript op-application engine themselves (subscribe_v2 pushes TranscriptOperation batches with upsert/append/offset semantics) or fall back to the legacy messages API, which covers only the main agent and carries no agent/turn/step identifiers. There is no message-granular streaming surface that is structurally identical to a REST read.

What changed

  • @moonshot-ai/transcript — v3 wire contract + materializer: a 20-type snake_case Message union (turn/step lifecycle incl. step retry, text/thinking/tool frames, marker/taskref, task/interaction/attachment/todo/prompt, four flat meta singletons, remove) plus MessageDelta (append); MessageV3Materializer converts transcript ops into complete messages and snapshots into time-ordered message lists.
  • WS subscribe_v3 / unsubscribe_v3 on the existing /api/v1/ws endpoint: pushes message.reset / message / message.delta frames and reuses the v2 grade machinery (off/turn/block/delta). Deliberately no watermark/resume semantics: a (re)subscribe always starts with a full-snapshot message.reset, then only live frames; reconnect = resubscribe for a fresh snapshot. Reset is a subscribe invariant — every subscribed agent gets one (empty when stateless) — and any undo/clear re-sends a full reset instead of incremental removals.
  • REST GET /api/v3/sessions/{session_id}/transcript?agent_id=: returns the same full Message[] (unpaginated), wrapped in the standard response envelope; isomorphic to message.reset.
  • kimi-inspect migrated to v3: the transcript chat/audit views now consume subscribe_v3 natively (no subscribe_v2, no op application, no paging machinery left); plan projections are derived client-side from messages. This migration doubles as the v3 completeness validation — a scripted smoke session (streaming deltas, approvals, questions, todos, subagents, shell tasks, step retry, goal/plan, attachments, undo, compaction, reconnects) passes 38/38 checks, and late subscribers converge byte-identically with the REST read.
  • Projector/consistency fixes: items.remove carries cascaded interaction ids; prompt.queued / context.undone are suppressed for graded connections (they were double-delivered before).
  • packages/agent-core-v2 is untouched; v1/v2 surfaces (incl. subscribe_v2 watermarks/replay) are unchanged.

Reference docs for the v3 surface will follow in a separate change.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue (external PRs: the issue must have a maintainer's /approve).
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: ed38e86

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Sep 4, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@ed38e86
npx https://pkg.pr.new/@moonshot-ai/kimi-code@ed38e86

commit: ed38e86

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e28327a85d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +520 to +521
for (const item of materializer.materialize(op)) {
target.send(this.buildV3Envelope(state, v3ItemFrame(item, seq)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve op-batch atomicity in v3 catch-up

When one transcript op batch materializes into multiple items, this sends each as a separate frame carrying the same seq. If the connection drops after the client receives and persists that sequence from an early frame, reconnecting with transcript_since skips the entire batch, permanently losing the remaining messages; the client also has no marker indicating which frame is last. Send the materialized batch atomically or add an item index/count or completion marker so the watermark can be committed safely.

AGENTS.md reference: AGENTS.md:L28-L28

Useful? React with 👍 / 👎.

id: `remove.${this.removeCounter}`,
session_id: env.sessionId,
agent_id: env.agentId,
ids: [...op.ids],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove child messages when undoing a turn

When context.undone removes a turn that has already streamed steps and frames, onContextUndone puts only top-level item IDs and anchored interaction IDs in op.ids, and this forwards that list unchanged. Because v3 exposes each step and frame as an independent message, applying this removal deletes the turn message but leaves its step_*, text, thinking, and tool messages orphaned, diverging from the REST snapshot where the whole turn subtree is gone. Include every flattened descendant ID in the removal.

Useful? React with 👍 / 👎.

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.

1 participant