@clawos-dev/clawd 0.2.333 → 0.2.334

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -6905,7 +6905,7 @@ var init_principal = __esm({
6905
6905
  });
6906
6906
 
6907
6907
  // ../protocol/src/schemas.ts
6908
- var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, SelectOptionSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, ToolFeaturesSchema, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionImportExternalArgs, SessionListArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionInterruptArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionCurrentTurnSenderArgs, SessionSubscribeArgs, SessionPinArgs, SessionArchiveArgs, PeerSessionUpsertArgs, PeerSessionUpsertResponseSchema, PeerSessionRemoveArgs, PeerSessionRemoveResponseSchema, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, ClientInfoSchema, AuthRequestFrameSchema, AuthOkFrameSchema, DeviceConnectionEntrySchema, DeviceConnectionsResponseSchema, TunnelReadyEventSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema, PROJECT_PORT_MIN, PROJECT_PORT_MAX, projectNameRegex, DEFAULT_DEV_COMMAND, ProjectMetadataSchema, PROJECT_STAGE_VALUES, ProjectStageSchema, ProjectWithStatusSchema, ListProjectsArgsSchema, ListProjectsResultSchema, GetProjectArgsSchema, GetProjectResultSchema, CreateProjectArgsSchema, CreateProjectResultSchema, DeleteProjectArgsSchema, DeleteProjectResultSchema, UpdateProjectPortArgsSchema, UpdateProjectPortResultSchema, SetProdUrlArgsSchema, SetProdUrlResultSchema, StartDevServerArgsSchema, StartDevServerResultSchema, ASSISTANT_REPORTABLE_STAGES, ReportStageArgsSchema, ReportStageResultSchema, StopDevServerArgsSchema, StopDevServerResultSchema, AppBuilderProjectUpdatedEventSchema, PublishArgsSchema, PublishResultSchema, DismissPublishJobArgsSchema, DismissPublishJobResultSchema, AppBuilderPublishProgressEventSchema, AppBuilderPublishFailedEventSchema;
6908
+ var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, SelectOptionSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, ToolFeaturesSchema, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, TURN_END_REASONS, ParsedEventSchema, SessionCreateArgs, SessionImportExternalArgs, SessionListArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionInterruptArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionCurrentTurnSenderArgs, SessionSubscribeArgs, SessionPinArgs, SessionArchiveArgs, PeerSessionUpsertArgs, PeerSessionUpsertResponseSchema, PeerSessionRemoveArgs, PeerSessionRemoveResponseSchema, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, ClientInfoSchema, AuthRequestFrameSchema, AuthOkFrameSchema, DeviceConnectionEntrySchema, DeviceConnectionsResponseSchema, TunnelReadyEventSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema, PROJECT_PORT_MIN, PROJECT_PORT_MAX, projectNameRegex, DEFAULT_DEV_COMMAND, ProjectMetadataSchema, PROJECT_STAGE_VALUES, ProjectStageSchema, ProjectWithStatusSchema, ListProjectsArgsSchema, ListProjectsResultSchema, GetProjectArgsSchema, GetProjectResultSchema, CreateProjectArgsSchema, CreateProjectResultSchema, DeleteProjectArgsSchema, DeleteProjectResultSchema, UpdateProjectPortArgsSchema, UpdateProjectPortResultSchema, SetProdUrlArgsSchema, SetProdUrlResultSchema, StartDevServerArgsSchema, StartDevServerResultSchema, ASSISTANT_REPORTABLE_STAGES, ReportStageArgsSchema, ReportStageResultSchema, StopDevServerArgsSchema, StopDevServerResultSchema, AppBuilderProjectUpdatedEventSchema, PublishArgsSchema, PublishResultSchema, DismissPublishJobArgsSchema, DismissPublishJobResultSchema, AppBuilderPublishProgressEventSchema, AppBuilderPublishFailedEventSchema;
6909
6909
  var init_schemas = __esm({
6910
6910
  "../protocol/src/schemas.ts"() {
6911
6911
  "use strict";
@@ -7198,6 +7198,7 @@ var init_schemas = __esm({
7198
7198
  multiSelect: external_exports.boolean(),
7199
7199
  options: external_exports.array(AskQuestionOptionSchema).min(1)
7200
7200
  });
7201
+ TURN_END_REASONS = ["completed", "interrupted"];
7201
7202
  ParsedEventSchema = external_exports.discriminatedUnion("kind", [
7202
7203
  // session_init 仅携带 session 标识;resolvedModel 等元信息走 meta_update
7203
7204
  external_exports.object({
@@ -7302,11 +7303,14 @@ var init_schemas = __esm({
7302
7303
  // ① SDK 模式 stream-json `result` 帧(claude.ts)—— stdout 最后一帧,可靠
7303
7304
  // ② TUI 模式 observer 读 JSONL `system/turn_duration` 行(claude-tui.ts parseLine)
7304
7305
  // ⚠️ CC 写此行早于该轮尾段正文落盘,可能被尾随 text 覆盖 lastEventKind(③ 存在的原因)
7305
- // ③ TUI 模式屏幕静止 AND observer 静止(observeScreenIdle + manager.observerIdleWaitMs 复合闸 →
7306
- // dispatchTurnIdle inject)—— 的覆盖;等尾随 text 全部 poll 落盘后补,排在 buffer 末条
7306
+ // ③ TUI 模式 gate 关闭期被 drop ② 信号,屏幕稳定后由 manager.notifyScreenIdle flush
7307
+ // 注入(PR #962 双源确认模型;旧 dispatchTurnIdle 已拆除)—— 排在 buffer 末条
7307
7308
  external_exports.object({
7308
7309
  ...ParsedEventBase,
7309
- kind: external_exports.literal("turn_end")
7310
+ kind: external_exports.literal("turn_end"),
7311
+ // 本轮耗时(ms)。SDK=result.duration_ms;TUI=turn_duration.durationMs;缺失时 reducer 按 turnStartedAt 兜底
7312
+ durationMs: external_exports.number().int().nonnegative().optional(),
7313
+ reason: external_exports.enum(TURN_END_REASONS).optional()
7310
7314
  }),
7311
7315
  // SDK system 帧 task_started / task_progress / task_notification 的归一化产物:
7312
7316
  // 子 agent 执行过程中实时上报 agentId / lastToolName / stats,UI pending 期就能开抽屉、看进度。
@@ -14001,6 +14005,11 @@ function messageFromJsonl(obj) {
14001
14005
  }
14002
14006
  return null;
14003
14007
  }
14008
+ if (type === "system" && o.subtype === "turn_duration") {
14009
+ const msg = { kind: "turn-end", ts, raw: obj };
14010
+ if (typeof o.durationMs === "number") msg.durationMs = o.durationMs;
14011
+ return msg;
14012
+ }
14004
14013
  if (type === "summary" && typeof o.summary === "string") {
14005
14014
  return { kind: "summary", text: o.summary, ts, raw: obj };
14006
14015
  }
@@ -14803,7 +14812,12 @@ function parseClaudeObjectInner(obj) {
14803
14812
  }
14804
14813
  if (type === "usage") return events;
14805
14814
  if (type === "result") {
14806
- events.push({ kind: "turn_end" });
14815
+ const ev = {
14816
+ kind: "turn_end",
14817
+ reason: typeof subtype === "string" && subtype !== "success" ? "interrupted" : "completed"
14818
+ };
14819
+ if (typeof obj.duration_ms === "number") ev.durationMs = obj.duration_ms;
14820
+ events.push(ev);
14807
14821
  return events;
14808
14822
  }
14809
14823
  if (type === "error") {
@@ -44374,6 +44388,7 @@ function cloneState(s) {
44374
44388
  nextSeq: s.nextSeq,
44375
44389
  bufferStartSeq: s.bufferStartSeq,
44376
44390
  turnOpen: s.turnOpen,
44391
+ turnStartedAt: s.turnStartedAt,
44377
44392
  pendingPermissions: s.pendingPermissions,
44378
44393
  pendingQuestions: s.pendingQuestions,
44379
44394
  freshSpawn: s.freshSpawn,
@@ -44632,6 +44647,10 @@ function applyParsedEvent(state, event, deps) {
44632
44647
  }
44633
44648
  function pushEventToBuffer(state, event, deps) {
44634
44649
  const next = cloneState(state);
44650
+ const effects = pushEventToBufferInPlace(next, event, deps);
44651
+ return { state: next, effects };
44652
+ }
44653
+ function pushEventToBufferInPlace(next, event, deps) {
44635
44654
  const seq = next.nextSeq;
44636
44655
  const withSeq = { ...event, seq };
44637
44656
  const entry = { seq, event: withSeq };
@@ -44641,8 +44660,17 @@ function pushEventToBuffer(state, event, deps) {
44641
44660
  if (newBuffer.length === 1) next.bufferStartSeq = seq;
44642
44661
  const isTurnEnd = withSeq.kind === "turn_end";
44643
44662
  const isUserText = withSeq.kind === "user_text";
44644
- if (isTurnEnd) next.turnOpen = false;
44645
- else if (!next.turnOpen) next.turnOpen = true;
44663
+ if (isTurnEnd) {
44664
+ const te = withSeq;
44665
+ if (te.durationMs === void 0 && typeof next.turnStartedAt === "number") {
44666
+ te.durationMs = Math.max(0, deps.now() - next.turnStartedAt);
44667
+ }
44668
+ next.turnOpen = false;
44669
+ next.turnStartedAt = null;
44670
+ } else if (!next.turnOpen) {
44671
+ next.turnOpen = true;
44672
+ next.turnStartedAt = deps.now();
44673
+ }
44646
44674
  if (!next.turnOpen && next.buffer.length > deps.bufferCap) {
44647
44675
  const remove = next.buffer.length - deps.bufferCap;
44648
44676
  const trimmed = next.buffer.slice(remove);
@@ -44675,7 +44703,7 @@ function pushEventToBuffer(state, event, deps) {
44675
44703
  });
44676
44704
  }
44677
44705
  }
44678
- return { state: next, effects };
44706
+ return effects;
44679
44707
  }
44680
44708
  var RUNTIME_PATCH_KEYS = [
44681
44709
  "model",
@@ -44714,6 +44742,7 @@ function applyCommand(state, command, deps) {
44714
44742
  next.bufferStartSeq = 0;
44715
44743
  next.nextSeq = 0;
44716
44744
  next.turnOpen = false;
44745
+ next.turnStartedAt = null;
44717
44746
  next.status = "running";
44718
44747
  if (deps.mode === "tui" && (next.file.tool ?? "claude") === "claude") {
44719
44748
  next.readyForSend = false;
@@ -44780,6 +44809,11 @@ function applyCommand(state, command, deps) {
44780
44809
  next.status = "stopping";
44781
44810
  effects.push({ kind: "kill", signal: "SIGKILL" });
44782
44811
  }
44812
+ if (next.turnOpen) {
44813
+ effects.push(
44814
+ ...pushEventToBufferInPlace(next, { kind: "turn_end", reason: "interrupted" }, deps)
44815
+ );
44816
+ }
44783
44817
  return { state: next, effects };
44784
44818
  }
44785
44819
  case "spawn-if-needed": {
@@ -44792,6 +44826,7 @@ function applyCommand(state, command, deps) {
44792
44826
  next.bufferStartSeq = 0;
44793
44827
  next.nextSeq = 0;
44794
44828
  next.turnOpen = false;
44829
+ next.turnStartedAt = null;
44795
44830
  next.status = "running";
44796
44831
  if (deps.mode === "tui" && (next.file.tool ?? "claude") === "claude") {
44797
44832
  next.readyForSend = false;
@@ -44864,6 +44899,7 @@ function applyCommand(state, command, deps) {
44864
44899
  next.nextSeq = 0;
44865
44900
  next.bufferStartSeq = 0;
44866
44901
  next.turnOpen = false;
44902
+ next.turnStartedAt = null;
44867
44903
  next.pendingPermissions = {};
44868
44904
  next.freshSpawn = false;
44869
44905
  next.seenUuids = [];
@@ -44902,6 +44938,7 @@ function applyCommand(state, command, deps) {
44902
44938
  next.nextSeq = 0;
44903
44939
  next.bufferStartSeq = 0;
44904
44940
  next.turnOpen = false;
44941
+ next.turnStartedAt = null;
44905
44942
  next.pendingPermissions = {};
44906
44943
  next.freshSpawn = false;
44907
44944
  next.seenUuids = [];
@@ -44958,6 +44995,7 @@ function reduceSessionInner(state, input, deps) {
44958
44995
  const next = cloneState(state);
44959
44996
  next.procAlive = false;
44960
44997
  next.status = "stopped";
44998
+ const interruptEffects = next.turnOpen ? pushEventToBufferInPlace(next, { kind: "turn_end", reason: "interrupted" }, deps) : [];
44961
44999
  resetReadyGate(next);
44962
45000
  const sessionId = next.file.sessionId;
44963
45001
  const clearedEffects = Object.keys(state.pendingQuestions ?? {}).map(
@@ -44974,6 +45012,7 @@ function reduceSessionInner(state, input, deps) {
44974
45012
  return {
44975
45013
  state: next,
44976
45014
  effects: [
45015
+ ...interruptEffects,
44977
45016
  {
44978
45017
  kind: "emit-frame",
44979
45018
  frame: {
@@ -45786,6 +45825,7 @@ function makeInitialState(file, subSessionMeta) {
45786
45825
  nextSeq: 0,
45787
45826
  bufferStartSeq: 0,
45788
45827
  turnOpen: false,
45828
+ turnStartedAt: null,
45789
45829
  pendingPermissions: {},
45790
45830
  pendingQuestions: {},
45791
45831
  freshSpawn: false,
@@ -45829,7 +45869,8 @@ var SessionManager = class {
45829
45869
  // "屏幕真的稳定"作为触发点,signal-driven 而非 timer-driven。
45830
45870
  //
45831
45871
  // 清理点:newSession / stop / session-delete / stopAll。
45832
- pendingTurnDurationSignals = /* @__PURE__ */ new Set();
45872
+ // sessionId gate drop 的 turn_end 携带的 durationMs(可能 undefined);flush 注入时回填
45873
+ pendingTurnDurationSignals = /* @__PURE__ */ new Map();
45833
45874
  // SessionStore 按 scope 派生(root = <dataDir>/sessions/<scopeSubPath>/)。
45834
45875
  // default scope 直接复用 deps.store;persona scope(owner / listener)第一次访问时按需创建并缓存。
45835
45876
  // 取代旧的 storesByAgent —— agentId 概念由 SessionScope 取代,路径即身份,
@@ -47588,14 +47629,18 @@ var SessionManager = class {
47588
47629
  { sessionId, toolSessionId }
47589
47630
  );
47590
47631
  } else {
47632
+ const dropped = outEvents.find((e) => e.kind === "turn_end");
47591
47633
  feedEvents = outEvents.filter((e) => e.kind !== "turn_end");
47592
47634
  if (this.pendingTurnDurationSignals.has(sessionId)) {
47593
47635
  this.deps.screenIdleProbeLogger?.info(
47594
47636
  "turn_duration dedup: pending already set (repeated observer signal)",
47595
47637
  { sessionId, toolSessionId }
47596
47638
  );
47639
+ if (dropped?.durationMs !== void 0) {
47640
+ this.pendingTurnDurationSignals.set(sessionId, dropped.durationMs);
47641
+ }
47597
47642
  } else {
47598
- this.pendingTurnDurationSignals.add(sessionId);
47643
+ this.pendingTurnDurationSignals.set(sessionId, dropped?.durationMs);
47599
47644
  this.deps.screenIdleProbeLogger?.info(
47600
47645
  "turn_duration pending: gate closed \u2192 waiting for screen-idle signal",
47601
47646
  { sessionId, toolSessionId }
@@ -47644,12 +47689,16 @@ var SessionManager = class {
47644
47689
  );
47645
47690
  return;
47646
47691
  }
47692
+ const durationMs = this.pendingTurnDurationSignals.get(sid);
47647
47693
  this.pendingTurnDurationSignals.delete(sid);
47648
47694
  this.deps.screenIdleProbeLogger?.info(
47649
47695
  "notifyScreenIdle: pending turn_duration + screen idle confirmed \u2192 inject turn_end",
47650
47696
  { sessionId: sid, toolSessionId }
47651
47697
  );
47652
- runner.input({ kind: "inject-events", events: [{ kind: "turn_end" }] });
47698
+ runner.input({
47699
+ kind: "inject-events",
47700
+ events: [{ kind: "turn_end", ...durationMs !== void 0 ? { durationMs } : {} }]
47701
+ });
47653
47702
  }
47654
47703
  clearPendingTurnEnd(sessionId) {
47655
47704
  if (this.pendingTurnDurationSignals.delete(sessionId)) {
@@ -51251,7 +51300,9 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
51251
51300
  return super.parseLine(line);
51252
51301
  }
51253
51302
  if (obj.type === "system" && obj.subtype === "turn_duration") {
51254
- return [{ kind: "turn_end" }];
51303
+ const ev = { kind: "turn_end" };
51304
+ if (typeof obj.durationMs === "number") ev.durationMs = obj.durationMs;
51305
+ return [ev];
51255
51306
  }
51256
51307
  if (obj.type !== "user") return super.parseLine(line);
51257
51308
  const message = obj.message;
@@ -58894,6 +58945,7 @@ function slimHistoryMessages(messages) {
58894
58945
  if (m2.parentToolUseId !== void 0) out.parentToolUseId = m2.parentToolUseId;
58895
58946
  if (m2.isSidechain !== void 0) out.isSidechain = m2.isSidechain;
58896
58947
  if (m2.askQuestionAnswers !== void 0) out.askQuestionAnswers = m2.askQuestionAnswers;
58948
+ if (m2.durationMs !== void 0) out.durationMs = m2.durationMs;
58897
58949
  const isErrorPair = m2.toolUseId !== void 0 && errorToolUseIds.has(m2.toolUseId);
58898
58950
  if (m2.kind === "tool_call" && isErrorPair && m2.input !== void 0) out.input = m2.input;
58899
58951
  if (m2.kind === "tool_result" && m2.error !== void 0 && m2.output !== void 0) out.output = m2.output;
@@ -60071,7 +60123,7 @@ function computeMethodAccess(args) {
60071
60123
  }
60072
60124
 
60073
60125
  // src/version.ts
60074
- var version = "0.2.333".length > 0 ? "0.2.333" : "dev";
60126
+ var version = "0.2.334".length > 0 ? "0.2.334" : "dev";
60075
60127
 
60076
60128
  // src/cli-probe/probe.ts
60077
60129
  var fs59 = __toESM(require("fs"), 1);
@@ -22326,6 +22326,7 @@ var AskQuestionItemSchema = external_exports.object({
22326
22326
  multiSelect: external_exports.boolean(),
22327
22327
  options: external_exports.array(AskQuestionOptionSchema).min(1)
22328
22328
  });
22329
+ var TURN_END_REASONS = ["completed", "interrupted"];
22329
22330
  var ParsedEventSchema = external_exports.discriminatedUnion("kind", [
22330
22331
  // session_init 仅携带 session 标识;resolvedModel 等元信息走 meta_update
22331
22332
  external_exports.object({
@@ -22430,11 +22431,14 @@ var ParsedEventSchema = external_exports.discriminatedUnion("kind", [
22430
22431
  // ① SDK 模式 stream-json `result` 帧(claude.ts)—— stdout 最后一帧,可靠
22431
22432
  // ② TUI 模式 observer 读 JSONL `system/turn_duration` 行(claude-tui.ts parseLine)
22432
22433
  // ⚠️ CC 写此行早于该轮尾段正文落盘,可能被尾随 text 覆盖 lastEventKind(③ 存在的原因)
22433
- // ③ TUI 模式屏幕静止 AND observer 静止(observeScreenIdle + manager.observerIdleWaitMs 复合闸 →
22434
- // dispatchTurnIdle inject)—— 的覆盖;等尾随 text 全部 poll 落盘后补,排在 buffer 末条
22434
+ // ③ TUI 模式 gate 关闭期被 drop ② 信号,屏幕稳定后由 manager.notifyScreenIdle flush
22435
+ // 注入(PR #962 双源确认模型;旧 dispatchTurnIdle 已拆除)—— 排在 buffer 末条
22435
22436
  external_exports.object({
22436
22437
  ...ParsedEventBase,
22437
- kind: external_exports.literal("turn_end")
22438
+ kind: external_exports.literal("turn_end"),
22439
+ // 本轮耗时(ms)。SDK=result.duration_ms;TUI=turn_duration.durationMs;缺失时 reducer 按 turnStartedAt 兜底
22440
+ durationMs: external_exports.number().int().nonnegative().optional(),
22441
+ reason: external_exports.enum(TURN_END_REASONS).optional()
22438
22442
  }),
22439
22443
  // SDK system 帧 task_started / task_progress / task_notification 的归一化产物:
22440
22444
  // 子 agent 执行过程中实时上报 agentId / lastToolName / stats,UI pending 期就能开抽屉、看进度。