feat(core,server,web,cli): mid-run steering messages and square-bracket markers (#63)

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 23:01:18 +08:00
1 parent abd5b13d52
commit 7584171482
81 files changed
+3139 -930

No files matched your search

+20 -2
View File
@@ -11,7 +11,12 @@
*/
import fs from "node:fs/promises";
import path from "node:path";
import { agentsDir, readTraceTolerant, tracesDir } from "@prismshadow/penguin-core";
import {
agentsDir,
parseUserSteeringText,
readTraceTolerant,
tracesDir,
} from "@prismshadow/penguin-core";
import type { OmniMessage } from "@prismshadow/penguin-core";
import type {
AgentTracesResponse,
@@ -332,9 +337,22 @@ export class TraceService {
// images" = multiple messages; only the **first** one counts (once
// pendingFrom is set, it's not changed again), otherwise the turn's start
// would shift to the last image.
// Mid-run steering (`[user_steering]`-wrapped user text, delivered between turns of a
// running Task): never a turn starter — same exclusion idea as the compaction summary —
// and it forces the next request to be a continuation (a steering-only continuation
// turn has no preceding tool call, but it is still the same Task).
const isSteeringText =
!hasOrigin &&
msg.type === "model_msg" &&
p.type === "text" &&
p.role === "user" &&
typeof p.text === "string" &&
parseUserSteeringText(p.text) !== null;
if (isSteeringText) continuation = true;
const startsUserTurn =
!hasOrigin &&
!compactionActive &&
!isSteeringText &&
msg.type === "model_msg" &&
((p.type === "text" && p.role === "user") || p.type === "image_url");
const startsCompactionTurn =
@@ -370,7 +388,7 @@ export class TraceService {
if (compactionActive) t.compaction = true; // This turn is a compaction turn
// This turn's duration starts at the first request_begin. It doesn't
// use the timestamp of the user Prompt / compaction summary or other
// user text: `<context_summary>` is created during compaction but only
// user text: `[context_summary]` is created during compaction but only
// written to disk on the next run, so resuming the next day would
// stretch the first turn out by a whole day for no reason; the Prompt
// to request-dispatch gap is only ever milliseconds anyway.