Skip to content

Merge dev into main: kap-server steer flag & agent-core-v2 full compaction - #3708

Open
sailist wants to merge 8 commits into
mainfrom
dev
Open

Merge dev into main: kap-server steer flag & agent-core-v2 full compaction#3708
sailist wants to merge 8 commits into
mainfrom
dev

Conversation

@sailist

@sailist sailist commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Changes

@changeset-bot

changeset-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 0d48c45

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 10, 2026

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

commit: 0d48c45

@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: 1506063502

ℹ️ 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".

nextTurnId: state.turnIndex.nextTurnId,
branch: store.ref.branch,
head: deps.stores.tree.openBranch(store.ref.branch).head,
tokensBefore: estimateUsedContextTokens(state.history),

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 Use the same token basis across compaction rounds

When usage metadata is unavailable and the system prompt or tool definitions are large, onBeforeStep calculates usage including those prefixes, while this snapshot records tokensBefore from history alone. The controller later assigns this smaller value to lastCompactedTokens, so if the fixed prefix still puts the compacted context above the threshold, the continuation immediately triggers another compaction; every round repeats the mismatch and can loop through paid summary requests without reaching the normal LLM call. Record and compare token counts using the same prefix-aware calculation.

Useful? React with 👍 / 👎.

Comment on lines +461 to +464
({ context }) => {
if (context.cause !== 'user-abort') {
deps.actor.send({ type: 'input.continue' });
}

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 Resume the blocked prompt when auto-compaction fails

When budget compaction is triggered before a prompt's first LLM step and summarization then fails, the before-step hook has already ended that turn without producing a response. This cancellation path sends only input.continue, but the idle agent resumes on that event only when history ends mid-tool-chain; a history ending with the triggering user message therefore stays idle, while the prompt has already settled as successfully completed with no answer. Auto-compaction failure needs to requeue a continuation or otherwise restart the blocked turn.

Useful? React with 👍 / 👎.

Comment on lines +239 to +242
return {
history: state.history,
queue: state.queue,
nextTurnId: state.turnIndex.nextTurnId,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve pending reminders when switching branches

An idle agent may legitimately have persisted input.remind entries waiting for its next turn, but the quiesce snapshot captures only history and queue. The fresh compaction branch therefore initializes reminders as empty, and replay starts after this snapshot's head, so any reminder already present before compaction is silently discarded and never delivered. Include the current reminder state in the seed, along with any other pending input state that must survive the reset.

Useful? React with 👍 / 👎.

@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: 619717435b

ℹ️ 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 +495 to +497
function defaultContinuation(reason: CompactionReason): UserMessage | undefined {
if (reason === 'manual') return undefined;
return compactionContinuationMessage();

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 Resume work interrupted by manual compaction

When manual compaction begins while a turn is executing tools, the pause ends that turn at the next tool-result boundary, and branch switching replaces the mid-tool-chain history with user messages plus the summary. Returning no continuation for every manual run then leaves the reset agent idle, so the original prompt is reported as done without ever producing its final response. Enqueue a continuation when a manual compaction actually interrupted a running turn.

Useful? React with 👍 / 👎.

Comment on lines +230 to +233
deps.actor.send({ type: 'input.pause' });
const waiting = waitFor(deps.actor, (s) => s.matches('idle'), { timeout: PAUSE_TIMEOUT_MS });
void waiting.catch(() => undefined);
await Promise.race([waiting, aborted(signal)]);

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 Wait for detached tools before switching branches

When the agent has detached background tools, its state is idle.waiting, which still satisfies this broad matches('idle') predicate. Compaction therefore proceeds to store.reset; the agent reset aborts its scope and clears background, silently terminating those tools and discarding their eventual completion notifications. Quiescing should wait for an idle state with no background work, or explicitly preserve the detached tasks across the reset.

Useful? React with 👍 / 👎.

goal_control: z.enum(['pause', 'resume', 'cancel']).optional(),
disabled_tools: z.array(z.string()).optional(),
prompt_id: z.string().min(1).optional(),
steer: z.boolean().optional(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add a changeset for the new steer behavior

This adds a documented, user-visible prompt submission capability, but the reviewed diff contains no .changeset/ entry, so the CLI release changelog and versioning will omit it. Add the required user-facing changeset before merging.

AGENTS.md reference: AGENTS.md:L86-L87

Useful? React with 👍 / 👎.

@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: 1814aa78d5

ℹ️ 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 +211 to +213
deps.actor.on('turn.aborting', () => {
active?.actor.send({ type: 'cancel', cause: 'user-abort' });
}),

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 Route idle aborts to the active compaction

Once budget compaction has quiesced the agent, the agent is paused in idle, where input.abort has no handler and therefore emits no turn.aborting; this subscription is consequently unable to cancel the active summarization. An abort issued during that potentially long or paid phase does nothing, and a successful automatic compaction subsequently submits its continuation and restarts work the user tried to stop. Ensure aborts reach the active compaction even when no turn is running.

Useful? React with 👍 / 👎.

Comment on lines +150 to +152
const seedStore = await createEventStore({ journal, slices: agentSlices });
try {
await seedStore.dispatch([...opts.seed]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve registered slice state across the branch switch

When the original agent store has a registered stateful slice such as todoSlice, this fresh branch is populated only with the fixed agentSlices and the compaction seed's history/queue events. Resetting the original store then refolds its registered todo slice over that branch without any state.updated event, so a nonempty structured TodoList becomes empty; appending rendered todo text to the LLM summary does not restore what the TodoList tool or UI reads. Seed the current registered state, including the todo snapshot, before resetting.

Useful? React with 👍 / 👎.

@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: 5f639d6e62

ℹ️ 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".

compactionStarted(): boolean {
if (this.compacting) return false;
this.compacting = true;
if (this.status !== 'running' || this.turn === undefined) return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Publish manual compaction as an agent turn

When POST /sessions/{id}:compact starts manual compaction, AgentFullCompactionService.begin requires the loop to be idle, so this tracker normally has status === 'idle' and no turn. This guard therefore suppresses the agent.state update, and because this change also removes compacting from session.state, clients receive no indication that the asynchronous manual compaction is running. Transition idle agents to a running { status: 'compacting' } turn here as well.

Useful? React with 👍 / 👎.

@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: be69ace220

ℹ️ 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".

index: number,
member: SwarmMemberResult | undefined,
): void => {
if (tasks.has(agentId)) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Refresh repeated swarm member tasks

When a later AgentSwarm call resumes an agent that appeared in an earlier call, tasks already contains that agent ID, so this return discards the later run's status, result, and timeline placement. Cold history consequently keeps showing the first run even though the live projector has updated the member; update the existing task or key synthesized tasks by both tool call and agent.

Useful? React with 👍 / 👎.

Comment on lines +201 to +205
deps.actor.on('turn.done', () => {
overflowAttempts = 0;
}),
deps.actor.on('turn.failed', (event) => {
if (!isContextOverflowError(event.error) || overflowAttempts >= maxAutoAttempts) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reset overflow retries after aborted turns

After an overflow triggers compaction, overflowAttempts is reset only by turn.done. If the resumed turn is aborted, the next unrelated prompt inherits the previous attempt count; at the configured cap its first context-overflow failure is no longer compacted and is surfaced immediately. Reset the counter on aborted turns and on terminal non-overflow failures while preserving it only across the same overflow recovery chain.

Useful? React with 👍 / 👎.

const current = { actor, reason, startedAt: Date.now() };
active = current;
const subscriptions = pipeEvents(actor);
await deps.stores.session();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clear active compaction when session-store setup fails

If opening the session store rejects because of an I/O or backend failure, this await runs before the try/finally, after active and the event subscriptions have already been installed. The caller receives the error, but every subsequent manual compaction reports busy and the subscriptions leak until the controller is recreated. Include setup and actor startup in the cleanup-protected region.

Useful? React with 👍 / 👎.

function parseSwarmMembers(output: string): SwarmMemberResult[] {
if (!output.includes('<agent_swarm_result>')) return [];
const members: SwarmMemberResult[] = [];
for (const match of output.matchAll(/<subagent\b([^>]*)>([\s\S]*?)<\/subagent>/g)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Parse swarm results without treating report text as markup

When a subagent report contains the literal text </subagent>—for example while discussing this result format—the producer inserts the report body without escaping it, so this non-greedy regex closes at that text and stores a truncated result_summary or error in cold history. Recover member results from structured events or use an encoding that cannot conflict with arbitrary report content.

Useful? React with 👍 / 👎.

@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: 9329c09edb

ℹ️ 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".

const isV3 = url === WS_PATH_V3 || url.startsWith(`${WS_PATH_V3}?`);
const isDebug = url === WS_DEBUG_PATH || url.startsWith(`${WS_DEBUG_PATH}?`);
const wss = isV1 ? wssV1 : isV3 ? wssV3 : isDebug ? wssDebug : undefined;
const wss = isV3 ? wssV3 : isDebug ? wssDebug : undefined;

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 Sync the shipped web bundle with the v3-only server

At this commit, the committed apps/kimi-code/dist-web/assets/index-HU0LCM-X.js still constructs /api/v1/ws, contains no /api/v3/ws client, and calls the removed transcript/message REST endpoints, while this branch now accepts only v3/debug WebSocket upgrades and removes those REST registrations. Consequently, the web UI shipped by kimi web cannot establish its chat socket or load history; sync and commit the code-app bundle together with the protocol removal.

AGENTS.md reference: AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

Comment on lines +63 to +64
if (getLiveSessionById(this.deps.core.accessor, sessionId) !== undefined) {
return existing.view;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Refresh the cached roster for live session searches

When a live session is searched once and later creates a new subagent, this returns the existing view whose roster was populated only once by loadRoster. Session-wide search derives its agent IDs from view.agents(), so it never calls ensureAgentHistory for the new subagent and silently omits that agent's messages from all subsequent searches until the cached source is dropped; refresh the roster or subscribe to agent lifecycle changes.

Useful? React with 👍 / 👎.

Comment on lines +152 to +154
const cached = this.sessions.get(sessionId);
this.sessions.delete(sessionId);
if (cached === undefined) return [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Emit deletions for sessions absent from the event cache

Deleting a cold session, or any session that has not emitted a created/meta/activity event since this translator started, always hits this empty-cache return. The session has already been removed from ISessionIndex, so it cannot be fetched afterward, and v3 clients receive no deletion message; for example, kimi-inspect retains its seeded session entry until a later poll or unrelated invalidation. Seed the cache from existing sessions or construct a deletion entity from lifecycle data.

Useful? React with 👍 / 👎.

@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: fde8ccef73

ℹ️ 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 +172 to +173
function replaceEntryText(entry: UserEntry, text: string): UserEntry {
return { ...entry, message: { ...entry.message, content: [{ type: 'text', text }] } };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve media when truncating retained user messages

When a boundary user message exceeds the head/tail token budget and contains images, audio, or video alongside text, this replacement rebuilds its content from a single text part and silently discards every non-text part. For example, a recent prompt containing several screenshots can cross the 20k compaction budget and lose all screenshots from the compacted branch, leaving the continued turn unable to inspect the original inputs. Preserve the non-text parts on one retained fragment while accounting for their token cost.

Useful? React with 👍 / 👎.

@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: 0d48c459aa

ℹ️ 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".

agentId: file.agentId,
role: e.role,
text: e.text.length > MAX_DOC_TEXT_CHARS ? e.text.slice(0, MAX_DOC_TEXT_CHARS) : e.text,
text: e.text,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore the per-message cap before indexing wire text

When a user or assistant message exceeds 20,000 characters and the only match occurs in its suffix, the persistent route now indexes the entire e.text, while collectLiveDocs in searchService.ts still truncates the same message to MAX_DOC_TEXT_CHARS. Consequently, an identical session-scoped search can return no hit while the session is live and then return a hit after it becomes cold; retaining the existing cap here also prevents exceptionally large prompts from unnecessarily inflating the persisted text indexes.

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