Handoff-style /model switch command and per-turn thinking level (#64)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Yaowei ZhengandClaude Fable 5 authored and GitHub committed 2026-07-26 16:31:51 +08:00
1 parent 816a823b75
commit 1e23452f48
58 files changed
+1064 -336

No files matched your search

+60 -1
View File
@@ -580,7 +580,6 @@ describe("ContextEngine ReAct loop (mock LLM, approve callback)", () => {
model_context_window: 1000,
system_prompt: "sys",
tools: [],
thinking_level: "medium",
agent_state: "/root/p/worker/agent_state",
workspace: "/tmp/w",
});
@@ -666,6 +665,66 @@ describe("ContextEngine ReAct loop (mock LLM, approve callback)", () => {
).toBe(false);
expect(recorded.filter((m) => (m.payload as { text?: string }).text === "go")).toHaveLength(1);
});
it("forwards RunOptions.thinkingLevel to every LLM request of the run (reconnects included); compaction keeps the default", async () => {
const levels: (string | undefined)[] = [];
let calls = 0;
const llm: LLMInterface = {
async *streamGenerate(params) {
calls += 1;
levels.push(params.thinkingLevel);
if (calls === 1) {
// First attempt drops: the reconnect retry must carry the same per-turn level.
yield assistantText("half", "timeout");
return { status: "timeout" };
}
if (calls === 2) {
// Retry completes with usage above the compaction threshold → a Task-boundary
// summarize compaction issues one more request (the engine's, not this run's turn):
// it must NOT carry the per-turn override.
yield assistantText("recovered");
yield tokenUsage(emptyTokenCounts(), {
cache_read: 0,
cache_write: 0,
output: 1,
total: 100,
});
return { status: "completed" };
}
yield assistantText("<summary>s</summary>");
yield tokenUsage(emptyTokenCounts(), {
cache_read: 0,
cache_write: 0,
output: 1,
total: 5,
});
return { status: "completed" };
},
};
const environment = new Environment({
workspaceDir: workspace,
toolConfig: execCommandToolConfig(),
});
const engine = new ContextEngine({
llm,
environment,
maxReconnects: 1,
reconnectBackoffMs: 1,
createLLM: () => llm,
compaction: { maxContextLength: 10, maxSessionTurns: -1, mode: "summarize", prompt: "SUM" },
});
const all: OmniMessage[] = [];
for await (const msg of engine.run([userText("go")], {
approve: allowAll,
thinkingLevel: "high",
})) {
all.push(msg);
}
expect(calls).toBe(3);
// Turn attempt + reconnect retry carry the run's level; the compaction request does not.
expect(levels).toEqual(["high", "high", undefined]);
});
});
describe("ContextEngine async/incremental tool calls (overlapping execution)", () => {