@tea-agent/loop-agent 0.42.0-next.9 → 0.43.0-next.1

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.
Files changed (157) hide show
  1. package/CHANGELOG.md +65 -59
  2. package/dist/application/dag/run-dag.js +3 -2
  3. package/dist/application/task-lifecycle/advance.js +9 -4
  4. package/dist/build-stamp.json +3 -3
  5. package/dist/cli/program.js +1 -1
  6. package/dist/commands/dag-rerun-task.js +2 -0
  7. package/dist/commands/task-source-prepare.js +3 -1
  8. package/dist/executors/dag-pi-executor.js +1514 -175
  9. package/dist/executors/pi-extension-resolver.js +14 -2
  10. package/dist/executors/shell-executor.js +131 -54
  11. package/dist/shared/dag-failure-category.js +6 -0
  12. package/dist/task/contract/apply.js +36 -2
  13. package/dist/task/source-prepare/parse-intent.js +7 -0
  14. package/dist/worker/console/chat/chat-event-store.js +4 -2
  15. package/dist/worker/console/chat/pi-runtime.js +45 -2
  16. package/dist/worker/console/chat/resource-loader.js +4 -1
  17. package/dist/worker/console/chat/routes.js +28 -12
  18. package/dist/worker/console/chat/sdd-data-alignment.js +13 -2
  19. package/dist/worker/console/chat/session-store.js +5 -1
  20. package/dist/worker/console/chat/subagents/agent-tool.js +62 -0
  21. package/dist/worker/console/chat/subagents/explore-agent.js +169 -0
  22. package/dist/worker/console/chat/subagents/index.js +5 -0
  23. package/dist/worker/console/chat/subagents/orchestrator.js +273 -0
  24. package/dist/worker/console/chat/subagents/tool-policy.js +53 -0
  25. package/dist/worker/console/chat/subagents/types.js +13 -0
  26. package/dist/worker/console/chat/tool-preview.js +10 -0
  27. package/dist/worker/console/chat/tools.js +11 -1
  28. package/dist/worker/console/chat/turn-process.js +1 -0
  29. package/dist/worker/console/interview/tools.js +1 -0
  30. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C6n9_m0P.js → abnfDiagram-N423BO3Z-B0Q0nClf.js} +1 -1
  31. package/dist/worker/console/static/assets/{arc-DQh-IfZ1.js → arc-DCPjC19G.js} +1 -1
  32. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-54NnrwUC.js → architectureDiagram-T3A2C74G-CP5n9jmG.js} +1 -1
  33. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-pivRALGK.js → blockDiagram-VBNYF7ZC-CmaWi_Wg.js} +1 -1
  34. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BR7OV2NJ.js → c4Diagram-5PPSVZJV-Ct5tcMfZ.js} +1 -1
  35. package/dist/worker/console/static/assets/channel-DAS07MdS.js +1 -0
  36. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-B1Aq6BcK.js → chunk-2GRJ4B5K-C0osm1Zf.js} +1 -1
  37. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CbdU0rjo.js → chunk-2Q5K7J3B-CDWviED7.js} +1 -1
  38. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-Dqi2GJeD.js → chunk-5RXB4S5H-mtSk1-j7.js} +1 -1
  39. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BYn1Hu4R.js → chunk-5VM5RSS4-D5J9PHC7.js} +1 -1
  40. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DRLjDL0k.js → chunk-6Q2QTUOP-Begg4WAa.js} +1 -1
  41. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CY9Xx2jV.js → chunk-GF5L2VYU-sF1AEy7T.js} +1 -1
  42. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BNCZs7_z.js → chunk-JWPE2WC7-BqbsWXZb.js} +1 -1
  43. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DZ8AStLL.js → chunk-KBJHAD2P-BKJrPcJ6.js} +1 -1
  44. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DsxjYrzz.js → chunk-RYQCIY6F-CcwNMRho.js} +1 -1
  45. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-Ddx1KC1l.js → chunk-XXDRQBXY-BEJi3iIs.js} +1 -1
  46. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Cwk-5jiW.js +1 -0
  47. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Cwk-5jiW.js +1 -0
  48. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-W9TveCnK.js → cose-bilkent-JH36ORCC-DRLgTvVu.js} +1 -1
  49. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-l9j_ztZH.js → cynefin-VYW2F7L2-BoAVG3cs.js} +1 -1
  50. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BMJMKi4G.js → cynefinDiagram-MW4NZA55-Bzol06hR.js} +1 -1
  51. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-Bb4mG9pH.js → dagre-VZM6K2ZE-UmliJM77.js} +1 -1
  52. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-BMgL_Qv0.js → diagram-7IWD3JNH-BWLcJkFo.js} +1 -1
  53. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Bvo2T4OQ.js → diagram-B4RE2ZJO-CgApOm-O.js} +1 -1
  54. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-_5kWRN9c.js → diagram-LBJQPF4R-Bh3RgTLs.js} +1 -1
  55. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DqdMrltM.js → diagram-Q27KOJAE-Dsh-D5nE.js} +1 -1
  56. package/dist/worker/console/static/assets/{diagram-UB23O5K3-CDDYsNkp.js → diagram-UB23O5K3-Dkbbpcpb.js} +1 -1
  57. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-c4nfnZUV.js → ebnfDiagram-BXEA7PRR-3EBaA3t3.js} +1 -1
  58. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DnkUcNMs.js → erDiagram-JOGREHBK-Bq2Dc5ok.js} +1 -1
  59. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-Dz0KGLZE.js → flowDiagram-UKHOOZJN-De7y55ha.js} +1 -1
  60. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Cj1t1uka.js → ganttDiagram-PKOTCBZU-fLiDbQRh.js} +1 -1
  61. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-tp2FrBHd.js → gitGraphDiagram-DS77QQ5N-Du617mp1.js} +1 -1
  62. package/dist/worker/console/static/assets/index-C0O48S_P.js +449 -0
  63. package/dist/worker/console/static/assets/index-CzKf4U8P.css +1 -0
  64. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DQwJS8DH.js → infoDiagram-6WML65LV-BwmlF-XP.js} +1 -1
  65. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-eimCQWD4.js → ishikawaDiagram-WSZJBQD7-zsGtS59u.js} +1 -1
  66. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-Dd9Gbwgv.js → journeyDiagram-NVQOT4AX-DTTPTe3f.js} +1 -1
  67. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Qve3cyft.js → kanban-definition-27J2QSJJ-BkXg9aP-.js} +1 -1
  68. package/dist/worker/console/static/assets/{linear-UXKSe36Z.js → linear-7U2ue5IE.js} +1 -1
  69. package/dist/worker/console/static/assets/{mermaid.core-CWhj4JXN.js → mermaid.core-BUuGHmWO.js} +5 -5
  70. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-yTcwf4SJ.js → mindmap-definition-FAOFIHXS-7q6fX0Sv.js} +1 -1
  71. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-_7qToaZP.js → pegDiagram-VL7TDLO6-CkQPJN55.js} +1 -1
  72. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CXmrKmDm.js → pieDiagram-7S7Q4E2Y-CCal_tfX.js} +1 -1
  73. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-hMmrJyaS.js → quadrantDiagram-CIZ2JOQS-B7bpxyAZ.js} +1 -1
  74. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BXw8tCBe.js → railroadDiagram-AXF67PYL-CJmww7D-.js} +1 -1
  75. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BmjgnLZl.js → requirementDiagram-LRYGKXZP-D6ldWJEv.js} +1 -1
  76. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Bj77SPpN.js → sankeyDiagram-W5VNT64P-VGh33I9e.js} +1 -1
  77. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-B2FDVysL.js → sequenceDiagram-SI44F4Z6-CCkDrIjU.js} +1 -1
  78. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-UChNY9ZZ.js → sizeCapture-X5ZJPWSS-NC8f5Otb.js} +1 -1
  79. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-wbAEkbd7.js → stateDiagram-OKZ733FA-_92ezZdF.js} +1 -1
  80. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DyJg5gzW.js +1 -0
  81. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DCEkU8HR.js → swimlanes-SLNWSIFB-BdUCGtbP.js} +2 -2
  82. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-B1cw_0Uy.js +8 -0
  83. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-BGp7H06U.js → timeline-definition-Z64GVDOM-CdD1H8ia.js} +1 -1
  84. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DsCIQuWR.js → vennDiagram-T6HMQDX7-Dkdk3oFo.js} +1 -1
  85. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-cRZLP4Xe.js → wardleyDiagram-T6FBY63Y-CKu2uPPY.js} +1 -1
  86. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CP0xLR9Y.js → xychartDiagram-ELKLHX3M-ClqAnuG8.js} +1 -1
  87. package/dist/worker/console/static/index.html +2 -2
  88. package/dist/worker/console/static-src/chat-view-types.js +1 -1
  89. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +23 -0
  90. package/dist/worker/console/static-src/operator-chat/pending-user-message.js +32 -0
  91. package/dist/worker/console/static-src/operator-chat/tools-catalog.js +21 -2
  92. package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +2 -0
  93. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -0
  94. package/dist/worker/console/static-src/operator-chat/useChatStream.js +30 -14
  95. package/dist/worker/console/static-src/operator-chat/useChatThread.js +133 -5
  96. package/dist/worker/console/static-src/shell/workspace-route.js +4 -0
  97. package/dist/worker/observe/static/constants.js +22 -22
  98. package/dist/worker/observe/static/dag-context-reason-labels.js +19 -0
  99. package/dist/worker/observe/static/dag-history-labels.js +1 -0
  100. package/dist/worker/observe/static/dag-inspector-humanize.d.ts +16 -0
  101. package/dist/worker/observe/static/dag-inspector-humanize.js +339 -0
  102. package/dist/worker/observe/static/dag-node-purpose.js +10 -10
  103. package/dist/worker/observe/static/index.html +4 -4
  104. package/dist/worker/observe/static/prompt-restart-candidates.js +4 -2
  105. package/dist/worker/observe/static/relations.js +5 -5
  106. package/dist/worker/observe/static/styles.css +171 -0
  107. package/dist/worker/observe/static/views/dag-graph.js +1 -1
  108. package/dist/worker/observe/static/views/dag-inspector.js +329 -174
  109. package/dist/worker/observe/static/views/dag.js +16 -12
  110. package/dist/worker/observe/static/views/session-timeline.js +5 -3
  111. package/dist/workflows/dag/backend-test-plan-protocol.js +104 -0
  112. package/dist/workflows/dag/dag-retry-schema.js +3 -0
  113. package/dist/workflows/dag/frontend-contract-facts.js +130 -0
  114. package/dist/workflows/dag/frontend-design-policy.js +101 -16
  115. package/dist/workflows/dag/frontend-implementation-contract.js +410 -41
  116. package/dist/workflows/dag/frontend-plan-render.js +13 -2
  117. package/dist/workflows/dag/frontend-prewrite-gate.js +1 -1
  118. package/dist/workflows/dag/frontend-recovery-controller.js +25 -1
  119. package/dist/workflows/dag/frontend-recovery-plan.js +4 -1
  120. package/dist/workflows/dag/frontend-recovery-run.js +142 -16
  121. package/dist/workflows/dag/frontend-risk.js +2 -0
  122. package/dist/workflows/dag/frontend-shadow-dual-write.js +17 -1
  123. package/dist/workflows/dag/frontend-shape.js +16 -6
  124. package/dist/workflows/dag/frontend-test-execution-evidence.js +48 -0
  125. package/dist/workflows/dag/frontend-typed-event-store.js +3 -0
  126. package/dist/workflows/dag/frontend-verification-trace.js +38 -4
  127. package/dist/workflows/dag/frontend-writer-admission.js +2 -2
  128. package/dist/workflows/dag/init-hybrid.js +57 -28
  129. package/dist/workflows/dag/node-execution.js +201 -85
  130. package/dist/workflows/dag/recovery-lease.js +106 -16
  131. package/dist/workflows/dag/rerun-feedback.js +1 -0
  132. package/dist/workflows/dag/rerun-plan.js +90 -4
  133. package/dist/workflows/dag/rerun-run.js +28 -6
  134. package/dist/workflows/dag/rerun-task.js +221 -18
  135. package/dist/workflows/dag/retry-policy.js +27 -10
  136. package/dist/workflows/dag/runner-exit-diagnostics.js +125 -0
  137. package/dist/workflows/dag/runner.js +220 -18
  138. package/dist/workflows/dag/structured-output-repair.js +4 -1
  139. package/dist/workflows/dag/types.js +4 -3
  140. package/dist/workflows/dag/validate.js +10 -8
  141. package/dist/workflows/dag/workspace-checkpoint.js +66 -0
  142. package/docs/operations/README.md +1 -0
  143. package/docs/templates/agent-dag.schema.json +2 -2
  144. package/docs/templates/backend-test-dag.json +6 -4
  145. package/docs/templates/frontend-implementation-contract.schema.json +34 -2
  146. package/harness.json +1 -1
  147. package/package.json +4 -5
  148. package/skills/frontend-plan/SKILL.md +14 -1
  149. package/skills/frontend-plan/references/decision-contract.md +101 -5
  150. package/skills/frontend-plan/references/design-decisions.md +32 -0
  151. package/dist/worker/console/static/assets/channel-DsZxrgqe.js +0 -1
  152. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-CuToPeGV.js +0 -1
  153. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-CuToPeGV.js +0 -1
  154. package/dist/worker/console/static/assets/index-D9Sc0f0y.js +0 -449
  155. package/dist/worker/console/static/assets/index-DDQc5a50.css +0 -1
  156. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-yPoT19ft.js +0 -1
  157. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-VWdarchG.js +0 -8
