@tea-agent/loop-agent 0.44.0-next.6 → 0.44.0-next.8
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/CHANGELOG.md +288 -454
- package/dist/build-stamp.json +3 -3
- package/dist/executors/dag-pi/guards.js +4 -0
- package/dist/executors/dag-pi/model-config.js +30 -0
- package/dist/{workflows/dag/frontend-plan-completeness.js → executors/dag-pi/plan/facts.js} +25 -41
- package/dist/executors/dag-pi/plan/ledger-contract.js +55 -0
- package/dist/executors/dag-pi/tools/contract-tools.js +515 -0
- package/dist/executors/dag-pi/tools/design-terminal-tools.js +156 -0
- package/dist/executors/dag-pi/tools/plan-decision-tools.js +519 -0
- package/dist/executors/dag-pi/tools/review-terminal-tools.js +156 -0
- package/dist/executors/dag-pi/tools/scout-evidence-tools.js +270 -0
- package/dist/executors/dag-pi-executor.js +64 -1907
- package/dist/shared/git-workspace-status.js +2 -0
- package/dist/task/frontend-preflight.js +1 -1
- package/dist/task/source-prepare/semantic-intake.js +1 -1
- package/dist/task/source-prepare/source-fidelity-pi.js +1 -1
- package/dist/worker/console/chat/assistant-content.js +5 -34
- package/dist/worker/console/chat/chat-event-store.js +27 -10
- package/dist/worker/console/chat/db-connections.js +72 -8
- package/dist/worker/console/chat/pi-runtime/custom-tools/sql-tools.js +52 -24
- package/dist/worker/console/chat/pi-runtime.js +34 -0
- package/dist/worker/console/chat/routes.js +138 -9
- package/dist/worker/console/chat/session-store.js +147 -19
- package/dist/worker/console/chat/turn-process.js +69 -23
- package/dist/worker/console/chat/user-turn-outline.js +19 -0
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Brn2sPzL.js → abnfDiagram-N423BO3Z-r1NAPU_5.js} +1 -1
- package/dist/worker/console/static/assets/{arc-BIMNTG0W.js → arc-dT5T4sVL.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G--WtcgR_A.js → architectureDiagram-T3A2C74G-CP_cOq46.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-BT_Ztog1.js → blockDiagram-VBNYF7ZC-sToEZxEf.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-C5hbVr-l.js → c4Diagram-5PPSVZJV-DSxwwi2m.js} +1 -1
- package/dist/worker/console/static/assets/channel-CyBY_yGk.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-BKKnyR9Z.js → chunk-2GRJ4B5K-B9fh0IkF.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-BHs6biqA.js → chunk-2Q5K7J3B-CAUNl-A6.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BdSFy_vP.js → chunk-5RXB4S5H-BomeqbNX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BpJIdTKV.js → chunk-5VM5RSS4-BNAuTOLE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-C_iWJhkT.js → chunk-6Q2QTUOP-DfzjRD5y.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-BTbmx3-k.js → chunk-GF5L2VYU-C3uE-yc2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-D4Ee6DmP.js → chunk-JWPE2WC7-C3sQMMYr.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-B487SORR.js → chunk-KBJHAD2P-D_AtEYQL.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-BKYHjNrr.js → chunk-RYQCIY6F-DW4TwhKv.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DrTdoYZG.js → chunk-XXDRQBXY-CTQDmJcp.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D5lN4E_E.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D5lN4E_E.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CttUY_Jo.js → cose-bilkent-JH36ORCC-iMqPuBsL.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-B4Rm5gnR.js → cynefin-VYW2F7L2-DktIuDWs.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-ByxHBq_S.js → cynefinDiagram-MW4NZA55-BgVnjyEs.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-DGrfNFA0.js → dagre-VZM6K2ZE-CR25E4bu.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-KjrUPquv.js → diagram-7IWD3JNH-CPM2h5HY.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-VS4mlm75.js → diagram-B4RE2ZJO-DqF0x2g1.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BLXYmFTM.js → diagram-LBJQPF4R-G8BYp2eb.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-C6xoFAqH.js → diagram-Q27KOJAE-BbC4kT_D.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-C478dCe7.js → diagram-UB23O5K3-CKZwZ-G5.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DHEpW5zN.js → ebnfDiagram-BXEA7PRR-kJDmheia.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CA5GKfo9.js → erDiagram-JOGREHBK-DFTVHyxB.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-zysi0Fl-.js → flowDiagram-UKHOOZJN-BqdN5_os.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DGzcKA8Y.js → ganttDiagram-PKOTCBZU-SYDjVakh.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-CHsuIG1w.js → gitGraphDiagram-DS77QQ5N-Bf8bNpGA.js} +1 -1
- package/dist/worker/console/static/assets/index-B28Onmfy.css +1 -0
- package/dist/worker/console/static/assets/index-CTMZsDmh.js +486 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BexZHPCp.js → infoDiagram-6WML65LV-DIeAmJ45.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-Gkx8q-DB.js → ishikawaDiagram-WSZJBQD7-oikqUAlo.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-XDW3qrJ7.js → journeyDiagram-NVQOT4AX-mKEF_xYT.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DJ07eEaN.js → kanban-definition-27J2QSJJ-BdWJHPnN.js} +1 -1
- package/dist/worker/console/static/assets/{linear-DL-zeqOn.js → linear-DGRlieMH.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-C0HdXtOf.js → mermaid.core-4P9yPC9c.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CqRX0lrt.js → mindmap-definition-FAOFIHXS-5PTSkos6.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BVM9JZ2H.js → pegDiagram-VL7TDLO6-DONIFpG5.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BA3ozdKk.js → pieDiagram-7S7Q4E2Y-D_Z4S70M.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-B-0_p9_4.js → quadrantDiagram-CIZ2JOQS-CAsjh8iY.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-DHRzPWFc.js → railroadDiagram-AXF67PYL-Cx4Dd6ac.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-9BEC_PcW.js → requirementDiagram-LRYGKXZP-cQb7mwyH.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-DMxeW4rN.js → sankeyDiagram-W5VNT64P-Cd-DhUdf.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DixP6LIU.js → sequenceDiagram-SI44F4Z6-AlKYRgIk.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-B_EifJBo.js → sizeCapture-X5ZJPWSS-CUy_ET4e.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BwikwWbX.js → stateDiagram-OKZ733FA-CTuVe6Sa.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BsWhs8O7.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-C162l9o1.js → swimlanes-SLNWSIFB-ChFLJb-v.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CJcioYGH.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-mpe_u1i4.js → timeline-definition-Z64GVDOM-DZZeiAPr.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DyUk54HX.js → vennDiagram-T6HMQDX7-t4O91cZU.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-HYyMkzfm.js → wardleyDiagram-T6FBY63Y-CV5qGHZu.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-DRoh7skR.js → xychartDiagram-ELKLHX3M-DyXbytUI.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-link.js +20 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +58 -3
- package/dist/worker/console/static-src/operator-chat/process-label.js +19 -6
- package/dist/worker/console/static-src/operator-chat/transcript-mode.js +21 -0
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +2 -0
- package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +13 -5
- package/dist/worker/console/static-src/operator-chat/turn-state-projection.js +166 -0
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +56 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +202 -43
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +78 -23
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +55 -18
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +5 -2
- package/dist/worker/scheduler/scheduled-goal-dispatch.js +3 -2
- package/dist/worker/scheduler/scheduled-goal-evidence.js +6 -1
- package/package.json +1 -1
- package/dist/worker/console/static/assets/channel-DNWB4hpR.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-COhFgJji.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-COhFgJji.js +0 -1
- package/dist/worker/console/static/assets/index-CJh6pVLm.js +0 -482
- package/dist/worker/console/static/assets/index-C_kvKmFM.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-S2ZHMo1c.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BZm4ByfV.js +0 -8
|
@@ -3,8 +3,50 @@ import { formatOperatorUserError } from "../../operator-user-error.js";
|
|
|
3
3
|
import { inspectChatSseContinuity, readChatStreamReadyCursor, selectChatSseRepairBlocks, selectLaterChatEventId, } from "./chat-stream-continuity.js";
|
|
4
4
|
import { confirmationToken, requestId, sleep } from "./format.js";
|
|
5
5
|
import { classifyCreateTurnNetworkFailure, classifyCreateTurnResponse, createPendingSubmission, decideSubmissionRoute, isRuntimeBusyUnion, isSubmissionCurrent, isTerminalTurnState, keepAmbiguousAfterRetry, reconcileDeferredSubmissionFromState, reconcilePendingSubmissionFromState, resolveAmbiguousFromState, } from "./turn-submission.js";
|
|
6
|
-
import { applyAbortDecision, applyPendingReconcileDecision, classifyAbortResponse, markStopRequested, operatorChatAbortUrl, operatorChatEventsUrl, operatorChatStateUrl, operatorChatTurnsUrl, releaseOwnershipOnTerminalEvidence, releaseSubmitOwnership as releaseOwnershipBag, requestStopOnOwnership, settleCreateTurnOutcome, turnPhaseFromOwnership, visualTurnPhaseFromOwnership, } from "./turn-stream-controller.js";
|
|
6
|
+
import { applyAbortDecision, applyPendingReconcileDecision, classifyAbortResponse, createBoundedOwnerSignal, markStopRequested, operatorChatAbortUrl, operatorChatEventsUrl, operatorChatStateUrl, operatorChatTurnsUrl, releaseOwnershipOnTerminalEvidence, releaseSubmitOwnership as releaseOwnershipBag, requestStopOnOwnership, settleCreateTurnOutcome, turnPhaseFromOwnership, visualTurnPhaseFromOwnership, } from "./turn-stream-controller.js";
|
|
7
7
|
import { appendPendingSubmission, removePendingSubmission } from "./pending-user-message.js";
|
|
8
|
+
import { createTurnStateReconcileQueue, turnStateReconcileTrigger, } from "./turn-state-projection.js";
|
|
9
|
+
const STATE_REQUEST_TIMEOUT_MS = 2_000;
|
|
10
|
+
async function fetchReconciledSessionState(origin, sessionId, options) {
|
|
11
|
+
const bounded = createBoundedOwnerSignal({
|
|
12
|
+
ownerSignal: options?.ownerSignal,
|
|
13
|
+
timeoutMs: STATE_REQUEST_TIMEOUT_MS,
|
|
14
|
+
});
|
|
15
|
+
try {
|
|
16
|
+
const res = await fetch(operatorChatStateUrl(origin, sessionId, options?.turnIds), {
|
|
17
|
+
credentials: "include",
|
|
18
|
+
signal: bounded.signal,
|
|
19
|
+
});
|
|
20
|
+
const body = (await res.json().catch(() => ({})));
|
|
21
|
+
if (!res.ok)
|
|
22
|
+
return null;
|
|
23
|
+
return body.state ?? null;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
bounded.dispose();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function readChatSseTurnId(block) {
|
|
33
|
+
const data = block
|
|
34
|
+
.split("\n")
|
|
35
|
+
.filter((line) => line.startsWith("data: "))
|
|
36
|
+
.map((line) => line.slice(6))
|
|
37
|
+
.join("");
|
|
38
|
+
if (!data)
|
|
39
|
+
return undefined;
|
|
40
|
+
try {
|
|
41
|
+
const parsed = JSON.parse(data);
|
|
42
|
+
return typeof parsed.turnId === "string" && parsed.turnId
|
|
43
|
+
? parsed.turnId
|
|
44
|
+
: undefined;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
8
50
|
/** Project ChatRefs into the executable ownership bag used by the controller. */
|
|
9
51
|
function ownershipBagFromRefs(refs) {
|
|
10
52
|
return {
|
|
@@ -106,6 +148,17 @@ export function useChatStream(params) {
|
|
|
106
148
|
* smooth (M4.1/M4.3). */
|
|
107
149
|
const openEventsStream = useCallback(async (sessionId, generation, signal) => {
|
|
108
150
|
const gapReplayBuffer = [];
|
|
151
|
+
const turnStateReconciles = createTurnStateReconcileQueue({
|
|
152
|
+
read: (turnIds) => fetchReconciledSessionState(origin, sessionId, {
|
|
153
|
+
turnIds,
|
|
154
|
+
ownerSignal: signal,
|
|
155
|
+
}),
|
|
156
|
+
apply: (summaries) => thread.reconcileTurnStates([...summaries]),
|
|
157
|
+
wait: (delayMs) => sleep(delayMs, signal),
|
|
158
|
+
isCancelled: () => signal.aborted ||
|
|
159
|
+
refs.sessionRef.current?.sessionId !== sessionId ||
|
|
160
|
+
refs.sessionGenerationRef.current !== generation,
|
|
161
|
+
});
|
|
109
162
|
while (!signal.aborted) {
|
|
110
163
|
const state = refs.eventsStreamStateRef.current;
|
|
111
164
|
if (!state ||
|
|
@@ -145,6 +198,16 @@ export function useChatStream(params) {
|
|
|
145
198
|
const block = blocks[blockIndex];
|
|
146
199
|
if (block === undefined)
|
|
147
200
|
continue;
|
|
201
|
+
const eventName = sseEventName(block);
|
|
202
|
+
const reconcileTrigger = turnStateReconcileTrigger(replay, eventName);
|
|
203
|
+
if (reconcileTrigger) {
|
|
204
|
+
const settledTurnId = readChatSseTurnId(block);
|
|
205
|
+
if (settledTurnId) {
|
|
206
|
+
turnStateReconciles.enqueue(settledTurnId, {
|
|
207
|
+
defer: reconcileTrigger === "after-replay",
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
148
211
|
if (!replay) {
|
|
149
212
|
const continuity = inspectChatSseContinuity(block, liveContinuityCursor);
|
|
150
213
|
if (continuity.action === "reconnect") {
|
|
@@ -156,7 +219,7 @@ export function useChatStream(params) {
|
|
|
156
219
|
break readLoop;
|
|
157
220
|
}
|
|
158
221
|
}
|
|
159
|
-
if (
|
|
222
|
+
if (eventName === "stream_ready") {
|
|
160
223
|
const current = refs.eventsStreamStateRef.current;
|
|
161
224
|
if (current?.sessionId === sessionId &&
|
|
162
225
|
current.generation === generation)
|
|
@@ -179,7 +242,7 @@ export function useChatStream(params) {
|
|
|
179
242
|
if (!replay)
|
|
180
243
|
liveContinuityCursor = selectLaterChatEventId(liveContinuityCursor, eventId);
|
|
181
244
|
}
|
|
182
|
-
if (
|
|
245
|
+
if (eventName === "stream_ready" &&
|
|
183
246
|
gapReplayBuffer.length > 0) {
|
|
184
247
|
const repairedBlocks = selectChatSseRepairBlocks(gapReplayBuffer.splice(0), liveContinuityCursor);
|
|
185
248
|
for (const repairedBlock of repairedBlocks) {
|
|
@@ -193,6 +256,9 @@ export function useChatStream(params) {
|
|
|
193
256
|
refs.lastEventIdRef.current = selectLaterChatEventId(refs.lastEventIdRef.current, repairedEventId);
|
|
194
257
|
}
|
|
195
258
|
}
|
|
259
|
+
if (eventName === "stream_ready") {
|
|
260
|
+
void turnStateReconciles.start();
|
|
261
|
+
}
|
|
196
262
|
}
|
|
197
263
|
}
|
|
198
264
|
if (replayRepairNeeded) {
|
|
@@ -213,7 +279,7 @@ export function useChatStream(params) {
|
|
|
213
279
|
await sleep(2_000, signal);
|
|
214
280
|
}
|
|
215
281
|
}
|
|
216
|
-
}, [origin, refs, applySseBlock]);
|
|
282
|
+
}, [origin, refs, applySseBlock, thread.reconcileTurnStates]);
|
|
217
283
|
const startEventsStream = useCallback((sessionId, generation) => {
|
|
218
284
|
const existing = refs.eventsStreamStateRef.current;
|
|
219
285
|
if (existing?.sessionId === sessionId &&
|
|
@@ -249,20 +315,7 @@ export function useChatStream(params) {
|
|
|
249
315
|
}
|
|
250
316
|
throw new Error("事件连接未就绪,请检查 Console 连接后重试");
|
|
251
317
|
}, [refs, startEventsStream]);
|
|
252
|
-
const fetchSessionState = useCallback(
|
|
253
|
-
try {
|
|
254
|
-
const res = await fetch(operatorChatStateUrl(origin, sessionId), {
|
|
255
|
-
credentials: "include",
|
|
256
|
-
});
|
|
257
|
-
const body = (await res.json().catch(() => ({})));
|
|
258
|
-
if (!res.ok)
|
|
259
|
-
return null;
|
|
260
|
-
return body.state ?? null;
|
|
261
|
-
}
|
|
262
|
-
catch {
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
}, [origin]);
|
|
318
|
+
const fetchSessionState = useCallback((sessionId) => fetchReconciledSessionState(origin, sessionId), [origin]);
|
|
266
319
|
const postCreateTurn = useCallback(async (input) => {
|
|
267
320
|
try {
|
|
268
321
|
// Resolve against the configured Console origin and fail closed if a
|
|
@@ -1042,20 +1095,20 @@ export function useChatStream(params) {
|
|
|
1042
1095
|
const sessionId = session.sessionId;
|
|
1043
1096
|
const sessionIdentity = { ...session };
|
|
1044
1097
|
const generation = refs.sessionGenerationRef.current;
|
|
1098
|
+
const stateReconcileAbort = new AbortController();
|
|
1045
1099
|
let cancelled = false;
|
|
1046
1100
|
let syncInFlight = null;
|
|
1047
1101
|
const runSync = async () => {
|
|
1048
1102
|
try {
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1103
|
+
const state = await fetchReconciledSessionState(origin, sessionId, {
|
|
1104
|
+
ownerSignal: stateReconcileAbort.signal,
|
|
1051
1105
|
});
|
|
1052
|
-
const body = (await res.json().catch(() => ({})));
|
|
1053
1106
|
if (cancelled ||
|
|
1054
|
-
!
|
|
1107
|
+
!state ||
|
|
1055
1108
|
refs.sessionRef.current?.sessionId !== sessionId ||
|
|
1056
1109
|
refs.sessionGenerationRef.current !== generation)
|
|
1057
1110
|
return;
|
|
1058
|
-
|
|
1111
|
+
thread.reconcileTurnStates(state?.turnStates);
|
|
1059
1112
|
const pending = refs.pendingSubmissionRef.current;
|
|
1060
1113
|
// Pending ownership reconcile. Controller owns bind/release; same
|
|
1061
1114
|
// clientRequestId only. Re-enter after acceptedTurnId so terminal
|
|
@@ -1200,6 +1253,7 @@ export function useChatStream(params) {
|
|
|
1200
1253
|
void sync().finally(scheduleStopRetry);
|
|
1201
1254
|
return () => {
|
|
1202
1255
|
cancelled = true;
|
|
1256
|
+
stateReconcileAbort.abort();
|
|
1203
1257
|
window.clearInterval(interval);
|
|
1204
1258
|
if (stopRetryTimer !== undefined)
|
|
1205
1259
|
window.clearTimeout(stopRetryTimer);
|
|
@@ -1216,6 +1270,7 @@ export function useChatStream(params) {
|
|
|
1216
1270
|
markIdleIfCurrent,
|
|
1217
1271
|
releaseSubmitOwnership,
|
|
1218
1272
|
postAbortForTurn,
|
|
1273
|
+
thread.reconcileTurnStates,
|
|
1219
1274
|
]);
|
|
1220
1275
|
// Exactly one owner starts/aborts GET /events. Switching sessions or
|
|
1221
1276
|
// recovering a cursor aborts the prior stream before the next one is made.
|
|
@@ -9,6 +9,7 @@ import { taskContextUnchanged } from "./format.js";
|
|
|
9
9
|
import { upsertCompactionMessage } from "./compaction-message.js";
|
|
10
10
|
import { sameTurnGroupInputs } from "./turn-group-equality.js";
|
|
11
11
|
import { conversationNodesFromEvents, } from "../../chat/conversation-nodes.js";
|
|
12
|
+
import { mergeTurnStateSummaries, setProjectedTurnState, } from "./turn-state-projection.js";
|
|
12
13
|
const EMPTY_USAGE = {
|
|
13
14
|
inputTokens: 0,
|
|
14
15
|
outputTokens: 0,
|
|
@@ -141,8 +142,13 @@ export function useChatThread(params) {
|
|
|
141
142
|
const [usage, setUsage] = useState(EMPTY_USAGE);
|
|
142
143
|
const [sessionStats, setSessionStats] = useState(EMPTY_SESSION_STATS);
|
|
143
144
|
const [turnTelemetry, setTurnTelemetry] = useState([]);
|
|
145
|
+
const [userTurnOutline, setUserTurnOutline] = useState([]);
|
|
144
146
|
const [operatorActions, setOperatorActions] = useState([]);
|
|
145
147
|
const [conversationNodes, setConversationNodes] = useState([]);
|
|
148
|
+
const [turnStatesById, setTurnStatesById] = useState({});
|
|
149
|
+
const reconcileTurnStates = useCallback((summaries) => {
|
|
150
|
+
setTurnStatesById((current) => mergeTurnStateSummaries(current, summaries));
|
|
151
|
+
}, []);
|
|
146
152
|
const [sddSessionIdentity, setSddSessionIdentity] = useState(null);
|
|
147
153
|
const [streaming, setStreaming] = useState(false);
|
|
148
154
|
const [turnPhase, setTurnPhase] = useState("idle");
|
|
@@ -172,11 +178,12 @@ export function useChatThread(params) {
|
|
|
172
178
|
setUsage(body.usage);
|
|
173
179
|
setTurnTelemetry(body.turnTelemetry ?? []);
|
|
174
180
|
setSddSessionIdentity(body.sddDataAlignment ?? null);
|
|
181
|
+
reconcileTurnStates(body.session?.turnStates);
|
|
175
182
|
}
|
|
176
183
|
catch {
|
|
177
184
|
// Telemetry is supplementary; the normal event stream remains authoritative.
|
|
178
185
|
}
|
|
179
|
-
}, [origin, refs]);
|
|
186
|
+
}, [origin, refs, reconcileTurnStates]);
|
|
180
187
|
// All inputs are stable (state setters + the memoized refs bag), so the
|
|
181
188
|
// applier identity is stable across renders.
|
|
182
189
|
const applyChatSseEvent = useMemo(() => createChatSseEventApplier({
|
|
@@ -195,6 +202,7 @@ export function useChatThread(params) {
|
|
|
195
202
|
setGoal,
|
|
196
203
|
setOperatorActions,
|
|
197
204
|
setConversationNodes,
|
|
205
|
+
setTurnState: (turnId, state) => setTurnStatesById((current) => setProjectedTurnState(current, turnId, state)),
|
|
198
206
|
setSddSessionIdentity,
|
|
199
207
|
setStreamingAssistantId,
|
|
200
208
|
setUnread,
|
|
@@ -334,6 +342,7 @@ export function useChatThread(params) {
|
|
|
334
342
|
streaming,
|
|
335
343
|
activeAssistantId: streamingAssistantId,
|
|
336
344
|
conversationNodes,
|
|
345
|
+
turnStatesById,
|
|
337
346
|
});
|
|
338
347
|
// Preserve completed group objects across streaming tokens. Stable
|
|
339
348
|
// historical groups keep their references so
|
|
@@ -353,11 +362,12 @@ export function useChatThread(params) {
|
|
|
353
362
|
streaming,
|
|
354
363
|
streamingAssistantId,
|
|
355
364
|
conversationNodes,
|
|
365
|
+
turnStatesById,
|
|
356
366
|
historyLimit,
|
|
357
367
|
]);
|
|
358
|
-
const
|
|
368
|
+
const loadHistoryPages = useCallback(async (input) => {
|
|
359
369
|
const targetSessionId = refs.sessionRef.current?.sessionId;
|
|
360
|
-
|
|
370
|
+
let beforeId = historyNextCursor;
|
|
361
371
|
if (!targetSessionId || !historyHasMore || !beforeId || historyLoadingRef.current)
|
|
362
372
|
return false;
|
|
363
373
|
const generation = refs.sessionGenerationRef.current;
|
|
@@ -365,17 +375,29 @@ export function useChatThread(params) {
|
|
|
365
375
|
historyLoadingRef.current = request;
|
|
366
376
|
setHistoryLoading(true);
|
|
367
377
|
try {
|
|
368
|
-
const
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
378
|
+
const collectedMessages = [];
|
|
379
|
+
const collectedTurnStates = [];
|
|
380
|
+
let hasMore = historyHasMore;
|
|
381
|
+
let found = false;
|
|
382
|
+
do {
|
|
383
|
+
const query = new URLSearchParams({ limit: "50", beforeId });
|
|
384
|
+
const res = await fetch(`${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(targetSessionId)}/messages?${query.toString()}`, { credentials: "include" });
|
|
385
|
+
if (!res.ok || refs.sessionRef.current?.sessionId !== targetSessionId)
|
|
386
|
+
return false;
|
|
387
|
+
const body = (await res.json());
|
|
388
|
+
if (refs.sessionRef.current?.sessionId !== targetSessionId ||
|
|
389
|
+
refs.sessionGenerationRef.current !== generation ||
|
|
390
|
+
historyLoadingRef.current !== request)
|
|
391
|
+
return false;
|
|
392
|
+
const pageMessages = body.messages ?? [];
|
|
393
|
+
collectedMessages.unshift(...pageMessages);
|
|
394
|
+
collectedTurnStates.push(...(body.turnStates ?? []));
|
|
395
|
+
found = Boolean(input?.untilMessageId && pageMessages.some((message) => message.id === input.untilMessageId));
|
|
396
|
+
hasMore = body.hasMore === true;
|
|
397
|
+
beforeId = body.nextCursor ?? "";
|
|
398
|
+
} while (input?.untilMessageId && !found && hasMore && beforeId);
|
|
399
|
+
const page = hydrateSessionThread(collectedMessages);
|
|
400
|
+
input?.beforePrepend?.();
|
|
379
401
|
setMessages((current) => {
|
|
380
402
|
const seen = new Set();
|
|
381
403
|
const merged = [...page.messages, ...current].filter((message) => {
|
|
@@ -392,10 +414,11 @@ export function useChatThread(params) {
|
|
|
392
414
|
byId.set(tool.id, tool);
|
|
393
415
|
return [...byId.values()].sort((a, b) => a.createdAt - b.createdAt);
|
|
394
416
|
});
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
417
|
+
setTurnStatesById((current) => mergeTurnStateSummaries(current, collectedTurnStates));
|
|
418
|
+
setHistoryHasMore(hasMore);
|
|
419
|
+
setHistoryNextCursor(beforeId || null);
|
|
420
|
+
setHistoryLimit((value) => value + collectedMessages.length);
|
|
421
|
+
return input?.untilMessageId ? found : true;
|
|
399
422
|
}
|
|
400
423
|
catch (error) {
|
|
401
424
|
if (refs.sessionRef.current?.sessionId === targetSessionId && refs.sessionGenerationRef.current === generation) {
|
|
@@ -410,6 +433,10 @@ export function useChatThread(params) {
|
|
|
410
433
|
}
|
|
411
434
|
}
|
|
412
435
|
}, [historyHasMore, historyNextCursor, origin, refs, setError]);
|
|
436
|
+
const loadEarlierMessages = useCallback((beforePrepend) => loadHistoryPages({ beforePrepend }), [loadHistoryPages]);
|
|
437
|
+
const loadThroughMessage = useCallback((messageId) => messagesRef.current.some((message) => message.id === messageId)
|
|
438
|
+
? Promise.resolve(true)
|
|
439
|
+
: loadHistoryPages({ untilMessageId: messageId }), [loadHistoryPages]);
|
|
413
440
|
const visibleMessages = useMemo(() => {
|
|
414
441
|
const next = [];
|
|
415
442
|
for (const group of turnGroups) {
|
|
@@ -431,8 +458,10 @@ export function useChatThread(params) {
|
|
|
431
458
|
setUsage(EMPTY_USAGE);
|
|
432
459
|
setSessionStats(EMPTY_SESSION_STATS);
|
|
433
460
|
setTurnTelemetry([]);
|
|
461
|
+
setUserTurnOutline([]);
|
|
434
462
|
setOperatorActions([]);
|
|
435
463
|
setConversationNodes([]);
|
|
464
|
+
setTurnStatesById({});
|
|
436
465
|
setSddSessionIdentity(null);
|
|
437
466
|
setStreaming(false);
|
|
438
467
|
setTurnPhase("idle");
|
|
@@ -483,6 +512,7 @@ export function useChatThread(params) {
|
|
|
483
512
|
: undefined));
|
|
484
513
|
setToolCalls(next.toolCalls);
|
|
485
514
|
setConversationNodes(conversationNodesFromEvents(next.conversationEvents ?? []));
|
|
515
|
+
setTurnStatesById(mergeTurnStateSummaries({}, next.turnStates));
|
|
486
516
|
setOperationCards([]);
|
|
487
517
|
setHumanGateCards([]);
|
|
488
518
|
setArtifactCards([]);
|
|
@@ -491,6 +521,7 @@ export function useChatThread(params) {
|
|
|
491
521
|
setUsage(next.usage ?? EMPTY_USAGE);
|
|
492
522
|
setSessionStats(next.sessionStats ?? EMPTY_SESSION_STATS);
|
|
493
523
|
setTurnTelemetry(next.turnTelemetry ?? []);
|
|
524
|
+
setUserTurnOutline(next.userTurnOutline ?? []);
|
|
494
525
|
setOperatorActions([]);
|
|
495
526
|
setSddSessionIdentity(next.sddSessionIdentity ?? null);
|
|
496
527
|
refs.usageResponseKeysRef.current = new Set();
|
|
@@ -544,6 +575,7 @@ export function useChatThread(params) {
|
|
|
544
575
|
if (body.usage)
|
|
545
576
|
setUsage(body.usage);
|
|
546
577
|
setTurnTelemetry(body.turnTelemetry ?? []);
|
|
578
|
+
setUserTurnOutline(body.userTurnOutline ?? []);
|
|
547
579
|
setSddSessionIdentity(body.sddDataAlignment ?? null);
|
|
548
580
|
// Resume the events stream from the snapshot tail so the next
|
|
549
581
|
// reconnect never immediately re-expires (AC-003). The refs below
|
|
@@ -554,6 +586,7 @@ export function useChatThread(params) {
|
|
|
554
586
|
refs.sealedAssistantIdsRef.current = new Set();
|
|
555
587
|
const hydrated = hydrateSessionThread(body.session.messages ?? []);
|
|
556
588
|
setConversationNodes(conversationNodesFromEvents(body.conversationEvents ?? []));
|
|
589
|
+
setTurnStatesById((current) => mergeTurnStateSummaries(current, body.session?.turnStates));
|
|
557
590
|
// Recovery is addressed to targetSessionId, so an optimistic
|
|
558
591
|
// submission from another session must never be projected into
|
|
559
592
|
// this snapshot (the activation path enforces the same owner gate).
|
|
@@ -616,6 +649,7 @@ export function useChatThread(params) {
|
|
|
616
649
|
historyNextCursor,
|
|
617
650
|
historyLoading,
|
|
618
651
|
loadEarlierMessages,
|
|
652
|
+
loadThroughMessage,
|
|
619
653
|
unread,
|
|
620
654
|
humanGateCards,
|
|
621
655
|
interview,
|
|
@@ -625,8 +659,11 @@ export function useChatThread(params) {
|
|
|
625
659
|
usage,
|
|
626
660
|
sessionStats,
|
|
627
661
|
turnTelemetry,
|
|
662
|
+
userTurnOutline,
|
|
628
663
|
operatorActions,
|
|
629
664
|
conversationNodes,
|
|
665
|
+
turnStatesById,
|
|
666
|
+
reconcileTurnStates,
|
|
630
667
|
sddSessionIdentity,
|
|
631
668
|
setSddSessionIdentity,
|
|
632
669
|
streaming,
|
|
@@ -94,7 +94,7 @@ export function useRepoBrowser(params) {
|
|
|
94
94
|
document.addEventListener("visibilitychange", onVisibility);
|
|
95
95
|
return () => document.removeEventListener("visibilitychange", onVisibility);
|
|
96
96
|
}, [refreshTree]);
|
|
97
|
-
const openPreview = useCallback(async (file) => {
|
|
97
|
+
const openPreview = useCallback(async (file, focusLine) => {
|
|
98
98
|
if (blocked)
|
|
99
99
|
return; // AC-R5-002: fail-closed
|
|
100
100
|
if (!workspaceScopeReady(workspaceId))
|
|
@@ -108,7 +108,10 @@ export function useRepoBrowser(params) {
|
|
|
108
108
|
return;
|
|
109
109
|
if (!res.ok || !body.data)
|
|
110
110
|
throw new Error(body.error?.message ?? "无法预览文件");
|
|
111
|
-
const loaded =
|
|
111
|
+
const loaded = {
|
|
112
|
+
...withHtmlPreviewUrl(body.data, origin, workspaceId),
|
|
113
|
+
...(focusLine ? { focusLine } : {}),
|
|
114
|
+
};
|
|
112
115
|
setPreviews((current) => {
|
|
113
116
|
const next = [
|
|
114
117
|
...current.filter((item) => item.path !== loaded.path),
|
|
@@ -69,10 +69,11 @@ export async function prepareScheduledGoalDraft(input, client) {
|
|
|
69
69
|
if (!assessment.ok)
|
|
70
70
|
throw new Error(`scheduled goal ineligible: ${assessment.reason}`);
|
|
71
71
|
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
72
|
+
const repositoryPath = (file) => path.relative(root, file).split(path.sep).join("/");
|
|
72
73
|
return scheduledGoalDraftSchema.parse({ ...parsed, controllerRef: identity.packageFingerprint.value,
|
|
73
74
|
prepared: { gateToken: `${snapshot.gate.id}:${snapshot.gate.digest}`,
|
|
74
|
-
dagPath:
|
|
75
|
-
contractPath:
|
|
75
|
+
dagPath: repositoryPath(paths.dagDraftPath), dagHash: digest(dagBytes),
|
|
76
|
+
contractPath: repositoryPath(paths.taskConfigPath), contractHash: digest(configBytes) }, });
|
|
76
77
|
}
|
|
77
78
|
/** Materialize only contract/runtime inputs; execution remains owned by the operation host. */
|
|
78
79
|
export async function prepareDerivedScheduledGoalTask(goalId, ownerToken, goals, client) {
|
|
@@ -201,8 +201,13 @@ export async function captureScheduledGoalTree(worktree, base, allowedPaths, for
|
|
|
201
201
|
}
|
|
202
202
|
else if (stat.isFile()) {
|
|
203
203
|
const bytes = await readFile(target);
|
|
204
|
-
files.push({ name, kind: "file", hash: sha256(bytes), executable: Boolean(stat.mode & 0o111) });
|
|
205
204
|
actualId = normalizedIds.get(name) ?? blobId(bytes);
|
|
205
|
+
files.push({
|
|
206
|
+
name,
|
|
207
|
+
kind: "file",
|
|
208
|
+
hash: sha256(`${objectFormat}:${actualId}`),
|
|
209
|
+
executable: Boolean(stat.mode & 0o111),
|
|
210
|
+
});
|
|
206
211
|
actualMode = stat.mode & 0o111 ? "100755" : "100644";
|
|
207
212
|
}
|
|
208
213
|
else
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{ag as o,ah as n}from"./mermaid.core-C0HdXtOf.js";const t=(a,r)=>o.lang.round(n.parse(a)[r]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-BTbmx3-k.js";import{_ as i}from"./mermaid.core-C0HdXtOf.js";import"./chunk-5VM5RSS4-BpJIdTKV.js";import"./chunk-XXDRQBXY-DrTdoYZG.js";import"./chunk-KBJHAD2P-B487SORR.js";import"./chunk-2GRJ4B5K-BKKnyR9Z.js";import"./index-CJh6pVLm.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-BTbmx3-k.js";import{_ as i}from"./mermaid.core-C0HdXtOf.js";import"./chunk-5VM5RSS4-BpJIdTKV.js";import"./chunk-XXDRQBXY-DrTdoYZG.js";import"./chunk-KBJHAD2P-B487SORR.js";import"./chunk-2GRJ4B5K-BKKnyR9Z.js";import"./index-CJh6pVLm.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
|