Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/goal-replay-leak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Fix goal mode continuation prompts leaking into the transcript when resuming a session.
27 changes: 4 additions & 23 deletions apps/kimi-code/src/tui/controllers/session-replay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,17 +301,10 @@ export class SessionReplayRenderer {
this.renderCronMissed(context, message);
return;
}
if (isGoalForkClearedSystemReminder(message)) {
return;
}
const goalReminder = goalOutcomeReminderFromSystemMessage(message);
if (goalReminder !== null) {
if (goalReminder !== undefined) {
this.flushAssistant(context);
this.host.appendTranscriptEntry(
replayEntry(context, 'assistant', goalReminder, 'markdown'),
);
}
// System-trigger messages (goal continuation prompts, goal outcome
// reminders, stop-hook reasons, …) are model-facing only: the live event
// stream never renders them, so replay must not leak them either.
if (message.origin?.kind === 'system_trigger') {
return;
Comment thread
liruifengv marked this conversation as resolved.
}

Expand Down Expand Up @@ -741,18 +734,6 @@ function isModelBlockedGoalLifecycle(change: GoalReplayLifecycleChange): boolean
return change.status === 'blocked' && change.actor === 'model';
}

function goalOutcomeReminderFromSystemMessage(message: ContextMessage): string | undefined | null {
if (message.origin?.kind !== 'system_trigger') return null;
if (message.origin.name !== 'goal_completion' && message.origin.name !== 'goal_blocked') {
return null;
}
return undefined;
}

function isGoalForkClearedSystemReminder(message: ContextMessage): boolean {
return message.origin?.kind === 'system_trigger' && message.origin.name === 'goal_fork_cleared';
}

function extractCronPrompt(text: string): string {
const open = '<prompt>\n';
const close = '\n</prompt>';
Expand Down
32 changes: 32 additions & 0 deletions apps/kimi-code/test/tui/message-replay.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,38 @@ describe('KimiTUI resume message replay', () => {
expect(content).not.toContain('Write a concise final message for the user');
});

it('does not replay system-trigger prompts such as goal continuation as user messages', async () => {
const driver = await replayIntoDriver([
message(
'user',
[
{
type: 'text',
text: 'Continue working toward the active goal. Keep the self-audit brief.',
},
],
{ origin: { kind: 'system_trigger', name: 'goal_continuation' } },
),
message(
'user',
[
{
type: 'text',
text: '<system-reminder>\nThe goal was cancelled.\n</system-reminder>',
},
],
{ origin: { kind: 'system_trigger', name: 'goal_cancelled' } },
),
message('assistant', [{ type: 'text', text: 'Working on it.' }]),
]);

expect(driver.state.transcriptEntries.filter((entry) => entry.kind === 'user')).toEqual([]);
const transcript = stripAnsi(driver.state.transcriptContainer.render(140).join('\n'));
expect(transcript).not.toContain('Continue working toward the active goal');
expect(transcript).not.toContain('The goal was cancelled');
expect(transcript).toContain('Working on it.');
});

it('does not replay the model-blocked lifecycle marker when the follow-up is replayed', async () => {
const driver = await replayIntoDriver([
goalReplay(
Expand Down
Loading