@@ -1,7 +1,8 @@
1
- import { useCallback, useEffect, useMemo, useState } from "react";
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
2
  import { buildTurnProcessGroups, hydrateSessionThread, selectRecentTurnGroups, } from "../../chat/turn-process.js";
3
3
  import { mergeOperationCardState, } from "../../chat/operation-card.js";
4
4
  import { createChatSseEventApplier, } from "./chat-sse-events.js";
5
+ import { mergePendingSubmissionOnHydration } from "./pending-user-message.js";
5
6
  import { taskContextUnchanged } from "./format.js";
6
7
  import { upsertCompactionMessage } from "./compaction-message.js";
7
8
  const EMPTY_USAGE = {
@@ -118,6 +119,10 @@ export function useChatThread(params) {
118
119
  const [operationCards, setOperationCards] = useState([]);
119
120
  const [artifactCards, setArtifactCards] = useState([]);
120
121
  const [historyLimit, setHistoryLimit] = useState(50);
122
+ const [historyHasMore, setHistoryHasMore] = useState(false);
123
+ const [historyNextCursor, setHistoryNextCursor] = useState(null);
124
+ const [historyLoading, setHistoryLoading] = useState(false);
125
+ const historyLoadingRef = useRef(false);
121
126
  const [unread, setUnread] = useState(0);
122
127
  const [humanGateCards, setHumanGateCards] = useState([]);
123
128
  const [interview, setInterview] = useState(null);
@@ -136,6 +141,8 @@ export function useChatThread(params) {
136
141
  /** Assistant bubble id for the in-flight turn; only this row shows the streaming cursor. */
137
142
  const [streamingAssistantId, setStreamingAssistantId] = useState(null);
138
143
  const [showSystemInMessages] = useState(false);
144
+ const completedGroupsRef = useRef([]);
145
+ const previousTimelineRef = useRef(null);
139
146
  const refreshSessionTelemetry = useCallback(async () => {
140
147
  const targetSessionId = refs.sessionRef.current?.sessionId;
141
148
  if (!targetSessionId)
@@ -301,12 +308,55 @@ export function useChatThread(params) {
301
308
  };
302
309
  }, [toolCalls]);
303
310
  const turnGroups = useMemo(() => {
304
- const all = buildTurnProcessGroups({
311
+ const previousTimeline = previousTimelineRef.current;
312
+ let built;
313
+ const activeIndex = streamingAssistantId
314
+ ? timelineMessages.findIndex((message) => message.id === streamingAssistantId)
315
+ : -1;
316
+ const canBuildActiveTail = Boolean(previousTimeline && streaming && streamingAssistantId && activeIndex >= 0) &&
317
+ previousTimeline?.activeAssistantId === streamingAssistantId &&
318
+ (previousTimeline?.messages.every((message, index) => message.id === streamingAssistantId || timelineMessages[index]?.id === message.id) ?? false);
319
+ if (canBuildActiveTail && previousTimeline) {
320
+ let tailStart = activeIndex;
321
+ while (tailStart > 0 && timelineMessages[tailStart - 1]?.role !== "user")
322
+ tailStart -= 1;
323
+ const tailMessages = timelineMessages.slice(tailStart);
324
+ const tailIds = new Set(tailMessages.map((message) => message.id));
325
+ const tailTurnIds = new Set(tailMessages.map((message) => message.turnId).filter(Boolean));
326
+ const tailTools = toolCalls.filter((tool) => tailIds.has(tool.assistantMessageId ?? "") ||
327
+ (Boolean(tool.turnId) && tailTurnIds.has(tool.turnId)) ||
328
+ (tool.createdAt >= (tailMessages[0]?.createdAt ?? Number.POSITIVE_INFINITY)));
329
+ const activeTail = buildTurnProcessGroups({
330
+ messages: tailMessages,
331
+ toolCalls: tailTools,
332
+ streaming,
333
+ activeAssistantId: streamingAssistantId,
334
+ });
335
+ built = [...previousTimeline.groups.filter((group) => !group.live), ...activeTail];
336
+ }
337
+ else {
338
+ built = buildTurnProcessGroups({
339
+ messages: timelineMessages,
340
+ toolCalls,
341
+ streaming,
342
+ activeAssistantId: streamingAssistantId,
343
+ });
344
+ }
345
+ // Preserve completed group objects across streaming tokens. The active
346
+ // tail is rebuilt, while stable historical groups keep their references so
347
+ // memoized rows do not re-render or re-parse the full conversation.
348
+ const previous = new Map(completedGroupsRef.current.map((group) => [group.key, group]));
349
+ const all = built.map((group) => {
350
+ const cached = previous.get(group.key);
351
+ return cached && !group.live ? cached : group;
352
+ });
353
+ completedGroupsRef.current = all.filter((group) => !group.live);
354
+ previousTimelineRef.current = {
305
355
  messages: timelineMessages,
306
356
  toolCalls,
307
- streaming,
308
357
  activeAssistantId: streamingAssistantId,
309
- });
358
+ groups: all,
359
+ };
310
360
  return selectRecentTurnGroups(all, historyLimit);
311
361
  }, [
312
362
  timelineMessages,
@@ -315,6 +365,50 @@ export function useChatThread(params) {
315
365
  streamingAssistantId,
316
366
  historyLimit,
317
367
  ]);
368
+ const loadEarlierMessages = useCallback(async () => {
369
+ const targetSessionId = refs.sessionRef.current?.sessionId;
370
+ const beforeId = historyNextCursor;
371
+ if (!targetSessionId || !historyHasMore || !beforeId || historyLoadingRef.current)
372
+ return false;
373
+ historyLoadingRef.current = true;
374
+ setHistoryLoading(true);
375
+ try {
376
+ const query = new URLSearchParams({ limit: "50", beforeId });
377
+ const res = await fetch(`${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(targetSessionId)}/messages?${query.toString()}`, { credentials: "include" });
378
+ if (!res.ok || refs.sessionRef.current?.sessionId !== targetSessionId)
379
+ return false;
380
+ const body = (await res.json());
381
+ const page = hydrateSessionThread(body.messages ?? []);
382
+ setMessages((current) => {
383
+ const seen = new Set();
384
+ const merged = [...page.messages, ...current].filter((message) => {
385
+ if (seen.has(message.id))
386
+ return false;
387
+ seen.add(message.id);
388
+ return true;
389
+ });
390
+ return merged.sort((a, b) => {
391
+ if (a.eventSeq !== undefined && b.eventSeq !== undefined && a.eventSeq !== b.eventSeq)
392
+ return a.eventSeq - b.eventSeq;
393
+ return a.createdAt - b.createdAt;
394
+ });
395
+ });
396
+ setToolCalls((current) => {
397
+ const byId = new Map(current.map((tool) => [tool.id, tool]));
398
+ for (const tool of page.toolCalls)
399
+ byId.set(tool.id, tool);
400
+ return [...byId.values()].sort((a, b) => a.createdAt - b.createdAt);
401
+ });
402
+ setHistoryHasMore(body.hasMore === true);
403
+ setHistoryNextCursor(body.nextCursor ?? null);
404
+ setHistoryLimit((value) => value + 50);
405
+ return true;
406
+ }
407
+ finally {
408
+ historyLoadingRef.current = false;
409
+ setHistoryLoading(false);
410
+ }
411
+ }, [historyHasMore, historyNextCursor, origin, refs]);
318
412
  const visibleMessages = useMemo(() => {
319
413
  const next = [];
320
414
  for (const group of turnGroups) {
@@ -346,6 +440,11 @@ export function useChatThread(params) {
346
440
  setStreamingAssistantId(null);
347
441
  setUnread(0);
348
442
  setHistoryLimit(50);
443
+ setHistoryHasMore(false);
444
+ setHistoryNextCursor(null);
445
+ historyLoadingRef.current = false;
446
+ completedGroupsRef.current = [];
447
+ previousTimelineRef.current = null;
349
448
  refs.usageResponseKeysRef.current = new Set();
350
449
  }, [refs]);
351
450
  /** Adopt a freshly activated session's hydrated thread + streaming flags. */
@@ -374,6 +473,10 @@ export function useChatThread(params) {
374
473
  setStreamingAssistantId(null);
375
474
  setUnread(0);
376
475
  setHistoryLimit(50);
476
+ setHistoryHasMore(next.history?.hasMore === true);
477
+ setHistoryNextCursor(next.history?.nextCursor ?? null);
478
+ completedGroupsRef.current = [];
479
+ previousTimelineRef.current = null;
377
480
  }, [refs]);
378
481
  /** Reconcile recovery (AC-001/AC-002/AC-003): reload the canonical session
379
482
  * facts (session-store messages + event-ring tail cursor) and REPLACE the
@@ -415,8 +518,29 @@ export function useChatThread(params) {
415
518
  refs.turnAssistantIdsRef.current = new Map();
416
519
  refs.sealedAssistantIdsRef.current = new Set();
417
520
  const hydrated = hydrateSessionThread(body.session.messages ?? []);
418
- setMessages(mergeCompactionMessages(hydrated.messages, body.compactions));
521
+ const pending = refs.pendingSubmissionRef.current;
522
+ const recovered = mergePendingSubmissionOnHydration(hydrated.messages, pending
523
+ ? {
524
+ clientRequestId: pending.clientRequestId,
525
+ user: {
526
+ id: pending.userMessageId,
527
+ role: "user",
528
+ text: pending.text,
529
+ createdAt: Date.now(),
530
+ clientRequestId: pending.clientRequestId,
531
+ },
532
+ assistant: {
533
+ id: pending.assistantId,
534
+ role: "assistant",
535
+ text: "",
536
+ createdAt: Date.now(),
537
+ },
538
+ }
539
+ : undefined);
540
+ setMessages(mergeCompactionMessages(recovered, body.compactions));
419
541
  setToolCalls(hydrated.toolCalls);
542
+ setHistoryHasMore(body.history?.hasMore === true);
543
+ setHistoryNextCursor(body.history?.nextCursor ?? null);
420
544
  setStreamingAssistantId(null);
421
545
  return true;
422
546
  }
@@ -446,6 +570,10 @@ export function useChatThread(params) {
446
570
  artifactCards,
447
571
  historyLimit,
448
572
  setHistoryLimit,
573
+ historyHasMore,
574
+ historyNextCursor,
575
+ historyLoading,
576
+ loadEarlierMessages,
449
577
  unread,
450
578
  humanGateCards,
451
579
  interview,
@@ -170,6 +170,10 @@ export function withWorkspaceId(href, workspaceId) {
170
170
  const qs = query.toString();
171
171
  return `/#${path}${qs ? `?${qs}` : ""}`;
172
172
  }
173
+ /** The primary Observe mode is a section entry, not an object deep link. */
174
+ export function buildPrimaryInspectHref(workspaceId) {
175
+ return withWorkspaceId(DEFAULT_INSPECT_HREF, workspaceId);
176
+ }
173
177
  /** Preserve the selected scope for a deep link emitted inside an Operate page.
174
178
  * Components should prefer this to hand-writing `/#/inspect/...`: it reads the
175
179
  * canonical hash at click/render time and intentionally leaves bare Chat URLs
@@ -20,20 +20,20 @@ export const OUTPUT_FOLLOW_LATEST_PX = 48;
20
20
 
21
21
  export const UI_TEXT = {
22
22
  dashboard: "总览",
23
- dagRuns: "DAG 运行",
24
- dagHistory: "DAG 运行历史",
23
+ dagRuns: "运行流程",
24
+ dagHistory: "运行历史",
25
25
  viewAllDags: "查看全部 →",
26
- failures: "异常 Task",
26
+ failures: "异常任务",
27
27
  nightJobs: "夜间任务",
28
28
  batchDetail: "批次详情",
29
29
  runDetail: "运行详情",
30
- dagDetail: "DAG 详情",
31
- activeDags: "进行中的 DAG",
32
- recentDags: "最近 DAG 运行",
33
- batches: "Worker 批次",
34
- noActiveDags: "当前没有进行中的 DAG,启动后将出现在这里。",
35
- noRecentDags: "暂无 DAG 运行记录。",
36
- noFormalDagHistory: "暂无正式 DAG 运行记录",
30
+ dagDetail: "运行详情",
31
+ activeDags: "进行中的流程",
32
+ recentDags: "最近运行",
33
+ batches: "任务批次",
34
+ noActiveDags: "当前没有进行中的流程,启动后将出现在这里。",
35
+ noRecentDags: "暂无运行记录。",
36
+ noFormalDagHistory: "暂无正式运行记录",
37
37
  noFormalDagHistoryHint:
38
38
  "dry-run / init-only 预检记录不会出现在此列表中。",
39
39
  dagHistoryRefreshFailed: "刷新失败,当前展示上一次结果",
@@ -41,34 +41,34 @@ export const UI_TEXT = {
41
41
  dagHistoryCopiedAnnounce: "已复制运行 ID",
42
42
  dagHistoryCopyFailed: "复制失败,请手动选择运行 ID",
43
43
  dagHistoryCopyTooltip: "复制运行 ID",
44
- noBatches: "暂无 Worker 批次,运行后将出现在这里。",
44
+ noBatches: "暂无任务批次,运行后将出现在这里。",
45
45
  noNodes: "暂无节点。",
46
46
  noOutput: "暂无节点输出。",
47
47
  noInput: "暂无节点输入。",
48
48
  inputLoading: "正在加载节点输入…",
49
- inputUnavailable: "未在冻结 DAG tasks[] 中找到该节点输入。",
49
+ inputUnavailable: "没有在本次运行保存的执行计划中找到该节点设置。",
50
50
  inputDynamicUnsupported:
51
- "该节点为运行时动态展开节点,Phase A 暂不提供完整输入。",
52
- inputRunSpecUnavailable: "无法读取冻结 DAG 规格(run.json)。",
51
+ "该节点是在运行过程中动态生成的,暂时无法展示完整的运行前设置。",
52
+ inputRunSpecUnavailable: "无法读取本次运行开始前保存的执行计划(run.json)。",
53
53
  inputError: "加载节点输入失败。",
54
- inputFrozenLabel: "冻结 DAG 节点定义",
55
- inputFingerprintNote: "仅保存 assembled prompt 指纹,全文未持久化",
56
- noSessionEvents: "该 Pi 节点暂无过程日志(可能尚未执行、走 CLI 路径,或为历史 run)",
57
- noShellProcess: "该 shell 节点尚未留下命令回执。",
54
+ inputFrozenLabel: "本次运行开始前保存的执行设置",
55
+ inputFingerprintNote: "这里只保存最终提示内容的校验信息,没有保存完整文本。",
56
+ noSessionEvents: "该 AI 节点暂无过程日志(可能尚未执行、通过命令行执行,或来自较早的运行)。",
57
+ noShellProcess: "该命令节点尚未留下执行记录。",
58
58
  noPresetProcess: "该内部处理器尚未留下过程回执。",
59
- staticNoProcess: "静态节点没有逐步执行过程,请查看节点输出。",
59
+ staticNoProcess: "系统直接生成的节点没有逐步执行过程,请查看节点输出。",
60
60
  processLoading: "正在加载执行过程…",
61
61
  processError: "加载执行过程失败。",
62
- shellCommandsHeading: "Shell 命令",
62
+ shellCommandsHeading: "命令执行记录",
63
63
  shellPresetHeading: "内部处理器",
64
64
  noArtifacts: "暂无产物记录。",
65
65
  noActiveCommand: "当前没有正在执行的命令。",
66
- noFailures: "当前没有异常 Task。",
66
+ noFailures: "当前没有异常任务。",
67
67
  enterDetail: "查看详情 →",
68
68
  repoRoot: "仓库根目录",
69
69
  generatedAt: "生成时间",
70
70
  refreshStatus: "更新",
71
- failureInbox: "异常 Task",
71
+ failureInbox: "异常任务",
72
72
  nearRealtime: "轮询刷新",
73
73
  manualRefresh: "手动刷新",
74
74
  autoRefresh: "自动刷新",
@@ -30,6 +30,25 @@ const CONTEXT_TRANSFER_REASON_LABELS = {
30
30
  WORKER_CONTINUATION_AUTHORITY_MISMATCH: "Worker 派生运行的归属事实不一致",
31
31
  WORKER_CONTINUATION_NEEDS_RECONCILE: "Worker 派生运行已存在,需要先恢复核对",
32
32
  WORKER_CONTINUATION_LEASE_CONFLICT: "该 Worker Task 已有运行占用",
33
+ "parent-lifecycle-ineligible": "原运行尚未完整结束,只有已完成的运行才能从这里继续",
34
+ "convergence-rerun-unsupported": "原运行使用自动收敛流程,暂不支持替换产出后继续",
35
+ "evaluation-rerun-unsupported": "评测运行暂不支持替换产出后继续",
36
+ "budget-lineage-missing": "缺少原运行的额度使用记录",
37
+ "budget-lineage-breached": "原运行已经用完或超出额度",
38
+ "budget-lineage-drift": "原运行的额度规则已经变化",
39
+ "sourceBindingMatched-drift": "任务来源与原运行不一致",
40
+ "taskContractBindingMatched-drift": "任务约定与原运行不一致",
41
+ "controllerIdentityMatched-drift": "运行控制器版本与原运行不一致",
42
+ "skillSnapshotVerified-drift": "节点使用的技能版本无法与原运行核对",
43
+ "workspaceMatched-drift": "当前工作区内容与原运行结束时不一致",
44
+ "restart-subgraph-contains-writer": "受影响范围里有写入节点,但它的文件边界不够明确",
45
+ "restart-subgraph-contains-decision-gate": "受影响范围里包含需要人工重新决定的关卡",
46
+ "restart-subgraph-contains-unsafe-shell": "受影响范围里有不能安全自动重跑的命令",
47
+ "dynamic-rerun-unsupported": "受影响范围里有无法安全重新生成的动态节点",
48
+ "parent-facts-invalid": "准备沿用的节点没有完整的成功记录",
49
+ "workspace-checkpoint-missing": "缺少原运行结束时的工作区校验记录",
50
+ "workspace-drift": "当前工作区已经发生变化,不能安全接着写",
51
+ HIGH_RISK_AUTHORITY_MISSING: "高风险重跑缺少完整的写入、动态节点或额度校验信息",
33
52
  INELIGIBLE: "当前不满足继续运行的条件",
34
53
  PARENT_IMMUTABILITY_VIOLATION: "父运行事实发生变化,已阻止派生",
35
54
  PARENT_LIFECYCLE: "父运行状态不允许派生继续",
@@ -19,6 +19,7 @@ const ATTEMPT_FAILURE_LABELS = {
19
19
  "structured-repair-exhausted": "结构化修复耗尽",
20
20
  "governance-blocked": "治理规则阻断",
21
21
  "empty-output": "输出为空",
22
+ network: "网络连接失败",
22
23
  auth: "认证失败",
23
24
  quota: "额度或限流",
24
25
  "rate-limit": "额度或限流",
@@ -0,0 +1,16 @@
1
+ export type InspectorMetaCopy = {
2
+ label: string;
3
+ value: string;
4
+ help: string | null;
5
+ rawLabel: string | null;
6
+ rawValue: string | null;
7
+ };
8
+
9
+ export function inspectorFieldLabel(field: unknown): string;
10
+ export function inspectorValueLabel(field: unknown, value: unknown): string;
11
+ export function inspectorListValueLabel(value: unknown): string;
12
+ export function inspectorFieldHelp(field: unknown): string | null;
13
+ export function describeInspectorMeta(
14
+ field: unknown,
15
+ value: unknown,
16
+ ): InspectorMetaCopy;