feat(coding-agent): implemented threshold for demoting interrupted thinking

- Added a 60-character minimum length threshold for demoting interrupted thinking into hidden continuity context in agent-session.ts.
- Updated LLM message conversion in messages.ts to strip incomplete thinking from user-interrupted assistant turns regardless of continuity note presence.
- Added test coverage in agent-session-interrupted-thinking.test.ts verifying behavior for reasoning lengths below and at the threshold.
This commit is contained in:
can1357
2026-08-13 02:15:16 +02:00
parent f9c8519b68
commit 3e28a1afb4
4 changed files with 52 additions and 21 deletions
@@ -47,8 +47,8 @@ function baseAssistant(model: Model<Api>, content: AssistantMessage["content"]):
};
}
function thinkingAssistant(model: Model<Api>, errorMessage: string): AssistantMessage {
const thinking: ThinkingContent = { type: "thinking", thinking: REASONING_TEXT };
function thinkingAssistant(model: Model<Api>, errorMessage: string, reasoning = REASONING_TEXT): AssistantMessage {
const thinking: ThinkingContent = { type: "thinking", thinking: reasoning };
return { ...baseAssistant(model, [thinking]), errorMessage };
}
@@ -204,6 +204,39 @@ describe("AgentSession interrupted thinking persistence", () => {
const developerLlm = llm.filter(entry => entry.role === "developer");
expect(developerLlm.some(entry => JSON.stringify(entry.content).includes(REASONING_TEXT))).toBe(true);
});
it("skips hidden continuity for interrupted reasoning shorter than 60 characters", async () => {
const harness = createSession();
const reasoning = "x".repeat(59);
await emitAssistantEnd(
harness.session,
harness.sessionManager,
thinkingAssistant(harness.model, USER_INTERRUPT_LABEL, reasoning),
entry => entry.type === "message" && entry.message.role === "assistant",
);
const messages = harness.session.agent.state.messages;
expect(messages.find(isAssistantMessage)?.content).toEqual([{ type: "thinking", thinking: reasoning }]);
expect(messages.some(isInterruptedThinkingMessage)).toBe(false);
const llm = convertToLlm(messages);
expect(llm.some(entry => entry.role === "assistant")).toBe(false);
expect(llm.some(entry => JSON.stringify(entry.content).includes(reasoning))).toBe(false);
});
it("keeps hidden continuity for exactly 60 characters", async () => {
const harness = createSession();
const reasoning = "x".repeat(60);
await emitAssistantEnd(
harness.session,
harness.sessionManager,
thinkingAssistant(harness.model, USER_INTERRUPT_LABEL, reasoning),
entry => entry.type === "custom_message" && entry.customType === INTERRUPTED_THINKING_MESSAGE_TYPE,
);
const hidden = harness.session.agent.state.messages.find(isInterruptedThinkingMessage);
expect(typeof hidden?.content === "string" ? hidden.content : JSON.stringify(hidden?.content)).toContain(
reasoning,
);
});
it("makes hidden continuity available in agent state before awaited message_end delivery finishes", async () => {
const releaseExtension = Promise.withResolvers<void>();