@tea-agent/loop-agent 0.43.0-next.11 → 0.43.0-next.12
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 +3 -0
- package/dist/build-stamp.json +3 -3
- package/dist/commands/client-recovery.js +20 -55
- package/dist/shared/pi-context-pressure/extension.js +26 -16
- package/dist/shared/pi-provider-recovery.js +182 -0
- package/dist/shared/pi-retry-settings.js +40 -0
- package/dist/worker/console/chat/pi-runtime.js +7 -5
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CTSK0xbU.js → abnfDiagram-N423BO3Z-BEg5712w.js} +1 -1
- package/dist/worker/console/static/assets/{arc-_2MfctFP.js → arc-CkQvaBGZ.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DsDe2wTg.js → architectureDiagram-T3A2C74G-BrdwFNJ7.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Dtz_779U.js → blockDiagram-VBNYF7ZC-M_LjP2kx.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-LaULi-gw.js → c4Diagram-5PPSVZJV-Bwr5Dtjc.js} +1 -1
- package/dist/worker/console/static/assets/channel-CKmyKgY-.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DuHBqqX8.js → chunk-2GRJ4B5K-CDc44stW.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-BZgZs1dn.js → chunk-2Q5K7J3B-DZELwsTt.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-tzwmlIO_.js → chunk-5RXB4S5H-D7YI6SWX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CeYrLkSn.js → chunk-5VM5RSS4-Bc46bEyj.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-C92cgilm.js → chunk-6Q2QTUOP-Bj4vc-Dp.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-XOXpGC0F.js → chunk-GF5L2VYU-DRi-0nDX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CGHbJyCH.js → chunk-JWPE2WC7-Dr-wFY60.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Bs2-LTzf.js → chunk-KBJHAD2P-CqIHE_D7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-rN7up7E4.js → chunk-RYQCIY6F-C-Dl8wzk.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-B_fWjKpR.js → chunk-XXDRQBXY-CV4Mydz3.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D8Wc3jJP.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D8Wc3jJP.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-DE3SdJvB.js → cose-bilkent-JH36ORCC-C3MamSMJ.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-B-4yuRAX.js → cynefin-VYW2F7L2-zo_Jy2sf.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-TiCPFuO8.js → cynefinDiagram-MW4NZA55-BB2PN1AG.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-7crzLMzA.js → dagre-VZM6K2ZE-BimYueoi.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Cvr-x6Fd.js → diagram-7IWD3JNH-Di1ObJRS.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BzcRHUjH.js → diagram-B4RE2ZJO-C83l-IJx.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BjkAXilh.js → diagram-LBJQPF4R-B3S3fOpm.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BkzyATK7.js → diagram-Q27KOJAE-urW_Zhe7.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-rZuTarYP.js → diagram-UB23O5K3-nvIbCwF6.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CAYENaN1.js → ebnfDiagram-BXEA7PRR-DG6O3KpP.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DCEam0Uq.js → erDiagram-JOGREHBK-DpXdtdsj.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-e_dH4wVO.js → flowDiagram-UKHOOZJN-DvXWHrND.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CvZa2zOK.js → ganttDiagram-PKOTCBZU-6F7SbvUS.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-CbT5TuKp.js → gitGraphDiagram-DS77QQ5N-D1tZnFec.js} +1 -1
- package/dist/worker/console/static/assets/{index-CUPeoE8W.js → index-CWarwRqc.js} +94 -94
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BWzHQa_Z.js → infoDiagram-6WML65LV-HN4qwJ2M.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BTjlovtU.js → ishikawaDiagram-WSZJBQD7-OJ4qwDRo.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DkvQoCc1.js → journeyDiagram-NVQOT4AX-CJZ6giQk.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-CHSzGi3W.js → kanban-definition-27J2QSJJ-co60m19S.js} +1 -1
- package/dist/worker/console/static/assets/{linear-DZMkTCWH.js → linear-D1KeFqZY.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-BIMhty7A.js → mermaid.core-i7dDGqov.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-Dx-tyMl3.js → mindmap-definition-FAOFIHXS-1SkQxBh1.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-C6G34rbY.js → pegDiagram-VL7TDLO6-B10dhI-Y.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CHK9XOfm.js → pieDiagram-7S7Q4E2Y-CiUKUo6j.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CDARkI0w.js → quadrantDiagram-CIZ2JOQS-C5vH4LXZ.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-DiuUe0ZQ.js → railroadDiagram-AXF67PYL-5nlWOCEj.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-RE61UR56.js → requirementDiagram-LRYGKXZP-CILd6QS3.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-KDNLHMEG.js → sankeyDiagram-W5VNT64P-Dfp18ZO2.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CeVgXnD9.js → sequenceDiagram-SI44F4Z6-B9pkswBi.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-CXwGyjjG.js → sizeCapture-X5ZJPWSS-C1-eSgx4.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BjTfozab.js → stateDiagram-OKZ733FA-COJsOoAF.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Bpfb0q5s.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BaXOB8GT.js → swimlanes-SLNWSIFB-Dv5NXJUM.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BEwGGabW.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-C3r2hqUU.js → timeline-definition-Z64GVDOM-DRdrZ7eR.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-MWKgl1S9.js → vennDiagram-T6HMQDX7-0-2TlwCj.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-C9iFcZPk.js → wardleyDiagram-T6FBY63Y-3-o3q92P.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-DqnM24Jp.js → xychartDiagram-ELKLHX3M-DSgOgdUi.js} +1 -1
- package/dist/worker/console/static/index.html +1 -1
- package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +192 -0
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +9 -1
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +78 -35
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +145 -70
- package/dist/worker/console/static-src/operator-chat/useComposer.js +182 -69
- package/docs/architecture/runtime-boundaries.md +3 -3
- package/package.json +1 -1
- package/dist/worker/console/static/assets/channel-CqS4yBWT.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DVOxNOq0.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DVOxNOq0.js +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BXoYsyr2.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DfKliS4e.js +0 -8
|
@@ -180,7 +180,7 @@ function mergeCompactionMessages(messages, compactions) {
|
|
|
180
180
|
export function useChatSessions(params) {
|
|
181
181
|
const { origin, refs, setSession, thread, composer, browser, setError, setNotice, onCompactionChange, setProcessOpen, setAutoScroll, } = params;
|
|
182
182
|
const { applyActivatedSession, resetForNewSession, setMessages } = thread;
|
|
183
|
-
const {
|
|
183
|
+
const { seedSession, releaseSession } = composer;
|
|
184
184
|
const { setPreviews, setActivePreviewPath } = browser;
|
|
185
185
|
const { workspaceId, blocked } = params;
|
|
186
186
|
const workspaceQuery = workspaceId
|
|
@@ -198,6 +198,9 @@ export function useChatSessions(params) {
|
|
|
198
198
|
return owner ? `?workspaceId=${encodeURIComponent(owner)}` : "";
|
|
199
199
|
}, [refs]);
|
|
200
200
|
const [sessionList, setSessionList] = useState([]);
|
|
201
|
+
const [selectedSession, setSelectedSession] = useState(null);
|
|
202
|
+
const selectedSessionRef = useRef(null);
|
|
203
|
+
selectedSessionRef.current = selectedSession;
|
|
201
204
|
const sessionListRef = useRef([]);
|
|
202
205
|
const pendingDeletedIdsRef = useRef(new Set());
|
|
203
206
|
const pendingCreatedRowsRef = useRef(new Map());
|
|
@@ -240,8 +243,6 @@ export function useChatSessions(params) {
|
|
|
240
243
|
refs.settledTurnIdsRef.current = new Set();
|
|
241
244
|
refs.activeTurnIdRef.current = null;
|
|
242
245
|
resetForNewSession();
|
|
243
|
-
setInput("");
|
|
244
|
-
setPendingImages([]);
|
|
245
246
|
setPreviews([]);
|
|
246
247
|
setActivePreviewPath(null);
|
|
247
248
|
setProcessOpen(false);
|
|
@@ -249,8 +250,6 @@ export function useChatSessions(params) {
|
|
|
249
250
|
}, [
|
|
250
251
|
refs,
|
|
251
252
|
resetForNewSession,
|
|
252
|
-
setInput,
|
|
253
|
-
setPendingImages,
|
|
254
253
|
setPreviews,
|
|
255
254
|
setActivePreviewPath,
|
|
256
255
|
setProcessOpen,
|
|
@@ -301,7 +300,15 @@ export function useChatSessions(params) {
|
|
|
301
300
|
const activeSession = refs.sessionRef.current?.sessionId === sessionId
|
|
302
301
|
? refs.sessionRef.current
|
|
303
302
|
: null;
|
|
304
|
-
const
|
|
303
|
+
const selectedForDelete = selectedSessionRef.current?.sessionId === sessionId
|
|
304
|
+
? selectedSessionRef.current
|
|
305
|
+
: null;
|
|
306
|
+
const deletingIdentity = selectedForDelete ??
|
|
307
|
+
activeSession ?? {
|
|
308
|
+
sessionId,
|
|
309
|
+
...(removed.workspaceId ? { workspaceId: removed.workspaceId } : {}),
|
|
310
|
+
};
|
|
311
|
+
const activeWorkspaceId = deletingIdentity.workspaceId ?? workspaceId;
|
|
305
312
|
const deletingRow = {
|
|
306
313
|
...removed,
|
|
307
314
|
optimisticState: "deleting",
|
|
@@ -329,7 +336,7 @@ export function useChatSessions(params) {
|
|
|
329
336
|
setSessionList(restored);
|
|
330
337
|
};
|
|
331
338
|
let deletionSelectionVersion = null;
|
|
332
|
-
if (activeSession) {
|
|
339
|
+
if (activeSession || selectedForDelete) {
|
|
333
340
|
deletionSelectionVersion = ++sessionSelectionVersionRef.current;
|
|
334
341
|
refs.sessionRef.current = null;
|
|
335
342
|
resetActiveProjection();
|
|
@@ -337,10 +344,10 @@ export function useChatSessions(params) {
|
|
|
337
344
|
forgetActiveChatSession(window.localStorage, activeWorkspaceId, sessionId);
|
|
338
345
|
}
|
|
339
346
|
const restoreActiveSession = async () => {
|
|
340
|
-
if (activeSession &&
|
|
347
|
+
if ((activeSession || selectedForDelete) &&
|
|
341
348
|
deletionSelectionVersion === sessionSelectionVersionRef.current &&
|
|
342
349
|
!refs.sessionRef.current) {
|
|
343
|
-
await activateSessionRef.current?.(
|
|
350
|
+
await activateSessionRef.current?.(deletingIdentity.sessionId, deletingIdentity.workspaceId);
|
|
344
351
|
}
|
|
345
352
|
};
|
|
346
353
|
try {
|
|
@@ -362,6 +369,10 @@ export function useChatSessions(params) {
|
|
|
362
369
|
return false;
|
|
363
370
|
}
|
|
364
371
|
titleWatcherRef.current?.cancel(sessionId);
|
|
372
|
+
if (deletionSelectionVersion === sessionSelectionVersionRef.current &&
|
|
373
|
+
selectedSessionRef.current?.sessionId === sessionId)
|
|
374
|
+
setSelectedSession(null);
|
|
375
|
+
releaseSession(deletingIdentity);
|
|
365
376
|
void refreshSessionList().finally(() => {
|
|
366
377
|
pendingDeletedIdsRef.current.delete(sessionId);
|
|
367
378
|
deleteRequestVersionsRef.current.delete(sessionId);
|
|
@@ -379,6 +390,7 @@ export function useChatSessions(params) {
|
|
|
379
390
|
refs,
|
|
380
391
|
setSession,
|
|
381
392
|
resetActiveProjection,
|
|
393
|
+
releaseSession,
|
|
382
394
|
refreshSessionList,
|
|
383
395
|
setError,
|
|
384
396
|
sessionOwnerQuery,
|
|
@@ -388,25 +400,45 @@ export function useChatSessions(params) {
|
|
|
388
400
|
const active = refs.sessionRef.current;
|
|
389
401
|
const listed = sessionListRef.current.find((item) => item.sessionId === sessionId);
|
|
390
402
|
const scope = ownerWorkspaceId ?? listed?.workspaceId ?? active?.workspaceId ?? workspaceId;
|
|
403
|
+
const identity = {
|
|
404
|
+
sessionId,
|
|
405
|
+
...(scope ? { workspaceId: scope } : {}),
|
|
406
|
+
};
|
|
391
407
|
forgetActiveChatSession(window.localStorage, scope, sessionId);
|
|
408
|
+
releaseSession(identity);
|
|
392
409
|
pendingDeletedIdsRef.current.add(sessionId);
|
|
393
410
|
const { next } = removeSessionById(sessionListRef.current, sessionId);
|
|
394
411
|
sessionListRef.current = next;
|
|
395
412
|
setSessionList(next);
|
|
396
|
-
if (active?.sessionId === sessionId
|
|
413
|
+
if (active?.sessionId === sessionId ||
|
|
414
|
+
selectedSessionRef.current?.sessionId === sessionId) {
|
|
397
415
|
sessionSelectionVersionRef.current += 1;
|
|
398
416
|
refs.sessionRef.current = null;
|
|
417
|
+
setSelectedSession(null);
|
|
399
418
|
resetActiveProjection();
|
|
400
419
|
setSession(null);
|
|
401
420
|
}
|
|
402
421
|
void refreshSessionList();
|
|
403
|
-
}, [refs, resetActiveProjection, setSession, workspaceId, refreshSessionList]);
|
|
422
|
+
}, [refs, releaseSession, resetActiveProjection, setSession, workspaceId, refreshSessionList]);
|
|
404
423
|
const activateSession = useCallback(async (sessionId, ownerWorkspaceId) => {
|
|
405
424
|
const selectionVersion = ++sessionSelectionVersionRef.current;
|
|
425
|
+
const listedOwner = sessionListRef.current.find((item) => item.sessionId === sessionId)?.workspaceId;
|
|
426
|
+
const requestedOwner = ownerWorkspaceId ?? listedOwner;
|
|
427
|
+
const requested = {
|
|
428
|
+
sessionId,
|
|
429
|
+
...(requestedOwner ? { workspaceId: requestedOwner } : {}),
|
|
430
|
+
};
|
|
431
|
+
// DSH-style staging: selection identity changes synchronously; detail
|
|
432
|
+
// hydration follows. The previous session loses send authority now.
|
|
433
|
+
setSelectedSession(requested);
|
|
434
|
+
resetActiveProjection({ keepStreams: true });
|
|
435
|
+
refs.sessionRef.current = null;
|
|
436
|
+
setSession(null);
|
|
437
|
+
setError(null);
|
|
406
438
|
// AC-002: activation targets the session's durable owning workspace —
|
|
407
439
|
// never the global active workspace (no cross-workspace leak when
|
|
408
440
|
// Operate/Inspect switch their scope while a session stays open).
|
|
409
|
-
const ownerQuery = sessionOwnerQuery(
|
|
441
|
+
const ownerQuery = sessionOwnerQuery(requested.workspaceId);
|
|
410
442
|
try {
|
|
411
443
|
const res = await fetch(`${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(sessionId)}${ownerQuery}`, { credentials: "include" });
|
|
412
444
|
const body = (await res.json());
|
|
@@ -427,7 +459,7 @@ export function useChatSessions(params) {
|
|
|
427
459
|
// AC-002: session switch (same or cross workspace) never aborts other
|
|
428
460
|
// sessions' background request controllers; the single /events owner is
|
|
429
461
|
// re-bound by useChatStream's session effect.
|
|
430
|
-
|
|
462
|
+
setSelectedSession(next);
|
|
431
463
|
refs.sessionRef.current = next;
|
|
432
464
|
refs.activeTurnIdRef.current = body.session.activeTurnId ?? null;
|
|
433
465
|
const visuallyStopped = body.session.turnPhase === "stopping";
|
|
@@ -447,9 +479,8 @@ export function useChatSessions(params) {
|
|
|
447
479
|
refs.assistantIdRef.current = null;
|
|
448
480
|
refs.abortRef.current =
|
|
449
481
|
refs.sessionAbortControllersRef.current.get(sessionId) ?? null;
|
|
450
|
-
setPendingImages([]);
|
|
451
482
|
setPreviews([]);
|
|
452
|
-
|
|
483
|
+
seedSession(next, body.session.composerDraft ?? "");
|
|
453
484
|
const hydrated = hydrateSessionThread(body.session.messages ?? []);
|
|
454
485
|
hydrated.messages = mergeCompactionMessages(hydrated.messages, body.compactions);
|
|
455
486
|
applyActivatedSession({
|
|
@@ -482,9 +513,8 @@ export function useChatSessions(params) {
|
|
|
482
513
|
origin,
|
|
483
514
|
refs,
|
|
484
515
|
setSession,
|
|
485
|
-
setPendingImages,
|
|
486
516
|
setPreviews,
|
|
487
|
-
|
|
517
|
+
seedSession,
|
|
488
518
|
applyActivatedSession,
|
|
489
519
|
resetActiveProjection,
|
|
490
520
|
setActivePreviewPath,
|
|
@@ -518,9 +548,7 @@ export function useChatSessions(params) {
|
|
|
518
548
|
}
|
|
519
549
|
const watchSessionTitle = useCallback((sessionId) => titleWatcherRef.current?.startIfEligible(sessionId), []);
|
|
520
550
|
useEffect(() => {
|
|
521
|
-
titleWatcherRef.current?.reconcile(sessionList
|
|
522
|
-
.filter((item) => item.state !== "archived" && !item.title)
|
|
523
|
-
.map((item) => item.sessionId));
|
|
551
|
+
titleWatcherRef.current?.reconcile(sessionList.flatMap((item) => item.state !== "archived" && !item.title ? [item.sessionId] : []));
|
|
524
552
|
}, [sessionList]);
|
|
525
553
|
useEffect(() => () => titleWatcherRef.current?.dispose(), []);
|
|
526
554
|
// Browser refresh/workspace-switch recovery: selection is client state keyed
|
|
@@ -537,15 +565,22 @@ export function useChatSessions(params) {
|
|
|
537
565
|
setSession(null);
|
|
538
566
|
const savedSessionId = readActiveChatSessionId(window.localStorage, workspaceId);
|
|
539
567
|
if (!savedSessionId) {
|
|
568
|
+
setSelectedSession(null);
|
|
540
569
|
// Keep the per-workspace map intact, but clear the legacy global pointer
|
|
541
570
|
// so Operate/Models cannot link a session from another workspace.
|
|
542
571
|
forgetActiveChatSession(window.localStorage, workspaceId);
|
|
543
572
|
return;
|
|
544
573
|
}
|
|
574
|
+
setSelectedSession({
|
|
575
|
+
sessionId: savedSessionId,
|
|
576
|
+
...(workspaceId ? { workspaceId } : {}),
|
|
577
|
+
});
|
|
545
578
|
void (async () => {
|
|
546
579
|
try {
|
|
547
580
|
const res = await fetch(`${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(savedSessionId)}${workspaceQuery}`, { credentials: "include" });
|
|
548
581
|
if (!res.ok) {
|
|
582
|
+
if (selectionVersion === sessionSelectionVersionRef.current)
|
|
583
|
+
setSelectedSession(null);
|
|
549
584
|
forgetActiveChatSession(window.localStorage, workspaceId, savedSessionId);
|
|
550
585
|
return;
|
|
551
586
|
}
|
|
@@ -557,6 +592,7 @@ export function useChatSessions(params) {
|
|
|
557
592
|
return;
|
|
558
593
|
const restored = projectActiveChatSession(body.session, workspaceId);
|
|
559
594
|
refs.sessionGenerationRef.current += 1;
|
|
595
|
+
setSelectedSession(restored);
|
|
560
596
|
refs.sessionRef.current = restored;
|
|
561
597
|
// Do not seed Last-Event-ID here: session messages are restored
|
|
562
598
|
// from the durable store, but tool/gate/operation projections live
|
|
@@ -577,8 +613,8 @@ export function useChatSessions(params) {
|
|
|
577
613
|
refs.settledTurnIdsRef.current = new Set();
|
|
578
614
|
refs.lastEventIdRef.current = null;
|
|
579
615
|
setSession(restored);
|
|
616
|
+
seedSession(restored, body.session.composerDraft ?? "");
|
|
580
617
|
rememberActiveChatSession(window.localStorage, restored.workspaceId ?? workspaceId, restored.sessionId);
|
|
581
|
-
setInput(body.session.composerDraft ?? "");
|
|
582
618
|
const hydrated = hydrateSessionThread(body.session.messages ?? []);
|
|
583
619
|
hydrated.messages = mergeCompactionMessages(hydrated.messages, body.compactions);
|
|
584
620
|
applyActivatedSession({
|
|
@@ -610,7 +646,7 @@ export function useChatSessions(params) {
|
|
|
610
646
|
workspaceQuery,
|
|
611
647
|
refs,
|
|
612
648
|
setSession,
|
|
613
|
-
|
|
649
|
+
seedSession,
|
|
614
650
|
applyActivatedSession,
|
|
615
651
|
blocked,
|
|
616
652
|
resetActiveProjection,
|
|
@@ -622,7 +658,7 @@ export function useChatSessions(params) {
|
|
|
622
658
|
// either explicit (sidebar create-in-workspace) or the current valid
|
|
623
659
|
// selection. No scope → fail closed client-side (the server would reject
|
|
624
660
|
// with WORKSPACE_REQUIRED anyway); never a default-workspace fallback.
|
|
625
|
-
const createSessionAndPrimeTitleWatcherForHook = useCallback((options) => {
|
|
661
|
+
const createSessionAndPrimeTitleWatcherForHook = useCallback(async (options) => {
|
|
626
662
|
const scope = options?.workspaceId?.trim() ?? workspaceId?.trim();
|
|
627
663
|
if (!scope) {
|
|
628
664
|
setError("创建会话需要选择一个有效的工作区(不会回退默认工作区)");
|
|
@@ -644,25 +680,27 @@ export function useChatSessions(params) {
|
|
|
644
680
|
const optimisticList = insertOptimisticSession(sessionListRef.current, optimisticRow);
|
|
645
681
|
sessionListRef.current = optimisticList;
|
|
646
682
|
setSessionList(optimisticList);
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
683
|
+
try {
|
|
684
|
+
const created = await createSessionAndPrimeTitleWatcher({
|
|
685
|
+
origin,
|
|
686
|
+
sessionListRef,
|
|
687
|
+
setSessionList,
|
|
688
|
+
titleWatcher: titleWatcherRef.current,
|
|
689
|
+
refreshSessionList,
|
|
690
|
+
options: { ...options, workspaceId: scope, optimisticSessionId },
|
|
691
|
+
setCreatingSession,
|
|
692
|
+
creatingRef: creatingSessionRef,
|
|
693
|
+
});
|
|
657
694
|
pendingCreatedRowsRef.current.delete(optimisticSessionId);
|
|
658
695
|
return created;
|
|
659
|
-
}
|
|
696
|
+
}
|
|
697
|
+
catch (error) {
|
|
660
698
|
pendingCreatedRowsRef.current.delete(optimisticSessionId);
|
|
661
699
|
const cleaned = sessionListRef.current.filter((item) => item.sessionId !== optimisticSessionId);
|
|
662
700
|
sessionListRef.current = cleaned;
|
|
663
701
|
setSessionList(cleaned);
|
|
664
702
|
throw error;
|
|
665
|
-
}
|
|
703
|
+
}
|
|
666
704
|
}, [origin, refreshSessionList, workspaceId, setError]);
|
|
667
705
|
const createSession = useCallback(async (options) => {
|
|
668
706
|
// Suppress concurrent create from any entry (sidebar / Landing / chip).
|
|
@@ -708,6 +746,7 @@ export function useChatSessions(params) {
|
|
|
708
746
|
// createSession().then(sendPrompt) reads the new session even
|
|
709
747
|
// though sendPrompt's closure captured the stale (null) value.
|
|
710
748
|
refs.sessionRef.current = created;
|
|
749
|
+
setSelectedSession(created);
|
|
711
750
|
rememberActiveChatSession(window.localStorage, created.workspaceId ?? options?.workspaceId ?? workspaceId, created.sessionId);
|
|
712
751
|
setSession(created);
|
|
713
752
|
return created;
|
|
@@ -834,6 +873,7 @@ export function useChatSessions(params) {
|
|
|
834
873
|
const activeSessionId = refs.sessionRef.current.sessionId;
|
|
835
874
|
sessionSelectionVersionRef.current += 1;
|
|
836
875
|
refs.sessionRef.current = null;
|
|
876
|
+
setSelectedSession(null);
|
|
837
877
|
resetActiveProjection();
|
|
838
878
|
setSession(null);
|
|
839
879
|
forgetActiveChatSession(window.localStorage, activeWorkspaceId, activeSessionId);
|
|
@@ -841,6 +881,9 @@ export function useChatSessions(params) {
|
|
|
841
881
|
};
|
|
842
882
|
return {
|
|
843
883
|
sessionList,
|
|
884
|
+
selectedSession,
|
|
885
|
+
sessionSwitching: Boolean(selectedSession &&
|
|
886
|
+
refs.sessionRef.current?.sessionId !== selectedSession.sessionId),
|
|
844
887
|
creatingSession,
|
|
845
888
|
activateSession,
|
|
846
889
|
refreshSessionList,
|