@tea-agent/loop-agent 0.43.0-next.17 → 0.43.0-next.3
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 +9 -140
- package/dist/application/task-lifecycle/advance.js +4 -17
- package/dist/application/task-lifecycle/observe.js +29 -43
- package/dist/application/task-lifecycle/plan-transitions.js +4 -5
- package/dist/build-stamp.json +3 -3
- package/dist/commands/client-recovery.js +55 -20
- package/dist/commands/new-task.js +5 -0
- package/dist/commands/status.js +57 -0
- package/dist/commands/task-contract.js +269 -0
- package/dist/executors/dag-pi-executor.js +230 -269
- package/dist/executors/pi-executor.js +0 -2
- package/dist/executors/pi-sdk-executor.js +39 -77
- package/dist/executors/shell-executor.js +2 -3
- package/dist/executors/shell-write-guard.js +32 -27
- package/dist/shared/pi-context-pressure/extension.js +16 -26
- package/dist/shared/pi-retry-settings.js +0 -40
- package/dist/shared/prompts.js +26 -0
- package/dist/task/config.js +2 -0
- package/dist/task/contract/validate-draft.js +106 -0
- package/dist/task/goal.js +3 -0
- package/dist/task/index.js +12 -0
- package/dist/task/lifecycle.js +1 -0
- package/dist/task/operator/capabilities.js +6 -0
- package/dist/task/operator/envelope.js +2 -0
- package/dist/task/operator/index.js +5 -0
- package/dist/task/operator/registry.js +2 -0
- package/dist/task/operator/types.js +1 -0
- package/dist/task/paths.js +1 -0
- package/dist/task/source-prepare/source-fidelity-pi.js +2 -2
- package/dist/task/source-references.js +23 -48
- package/dist/task/source-state.js +1 -0
- package/dist/task/subagent-guidance.js +1 -0
- package/dist/worker/console/chat/assistant-content.js +2 -23
- package/dist/worker/console/chat/explore-tools.js +0 -13
- package/dist/worker/console/chat/pi-runtime.js +1182 -221
- package/dist/worker/console/chat/routes.js +71 -213
- package/dist/worker/console/chat/sdd-data-alignment.js +9 -65
- package/dist/worker/console/chat/session-catalog.js +0 -32
- package/dist/worker/console/chat/session-store.js +6 -22
- package/dist/worker/console/chat/shortcuts.js +0 -6
- package/dist/worker/console/chat/sift-bridge.js +1 -0
- package/dist/worker/console/chat/tool-preview.js +0 -11
- package/dist/worker/console/chat/tools.js +0 -6
- package/dist/worker/console/console-update-and-init.js +19 -1
- package/dist/worker/console/console-update-runtime.js +20 -5
- package/dist/worker/console/index.js +20 -0
- package/dist/worker/console/operator-actions.js +1 -13
- package/dist/worker/console/routes.js +0 -8
- package/dist/worker/console/server.js +29 -11
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4NXyedy.js → abnfDiagram-N423BO3Z-hUmM_GRf.js} +1 -1
- package/dist/worker/console/static/assets/{arc-NZ3qXvBI.js → arc-Bt-xuieW.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-COZSRvml.js → architectureDiagram-T3A2C74G-DTqkL4DJ.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Ck0Gxi9C.js → blockDiagram-VBNYF7ZC-Cy0MNnzV.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BX5HQ4Ox.js → c4Diagram-5PPSVZJV-DDdlT0Pd.js} +1 -1
- package/dist/worker/console/static/assets/channel-BpzRnZmU.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-CoviemSL.js → chunk-2GRJ4B5K-3JawwNZ6.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DbOdOkbZ.js → chunk-2Q5K7J3B-DoTp7Cri.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BsG2pmdQ.js → chunk-5RXB4S5H-CcirhZaS.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-DGdvrNm8.js → chunk-5VM5RSS4-VrG21gnP.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BAy7Yd6y.js → chunk-6Q2QTUOP-DDOgIS70.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D9UA7hUb.js → chunk-GF5L2VYU-CBjmgvJ_.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-DPz7SZ8V.js → chunk-JWPE2WC7-CCQSht8M.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BmuEOIh7.js → chunk-KBJHAD2P-BpGMkUUV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CIhBWnd8.js → chunk-RYQCIY6F-DNDT41QL.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CScR6mDD.js → chunk-XXDRQBXY-euXnDFbn.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BhlMVqCc.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BhlMVqCc.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BjpfWaUr.js → cose-bilkent-JH36ORCC-BJ6NAeql.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BFQohJgT.js → cynefin-VYW2F7L2-F5JKIvIq.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-D3gzRJnS.js → cynefinDiagram-MW4NZA55-Cwmkl_Gi.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-5eojkhoA.js → dagre-VZM6K2ZE-BmCZ8815.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CpD8LWu_.js → diagram-7IWD3JNH-zWA3hUnX.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B8_4qJ2a.js → diagram-B4RE2ZJO-BzA-888F.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-HOsXf0eu.js → diagram-LBJQPF4R-tPNheoch.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BqwRwiWP.js → diagram-Q27KOJAE-Cdi7Fyqp.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BRVCNZe1.js → diagram-UB23O5K3-DFK9VBf1.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Cvb1TgGh.js → ebnfDiagram-BXEA7PRR-xCUr1kpg.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DS0O0qG9.js → erDiagram-JOGREHBK-BANQHY_A.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-BHIRvRr3.js → flowDiagram-UKHOOZJN-VHJYEMkP.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DcCJ1JWx.js → ganttDiagram-PKOTCBZU-DiyZQ0C6.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-B9ia5ony.js → gitGraphDiagram-DS77QQ5N-CZtIeBBa.js} +1 -1
- package/dist/worker/console/static/assets/index-BlN6ytLr.css +1 -0
- package/dist/worker/console/static/assets/index-CA-jfWlE.js +449 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-3ogpgegn.js → infoDiagram-6WML65LV-BuSspC0X.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-4tgpQ5SL.js → ishikawaDiagram-WSZJBQD7-DRJZyPFy.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DNfgHqFx.js → journeyDiagram-NVQOT4AX-DIfXIVuE.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Dz7ngC8z.js → kanban-definition-27J2QSJJ-CT10_7Lt.js} +1 -1
- package/dist/worker/console/static/assets/{linear-DI7Jv62E.js → linear-ufemj74H.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-CQA4Nzmo.js → mermaid.core-DEQe8-_m.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CtsMc8Mf.js → mindmap-definition-FAOFIHXS-BRLUrbrC.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-ByppE9yH.js → pegDiagram-VL7TDLO6-BgibKtiF.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-B5PtgFgt.js → pieDiagram-7S7Q4E2Y-D3eyfdV9.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Cq4p0k2K.js → quadrantDiagram-CIZ2JOQS-DXeTk5Px.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-DjfkyljN.js → railroadDiagram-AXF67PYL-BgXdFEe7.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DzynNRSl.js → requirementDiagram-LRYGKXZP-CseC2A7R.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cj7TCpTJ.js → sankeyDiagram-W5VNT64P-D80PFzfJ.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-C73C6ykA.js → sequenceDiagram-SI44F4Z6-BWzHW7LS.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-BiNLgN2x.js → sizeCapture-X5ZJPWSS-xWQYTLAn.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-UwvjS64-.js → stateDiagram-OKZ733FA-CLxtpZeL.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CiVoq4G-.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CC7DH98r.js → swimlanes-SLNWSIFB-DwugtmWV.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BkdgdpfR.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-LSBXTR70.js → timeline-definition-Z64GVDOM-DHEOwHIe.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BAuxWwGP.js → vennDiagram-T6HMQDX7-pmbZKlBK.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y--E5_gjZx.js → wardleyDiagram-T6FBY63Y-CivHoM5q.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-dJWNmyzF.js → xychartDiagram-ELKLHX3M-BfHIE7o6.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +10 -122
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +0 -7
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +15 -35
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +62 -136
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +68 -159
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +56 -75
- package/dist/worker/console/static-src/operator-chat/useComposer.js +78 -206
- package/dist/worker/console/workspace-context.js +1 -21
- package/dist/worker/observe/static/router.js +1 -1
- package/dist/worker/observe/static/styles.css +4 -7
- package/dist/worker/observe/static/views/dag-inspector.js +19 -12
- package/dist/worker/observe/static/views/dag.js +2 -2
- package/dist/worker/scheduler/index.js +25 -0
- package/dist/workflows/dag/facts.js +4 -0
- package/dist/workflows/dag/frontend-closeout.js +1 -1
- package/dist/workflows/dag/frontend-design-policy.js +1 -2
- package/dist/workflows/dag/frontend-implementation-contract.js +4 -8
- package/dist/workflows/dag/frontend-prewrite-gate.js +3 -3
- package/dist/workflows/dag/frontend-repair.js +76 -55
- package/dist/workflows/dag/frontend-review-context.js +1 -2
- package/dist/workflows/dag/frontend-review-scopes.js +12 -34
- package/dist/workflows/dag/frontend-shape-facts.js +2 -12
- package/dist/workflows/dag/frontend-verification-trace.js +42 -8
- package/dist/workflows/dag/index.js +6 -0
- package/dist/workflows/dag/init-hybrid.js +160 -97
- package/dist/workflows/dynamic/index.js +7 -0
- package/docs/architecture/runtime-boundaries.md +3 -3
- package/docs/templates/frontend-implementation-dag.json +8 -9
- package/package.json +3 -7
- package/skills/frontend-bounded-implement/SKILL.md +3 -4
- package/skills/frontend-bounded-implement/references/code-standards.md +3 -3
- package/skills/frontend-contract/references/contract-protocol.md +1 -3
- package/skills/frontend-design-review/SKILL.md +7 -12
- package/skills/frontend-design-review/references/review-checklist.md +7 -7
- package/skills/frontend-plan/SKILL.md +0 -19
- package/skills/frontend-plan/references/decision-contract.md +19 -26
- package/skills/frontend-review/SKILL.md +18 -12
- package/skills/frontend-review/references/review-findings.md +43 -24
- package/dist/shared/pi-provider-recovery.js +0 -182
- package/dist/worker/console/chat/browser-automation.js +0 -363
- package/dist/worker/console/chat/browser-policy.js +0 -113
- package/dist/worker/console/chat/browser-routes.js +0 -162
- package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +0 -44
- package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +0 -89
- package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +0 -202
- package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +0 -79
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +0 -86
- package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +0 -38
- package/dist/worker/console/chat/pi-runtime/inspection-types.js +0 -28
- package/dist/worker/console/chat/pi-runtime/inspection.js +0 -439
- package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +0 -153
- package/dist/worker/console/chat/pi-runtime/sdk-session.js +0 -5
- package/dist/worker/console/chat/scm-routes.js +0 -217
- package/dist/worker/console/chat/scm-service.js +0 -283
- package/dist/worker/console/chat/scm-tools.js +0 -111
- package/dist/worker/console/chat/session-mode-view.js +0 -49
- package/dist/worker/console/chat/session-mode.js +0 -220
- package/dist/worker/console/chat/terminal-routes.js +0 -216
- package/dist/worker/console/chat/terminal-sessions.js +0 -348
- package/dist/worker/console/chat/terminal-tools.js +0 -211
- package/dist/worker/console/static/assets/channel-BxdTlb_5.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-_ByA1Nf8.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-_ByA1Nf8.js +0 -1
- package/dist/worker/console/static/assets/index-B9goN3S5.css +0 -1
- package/dist/worker/console/static/assets/index-wXlQohNs.js +0 -469
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-nLgMZ0D3.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BcYqTady.js +0 -8
- package/dist/worker/console/static-src/operator-chat/active-turn-tail.js +0 -10
- package/dist/worker/console/static-src/operator-chat/chat-link.js +0 -94
- package/dist/worker/console/static-src/operator-chat/chat-scroll-position.js +0 -24
- package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +0 -192
- package/dist/worker/console/static-src/operator-chat/process-label.js +0 -41
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +0 -13
- package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +0 -10
- package/dist/worker/console/static-src/operator-chat/use-searchable-hidden.js +0 -51
- package/dist/worker/console/static-src/operator-chat/user-turn-anchor-equality.js +0 -21
- package/dist/worker/console/workspace-initialization.js +0 -209
- package/dist/workflows/dag/frontend-capacity.js +0 -9
- package/dist/workflows/dag/frontend-plan-completeness.js +0 -186
- package/dist/workflows/dag/frontend-plan-recovery-policy.js +0 -18
|
@@ -2,10 +2,9 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
2
2
|
import { runtimeSelectionFromRecord } from "../../chat/runtime-selection.js";
|
|
3
3
|
import { hydrateSessionThread } from "../../chat/turn-process.js";
|
|
4
4
|
import { forgetActiveChatSession, readActiveChatSessionId, rememberActiveChatSession, } from "../../chat/workspace-landing.js";
|
|
5
|
-
import { DEFAULT_CONSOLE_CHAT_SESSION_MODE } from "../../chat/session-mode-view.js";
|
|
6
5
|
import { confirmationToken } from "./format.js";
|
|
7
6
|
import { isLostChatSessionError } from "./runtime-snapshot-store.js";
|
|
8
|
-
import { upsertCompactionMessage
|
|
7
|
+
import { upsertCompactionMessage } from "./compaction-message.js";
|
|
9
8
|
import { describeMutationGateFailure, isMutationGateFailureCode, isStaleTokenFailure, } from "./mutation-gate.js";
|
|
10
9
|
import { SessionTitleWatcher } from "./session-title-watcher.js";
|
|
11
10
|
/** Pure list mutations keep optimistic UI deterministic and easy to verify. */
|
|
@@ -68,8 +67,6 @@ function sameSessionSummary(a, b) {
|
|
|
68
67
|
a.model?.modelId === b.model?.modelId &&
|
|
69
68
|
a.thinkingLevel === b.thinkingLevel &&
|
|
70
69
|
a.isBlank === b.isBlank &&
|
|
71
|
-
(a.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE) ===
|
|
72
|
-
(b.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE) &&
|
|
73
70
|
a.optimisticState === b.optimisticState &&
|
|
74
71
|
sameQueueSummary(a, b));
|
|
75
72
|
}
|
|
@@ -86,18 +83,8 @@ export function stabilizeSessionList(previous, next) {
|
|
|
86
83
|
});
|
|
87
84
|
return changed ? stabilized : previous;
|
|
88
85
|
}
|
|
89
|
-
/** Project a session detail/list record into the active ChatSessionInfo. */
|
|
90
|
-
export function projectActiveChatSession(session, fallbackWorkspaceId) {
|
|
91
|
-
const workspaceId = session.workspaceId?.trim() || fallbackWorkspaceId?.trim() || "";
|
|
92
|
-
return {
|
|
93
|
-
sessionId: session.sessionId,
|
|
94
|
-
...(workspaceId ? { workspaceId } : {}),
|
|
95
|
-
sessionMode: session.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE,
|
|
96
|
-
...runtimeSelectionFromRecord(session),
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
86
|
/** Select a server-confirmed blank session owned by the requested workspace. */
|
|
100
|
-
export function findReusableBlankSession(list, workspaceId
|
|
87
|
+
export function findReusableBlankSession(list, workspaceId) {
|
|
101
88
|
const scope = workspaceId.trim();
|
|
102
89
|
if (!scope)
|
|
103
90
|
return undefined;
|
|
@@ -106,8 +93,7 @@ export function findReusableBlankSession(list, workspaceId, sessionMode = DEFAUL
|
|
|
106
93
|
item.isBlank === true &&
|
|
107
94
|
item.turnPhase === "idle" &&
|
|
108
95
|
!item.activeTurnId &&
|
|
109
|
-
!item.optimisticState
|
|
110
|
-
(item.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE) === sessionMode);
|
|
96
|
+
!item.optimisticState);
|
|
111
97
|
}
|
|
112
98
|
export async function createSessionAndPrimeTitleWatcher(input) {
|
|
113
99
|
if (input.creatingRef?.current) {
|
|
@@ -141,13 +127,7 @@ export async function createSessionAndPrimeTitleWatcher(input) {
|
|
|
141
127
|
const body = (await res.json());
|
|
142
128
|
if (!body.session)
|
|
143
129
|
throw new Error("创建会话响应缺少 durable session");
|
|
144
|
-
const durable = {
|
|
145
|
-
...body.session,
|
|
146
|
-
isBlank: true,
|
|
147
|
-
sessionMode: body.session.sessionMode ??
|
|
148
|
-
input.options?.sessionMode ??
|
|
149
|
-
DEFAULT_CONSOLE_CHAT_SESSION_MODE,
|
|
150
|
-
};
|
|
130
|
+
const durable = { ...body.session, isBlank: true };
|
|
151
131
|
const created = {
|
|
152
132
|
sessionId: durable.sessionId,
|
|
153
133
|
...(durable.workspaceId || input.options?.workspaceId
|
|
@@ -155,7 +135,6 @@ export async function createSessionAndPrimeTitleWatcher(input) {
|
|
|
155
135
|
workspaceId: durable.workspaceId ?? input.options?.workspaceId,
|
|
156
136
|
}
|
|
157
137
|
: {}),
|
|
158
|
-
sessionMode: durable.sessionMode,
|
|
159
138
|
...runtimeSelectionFromRecord(durable),
|
|
160
139
|
};
|
|
161
140
|
const nextList = replaceOptimisticSession(input.sessionListRef.current, input.options?.optimisticSessionId, durable);
|
|
@@ -179,8 +158,8 @@ function mergeCompactionMessages(messages, compactions) {
|
|
|
179
158
|
* compact, plus browser-refresh recovery from the durable session store. */
|
|
180
159
|
export function useChatSessions(params) {
|
|
181
160
|
const { origin, refs, setSession, thread, composer, browser, setError, setNotice, onCompactionChange, setProcessOpen, setAutoScroll, } = params;
|
|
182
|
-
const { applyActivatedSession, resetForNewSession
|
|
183
|
-
const {
|
|
161
|
+
const { applyActivatedSession, resetForNewSession } = thread;
|
|
162
|
+
const { setInput, setPendingImages } = composer;
|
|
184
163
|
const { setPreviews, setActivePreviewPath } = browser;
|
|
185
164
|
const { workspaceId, blocked } = params;
|
|
186
165
|
const workspaceQuery = workspaceId
|
|
@@ -198,11 +177,7 @@ export function useChatSessions(params) {
|
|
|
198
177
|
return owner ? `?workspaceId=${encodeURIComponent(owner)}` : "";
|
|
199
178
|
}, [refs]);
|
|
200
179
|
const [sessionList, setSessionList] = useState([]);
|
|
201
|
-
const [selectedSession, setSelectedSession] = useState(null);
|
|
202
|
-
const selectedSessionRef = useRef(null);
|
|
203
|
-
selectedSessionRef.current = selectedSession;
|
|
204
180
|
const sessionListRef = useRef([]);
|
|
205
|
-
const sessionListRequestVersionRef = useRef(0);
|
|
206
181
|
const pendingDeletedIdsRef = useRef(new Set());
|
|
207
182
|
const pendingCreatedRowsRef = useRef(new Map());
|
|
208
183
|
const sessionMutationVersionRef = useRef(0);
|
|
@@ -244,6 +219,8 @@ export function useChatSessions(params) {
|
|
|
244
219
|
refs.settledTurnIdsRef.current = new Set();
|
|
245
220
|
refs.activeTurnIdRef.current = null;
|
|
246
221
|
resetForNewSession();
|
|
222
|
+
setInput("");
|
|
223
|
+
setPendingImages([]);
|
|
247
224
|
setPreviews([]);
|
|
248
225
|
setActivePreviewPath(null);
|
|
249
226
|
setProcessOpen(false);
|
|
@@ -251,6 +228,8 @@ export function useChatSessions(params) {
|
|
|
251
228
|
}, [
|
|
252
229
|
refs,
|
|
253
230
|
resetForNewSession,
|
|
231
|
+
setInput,
|
|
232
|
+
setPendingImages,
|
|
254
233
|
setPreviews,
|
|
255
234
|
setActivePreviewPath,
|
|
256
235
|
setProcessOpen,
|
|
@@ -259,7 +238,6 @@ export function useChatSessions(params) {
|
|
|
259
238
|
const refreshSessionList = useCallback(async () => {
|
|
260
239
|
if (blocked)
|
|
261
240
|
return; // AC-R5-002: fail-closed, zero session requests
|
|
262
|
-
const version = ++sessionListRequestVersionRef.current;
|
|
263
241
|
try {
|
|
264
242
|
// The sidebar is a multi-workspace index. Keep one unscoped summary
|
|
265
243
|
// collection so expanding or switching a workspace never projects the
|
|
@@ -269,8 +247,6 @@ export function useChatSessions(params) {
|
|
|
269
247
|
credentials: "include",
|
|
270
248
|
});
|
|
271
249
|
const body = (await res.json().catch(() => ({})));
|
|
272
|
-
if (version !== sessionListRequestVersionRef.current)
|
|
273
|
-
return;
|
|
274
250
|
if (!res.ok) {
|
|
275
251
|
setError(body.error?.message ?? `会话列表加载失败(HTTP ${res.status})`);
|
|
276
252
|
return;
|
|
@@ -288,8 +264,6 @@ export function useChatSessions(params) {
|
|
|
288
264
|
}
|
|
289
265
|
}
|
|
290
266
|
catch (error) {
|
|
291
|
-
if (version !== sessionListRequestVersionRef.current)
|
|
292
|
-
return;
|
|
293
267
|
setError(`会话列表加载失败:${error instanceof Error ? error.message : String(error)}`);
|
|
294
268
|
}
|
|
295
269
|
}, [origin, blocked, setError]);
|
|
@@ -301,22 +275,12 @@ export function useChatSessions(params) {
|
|
|
301
275
|
const { next: removedList, removed, index: removedIndex } = removeSessionById(currentList, sessionId);
|
|
302
276
|
if (!removed || removedIndex < 0)
|
|
303
277
|
return false;
|
|
304
|
-
// No pre-mutation snapshot may overwrite this deletion or its rollback.
|
|
305
|
-
sessionListRequestVersionRef.current += 1;
|
|
306
278
|
pendingDeletedIdsRef.current.add(sessionId);
|
|
307
279
|
deleteRequestVersionsRef.current.set(sessionId, requestId);
|
|
308
280
|
const activeSession = refs.sessionRef.current?.sessionId === sessionId
|
|
309
281
|
? refs.sessionRef.current
|
|
310
282
|
: null;
|
|
311
|
-
const
|
|
312
|
-
? selectedSessionRef.current
|
|
313
|
-
: null;
|
|
314
|
-
const deletingIdentity = selectedForDelete ??
|
|
315
|
-
activeSession ?? {
|
|
316
|
-
sessionId,
|
|
317
|
-
...(removed.workspaceId ? { workspaceId: removed.workspaceId } : {}),
|
|
318
|
-
};
|
|
319
|
-
const activeWorkspaceId = deletingIdentity.workspaceId ?? workspaceId;
|
|
283
|
+
const activeWorkspaceId = activeSession?.workspaceId ?? workspaceId;
|
|
320
284
|
const deletingRow = {
|
|
321
285
|
...removed,
|
|
322
286
|
optimisticState: "deleting",
|
|
@@ -335,17 +299,16 @@ export function useChatSessions(params) {
|
|
|
335
299
|
const restore = () => {
|
|
336
300
|
if (deleteRequestVersionsRef.current.get(sessionId) !== requestId)
|
|
337
301
|
return;
|
|
338
|
-
sessionListRequestVersionRef.current += 1;
|
|
339
302
|
pendingDeletedIdsRef.current.delete(sessionId);
|
|
340
303
|
deleteRequestVersionsRef.current.delete(sessionId);
|
|
341
|
-
const restored = restoreSessionAt(sessionListRef.current
|
|
304
|
+
const restored = restoreSessionAt(sessionListRef.current, removed, removedIndex);
|
|
342
305
|
if (restored === sessionListRef.current)
|
|
343
306
|
return;
|
|
344
307
|
sessionListRef.current = restored;
|
|
345
308
|
setSessionList(restored);
|
|
346
309
|
};
|
|
347
310
|
let deletionSelectionVersion = null;
|
|
348
|
-
if (activeSession
|
|
311
|
+
if (activeSession) {
|
|
349
312
|
deletionSelectionVersion = ++sessionSelectionVersionRef.current;
|
|
350
313
|
refs.sessionRef.current = null;
|
|
351
314
|
resetActiveProjection();
|
|
@@ -353,16 +316,17 @@ export function useChatSessions(params) {
|
|
|
353
316
|
forgetActiveChatSession(window.localStorage, activeWorkspaceId, sessionId);
|
|
354
317
|
}
|
|
355
318
|
const restoreActiveSession = async () => {
|
|
356
|
-
if (
|
|
319
|
+
if (activeSession &&
|
|
357
320
|
deletionSelectionVersion === sessionSelectionVersionRef.current &&
|
|
358
321
|
!refs.sessionRef.current) {
|
|
359
|
-
await activateSessionRef.current?.(
|
|
322
|
+
await activateSessionRef.current?.(activeSession.sessionId, activeSession.workspaceId);
|
|
360
323
|
}
|
|
361
324
|
};
|
|
362
325
|
try {
|
|
363
326
|
// AC-002: delete follows the session's durable owner, not the
|
|
364
327
|
// global active workspace.
|
|
365
|
-
const ownerQuery = sessionOwnerQuery(
|
|
328
|
+
const ownerQuery = sessionOwnerQuery(sessionListRef.current.find((item) => item.sessionId === sessionId)
|
|
329
|
+
?.workspaceId ?? null);
|
|
366
330
|
const res = await fetch(`${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(sessionId)}${ownerQuery}`, {
|
|
367
331
|
method: "DELETE",
|
|
368
332
|
credentials: "include",
|
|
@@ -377,13 +341,6 @@ export function useChatSessions(params) {
|
|
|
377
341
|
return false;
|
|
378
342
|
}
|
|
379
343
|
titleWatcherRef.current?.cancel(sessionId);
|
|
380
|
-
const next = sessionListRef.current.filter((item) => item.sessionId !== sessionId);
|
|
381
|
-
sessionListRef.current = next;
|
|
382
|
-
setSessionList(next);
|
|
383
|
-
if (deletionSelectionVersion === sessionSelectionVersionRef.current &&
|
|
384
|
-
selectedSessionRef.current?.sessionId === sessionId)
|
|
385
|
-
setSelectedSession(null);
|
|
386
|
-
releaseSession(deletingIdentity);
|
|
387
344
|
void refreshSessionList().finally(() => {
|
|
388
345
|
pendingDeletedIdsRef.current.delete(sessionId);
|
|
389
346
|
deleteRequestVersionsRef.current.delete(sessionId);
|
|
@@ -401,7 +358,6 @@ export function useChatSessions(params) {
|
|
|
401
358
|
refs,
|
|
402
359
|
setSession,
|
|
403
360
|
resetActiveProjection,
|
|
404
|
-
releaseSession,
|
|
405
361
|
refreshSessionList,
|
|
406
362
|
setError,
|
|
407
363
|
sessionOwnerQuery,
|
|
@@ -411,45 +367,25 @@ export function useChatSessions(params) {
|
|
|
411
367
|
const active = refs.sessionRef.current;
|
|
412
368
|
const listed = sessionListRef.current.find((item) => item.sessionId === sessionId);
|
|
413
369
|
const scope = ownerWorkspaceId ?? listed?.workspaceId ?? active?.workspaceId ?? workspaceId;
|
|
414
|
-
const identity = {
|
|
415
|
-
sessionId,
|
|
416
|
-
...(scope ? { workspaceId: scope } : {}),
|
|
417
|
-
};
|
|
418
370
|
forgetActiveChatSession(window.localStorage, scope, sessionId);
|
|
419
|
-
releaseSession(identity);
|
|
420
371
|
pendingDeletedIdsRef.current.add(sessionId);
|
|
421
372
|
const { next } = removeSessionById(sessionListRef.current, sessionId);
|
|
422
373
|
sessionListRef.current = next;
|
|
423
374
|
setSessionList(next);
|
|
424
|
-
if (active?.sessionId === sessionId
|
|
425
|
-
selectedSessionRef.current?.sessionId === sessionId) {
|
|
375
|
+
if (active?.sessionId === sessionId) {
|
|
426
376
|
sessionSelectionVersionRef.current += 1;
|
|
427
377
|
refs.sessionRef.current = null;
|
|
428
|
-
setSelectedSession(null);
|
|
429
378
|
resetActiveProjection();
|
|
430
379
|
setSession(null);
|
|
431
380
|
}
|
|
432
381
|
void refreshSessionList();
|
|
433
|
-
}, [refs,
|
|
382
|
+
}, [refs, resetActiveProjection, setSession, workspaceId, refreshSessionList]);
|
|
434
383
|
const activateSession = useCallback(async (sessionId, ownerWorkspaceId) => {
|
|
435
384
|
const selectionVersion = ++sessionSelectionVersionRef.current;
|
|
436
|
-
const listedOwner = sessionListRef.current.find((item) => item.sessionId === sessionId)?.workspaceId;
|
|
437
|
-
const requestedOwner = ownerWorkspaceId ?? listedOwner;
|
|
438
|
-
const requested = {
|
|
439
|
-
sessionId,
|
|
440
|
-
...(requestedOwner ? { workspaceId: requestedOwner } : {}),
|
|
441
|
-
};
|
|
442
|
-
// DSH-style staging: selection identity changes synchronously; detail
|
|
443
|
-
// hydration follows. The previous session loses send authority now.
|
|
444
|
-
setSelectedSession(requested);
|
|
445
|
-
resetActiveProjection({ keepStreams: true });
|
|
446
|
-
refs.sessionRef.current = null;
|
|
447
|
-
setSession(null);
|
|
448
|
-
setError(null);
|
|
449
385
|
// AC-002: activation targets the session's durable owning workspace —
|
|
450
386
|
// never the global active workspace (no cross-workspace leak when
|
|
451
387
|
// Operate/Inspect switch their scope while a session stays open).
|
|
452
|
-
const ownerQuery = sessionOwnerQuery(
|
|
388
|
+
const ownerQuery = sessionOwnerQuery(ownerWorkspaceId);
|
|
453
389
|
try {
|
|
454
390
|
const res = await fetch(`${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(sessionId)}${ownerQuery}`, { credentials: "include" });
|
|
455
391
|
const body = (await res.json());
|
|
@@ -466,11 +402,15 @@ export function useChatSessions(params) {
|
|
|
466
402
|
}
|
|
467
403
|
if (selectionVersion !== sessionSelectionVersionRef.current)
|
|
468
404
|
return false;
|
|
469
|
-
const next =
|
|
405
|
+
const next = {
|
|
406
|
+
sessionId: body.session.sessionId,
|
|
407
|
+
...(body.session.workspaceId ? { workspaceId: body.session.workspaceId } : {}),
|
|
408
|
+
...runtimeSelectionFromRecord(body.session),
|
|
409
|
+
};
|
|
470
410
|
// AC-002: session switch (same or cross workspace) never aborts other
|
|
471
411
|
// sessions' background request controllers; the single /events owner is
|
|
472
412
|
// re-bound by useChatStream's session effect.
|
|
473
|
-
|
|
413
|
+
resetActiveProjection({ keepStreams: true });
|
|
474
414
|
refs.sessionRef.current = next;
|
|
475
415
|
refs.activeTurnIdRef.current = body.session.activeTurnId ?? null;
|
|
476
416
|
const visuallyStopped = body.session.turnPhase === "stopping";
|
|
@@ -490,8 +430,9 @@ export function useChatSessions(params) {
|
|
|
490
430
|
refs.assistantIdRef.current = null;
|
|
491
431
|
refs.abortRef.current =
|
|
492
432
|
refs.sessionAbortControllersRef.current.get(sessionId) ?? null;
|
|
433
|
+
setPendingImages([]);
|
|
493
434
|
setPreviews([]);
|
|
494
|
-
|
|
435
|
+
setInput(body.session.composerDraft ?? "");
|
|
495
436
|
const hydrated = hydrateSessionThread(body.session.messages ?? []);
|
|
496
437
|
hydrated.messages = mergeCompactionMessages(hydrated.messages, body.compactions);
|
|
497
438
|
applyActivatedSession({
|
|
@@ -524,8 +465,9 @@ export function useChatSessions(params) {
|
|
|
524
465
|
origin,
|
|
525
466
|
refs,
|
|
526
467
|
setSession,
|
|
468
|
+
setPendingImages,
|
|
527
469
|
setPreviews,
|
|
528
|
-
|
|
470
|
+
setInput,
|
|
529
471
|
applyActivatedSession,
|
|
530
472
|
resetActiveProjection,
|
|
531
473
|
setActivePreviewPath,
|
|
@@ -559,7 +501,9 @@ export function useChatSessions(params) {
|
|
|
559
501
|
}
|
|
560
502
|
const watchSessionTitle = useCallback((sessionId) => titleWatcherRef.current?.startIfEligible(sessionId), []);
|
|
561
503
|
useEffect(() => {
|
|
562
|
-
titleWatcherRef.current?.reconcile(sessionList
|
|
504
|
+
titleWatcherRef.current?.reconcile(sessionList
|
|
505
|
+
.filter((item) => item.state !== "archived" && !item.title)
|
|
506
|
+
.map((item) => item.sessionId));
|
|
563
507
|
}, [sessionList]);
|
|
564
508
|
useEffect(() => () => titleWatcherRef.current?.dispose(), []);
|
|
565
509
|
// Browser refresh/workspace-switch recovery: selection is client state keyed
|
|
@@ -576,22 +520,15 @@ export function useChatSessions(params) {
|
|
|
576
520
|
setSession(null);
|
|
577
521
|
const savedSessionId = readActiveChatSessionId(window.localStorage, workspaceId);
|
|
578
522
|
if (!savedSessionId) {
|
|
579
|
-
setSelectedSession(null);
|
|
580
523
|
// Keep the per-workspace map intact, but clear the legacy global pointer
|
|
581
524
|
// so Operate/Models cannot link a session from another workspace.
|
|
582
525
|
forgetActiveChatSession(window.localStorage, workspaceId);
|
|
583
526
|
return;
|
|
584
527
|
}
|
|
585
|
-
setSelectedSession({
|
|
586
|
-
sessionId: savedSessionId,
|
|
587
|
-
...(workspaceId ? { workspaceId } : {}),
|
|
588
|
-
});
|
|
589
528
|
void (async () => {
|
|
590
529
|
try {
|
|
591
530
|
const res = await fetch(`${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(savedSessionId)}${workspaceQuery}`, { credentials: "include" });
|
|
592
531
|
if (!res.ok) {
|
|
593
|
-
if (selectionVersion === sessionSelectionVersionRef.current)
|
|
594
|
-
setSelectedSession(null);
|
|
595
532
|
forgetActiveChatSession(window.localStorage, workspaceId, savedSessionId);
|
|
596
533
|
return;
|
|
597
534
|
}
|
|
@@ -601,9 +538,16 @@ export function useChatSessions(params) {
|
|
|
601
538
|
selectionVersion !== sessionSelectionVersionRef.current ||
|
|
602
539
|
!body.session)
|
|
603
540
|
return;
|
|
604
|
-
const restored =
|
|
541
|
+
const restored = {
|
|
542
|
+
sessionId: body.session.sessionId,
|
|
543
|
+
...(body.session.workspaceId
|
|
544
|
+
? { workspaceId: body.session.workspaceId }
|
|
545
|
+
: workspaceId
|
|
546
|
+
? { workspaceId }
|
|
547
|
+
: {}),
|
|
548
|
+
...runtimeSelectionFromRecord(body.session),
|
|
549
|
+
};
|
|
605
550
|
refs.sessionGenerationRef.current += 1;
|
|
606
|
-
setSelectedSession(restored);
|
|
607
551
|
refs.sessionRef.current = restored;
|
|
608
552
|
// Do not seed Last-Event-ID here: session messages are restored
|
|
609
553
|
// from the durable store, but tool/gate/operation projections live
|
|
@@ -624,8 +568,8 @@ export function useChatSessions(params) {
|
|
|
624
568
|
refs.settledTurnIdsRef.current = new Set();
|
|
625
569
|
refs.lastEventIdRef.current = null;
|
|
626
570
|
setSession(restored);
|
|
627
|
-
seedSession(restored, body.session.composerDraft ?? "");
|
|
628
571
|
rememberActiveChatSession(window.localStorage, restored.workspaceId ?? workspaceId, restored.sessionId);
|
|
572
|
+
setInput(body.session.composerDraft ?? "");
|
|
629
573
|
const hydrated = hydrateSessionThread(body.session.messages ?? []);
|
|
630
574
|
hydrated.messages = mergeCompactionMessages(hydrated.messages, body.compactions);
|
|
631
575
|
applyActivatedSession({
|
|
@@ -657,7 +601,7 @@ export function useChatSessions(params) {
|
|
|
657
601
|
workspaceQuery,
|
|
658
602
|
refs,
|
|
659
603
|
setSession,
|
|
660
|
-
|
|
604
|
+
setInput,
|
|
661
605
|
applyActivatedSession,
|
|
662
606
|
blocked,
|
|
663
607
|
resetActiveProjection,
|
|
@@ -669,13 +613,12 @@ export function useChatSessions(params) {
|
|
|
669
613
|
// either explicit (sidebar create-in-workspace) or the current valid
|
|
670
614
|
// selection. No scope → fail closed client-side (the server would reject
|
|
671
615
|
// with WORKSPACE_REQUIRED anyway); never a default-workspace fallback.
|
|
672
|
-
const createSessionAndPrimeTitleWatcherForHook = useCallback(
|
|
616
|
+
const createSessionAndPrimeTitleWatcherForHook = useCallback((options) => {
|
|
673
617
|
const scope = options?.workspaceId?.trim() ?? workspaceId?.trim();
|
|
674
618
|
if (!scope) {
|
|
675
619
|
setError("创建会话需要选择一个有效的工作区(不会回退默认工作区)");
|
|
676
620
|
return Promise.reject(new Error("WORKSPACE_REQUIRED"));
|
|
677
621
|
}
|
|
678
|
-
const sessionMode = options?.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE;
|
|
679
622
|
const optimisticSessionId = `optimistic-chat-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
680
623
|
const now = new Date().toISOString();
|
|
681
624
|
const optimisticRow = {
|
|
@@ -684,34 +627,31 @@ export function useChatSessions(params) {
|
|
|
684
627
|
state: "active",
|
|
685
628
|
updatedAt: now,
|
|
686
629
|
turnPhase: "idle",
|
|
687
|
-
sessionMode,
|
|
688
630
|
optimisticState: "creating",
|
|
689
631
|
};
|
|
690
632
|
pendingCreatedRowsRef.current.set(optimisticSessionId, optimisticRow);
|
|
691
633
|
const optimisticList = insertOptimisticSession(sessionListRef.current, optimisticRow);
|
|
692
634
|
sessionListRef.current = optimisticList;
|
|
693
635
|
setSessionList(optimisticList);
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
});
|
|
636
|
+
return createSessionAndPrimeTitleWatcher({
|
|
637
|
+
origin,
|
|
638
|
+
sessionListRef,
|
|
639
|
+
setSessionList,
|
|
640
|
+
titleWatcher: titleWatcherRef.current,
|
|
641
|
+
refreshSessionList,
|
|
642
|
+
options: { ...options, workspaceId: scope, optimisticSessionId },
|
|
643
|
+
setCreatingSession,
|
|
644
|
+
creatingRef: creatingSessionRef,
|
|
645
|
+
}).then((created) => {
|
|
705
646
|
pendingCreatedRowsRef.current.delete(optimisticSessionId);
|
|
706
647
|
return created;
|
|
707
|
-
}
|
|
708
|
-
catch (error) {
|
|
648
|
+
}).catch((error) => {
|
|
709
649
|
pendingCreatedRowsRef.current.delete(optimisticSessionId);
|
|
710
650
|
const cleaned = sessionListRef.current.filter((item) => item.sessionId !== optimisticSessionId);
|
|
711
651
|
sessionListRef.current = cleaned;
|
|
712
652
|
setSessionList(cleaned);
|
|
713
653
|
throw error;
|
|
714
|
-
}
|
|
654
|
+
});
|
|
715
655
|
}, [origin, refreshSessionList, workspaceId, setError]);
|
|
716
656
|
const createSession = useCallback(async (options) => {
|
|
717
657
|
// Suppress concurrent create from any entry (sidebar / Landing / chip).
|
|
@@ -729,10 +669,9 @@ export function useChatSessions(params) {
|
|
|
729
669
|
}
|
|
730
670
|
// A caller-provided snapshot is an explicit new-session boundary; reusing
|
|
731
671
|
// an existing shell would silently drop that context suffix.
|
|
732
|
-
const sessionMode = options?.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE;
|
|
733
672
|
const reusable = options?.snapshot
|
|
734
673
|
? undefined
|
|
735
|
-
: findReusableBlankSession(sessionListRef.current, scope
|
|
674
|
+
: findReusableBlankSession(sessionListRef.current, scope);
|
|
736
675
|
if (reusable) {
|
|
737
676
|
if (previousSession?.sessionId === reusable.sessionId)
|
|
738
677
|
return previousSession;
|
|
@@ -742,7 +681,6 @@ export function useChatSessions(params) {
|
|
|
742
681
|
return {
|
|
743
682
|
sessionId: reusable.sessionId,
|
|
744
683
|
...(reusable.workspaceId ? { workspaceId: reusable.workspaceId } : {}),
|
|
745
|
-
sessionMode: reusable.sessionMode ?? sessionMode,
|
|
746
684
|
...runtimeSelectionFromRecord(reusable),
|
|
747
685
|
};
|
|
748
686
|
}
|
|
@@ -757,7 +695,6 @@ export function useChatSessions(params) {
|
|
|
757
695
|
// createSession().then(sendPrompt) reads the new session even
|
|
758
696
|
// though sendPrompt's closure captured the stale (null) value.
|
|
759
697
|
refs.sessionRef.current = created;
|
|
760
|
-
setSelectedSession(created);
|
|
761
698
|
rememberActiveChatSession(window.localStorage, created.workspaceId ?? options?.workspaceId ?? workspaceId, created.sessionId);
|
|
762
699
|
setSession(created);
|
|
763
700
|
return created;
|
|
@@ -826,18 +763,11 @@ export function useChatSessions(params) {
|
|
|
826
763
|
return;
|
|
827
764
|
}
|
|
828
765
|
setError(null);
|
|
829
|
-
//
|
|
830
|
-
//
|
|
766
|
+
// pi-web parity: reload the compacted session, then leave a distinct
|
|
767
|
+
// compaction summary card in the timeline plus a transient toast.
|
|
831
768
|
const summary = body.snapshot?.summary?.trim();
|
|
832
769
|
const summaryText = summary || "历史上下文已精简,关键决策与当前任务已保留。";
|
|
833
|
-
|
|
834
|
-
if (compaction &&
|
|
835
|
-
refs.sessionRef.current?.sessionId === current.sessionId) {
|
|
836
|
-
if (compaction.eventId) {
|
|
837
|
-
refs.seenEventIdsRef.current.add(compaction.eventId);
|
|
838
|
-
}
|
|
839
|
-
setMessages((messages) => upsertCompactionMessage(messages, compaction));
|
|
840
|
-
}
|
|
770
|
+
await activateSession(current.sessionId);
|
|
841
771
|
setNotice({
|
|
842
772
|
id: Date.now(),
|
|
843
773
|
message: `已压缩上下文:${summaryText.slice(0, 72)}${summaryText.length > 72 ? "…" : ""}`,
|
|
@@ -855,7 +785,7 @@ export function useChatSessions(params) {
|
|
|
855
785
|
setError,
|
|
856
786
|
setNotice,
|
|
857
787
|
onCompactionChange,
|
|
858
|
-
|
|
788
|
+
activateSession,
|
|
859
789
|
sessionOwnerQuery,
|
|
860
790
|
]);
|
|
861
791
|
const updateSession = async (sessionId, patch) => {
|
|
@@ -884,7 +814,6 @@ export function useChatSessions(params) {
|
|
|
884
814
|
const activeSessionId = refs.sessionRef.current.sessionId;
|
|
885
815
|
sessionSelectionVersionRef.current += 1;
|
|
886
816
|
refs.sessionRef.current = null;
|
|
887
|
-
setSelectedSession(null);
|
|
888
817
|
resetActiveProjection();
|
|
889
818
|
setSession(null);
|
|
890
819
|
forgetActiveChatSession(window.localStorage, activeWorkspaceId, activeSessionId);
|
|
@@ -892,9 +821,6 @@ export function useChatSessions(params) {
|
|
|
892
821
|
};
|
|
893
822
|
return {
|
|
894
823
|
sessionList,
|
|
895
|
-
selectedSession,
|
|
896
|
-
sessionSwitching: Boolean(selectedSession &&
|
|
897
|
-
refs.sessionRef.current?.sessionId !== selectedSession.sessionId),
|
|
898
824
|
creatingSession,
|
|
899
825
|
activateSession,
|
|
900
826
|
refreshSessionList,
|