@blade-hq/agent-kit 0.4.5 → 0.4.7
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/README.md +39 -1
- package/dist/{SkillStatusBar-DItrW2vv.d.ts → SkillStatusBar-DQyipdzn.d.ts} +112 -8
- package/dist/chunk-2UP7MG3J.js +66 -0
- package/dist/chunk-2UP7MG3J.js.map +1 -0
- package/dist/chunk-4VWLTG5L.js +2984 -0
- package/dist/chunk-4VWLTG5L.js.map +1 -0
- package/dist/chunk-7LEKQI47.js +32 -0
- package/dist/chunk-7LEKQI47.js.map +1 -0
- package/dist/chunk-CGOQI7ZL.js +8124 -0
- package/dist/chunk-CGOQI7ZL.js.map +1 -0
- package/dist/chunk-DQCXSPHP.js +33 -0
- package/dist/chunk-DQCXSPHP.js.map +1 -0
- package/dist/chunk-I3FFV63W.js +30 -0
- package/dist/chunk-I3FFV63W.js.map +1 -0
- package/dist/chunk-J3XVFPOV.js +58 -0
- package/dist/chunk-J3XVFPOV.js.map +1 -0
- package/dist/chunk-JCJFFJ42.js +39 -0
- package/dist/chunk-JCJFFJ42.js.map +1 -0
- package/dist/chunk-OKQWPNE3.js +1077 -0
- package/dist/chunk-OKQWPNE3.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-TC5BBLWO.js +29 -0
- package/dist/chunk-TC5BBLWO.js.map +1 -0
- package/dist/chunk-VD4CKRMT.js +127 -0
- package/dist/chunk-VD4CKRMT.js.map +1 -0
- package/dist/chunk-X6MEYCU7.js +1401 -0
- package/dist/chunk-X6MEYCU7.js.map +1 -0
- package/dist/client/index.js +24 -1052
- package/dist/client/index.js.map +1 -1
- package/dist/react/api/licenses.js +11 -1470
- package/dist/react/api/licenses.js.map +1 -1
- package/dist/react/api/vibe-coding.js +25 -1481
- package/dist/react/api/vibe-coding.js.map +1 -1
- package/dist/react/cards/register.js +45 -138
- package/dist/react/cards/register.js.map +1 -1
- package/dist/react/components/chat/index.d.ts +7 -21
- package/dist/react/components/chat/index.js +28 -11366
- package/dist/react/components/chat/index.js.map +1 -1
- package/dist/react/components/plan/index.js +135 -3054
- package/dist/react/components/plan/index.js.map +1 -1
- package/dist/react/components/session/index.js +21 -1499
- package/dist/react/components/session/index.js.map +1 -1
- package/dist/react/components/workspace/index.js +116 -1715
- package/dist/react/components/workspace/index.js.map +1 -1
- package/dist/react/devtools/bridge-devtools/index.js +8 -51
- package/dist/react/devtools/bridge-devtools/index.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +625 -14035
- package/dist/react/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
|
@@ -1,1473 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// src/client/socket.ts
|
|
13
|
-
import { io } from "socket.io-client";
|
|
14
|
-
|
|
15
|
-
// src/react/schemas/partner-skill.ts
|
|
16
|
-
import { type as type2 } from "arktype";
|
|
17
|
-
var PartnerSkillName = type2("/^[a-z0-9-]+\\/[a-z0-9-]+$/");
|
|
18
|
-
var PartnerSkillFile = type2({
|
|
19
|
-
path: "string > 0",
|
|
20
|
-
content: "string"
|
|
21
|
-
});
|
|
22
|
-
var PartnerSkillInstallPayload = type2({
|
|
23
|
-
name: PartnerSkillName,
|
|
24
|
-
files: PartnerSkillFile.array().atLeastLength(1)
|
|
25
|
-
});
|
|
26
|
-
var PartnerSkillInstallResult = type2({
|
|
27
|
-
name: PartnerSkillName,
|
|
28
|
-
skill_dir: "string",
|
|
29
|
-
file_count: "number.integer >= 0",
|
|
30
|
-
overwritten: "boolean"
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// src/react/stores/ui-bridge-store.ts
|
|
34
|
-
import { create } from "zustand";
|
|
35
|
-
|
|
36
|
-
// src/react/stores/client-aware.ts
|
|
37
|
-
function createClientActions(set) {
|
|
38
|
-
return {
|
|
39
|
-
_client: null,
|
|
40
|
-
setClient: (client) => set({ _client: client })
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// src/react/stores/ui-bridge-store.ts
|
|
45
|
-
function buildSignalId() {
|
|
46
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
47
|
-
return crypto.randomUUID();
|
|
48
|
-
}
|
|
49
|
-
return `bridge-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
50
|
-
}
|
|
51
|
-
function clearSignalRecord(record, sessionId) {
|
|
52
|
-
if (!(sessionId in record)) {
|
|
53
|
-
return record;
|
|
54
|
-
}
|
|
55
|
-
const next = { ...record };
|
|
56
|
-
delete next[sessionId];
|
|
57
|
-
return next;
|
|
58
|
-
}
|
|
59
|
-
var useUiBridgeStore = create()((set, get) => ({
|
|
60
|
-
...createClientActions(set),
|
|
61
|
-
pendingContexts: {},
|
|
62
|
-
draftAppends: {},
|
|
63
|
-
sendRequests: {},
|
|
64
|
-
addPendingContext: (sessionId, context) => set((state) => ({
|
|
65
|
-
pendingContexts: {
|
|
66
|
-
...state.pendingContexts,
|
|
67
|
-
[sessionId]: [
|
|
68
|
-
...state.pendingContexts[sessionId] ?? [],
|
|
69
|
-
{
|
|
70
|
-
id: buildSignalId(),
|
|
71
|
-
label: context.label,
|
|
72
|
-
content: context.content
|
|
73
|
-
}
|
|
74
|
-
]
|
|
75
|
-
}
|
|
76
|
-
})),
|
|
77
|
-
removePendingContext: (sessionId, contextId) => set((state) => {
|
|
78
|
-
const contexts = state.pendingContexts[sessionId];
|
|
79
|
-
if (!contexts?.length) {
|
|
80
|
-
return state;
|
|
81
|
-
}
|
|
82
|
-
const nextContexts = contexts.filter((context) => context.id !== contextId);
|
|
83
|
-
if (nextContexts.length === contexts.length) {
|
|
84
|
-
return state;
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
pendingContexts: nextContexts.length > 0 ? {
|
|
88
|
-
...state.pendingContexts,
|
|
89
|
-
[sessionId]: nextContexts
|
|
90
|
-
} : clearSignalRecord(state.pendingContexts, sessionId)
|
|
91
|
-
};
|
|
92
|
-
}),
|
|
93
|
-
consumePendingContexts: (sessionId) => {
|
|
94
|
-
const signals = get().pendingContexts[sessionId] ?? [];
|
|
95
|
-
if (signals.length === 0) return [];
|
|
96
|
-
set((state) => ({
|
|
97
|
-
pendingContexts: clearSignalRecord(state.pendingContexts, sessionId)
|
|
98
|
-
}));
|
|
99
|
-
return signals;
|
|
100
|
-
},
|
|
101
|
-
clearPendingContexts: (sessionId) => set((state) => ({
|
|
102
|
-
pendingContexts: clearSignalRecord(state.pendingContexts, sessionId)
|
|
103
|
-
})),
|
|
104
|
-
addDraftAppend: (sessionId, text) => set((state) => ({
|
|
105
|
-
draftAppends: {
|
|
106
|
-
...state.draftAppends,
|
|
107
|
-
[sessionId]: [
|
|
108
|
-
...state.draftAppends[sessionId] ?? [],
|
|
109
|
-
{
|
|
110
|
-
id: buildSignalId(),
|
|
111
|
-
text
|
|
112
|
-
}
|
|
113
|
-
]
|
|
114
|
-
}
|
|
115
|
-
})),
|
|
116
|
-
consumeDraftAppends: (sessionId) => {
|
|
117
|
-
const signals = get().draftAppends[sessionId] ?? [];
|
|
118
|
-
if (signals.length === 0) return [];
|
|
119
|
-
set((state) => ({
|
|
120
|
-
draftAppends: clearSignalRecord(state.draftAppends, sessionId)
|
|
121
|
-
}));
|
|
122
|
-
return signals;
|
|
123
|
-
},
|
|
124
|
-
clearDraftAppends: (sessionId) => set((state) => ({
|
|
125
|
-
draftAppends: clearSignalRecord(state.draftAppends, sessionId)
|
|
126
|
-
})),
|
|
127
|
-
addSendRequest: (sessionId) => set((state) => ({
|
|
128
|
-
sendRequests: {
|
|
129
|
-
...state.sendRequests,
|
|
130
|
-
[sessionId]: [
|
|
131
|
-
...state.sendRequests[sessionId] ?? [],
|
|
132
|
-
{
|
|
133
|
-
id: buildSignalId()
|
|
134
|
-
}
|
|
135
|
-
]
|
|
136
|
-
}
|
|
137
|
-
})),
|
|
138
|
-
consumeSendRequests: (sessionId) => {
|
|
139
|
-
const signals = get().sendRequests[sessionId] ?? [];
|
|
140
|
-
if (signals.length === 0) return [];
|
|
141
|
-
set((state) => ({
|
|
142
|
-
sendRequests: clearSignalRecord(state.sendRequests, sessionId)
|
|
143
|
-
}));
|
|
144
|
-
return signals;
|
|
145
|
-
},
|
|
146
|
-
clearSendRequests: (sessionId) => set((state) => ({
|
|
147
|
-
sendRequests: clearSignalRecord(state.sendRequests, sessionId)
|
|
148
|
-
})),
|
|
149
|
-
clearSession: (sessionId) => set((state) => ({
|
|
150
|
-
pendingContexts: clearSignalRecord(state.pendingContexts, sessionId),
|
|
151
|
-
draftAppends: clearSignalRecord(state.draftAppends, sessionId),
|
|
152
|
-
sendRequests: clearSignalRecord(state.sendRequests, sessionId)
|
|
153
|
-
}))
|
|
154
|
-
}));
|
|
155
|
-
|
|
156
|
-
// src/react/lib/chat.ts
|
|
157
|
-
function normalizeMessageContent(content) {
|
|
158
|
-
if (typeof content === "string") return content;
|
|
159
|
-
if (Array.isArray(content)) return content;
|
|
160
|
-
return String(content ?? "");
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// src/react/stores/auth-store.ts
|
|
164
|
-
import { create as create6 } from "zustand";
|
|
165
|
-
import { createJSONStorage, persist } from "zustand/middleware";
|
|
166
|
-
|
|
167
|
-
// src/react/api/auth.ts
|
|
168
|
-
var r = () => getClient().auth;
|
|
169
|
-
var getMe = (...args) => r().getMe(...args);
|
|
170
|
-
var logout = (...args) => r().logout(...args);
|
|
171
|
-
|
|
172
|
-
// src/react/sockets/socket-state.ts
|
|
173
|
-
var agentSocket = null;
|
|
174
|
-
|
|
175
|
-
// src/react/stores/session-store.ts
|
|
176
|
-
import { create as create5 } from "zustand";
|
|
177
|
-
|
|
178
|
-
// src/react/api/sessions.ts
|
|
179
|
-
var r2 = () => getClient().sessions;
|
|
180
|
-
var listSessions = (...args) => r2().listSessions(...args);
|
|
181
|
-
var createSession = (...args) => r2().createSession(...args);
|
|
182
|
-
var getSession = (...args) => r2().getSession(...args);
|
|
183
|
-
var pinSession = (...args) => r2().pinSession(...args);
|
|
184
|
-
var updateSharing = (...args) => r2().updateSharing(...args);
|
|
185
|
-
var getSessionTasks = (...args) => r2().getSessionTasks(...args);
|
|
186
|
-
var getSessionTurns = (...args) => r2().getSessionTurns(...args);
|
|
187
|
-
var deleteSession = (...args) => r2().deleteSession(...args);
|
|
188
|
-
|
|
189
|
-
// src/react/stores/chat-store.ts
|
|
190
|
-
import { create as create3 } from "zustand";
|
|
191
|
-
|
|
192
|
-
// src/react/components/chat/display-utils.ts
|
|
193
|
-
var TOOL_NAME_ALIASES = {
|
|
194
|
-
agent: "Agent",
|
|
195
|
-
ask_user_question: "AskUserQuestion",
|
|
196
|
-
bash: "Bash",
|
|
197
|
-
bg_bash: "BgBash",
|
|
198
|
-
edit: "Edit",
|
|
199
|
-
exit_plan_mode: "ExitPlanMode",
|
|
200
|
-
file_edit: "Edit",
|
|
201
|
-
file_read: "Read",
|
|
202
|
-
file_write: "Write",
|
|
203
|
-
finish_task: "FinishTask",
|
|
204
|
-
get_skill_content: "GetSkillContent",
|
|
205
|
-
glob: "Glob",
|
|
206
|
-
grep: "Grep",
|
|
207
|
-
list_skill_tools: "ListSkillTools",
|
|
208
|
-
load_skill_tools: "LoadSkillTools",
|
|
209
|
-
ls: "Ls",
|
|
210
|
-
read: "Read",
|
|
211
|
-
run_skill_tool: "RunSkillTool",
|
|
212
|
-
search_skills: "SearchSkills",
|
|
213
|
-
web_fetch: "WebFetch",
|
|
214
|
-
web_search: "WebSearch",
|
|
215
|
-
write: "Write"
|
|
216
|
-
};
|
|
217
|
-
var TOOL_DISPLAY_LABELS = {
|
|
218
|
-
Bash: "\u6267\u884C\u547D\u4EE4",
|
|
219
|
-
BgBash: "\u540E\u53F0\u6267\u884C\u547D\u4EE4",
|
|
220
|
-
Read: "\u8BFB\u53D6\u6587\u4EF6",
|
|
221
|
-
Write: "\u5199\u5165\u6587\u4EF6",
|
|
222
|
-
Edit: "\u7F16\u8F91\u6587\u4EF6",
|
|
223
|
-
Ls: "\u5217\u51FA\u76EE\u5F55",
|
|
224
|
-
Glob: "\u5339\u914D\u6587\u4EF6",
|
|
225
|
-
Grep: "\u641C\u7D22\u6587\u672C",
|
|
226
|
-
WebSearch: "\u641C\u7D22\u7F51\u9875",
|
|
227
|
-
WebFetch: "\u6574\u7406\u7F51\u9875\u5185\u5BB9",
|
|
228
|
-
Agent: "\u6D3E\u751F\u5B50\u667A\u80FD\u4F53",
|
|
229
|
-
AskUserQuestion: "\u5411\u7528\u6237\u63D0\u95EE",
|
|
230
|
-
SearchSkills: "\u641C\u7D22\u6280\u80FD",
|
|
231
|
-
GetSkillContent: "\u8BFB\u53D6\u6280\u80FD",
|
|
232
|
-
ListSkillTools: "\u67E5\u770B\u5DE5\u5177\u5217\u8868",
|
|
233
|
-
LoadSkillTools: "\u52A0\u8F7D\u6280\u80FD",
|
|
234
|
-
RunSkillTool: "\u6267\u884C\u6280\u80FD\u5DE5\u5177",
|
|
235
|
-
FinishTask: "\u4EFB\u52A1\u5B8C\u6210",
|
|
236
|
-
ExitPlanMode: "\u63D0\u4EA4\u8BA1\u5212",
|
|
237
|
-
ListSessions: "\u5217\u51FA\u5386\u53F2\u4F1A\u8BDD",
|
|
238
|
-
GetSessionHistory: "\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2"
|
|
239
|
-
};
|
|
240
|
-
var GENERIC_DISPLAY_NAMES = new Set(Object.values(TOOL_DISPLAY_LABELS));
|
|
241
|
-
function formatToolName(name) {
|
|
242
|
-
const trimmed = name.trim();
|
|
243
|
-
if (!trimmed) return name;
|
|
244
|
-
const stripped = trimmed.split(":").pop()?.split("/").pop()?.split(".").pop()?.trim() || trimmed;
|
|
245
|
-
const normalized = stripped.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
246
|
-
return TOOL_NAME_ALIASES[normalized] ?? stripped;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// src/react/stores/ui-store.ts
|
|
250
|
-
import { create as create2 } from "zustand";
|
|
251
|
-
var isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
252
|
-
function resolveEffectiveTheme(theme) {
|
|
253
|
-
if (theme !== "system") return theme;
|
|
254
|
-
return isBrowser && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
255
|
-
}
|
|
256
|
-
function applyTheme(theme) {
|
|
257
|
-
if (!isBrowser) return;
|
|
258
|
-
const effective = resolveEffectiveTheme(theme);
|
|
259
|
-
document.documentElement.setAttribute("data-theme", effective);
|
|
260
|
-
}
|
|
261
|
-
var storedTheme = isBrowser ? localStorage.getItem("blade-theme") ?? "light" : "light";
|
|
262
|
-
applyTheme(storedTheme);
|
|
263
|
-
if (isBrowser) {
|
|
264
|
-
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
|
|
265
|
-
const current = useUiStore?.getState?.()?.theme;
|
|
266
|
-
if (current === "system") applyTheme("system");
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
function removeArtifactAtIndex(state, index) {
|
|
270
|
-
const next = state.artifacts.filter((_, i) => i !== index);
|
|
271
|
-
let nextActive = state.activeArtifactIndex;
|
|
272
|
-
if (next.length === 0) {
|
|
273
|
-
return { artifacts: [], activeArtifactIndex: -1, rightPanelCollapsed: true };
|
|
274
|
-
}
|
|
275
|
-
if (index < nextActive) {
|
|
276
|
-
nextActive -= 1;
|
|
277
|
-
} else if (index === nextActive) {
|
|
278
|
-
nextActive = Math.min(index, next.length - 1);
|
|
279
|
-
}
|
|
280
|
-
return { artifacts: next, activeArtifactIndex: nextActive };
|
|
281
|
-
}
|
|
282
|
-
function upsertArtifactState(state, target, options) {
|
|
283
|
-
const reveal = options?.reveal ?? true;
|
|
284
|
-
const activate = options?.activate ?? true;
|
|
285
|
-
const targetKey = target.key ?? target.title;
|
|
286
|
-
const applyUiState = (partial) => ({
|
|
287
|
-
...partial,
|
|
288
|
-
...reveal ? { rightPanelCollapsed: false, activeRightTab: "preview" } : {}
|
|
289
|
-
});
|
|
290
|
-
const existing = state.artifacts.findIndex((artifact) => targetKey && (artifact.key ?? artifact.title) === targetKey);
|
|
291
|
-
if (existing >= 0) {
|
|
292
|
-
const updated = [...state.artifacts];
|
|
293
|
-
updated[existing] = target;
|
|
294
|
-
return applyUiState({
|
|
295
|
-
artifacts: updated,
|
|
296
|
-
activeArtifactIndex: activate ? existing : state.activeArtifactIndex
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
const next = [...state.artifacts, target];
|
|
300
|
-
return applyUiState({
|
|
301
|
-
artifacts: next,
|
|
302
|
-
activeArtifactIndex: activate ? next.length - 1 : state.activeArtifactIndex >= 0 ? state.activeArtifactIndex : 0
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
var useUiStore = create2()((set) => ({
|
|
306
|
-
...createClientActions(set),
|
|
307
|
-
leftPanelSize: 20,
|
|
308
|
-
rightPanelSize: 25,
|
|
309
|
-
leftPanelCollapsed: false,
|
|
310
|
-
rightPanelCollapsed: false,
|
|
311
|
-
activeRightTab: "situation",
|
|
312
|
-
artifacts: [],
|
|
313
|
-
activeArtifactIndex: -1,
|
|
314
|
-
theme: storedTheme,
|
|
315
|
-
setLeftPanelSize: (size) => set({ leftPanelSize: size }),
|
|
316
|
-
setRightPanelSize: (size) => set({ rightPanelSize: size }),
|
|
317
|
-
setLeftPanelCollapsed: (collapsed) => set({ leftPanelCollapsed: collapsed }),
|
|
318
|
-
setRightPanelCollapsed: (collapsed) => set({ rightPanelCollapsed: collapsed }),
|
|
319
|
-
toggleLeftPanel: () => set((s) => ({ leftPanelCollapsed: !s.leftPanelCollapsed })),
|
|
320
|
-
toggleRightPanel: () => set((s) => ({ rightPanelCollapsed: !s.rightPanelCollapsed })),
|
|
321
|
-
setActiveRightTab: (tab) => set({ activeRightTab: tab }),
|
|
322
|
-
pushArtifact: (target) => set((state) => upsertArtifactState(state, target)),
|
|
323
|
-
upsertArtifact: (target, options) => set((state) => upsertArtifactState(state, target, options)),
|
|
324
|
-
setActiveArtifact: (index) => set({ activeArtifactIndex: index }),
|
|
325
|
-
closeArtifact: (index) => set((state) => removeArtifactAtIndex(state, index)),
|
|
326
|
-
removeArtifactByKey: (key) => set((state) => {
|
|
327
|
-
const index = state.artifacts.findIndex((artifact) => (artifact.key ?? artifact.title) === key);
|
|
328
|
-
if (index < 0) return state;
|
|
329
|
-
return removeArtifactAtIndex(state, index);
|
|
330
|
-
}),
|
|
331
|
-
clearArtifacts: () => set({ artifacts: [], activeArtifactIndex: -1 }),
|
|
332
|
-
setPreviewTarget: (target) => set(() => {
|
|
333
|
-
if (target === null) {
|
|
334
|
-
return { artifacts: [], activeArtifactIndex: -1 };
|
|
335
|
-
}
|
|
336
|
-
return {
|
|
337
|
-
artifacts: [target],
|
|
338
|
-
activeArtifactIndex: 0,
|
|
339
|
-
rightPanelCollapsed: false,
|
|
340
|
-
activeRightTab: "preview"
|
|
341
|
-
};
|
|
342
|
-
}),
|
|
343
|
-
setTheme: (theme) => {
|
|
344
|
-
localStorage.setItem("blade-theme", theme);
|
|
345
|
-
applyTheme(theme);
|
|
346
|
-
set({ theme });
|
|
347
|
-
}
|
|
348
|
-
}));
|
|
349
|
-
|
|
350
|
-
// src/react/stores/chat-store.ts
|
|
351
|
-
var _getActiveSessionId = null;
|
|
352
|
-
function setChatStoreSessionAccessor(fn) {
|
|
353
|
-
_getActiveSessionId = fn;
|
|
354
|
-
}
|
|
355
|
-
function parseAgentDescription(argumentsJson) {
|
|
356
|
-
try {
|
|
357
|
-
return JSON.parse(argumentsJson)?.description ?? "\u5B50\u667A\u80FD\u4F53";
|
|
358
|
-
} catch {
|
|
359
|
-
return "\u5B50\u667A\u80FD\u4F53";
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
function inferLoopStatusFromMessages(messages) {
|
|
363
|
-
const toolCalls = messages.flatMap((message) => message.tool_calls ?? []);
|
|
364
|
-
if (messages.some((message) => message.status === "streaming")) return "running";
|
|
365
|
-
if (toolCalls.some((toolCall) => toolCall.status === "awaiting_answer")) return "awaiting_answer";
|
|
366
|
-
if (toolCalls.some((toolCall) => toolCall.status === "error")) return "error";
|
|
367
|
-
if (toolCalls.some((toolCall) => toolCall.status === "cancelled")) return "cancelled";
|
|
368
|
-
if (toolCalls.some((toolCall) => toolCall.status === "pending")) return "running";
|
|
369
|
-
return "done";
|
|
370
|
-
}
|
|
371
|
-
function inferLoopStatusFromTurns(turns, messages) {
|
|
372
|
-
const latestAgentNotification = [...turns].reverse().flatMap((turn) => turn.blocks).find((block) => {
|
|
373
|
-
if (block.type !== "system_notification" || !isRecord(block.content)) return false;
|
|
374
|
-
return block.content.notification_type === "agent:start" || block.content.notification_type === "agent:end";
|
|
375
|
-
});
|
|
376
|
-
if (latestAgentNotification?.type === "system_notification" && isRecord(latestAgentNotification.content)) {
|
|
377
|
-
const notificationType = latestAgentNotification.content.notification_type;
|
|
378
|
-
const status = latestAgentNotification.content.status;
|
|
379
|
-
if (notificationType === "agent:start" || status === "running") return "running";
|
|
380
|
-
if (status === "error") return "error";
|
|
381
|
-
if (status === "cancelled") return "cancelled";
|
|
382
|
-
}
|
|
383
|
-
return inferLoopStatusFromMessages(messages);
|
|
384
|
-
}
|
|
385
|
-
function isRecord(value) {
|
|
386
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
387
|
-
}
|
|
388
|
-
function parentForkToolCallIdFromTurn(turn) {
|
|
389
|
-
if (typeof turn.parent_fork_tool_call_id === "string" && turn.parent_fork_tool_call_id.length > 0) {
|
|
390
|
-
return turn.parent_fork_tool_call_id;
|
|
391
|
-
}
|
|
392
|
-
for (const block of turn.blocks) {
|
|
393
|
-
if (block.type !== "system_notification" || !isRecord(block.content)) continue;
|
|
394
|
-
const metadata = block.content.metadata;
|
|
395
|
-
if (!isRecord(metadata)) continue;
|
|
396
|
-
const parentId = metadata.parent_fork_tool_call_id;
|
|
397
|
-
if (typeof parentId === "string" && parentId.length > 0) return parentId;
|
|
398
|
-
}
|
|
399
|
-
return null;
|
|
400
|
-
}
|
|
401
|
-
function buildMessageContent(turn) {
|
|
402
|
-
const textBlocks = turn.blocks.filter((block) => block.type === "text");
|
|
403
|
-
if (textBlocks.length === 0) return "";
|
|
404
|
-
if (textBlocks.length === 1) return normalizeMessageContent(textBlocks[0].content);
|
|
405
|
-
return textBlocks.map((block) => {
|
|
406
|
-
if (typeof block.content === "string") return block.content;
|
|
407
|
-
return JSON.stringify(block.content);
|
|
408
|
-
}).join("");
|
|
409
|
-
}
|
|
410
|
-
function buildReasoning(turn) {
|
|
411
|
-
const thinking = turn.blocks.filter((block) => block.type === "thinking").map((block) => typeof block.content === "string" ? block.content : JSON.stringify(block.content)).filter(Boolean);
|
|
412
|
-
if (thinking.length === 0) return void 0;
|
|
413
|
-
return thinking.join("\n\n");
|
|
414
|
-
}
|
|
415
|
-
function isModeChangeContent(value) {
|
|
416
|
-
return typeof value === "object" && value !== null && typeof value.from === "string" && typeof value.to === "string";
|
|
417
|
-
}
|
|
418
|
-
function extractModeFromBlocks(blocks) {
|
|
419
|
-
const modeBlock = blocks.find((block) => block.type === "mode_change");
|
|
420
|
-
if (modeBlock && isModeChangeContent(modeBlock.content)) {
|
|
421
|
-
return modeBlock.content.to === "planning" || modeBlock.content.to === "executing" ? modeBlock.content.to : null;
|
|
422
|
-
}
|
|
423
|
-
if (blocks.some((block) => block.type === "planning_enter")) return "planning";
|
|
424
|
-
if (blocks.some((block) => block.type === "planning_exit")) return "executing";
|
|
425
|
-
return null;
|
|
426
|
-
}
|
|
427
|
-
function projectionToMessage(turn) {
|
|
428
|
-
if (turn.kind === "compaction" && turn.compaction_id) {
|
|
429
|
-
return {
|
|
430
|
-
role: "assistant",
|
|
431
|
-
content: turn.summary_preview ?? "",
|
|
432
|
-
kind: "compaction",
|
|
433
|
-
loop_name: turn.loop_id,
|
|
434
|
-
entry_id: turn.turn_id,
|
|
435
|
-
status: turn.status,
|
|
436
|
-
compaction: {
|
|
437
|
-
compaction_id: turn.compaction_id,
|
|
438
|
-
summary_preview: turn.summary_preview,
|
|
439
|
-
summary_full: turn.summary_full,
|
|
440
|
-
archived_count: turn.archived_count,
|
|
441
|
-
archived_files: turn.archived_files,
|
|
442
|
-
archived_tool_calls: turn.archived_tool_calls,
|
|
443
|
-
tokens_before: turn.tokens_before,
|
|
444
|
-
tokens_after: turn.tokens_after,
|
|
445
|
-
saved_ratio: turn.saved_ratio,
|
|
446
|
-
trigger: turn.trigger,
|
|
447
|
-
failure_reason: turn.failure_reason,
|
|
448
|
-
fallback_applied: turn.fallback_applied
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
const planningBlock = turn.blocks.find(
|
|
453
|
-
(block) => block.type === "mode_change" || block.type === "planning_enter" || block.type === "planning_exit" || block.type === "plan_status"
|
|
454
|
-
);
|
|
455
|
-
if (planningBlock) {
|
|
456
|
-
if (planningBlock.type === "plan_status") {
|
|
457
|
-
return {
|
|
458
|
-
role: "tool",
|
|
459
|
-
content: typeof planningBlock.content === "string" ? planningBlock.content : JSON.stringify(planningBlock.content ?? {}, null, 2),
|
|
460
|
-
kind: "plan_status",
|
|
461
|
-
loop_name: turn.loop_id,
|
|
462
|
-
entry_id: turn.turn_id,
|
|
463
|
-
status: turn.status
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
return {
|
|
467
|
-
role: "assistant",
|
|
468
|
-
content: planningBlock.type === "mode_change" ? typeof planningBlock.content === "string" ? planningBlock.content : JSON.stringify(planningBlock.content ?? {}) : "",
|
|
469
|
-
kind: planningBlock.type,
|
|
470
|
-
loop_name: turn.loop_id,
|
|
471
|
-
entry_id: turn.turn_id,
|
|
472
|
-
status: turn.status
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
if (turn.blocks.some((block) => block.type === "ask_user_answer")) {
|
|
476
|
-
return null;
|
|
477
|
-
}
|
|
478
|
-
const content = buildMessageContent(turn);
|
|
479
|
-
const reasoning = buildReasoning(turn);
|
|
480
|
-
const toolCalls = turn.tool_calls.length > 0 ? turn.tool_calls.map((toolCall) => ({
|
|
481
|
-
id: toolCall.id,
|
|
482
|
-
name: toolCall.tool_name,
|
|
483
|
-
display_name: toolCall.display_name,
|
|
484
|
-
arguments: toolCall.arguments,
|
|
485
|
-
result: toolCall.result ?? void 0,
|
|
486
|
-
pending_question_ref: toolCall.pending_question_ref ?? void 0,
|
|
487
|
-
status: toolCall.status === "pending" || toolCall.status === "awaiting_answer" || toolCall.status === "done" || toolCall.status === "error" || toolCall.status === "cancelled" ? toolCall.status : "pending",
|
|
488
|
-
...typeof toolCall.duration_ms === "number" ? { duration_ms: toolCall.duration_ms } : {}
|
|
489
|
-
})) : void 0;
|
|
490
|
-
if (turn.role === "system" && !content && !toolCalls?.length) {
|
|
491
|
-
return null;
|
|
492
|
-
}
|
|
493
|
-
return {
|
|
494
|
-
role: turn.role === "system" ? "assistant" : turn.role,
|
|
495
|
-
content,
|
|
496
|
-
blocks: turn.blocks,
|
|
497
|
-
...reasoning ? { reasoning } : {},
|
|
498
|
-
...toolCalls ? { tool_calls: toolCalls } : {},
|
|
499
|
-
loop_name: turn.loop_id,
|
|
500
|
-
entry_id: turn.turn_id,
|
|
501
|
-
status: turn.status,
|
|
502
|
-
...typeof turn.duration_ms === "number" ? { duration_ms: turn.duration_ms } : {},
|
|
503
|
-
...turn.started_at ? { timestamp: turn.started_at } : {},
|
|
504
|
-
...turn.memory_refs?.length ? { memory_refs: turn.memory_refs } : {}
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
function rebuildAgentLoops(turns) {
|
|
508
|
-
const messages = turns.map(projectionToMessage).filter(Boolean);
|
|
509
|
-
const childLoopNames = [...new Set(turns.map((turn) => turn.loop_id).filter((name) => name !== "root"))];
|
|
510
|
-
if (childLoopNames.length === 0) return {};
|
|
511
|
-
const agentToolCalls = messages.filter((message) => message.role === "assistant" && (message.loop_name ?? "root") === "root").flatMap((message) => message.tool_calls ?? []).filter((toolCall) => formatToolName(toolCall.name) === "Agent");
|
|
512
|
-
const loops = {};
|
|
513
|
-
const agentToolCallsById = new Map(agentToolCalls.map((toolCall) => [toolCall.id, toolCall]));
|
|
514
|
-
const explicitParentToolCallIds = new Set(
|
|
515
|
-
turns.map(parentForkToolCallIdFromTurn).filter((id) => id !== null)
|
|
516
|
-
);
|
|
517
|
-
const usedToolCallIds = /* @__PURE__ */ new Set();
|
|
518
|
-
for (const loopName of childLoopNames) {
|
|
519
|
-
const loopMessages = messages.filter((message) => (message.loop_name ?? "root") === loopName);
|
|
520
|
-
const loopTurns = turns.filter((turn) => turn.loop_id === loopName);
|
|
521
|
-
const parentToolCallId = loopTurns.map(parentForkToolCallIdFromTurn).find(Boolean);
|
|
522
|
-
const explicitToolCall = parentToolCallId && !usedToolCallIds.has(parentToolCallId) ? agentToolCallsById.get(parentToolCallId) ?? null : null;
|
|
523
|
-
const fallbackToolCall = explicitToolCall === null ? agentToolCalls.find(
|
|
524
|
-
(toolCall2) => !usedToolCallIds.has(toolCall2.id) && !explicitParentToolCallIds.has(toolCall2.id)
|
|
525
|
-
) : null;
|
|
526
|
-
const toolCall = explicitToolCall ?? fallbackToolCall;
|
|
527
|
-
if (!toolCall) continue;
|
|
528
|
-
usedToolCallIds.add(toolCall.id);
|
|
529
|
-
loops[loopName] = {
|
|
530
|
-
toolCallId: toolCall.id,
|
|
531
|
-
description: parseAgentDescription(toolCall.arguments),
|
|
532
|
-
status: inferLoopStatusFromTurns(loopTurns, loopMessages)
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
return loops;
|
|
536
|
-
}
|
|
537
|
-
function applyPlanningSideEffects(sessionId, turns) {
|
|
538
|
-
const latestMode = [...turns].reverse().map((turn) => extractModeFromBlocks(turn.blocks)).find((mode) => mode !== null);
|
|
539
|
-
if (latestMode !== "planning") return;
|
|
540
|
-
if (_getActiveSessionId?.() !== sessionId) return;
|
|
541
|
-
const ui = useUiStore.getState();
|
|
542
|
-
ui.setActiveRightTab("situation");
|
|
543
|
-
if (ui.rightPanelCollapsed) {
|
|
544
|
-
ui.toggleRightPanel();
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
function materialize(turns) {
|
|
548
|
-
const messages = turns.map(projectionToMessage).filter((message) => message !== null);
|
|
549
|
-
const activeCompaction = [...turns].reverse().find(
|
|
550
|
-
(turn) => turn.kind === "compaction" && turn.status === "streaming" && typeof turn.compaction_id === "string"
|
|
551
|
-
);
|
|
552
|
-
return {
|
|
553
|
-
messages,
|
|
554
|
-
agentLoops: rebuildAgentLoops(turns),
|
|
555
|
-
activeCompaction: activeCompaction ? {
|
|
556
|
-
turn_id: activeCompaction.turn_id,
|
|
557
|
-
status: activeCompaction.status,
|
|
558
|
-
compaction_id: activeCompaction.compaction_id,
|
|
559
|
-
summary_preview: activeCompaction.summary_preview,
|
|
560
|
-
summary_full: activeCompaction.summary_full,
|
|
561
|
-
archived_count: activeCompaction.archived_count,
|
|
562
|
-
archived_files: activeCompaction.archived_files,
|
|
563
|
-
archived_tool_calls: activeCompaction.archived_tool_calls,
|
|
564
|
-
tokens_before: activeCompaction.tokens_before,
|
|
565
|
-
tokens_after: activeCompaction.tokens_after,
|
|
566
|
-
saved_ratio: activeCompaction.saved_ratio,
|
|
567
|
-
trigger: activeCompaction.trigger,
|
|
568
|
-
failure_reason: activeCompaction.failure_reason,
|
|
569
|
-
fallback_applied: activeCompaction.fallback_applied
|
|
570
|
-
} : null
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
var ERROR_ANCHOR_PREFIX = "error-anchor:";
|
|
574
|
-
function updateSessionState(state, sessionId, turns) {
|
|
575
|
-
const orderedTurns = [...turns].sort((left, right) => left.sequence - right.sequence);
|
|
576
|
-
const { messages, agentLoops, activeCompaction } = materialize(orderedTurns);
|
|
577
|
-
applyPlanningSideEffects(sessionId, orderedTurns);
|
|
578
|
-
const lastTurnId = orderedTurns[orderedTurns.length - 1]?.turn_id ?? null;
|
|
579
|
-
const preservedErrors = lastTurnId ? (state.messages[sessionId] ?? []).filter(
|
|
580
|
-
(m) => m.role === "error" && typeof m.entry_id === "string" && m.entry_id.startsWith(`${ERROR_ANCHOR_PREFIX}${lastTurnId}:`)
|
|
581
|
-
) : [];
|
|
582
|
-
const mergedMessages = preservedErrors.length > 0 ? [...messages, ...preservedErrors] : messages;
|
|
583
|
-
return {
|
|
584
|
-
turns: { ...state.turns, [sessionId]: orderedTurns },
|
|
585
|
-
messages: { ...state.messages, [sessionId]: mergedMessages },
|
|
586
|
-
agentLoops: { ...state.agentLoops, [sessionId]: agentLoops },
|
|
587
|
-
activeCompactions: { ...state.activeCompactions, [sessionId]: activeCompaction }
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
var useChatStore = create3()((set) => ({
|
|
591
|
-
...createClientActions(set),
|
|
592
|
-
turns: {},
|
|
593
|
-
messages: {},
|
|
594
|
-
askAnswers: {},
|
|
595
|
-
isStreaming: {},
|
|
596
|
-
agentLoops: {},
|
|
597
|
-
activeCompactions: {},
|
|
598
|
-
addUserMessage: (sessionId, content) => {
|
|
599
|
-
set((state) => {
|
|
600
|
-
const existing = state.turns[sessionId] ?? [];
|
|
601
|
-
const turnId = `local-user-${Date.now()}`;
|
|
602
|
-
const optimisticTurn = {
|
|
603
|
-
id: turnId,
|
|
604
|
-
sequence: Math.max(0, ...existing.map((turn) => turn.sequence)) + 1,
|
|
605
|
-
turn_id: turnId,
|
|
606
|
-
loop_id: "root",
|
|
607
|
-
role: "user",
|
|
608
|
-
status: "completed",
|
|
609
|
-
blocks: [{ type: "text", content }],
|
|
610
|
-
tool_calls: [],
|
|
611
|
-
model: null,
|
|
612
|
-
usage: null,
|
|
613
|
-
duration_ms: 0
|
|
614
|
-
};
|
|
615
|
-
return updateSessionState(state, sessionId, [...existing, optimisticTurn]);
|
|
616
|
-
});
|
|
617
|
-
},
|
|
618
|
-
setTurns: (sessionId, turns) => {
|
|
619
|
-
set((state) => updateSessionState(state, sessionId, [...turns]));
|
|
620
|
-
},
|
|
621
|
-
upsertTurn: (sessionId, turn) => {
|
|
622
|
-
set((state) => {
|
|
623
|
-
const existing = [...state.turns[sessionId] ?? []];
|
|
624
|
-
const index = existing.findIndex((item) => item.turn_id === turn.turn_id);
|
|
625
|
-
if (index >= 0) {
|
|
626
|
-
existing[index] = turn;
|
|
627
|
-
} else {
|
|
628
|
-
existing.push(turn);
|
|
629
|
-
}
|
|
630
|
-
return {
|
|
631
|
-
...updateSessionState(state, sessionId, existing)
|
|
632
|
-
};
|
|
633
|
-
});
|
|
634
|
-
},
|
|
635
|
-
applyTurnPatch: (sessionId, patch) => {
|
|
636
|
-
set((state) => {
|
|
637
|
-
const turn = patch.data.turn;
|
|
638
|
-
if (!turn) return state;
|
|
639
|
-
const existing = [...state.turns[sessionId] ?? []];
|
|
640
|
-
const index = existing.findIndex((item) => item.turn_id === turn.turn_id);
|
|
641
|
-
const lastSequence = index >= 0 ? existing[index].sequence : null;
|
|
642
|
-
if (lastSequence !== null && patch.sequence <= lastSequence) {
|
|
643
|
-
return state;
|
|
644
|
-
}
|
|
645
|
-
const nextTurn = {
|
|
646
|
-
...turn,
|
|
647
|
-
sequence: patch.sequence
|
|
648
|
-
};
|
|
649
|
-
if (index >= 0) {
|
|
650
|
-
existing[index] = nextTurn;
|
|
651
|
-
} else {
|
|
652
|
-
existing.push(nextTurn);
|
|
653
|
-
}
|
|
654
|
-
return {
|
|
655
|
-
...updateSessionState(state, sessionId, existing)
|
|
656
|
-
};
|
|
657
|
-
});
|
|
658
|
-
},
|
|
659
|
-
addErrorMessage: (sessionId, content) => {
|
|
660
|
-
set((state) => {
|
|
661
|
-
const turns = state.turns[sessionId] ?? [];
|
|
662
|
-
const anchorTurnId = turns[turns.length - 1]?.turn_id ?? null;
|
|
663
|
-
const entry_id = anchorTurnId ? `${ERROR_ANCHOR_PREFIX}${anchorTurnId}:${Date.now()}` : void 0;
|
|
664
|
-
return {
|
|
665
|
-
messages: {
|
|
666
|
-
...state.messages,
|
|
667
|
-
[sessionId]: [
|
|
668
|
-
...state.messages[sessionId] ?? [],
|
|
669
|
-
{ role: "error", content, loop_name: "root", entry_id }
|
|
670
|
-
]
|
|
671
|
-
}
|
|
672
|
-
};
|
|
673
|
-
});
|
|
674
|
-
},
|
|
675
|
-
markInterrupted: (sessionId) => {
|
|
676
|
-
set((state) => {
|
|
677
|
-
const turns = (state.turns[sessionId] ?? []).map((turn) => {
|
|
678
|
-
if (turn.status !== "streaming") return turn;
|
|
679
|
-
return {
|
|
680
|
-
...turn,
|
|
681
|
-
status: "interrupted",
|
|
682
|
-
tool_calls: turn.tool_calls.map(
|
|
683
|
-
(toolCall) => toolCall.status === "pending" || toolCall.status === "awaiting_answer" ? { ...toolCall, status: "cancelled" } : toolCall
|
|
684
|
-
)
|
|
685
|
-
};
|
|
686
|
-
});
|
|
687
|
-
return {
|
|
688
|
-
...updateSessionState(state, sessionId, turns)
|
|
689
|
-
};
|
|
690
|
-
});
|
|
691
|
-
},
|
|
692
|
-
markFailed: (sessionId) => {
|
|
693
|
-
set((state) => {
|
|
694
|
-
const turns = (state.turns[sessionId] ?? []).map((turn) => {
|
|
695
|
-
if (turn.status !== "streaming") return turn;
|
|
696
|
-
return {
|
|
697
|
-
...turn,
|
|
698
|
-
status: "failed",
|
|
699
|
-
tool_calls: turn.tool_calls.map(
|
|
700
|
-
(toolCall) => toolCall.status === "pending" || toolCall.status === "awaiting_answer" ? { ...toolCall, status: "error" } : toolCall
|
|
701
|
-
)
|
|
702
|
-
};
|
|
703
|
-
});
|
|
704
|
-
return {
|
|
705
|
-
...updateSessionState(state, sessionId, turns)
|
|
706
|
-
};
|
|
707
|
-
});
|
|
708
|
-
},
|
|
709
|
-
setStreaming: (sessionId, streaming) => {
|
|
710
|
-
set((state) => ({
|
|
711
|
-
isStreaming: { ...state.isStreaming, [sessionId]: streaming }
|
|
712
|
-
}));
|
|
713
|
-
},
|
|
714
|
-
setAskAnswers: (sessionId, answers) => {
|
|
715
|
-
set((state) => ({
|
|
716
|
-
askAnswers: {
|
|
717
|
-
...state.askAnswers,
|
|
718
|
-
[sessionId]: answers
|
|
719
|
-
}
|
|
720
|
-
}));
|
|
721
|
-
},
|
|
722
|
-
clearMessages: (sessionId) => {
|
|
723
|
-
set((state) => {
|
|
724
|
-
const { [sessionId]: _turns, ...restTurns } = state.turns;
|
|
725
|
-
const { [sessionId]: _messages, ...restMessages } = state.messages;
|
|
726
|
-
const { [sessionId]: _answers, ...restAnswers } = state.askAnswers;
|
|
727
|
-
const { [sessionId]: _loops, ...restLoops } = state.agentLoops;
|
|
728
|
-
const { [sessionId]: _compaction, ...restCompactions } = state.activeCompactions;
|
|
729
|
-
return {
|
|
730
|
-
turns: restTurns,
|
|
731
|
-
messages: restMessages,
|
|
732
|
-
askAnswers: restAnswers,
|
|
733
|
-
agentLoops: restLoops,
|
|
734
|
-
activeCompactions: restCompactions
|
|
735
|
-
};
|
|
736
|
-
});
|
|
737
|
-
}
|
|
738
|
-
}));
|
|
739
|
-
|
|
740
|
-
// src/react/stores/task-store.ts
|
|
741
|
-
import { create as create4 } from "zustand";
|
|
742
|
-
var EMPTY_TASKS = [];
|
|
743
|
-
var useTaskStore = create4()((set, get) => ({
|
|
744
|
-
...createClientActions(set),
|
|
745
|
-
tasks: {},
|
|
746
|
-
setTasks: (sessionId, tasks) => {
|
|
747
|
-
set((state) => ({
|
|
748
|
-
tasks: { ...state.tasks, [sessionId]: tasks }
|
|
749
|
-
}));
|
|
750
|
-
},
|
|
751
|
-
getTasks: (sessionId) => {
|
|
752
|
-
return get().tasks[sessionId] ?? EMPTY_TASKS;
|
|
753
|
-
}
|
|
754
|
-
}));
|
|
755
|
-
|
|
756
|
-
// src/react/stores/session-store.ts
|
|
757
|
-
var DEFAULT_SESSION_MODE = "executing";
|
|
758
|
-
var onSessionChange = null;
|
|
759
|
-
function invalidateHomeSidebarSessions() {
|
|
760
|
-
const queryClient = globalThis.__agentQueryClient;
|
|
761
|
-
if (!queryClient) return;
|
|
762
|
-
void queryClient.invalidateQueries({ queryKey: ["sessions", "home-sidebar"] });
|
|
763
|
-
}
|
|
764
|
-
function isSessionAccessRevoked(error) {
|
|
765
|
-
if (error instanceof Error) {
|
|
766
|
-
const msg = error.message;
|
|
767
|
-
return msg.includes("API 403") || msg.includes("API 404");
|
|
768
|
-
}
|
|
769
|
-
return false;
|
|
770
|
-
}
|
|
771
|
-
function removeSessionArtifacts(sessionId) {
|
|
772
|
-
useChatStore.getState().clearMessages(sessionId);
|
|
773
|
-
useTaskStore.getState().setTasks(sessionId, []);
|
|
774
|
-
}
|
|
775
|
-
function pruneSessionState(state, sessionId) {
|
|
776
|
-
const nextFresh = new Set(state._freshSessions);
|
|
777
|
-
nextFresh.delete(sessionId);
|
|
778
|
-
const { [sessionId]: _mode, ...modes } = state.modes;
|
|
779
|
-
const { [sessionId]: _rewindDraft, ...rewindDrafts } = state.rewindDrafts;
|
|
780
|
-
return {
|
|
781
|
-
sessions: state.sessions.filter((session) => session.id !== sessionId),
|
|
782
|
-
activeSessionId: state.activeSessionId === sessionId ? null : state.activeSessionId,
|
|
783
|
-
modes,
|
|
784
|
-
rewindDrafts,
|
|
785
|
-
_freshSessions: nextFresh
|
|
786
|
-
};
|
|
787
|
-
}
|
|
788
|
-
function navigateAwayFromSession(sessionId) {
|
|
789
|
-
if (typeof window === "undefined") return;
|
|
790
|
-
if (window.location.pathname !== `/chat/${sessionId}`) return;
|
|
791
|
-
window.history.replaceState(window.history.state, "", "/chat");
|
|
792
|
-
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
793
|
-
}
|
|
794
|
-
function handleUnreadableSession(set, get, sessionId) {
|
|
795
|
-
const wasActive = get().activeSessionId === sessionId;
|
|
796
|
-
removeSessionArtifacts(sessionId);
|
|
797
|
-
set((state) => pruneSessionState(state, sessionId));
|
|
798
|
-
if (wasActive) {
|
|
799
|
-
onSessionChange?.(null);
|
|
800
|
-
navigateAwayFromSession(sessionId);
|
|
801
|
-
}
|
|
802
|
-
invalidateHomeSidebarSessions();
|
|
803
|
-
}
|
|
804
|
-
function isPlainRecord(value) {
|
|
805
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
806
|
-
}
|
|
807
|
-
function extractModeFromBlocks2(blocks) {
|
|
808
|
-
const modeBlock = blocks.find((block) => block.type === "mode_change");
|
|
809
|
-
if (modeBlock && isPlainRecord(modeBlock.content) && (modeBlock.content.to === "planning" || modeBlock.content.to === "executing")) {
|
|
810
|
-
return modeBlock.content.to;
|
|
811
|
-
}
|
|
812
|
-
if (blocks.some((block) => block.type === "planning_enter")) return "planning";
|
|
813
|
-
if (blocks.some((block) => block.type === "planning_exit")) return "executing";
|
|
814
|
-
return null;
|
|
815
|
-
}
|
|
816
|
-
function toSelectionMap(value) {
|
|
817
|
-
if (!isPlainRecord(value)) return {};
|
|
818
|
-
const entries = Object.entries(value).map(([questionKey, optionIndexes]) => {
|
|
819
|
-
if (!Array.isArray(optionIndexes)) return null;
|
|
820
|
-
const parsedIndexes = optionIndexes.map((item) => typeof item === "number" ? item : Number(item)).filter((item) => Number.isInteger(item));
|
|
821
|
-
return [Number(questionKey), parsedIndexes];
|
|
822
|
-
}).filter((entry) => entry !== null);
|
|
823
|
-
return Object.fromEntries(entries);
|
|
824
|
-
}
|
|
825
|
-
function toCustomMap(value) {
|
|
826
|
-
if (!isPlainRecord(value)) return {};
|
|
827
|
-
const entries = Object.entries(value).filter(([, text]) => typeof text === "string").map(([questionKey, text]) => [Number(questionKey), text]);
|
|
828
|
-
return Object.fromEntries(entries);
|
|
829
|
-
}
|
|
830
|
-
function extractAskAnswers(turns) {
|
|
831
|
-
const answers = {};
|
|
832
|
-
for (const turn of turns) {
|
|
833
|
-
for (const block of turn.blocks) {
|
|
834
|
-
if (block.type !== "ask_user_answer" || typeof block.tool_call_id !== "string") continue;
|
|
835
|
-
answers[block.tool_call_id] = {
|
|
836
|
-
selections: toSelectionMap(isPlainRecord(block.content) ? block.content.selections : void 0),
|
|
837
|
-
custom: toCustomMap(isPlainRecord(block.content) ? block.content.custom : void 0)
|
|
838
|
-
};
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
return answers;
|
|
842
|
-
}
|
|
843
|
-
function registerCreatedSessionState(set, session, mode = DEFAULT_SESSION_MODE) {
|
|
844
|
-
useChatStore.getState().setTurns(session.id, []);
|
|
845
|
-
useTaskStore.getState().setTasks(session.id, []);
|
|
846
|
-
set((state) => ({
|
|
847
|
-
sessions: [session, ...state.sessions.filter((item) => item.id !== session.id)],
|
|
848
|
-
modes: { ...state.modes, [session.id]: state.modes[session.id] ?? mode },
|
|
849
|
-
_freshSessions: new Set(state._freshSessions).add(session.id)
|
|
850
|
-
}));
|
|
851
|
-
}
|
|
852
|
-
async function revalidateViewerSessions(existingSessions) {
|
|
853
|
-
const viewerSessions = existingSessions.filter((session) => session.viewer_role === "viewer");
|
|
854
|
-
if (viewerSessions.length === 0) {
|
|
855
|
-
return [];
|
|
856
|
-
}
|
|
857
|
-
const refreshed = await Promise.all(
|
|
858
|
-
viewerSessions.map(async (session) => {
|
|
859
|
-
try {
|
|
860
|
-
return await getSession(session.id);
|
|
861
|
-
} catch (error) {
|
|
862
|
-
if (isSessionAccessRevoked(error)) {
|
|
863
|
-
return null;
|
|
864
|
-
}
|
|
865
|
-
return session;
|
|
866
|
-
}
|
|
867
|
-
})
|
|
868
|
-
);
|
|
869
|
-
return refreshed.filter((session) => session !== null);
|
|
870
|
-
}
|
|
871
|
-
var useSessionStore = create5()((set, get) => ({
|
|
872
|
-
...createClientActions(set),
|
|
873
|
-
sessions: [],
|
|
874
|
-
activeSessionId: null,
|
|
875
|
-
loading: false,
|
|
876
|
-
modes: {},
|
|
877
|
-
rewindDrafts: {},
|
|
878
|
-
_freshSessions: /* @__PURE__ */ new Set(),
|
|
879
|
-
fetchSessions: async () => {
|
|
880
|
-
set({ loading: true });
|
|
881
|
-
try {
|
|
882
|
-
const currentState = get();
|
|
883
|
-
const [sessions, viewerSessions] = await Promise.all([
|
|
884
|
-
listSessions(),
|
|
885
|
-
revalidateViewerSessions(currentState.sessions)
|
|
886
|
-
]);
|
|
887
|
-
const knownSessionIds = new Set(sessions.map((session) => session.id));
|
|
888
|
-
const mergedSessions = [
|
|
889
|
-
...sessions,
|
|
890
|
-
...viewerSessions.filter((session) => !knownSessionIds.has(session.id))
|
|
891
|
-
];
|
|
892
|
-
const removedSessionIds = currentState.sessions.filter(
|
|
893
|
-
(session) => session.viewer_role === "viewer" && !mergedSessions.some((candidate) => candidate.id === session.id)
|
|
894
|
-
).map((session) => session.id);
|
|
895
|
-
const activeSessionId = currentState.activeSessionId;
|
|
896
|
-
for (const sessionId of removedSessionIds) {
|
|
897
|
-
removeSessionArtifacts(sessionId);
|
|
898
|
-
}
|
|
899
|
-
let nextState = {
|
|
900
|
-
sessions: mergedSessions,
|
|
901
|
-
activeSessionId: currentState.activeSessionId,
|
|
902
|
-
loading: false,
|
|
903
|
-
modes: currentState.modes,
|
|
904
|
-
rewindDrafts: currentState.rewindDrafts,
|
|
905
|
-
_freshSessions: currentState._freshSessions
|
|
906
|
-
};
|
|
907
|
-
for (const sessionId of removedSessionIds) {
|
|
908
|
-
nextState = {
|
|
909
|
-
...nextState,
|
|
910
|
-
...pruneSessionState(
|
|
911
|
-
{
|
|
912
|
-
...currentState,
|
|
913
|
-
sessions: nextState.sessions ?? currentState.sessions,
|
|
914
|
-
activeSessionId: nextState.activeSessionId ?? currentState.activeSessionId,
|
|
915
|
-
loading: nextState.loading ?? currentState.loading,
|
|
916
|
-
modes: nextState.modes ?? currentState.modes,
|
|
917
|
-
rewindDrafts: nextState.rewindDrafts ?? currentState.rewindDrafts,
|
|
918
|
-
_freshSessions: nextState._freshSessions ?? currentState._freshSessions
|
|
919
|
-
},
|
|
920
|
-
sessionId
|
|
921
|
-
)
|
|
922
|
-
};
|
|
923
|
-
}
|
|
924
|
-
set(nextState);
|
|
925
|
-
if (activeSessionId && removedSessionIds.includes(activeSessionId)) {
|
|
926
|
-
onSessionChange?.(null);
|
|
927
|
-
navigateAwayFromSession(activeSessionId);
|
|
928
|
-
}
|
|
929
|
-
invalidateHomeSidebarSessions();
|
|
930
|
-
} catch (error) {
|
|
931
|
-
set({ loading: false });
|
|
932
|
-
throw error;
|
|
933
|
-
}
|
|
934
|
-
},
|
|
935
|
-
createSession: async (intent) => {
|
|
936
|
-
const { session_id } = await createSession(intent);
|
|
937
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
938
|
-
get().registerCreatedSession({
|
|
939
|
-
id: session_id,
|
|
940
|
-
intent: intent ?? "",
|
|
941
|
-
status: "created",
|
|
942
|
-
created_at: now,
|
|
943
|
-
updated_at: now
|
|
944
|
-
});
|
|
945
|
-
get().setActiveSession(session_id);
|
|
946
|
-
invalidateHomeSidebarSessions();
|
|
947
|
-
get().fetchSessions().catch(() => {
|
|
948
|
-
});
|
|
949
|
-
return session_id;
|
|
950
|
-
},
|
|
951
|
-
registerCreatedSession: (session, mode = DEFAULT_SESSION_MODE) => {
|
|
952
|
-
registerCreatedSessionState(set, session, mode);
|
|
953
|
-
},
|
|
954
|
-
upsertSession: (session) => {
|
|
955
|
-
set((state) => ({
|
|
956
|
-
sessions: state.sessions.some((item) => item.id === session.id) ? state.sessions.map((item) => item.id === session.id ? { ...item, ...session } : item) : [session, ...state.sessions]
|
|
957
|
-
}));
|
|
958
|
-
},
|
|
959
|
-
isFreshSession: (sessionId) => get()._freshSessions.has(sessionId),
|
|
960
|
-
setActiveSession: (id) => {
|
|
961
|
-
set({ activeSessionId: id });
|
|
962
|
-
onSessionChange?.(id);
|
|
963
|
-
getSession(id).then((detail) => {
|
|
964
|
-
set((state) => ({
|
|
965
|
-
sessions: state.sessions.some((s) => s.id === id) ? state.sessions.map(
|
|
966
|
-
(s) => s.id === id ? { ...s, status: detail.status, updated_at: detail.updated_at } : s
|
|
967
|
-
) : [detail, ...state.sessions]
|
|
968
|
-
}));
|
|
969
|
-
}).catch(() => {
|
|
970
|
-
});
|
|
971
|
-
const tasksPromise = getSessionTasks(id).catch(() => null);
|
|
972
|
-
Promise.all([getSessionTurns(id), tasksPromise]).then(([turns, tasks]) => {
|
|
973
|
-
if (tasks) useTaskStore.getState().setTasks(id, tasks);
|
|
974
|
-
useChatStore.getState().setAskAnswers(id, extractAskAnswers(turns));
|
|
975
|
-
let inferredMode = DEFAULT_SESSION_MODE;
|
|
976
|
-
for (const turn of turns) {
|
|
977
|
-
const nextMode = extractModeFromBlocks2(turn.blocks);
|
|
978
|
-
if (nextMode) {
|
|
979
|
-
inferredMode = nextMode;
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
set((state) => {
|
|
983
|
-
if (state.modes[id] == null) {
|
|
984
|
-
return { modes: { ...state.modes, [id]: inferredMode } };
|
|
985
|
-
}
|
|
986
|
-
return state;
|
|
987
|
-
});
|
|
988
|
-
const isFresh = get()._freshSessions.has(id);
|
|
989
|
-
if (isFresh) {
|
|
990
|
-
set((state) => {
|
|
991
|
-
const next = new Set(state._freshSessions);
|
|
992
|
-
next.delete(id);
|
|
993
|
-
return { _freshSessions: next };
|
|
994
|
-
});
|
|
995
|
-
if (turns.length > 0) {
|
|
996
|
-
useChatStore.getState().setTurns(id, turns);
|
|
997
|
-
}
|
|
998
|
-
} else {
|
|
999
|
-
useChatStore.getState().setTurns(id, turns);
|
|
1000
|
-
}
|
|
1001
|
-
}).catch((error) => {
|
|
1002
|
-
if (isSessionAccessRevoked(error)) {
|
|
1003
|
-
handleUnreadableSession(set, get, id);
|
|
1004
|
-
return;
|
|
1005
|
-
}
|
|
1006
|
-
console.error("Failed to load session data", error);
|
|
1007
|
-
});
|
|
1008
|
-
},
|
|
1009
|
-
clearActiveSession: () => {
|
|
1010
|
-
set({ activeSessionId: null });
|
|
1011
|
-
onSessionChange?.(null);
|
|
1012
|
-
},
|
|
1013
|
-
deleteSession: async (id) => {
|
|
1014
|
-
await deleteSession(id);
|
|
1015
|
-
invalidateHomeSidebarSessions();
|
|
1016
|
-
const wasActive = get().activeSessionId === id;
|
|
1017
|
-
await get().fetchSessions();
|
|
1018
|
-
if (!wasActive) {
|
|
1019
|
-
return;
|
|
1020
|
-
}
|
|
1021
|
-
const nextId = get().sessions[0]?.id ?? null;
|
|
1022
|
-
if (nextId) {
|
|
1023
|
-
get().setActiveSession(nextId);
|
|
1024
|
-
return;
|
|
1025
|
-
}
|
|
1026
|
-
get().clearActiveSession();
|
|
1027
|
-
},
|
|
1028
|
-
updateSessionStatus: (sessionId, status) => {
|
|
1029
|
-
set((state) => ({
|
|
1030
|
-
sessions: state.sessions.map((s) => s.id === sessionId ? { ...s, status } : s)
|
|
1031
|
-
}));
|
|
1032
|
-
if (status === "failed" || status === "interrupted") {
|
|
1033
|
-
useChatStore.getState().setStreaming(sessionId, false);
|
|
1034
|
-
if (status === "interrupted") {
|
|
1035
|
-
useChatStore.getState().markInterrupted(sessionId);
|
|
1036
|
-
} else {
|
|
1037
|
-
useChatStore.getState().markFailed(sessionId);
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
},
|
|
1041
|
-
updateSessionIntent: (sessionId, intent) => {
|
|
1042
|
-
set((state) => ({
|
|
1043
|
-
sessions: state.sessions.map((s) => s.id === sessionId ? { ...s, intent } : s)
|
|
1044
|
-
}));
|
|
1045
|
-
},
|
|
1046
|
-
patchSession: (sessionId, patch) => {
|
|
1047
|
-
set((state) => ({
|
|
1048
|
-
sessions: state.sessions.map(
|
|
1049
|
-
(s) => s.id === sessionId ? { ...s, ...patch } : s
|
|
1050
|
-
)
|
|
1051
|
-
}));
|
|
1052
|
-
},
|
|
1053
|
-
pinSession: async (sessionId, pinned) => {
|
|
1054
|
-
const updated = await pinSession(sessionId, pinned);
|
|
1055
|
-
set((state) => ({
|
|
1056
|
-
sessions: state.sessions.map(
|
|
1057
|
-
(s) => s.id === sessionId ? { ...s, is_pinned: updated.is_pinned, pinned_at: updated.pinned_at } : s
|
|
1058
|
-
)
|
|
1059
|
-
}));
|
|
1060
|
-
invalidateHomeSidebarSessions();
|
|
1061
|
-
},
|
|
1062
|
-
setRewindDraft: (sessionId, text) => {
|
|
1063
|
-
set((state) => {
|
|
1064
|
-
if (text == null) {
|
|
1065
|
-
const { [sessionId]: _, ...rest } = state.rewindDrafts;
|
|
1066
|
-
return { rewindDrafts: rest };
|
|
1067
|
-
}
|
|
1068
|
-
return {
|
|
1069
|
-
rewindDrafts: {
|
|
1070
|
-
...state.rewindDrafts,
|
|
1071
|
-
[sessionId]: text
|
|
1072
|
-
}
|
|
1073
|
-
};
|
|
1074
|
-
});
|
|
1075
|
-
},
|
|
1076
|
-
setMode: (sessionId, mode) => {
|
|
1077
|
-
set((state) => ({ modes: { ...state.modes, [sessionId]: mode } }));
|
|
1078
|
-
},
|
|
1079
|
-
togglePlanningMode: (sessionId) => {
|
|
1080
|
-
const current = get().modes[sessionId] ?? DEFAULT_SESSION_MODE;
|
|
1081
|
-
const next = current === "executing" ? "planning" : "executing";
|
|
1082
|
-
set((state) => ({ modes: { ...state.modes, [sessionId]: next } }));
|
|
1083
|
-
},
|
|
1084
|
-
toggleSharing: async (sessionId) => {
|
|
1085
|
-
const session = get().sessions.find((s) => s.id === sessionId);
|
|
1086
|
-
if (!session) return;
|
|
1087
|
-
const newShared = !session.shared;
|
|
1088
|
-
const result = await updateSharing(sessionId, newShared);
|
|
1089
|
-
set((state) => ({
|
|
1090
|
-
sessions: state.sessions.map(
|
|
1091
|
-
(s) => s.id === sessionId ? { ...s, shared: result.shared } : s
|
|
1092
|
-
)
|
|
1093
|
-
}));
|
|
1094
|
-
},
|
|
1095
|
-
reset: () => {
|
|
1096
|
-
set({
|
|
1097
|
-
sessions: [],
|
|
1098
|
-
activeSessionId: null,
|
|
1099
|
-
loading: false,
|
|
1100
|
-
modes: {},
|
|
1101
|
-
rewindDrafts: {},
|
|
1102
|
-
_freshSessions: /* @__PURE__ */ new Set()
|
|
1103
|
-
});
|
|
1104
|
-
invalidateHomeSidebarSessions();
|
|
1105
|
-
}
|
|
1106
|
-
}));
|
|
1107
|
-
setChatStoreSessionAccessor(() => useSessionStore.getState().activeSessionId);
|
|
1108
|
-
|
|
1109
|
-
// src/react/stores/auth-store.ts
|
|
1110
|
-
var noopStorage = {
|
|
1111
|
-
getItem: () => null,
|
|
1112
|
-
setItem: () => {
|
|
1113
|
-
},
|
|
1114
|
-
removeItem: () => {
|
|
1115
|
-
}
|
|
1116
|
-
};
|
|
1117
|
-
function shouldClearPersistedAuthState(value) {
|
|
1118
|
-
try {
|
|
1119
|
-
const parsed = JSON.parse(value);
|
|
1120
|
-
return parsed.state?.token == null && parsed.state?.user == null;
|
|
1121
|
-
} catch {
|
|
1122
|
-
return false;
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
var authStorage = createJSONStorage(() => {
|
|
1126
|
-
if (typeof localStorage === "undefined") {
|
|
1127
|
-
return noopStorage;
|
|
1128
|
-
}
|
|
1129
|
-
return {
|
|
1130
|
-
getItem: (name) => localStorage.getItem(name),
|
|
1131
|
-
setItem: (name, value) => {
|
|
1132
|
-
if (shouldClearPersistedAuthState(value)) {
|
|
1133
|
-
localStorage.removeItem(name);
|
|
1134
|
-
return;
|
|
1135
|
-
}
|
|
1136
|
-
localStorage.setItem(name, value);
|
|
1137
|
-
},
|
|
1138
|
-
removeItem: (name) => localStorage.removeItem(name)
|
|
1139
|
-
};
|
|
1140
|
-
});
|
|
1141
|
-
function finishAuth(set, payload) {
|
|
1142
|
-
set({
|
|
1143
|
-
token: payload.token,
|
|
1144
|
-
socketAuthToken: null,
|
|
1145
|
-
user: payload.user,
|
|
1146
|
-
loading: false,
|
|
1147
|
-
error: null
|
|
1148
|
-
});
|
|
1149
|
-
agentSocket?.reconnect();
|
|
1150
|
-
useSessionStore.getState().fetchSessions().catch(() => {
|
|
1151
|
-
});
|
|
1152
|
-
}
|
|
1153
|
-
function finishCookieHydration(set, payload) {
|
|
1154
|
-
set({
|
|
1155
|
-
token: null,
|
|
1156
|
-
socketAuthToken: payload.token,
|
|
1157
|
-
user: payload.user,
|
|
1158
|
-
loading: false,
|
|
1159
|
-
error: null
|
|
1160
|
-
});
|
|
1161
|
-
agentSocket?.reconnect();
|
|
1162
|
-
useSessionStore.getState().fetchSessions().catch(() => {
|
|
1163
|
-
});
|
|
1164
|
-
}
|
|
1165
|
-
function toUser(info) {
|
|
1166
|
-
return {
|
|
1167
|
-
id: info.id,
|
|
1168
|
-
username: info.username,
|
|
1169
|
-
display_name: info.display_name,
|
|
1170
|
-
avatar_url: info.avatar_url,
|
|
1171
|
-
is_admin: info.is_admin
|
|
1172
|
-
};
|
|
1173
|
-
}
|
|
1174
|
-
var useAuthStore = create6()(
|
|
1175
|
-
persist(
|
|
1176
|
-
(set, get) => ({
|
|
1177
|
-
...createClientActions(set),
|
|
1178
|
-
token: null,
|
|
1179
|
-
socketAuthToken: null,
|
|
1180
|
-
user: null,
|
|
1181
|
-
loading: false,
|
|
1182
|
-
error: null,
|
|
1183
|
-
logout: () => {
|
|
1184
|
-
void logout().catch(() => {
|
|
1185
|
-
});
|
|
1186
|
-
set({ token: null, socketAuthToken: null, user: null, error: null });
|
|
1187
|
-
agentSocket?.disconnect();
|
|
1188
|
-
useSessionStore.getState().reset();
|
|
1189
|
-
},
|
|
1190
|
-
checkAuth: async () => {
|
|
1191
|
-
const token = get().token;
|
|
1192
|
-
if (!token) return;
|
|
1193
|
-
try {
|
|
1194
|
-
const auth = await getMe();
|
|
1195
|
-
finishAuth(set, { token: auth.token, user: toUser(auth) });
|
|
1196
|
-
} catch {
|
|
1197
|
-
set({ token: null, socketAuthToken: null, user: null, error: null });
|
|
1198
|
-
useSessionStore.getState().reset();
|
|
1199
|
-
}
|
|
1200
|
-
},
|
|
1201
|
-
hydrateFromCookie: async () => {
|
|
1202
|
-
set({ loading: true, error: null });
|
|
1203
|
-
const previousToken = get().token;
|
|
1204
|
-
if (previousToken) {
|
|
1205
|
-
try {
|
|
1206
|
-
const auth = await getMe();
|
|
1207
|
-
finishAuth(set, { token: auth.token, user: toUser(auth) });
|
|
1208
|
-
return;
|
|
1209
|
-
} catch {
|
|
1210
|
-
set({ token: null, socketAuthToken: null, user: null, error: null });
|
|
1211
|
-
useSessionStore.getState().reset();
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
try {
|
|
1215
|
-
const auth = await getMe();
|
|
1216
|
-
finishCookieHydration(set, { token: auth.token, user: toUser(auth) });
|
|
1217
|
-
} catch {
|
|
1218
|
-
set({
|
|
1219
|
-
token: null,
|
|
1220
|
-
socketAuthToken: null,
|
|
1221
|
-
user: null,
|
|
1222
|
-
loading: false,
|
|
1223
|
-
error: null
|
|
1224
|
-
});
|
|
1225
|
-
useSessionStore.getState().reset();
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
}),
|
|
1229
|
-
{
|
|
1230
|
-
name: "agent-auth",
|
|
1231
|
-
storage: authStorage,
|
|
1232
|
-
partialize: (state) => {
|
|
1233
|
-
if (state.socketAuthToken) {
|
|
1234
|
-
return { token: null, user: null };
|
|
1235
|
-
}
|
|
1236
|
-
return { token: state.token, user: state.user };
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
)
|
|
1240
|
-
);
|
|
1241
|
-
|
|
1242
|
-
// src/react/stores/background-store.ts
|
|
1243
|
-
import { create as create7 } from "zustand";
|
|
1244
|
-
var useBackgroundStore = create7()((set) => ({
|
|
1245
|
-
...createClientActions(set),
|
|
1246
|
-
tasks: {},
|
|
1247
|
-
selectedTaskId: {},
|
|
1248
|
-
setTasks: (sessionId, tasks) => set((state) => ({
|
|
1249
|
-
tasks: { ...state.tasks, [sessionId]: tasks },
|
|
1250
|
-
selectedTaskId: {
|
|
1251
|
-
...state.selectedTaskId,
|
|
1252
|
-
[sessionId]: state.selectedTaskId[sessionId] ?? tasks[0]?.id ?? null
|
|
1253
|
-
}
|
|
1254
|
-
})),
|
|
1255
|
-
upsertTask: (sessionId, task) => set((state) => {
|
|
1256
|
-
const existing = state.tasks[sessionId] ?? [];
|
|
1257
|
-
const index = existing.findIndex((item) => item.id === task.id);
|
|
1258
|
-
const next = [...existing];
|
|
1259
|
-
if (index >= 0) {
|
|
1260
|
-
next[index] = { ...next[index], ...task };
|
|
1261
|
-
} else {
|
|
1262
|
-
next.unshift(task);
|
|
1263
|
-
}
|
|
1264
|
-
return {
|
|
1265
|
-
tasks: { ...state.tasks, [sessionId]: next },
|
|
1266
|
-
selectedTaskId: {
|
|
1267
|
-
...state.selectedTaskId,
|
|
1268
|
-
[sessionId]: state.selectedTaskId[sessionId] ?? task.id
|
|
1269
|
-
}
|
|
1270
|
-
};
|
|
1271
|
-
}),
|
|
1272
|
-
selectTask: (sessionId, taskId) => set((state) => ({
|
|
1273
|
-
selectedTaskId: { ...state.selectedTaskId, [sessionId]: taskId }
|
|
1274
|
-
}))
|
|
1275
|
-
}));
|
|
1276
|
-
|
|
1277
|
-
// src/react/stores/card-state-store.ts
|
|
1278
|
-
import { create as create8 } from "zustand";
|
|
1279
|
-
var useCardStateStore = create8((set, get) => ({
|
|
1280
|
-
...createClientActions(set),
|
|
1281
|
-
states: {},
|
|
1282
|
-
getCardState: (cardId) => {
|
|
1283
|
-
return get().states[cardId];
|
|
1284
|
-
},
|
|
1285
|
-
setCardState: (cardId, state) => {
|
|
1286
|
-
set((prev) => ({
|
|
1287
|
-
states: { ...prev.states, [cardId]: state }
|
|
1288
|
-
}));
|
|
1289
|
-
},
|
|
1290
|
-
removeCardState: (cardId) => {
|
|
1291
|
-
set((prev) => {
|
|
1292
|
-
const { [cardId]: _, ...rest } = prev.states;
|
|
1293
|
-
return { states: rest };
|
|
1294
|
-
});
|
|
1295
|
-
},
|
|
1296
|
-
clearAllStates: () => {
|
|
1297
|
-
set({ states: {} });
|
|
1298
|
-
}
|
|
1299
|
-
}));
|
|
1300
|
-
|
|
1301
|
-
// src/react/stores/connection-store.ts
|
|
1302
|
-
import { create as create9 } from "zustand";
|
|
1303
|
-
var initialConnectionState = {
|
|
1304
|
-
status: "disconnected",
|
|
1305
|
-
reconnectAttempt: 0,
|
|
1306
|
-
lastConnectedAt: null,
|
|
1307
|
-
lastDisconnectedAt: null,
|
|
1308
|
-
hasEverConnected: false
|
|
1309
|
-
};
|
|
1310
|
-
var useConnectionStore = create9()((set) => ({
|
|
1311
|
-
...createClientActions(set),
|
|
1312
|
-
...initialConnectionState,
|
|
1313
|
-
markConnecting: (attempt = 0) => set({
|
|
1314
|
-
status: "connecting",
|
|
1315
|
-
reconnectAttempt: attempt
|
|
1316
|
-
}),
|
|
1317
|
-
markConnected: () => set({
|
|
1318
|
-
status: "connected",
|
|
1319
|
-
reconnectAttempt: 0,
|
|
1320
|
-
lastConnectedAt: Date.now(),
|
|
1321
|
-
hasEverConnected: true
|
|
1322
|
-
}),
|
|
1323
|
-
markDisconnected: () => set({
|
|
1324
|
-
status: "disconnected",
|
|
1325
|
-
reconnectAttempt: 0,
|
|
1326
|
-
lastDisconnectedAt: Date.now()
|
|
1327
|
-
}),
|
|
1328
|
-
reset: () => set(initialConnectionState)
|
|
1329
|
-
}));
|
|
1330
|
-
|
|
1331
|
-
// src/react/stores/runtime-store.ts
|
|
1332
|
-
import { create as create10 } from "zustand";
|
|
1333
|
-
var useRuntimeStore = create10()((set) => ({
|
|
1334
|
-
...createClientActions(set),
|
|
1335
|
-
events: {},
|
|
1336
|
-
addEvent: (sessionId, event) => set((state) => {
|
|
1337
|
-
const current = state.events[sessionId] ?? [];
|
|
1338
|
-
const nextEvent = {
|
|
1339
|
-
...event,
|
|
1340
|
-
id: `${Date.now()}-${current.length}`,
|
|
1341
|
-
sessionId,
|
|
1342
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1343
|
-
};
|
|
1344
|
-
return {
|
|
1345
|
-
events: {
|
|
1346
|
-
...state.events,
|
|
1347
|
-
[sessionId]: [...current.slice(-59), nextEvent]
|
|
1348
|
-
}
|
|
1349
|
-
};
|
|
1350
|
-
}),
|
|
1351
|
-
clearSession: (sessionId) => set((state) => ({
|
|
1352
|
-
events: { ...state.events, [sessionId]: [] }
|
|
1353
|
-
}))
|
|
1354
|
-
}));
|
|
1355
|
-
|
|
1356
|
-
// src/react/stores/gis-store.ts
|
|
1357
|
-
import { create as create11 } from "zustand";
|
|
1358
|
-
var EMPTY_GOALS = [];
|
|
1359
|
-
var EMPTY_RESOURCES = [];
|
|
1360
|
-
var EMPTY_TARGETS = [];
|
|
1361
|
-
var EMPTY_COMMANDS = [];
|
|
1362
|
-
function newCommandId() {
|
|
1363
|
-
if (typeof globalThis !== "undefined" && "crypto" in globalThis) {
|
|
1364
|
-
return globalThis.crypto?.randomUUID?.() ?? `gis-map-${Date.now()}-${Math.random()}`;
|
|
1365
|
-
}
|
|
1366
|
-
return `gis-map-${Date.now()}-${Math.random()}`;
|
|
1367
|
-
}
|
|
1368
|
-
var useGisStore = create11()((set, get) => ({
|
|
1369
|
-
...createClientActions(set),
|
|
1370
|
-
goalsBySession: {},
|
|
1371
|
-
resourcesBySession: {},
|
|
1372
|
-
targetsBySession: {},
|
|
1373
|
-
pendingMapCommandsBySession: {},
|
|
1374
|
-
setGoals: (sessionId, goals) => {
|
|
1375
|
-
set((state) => ({
|
|
1376
|
-
goalsBySession: { ...state.goalsBySession, [sessionId]: goals }
|
|
1377
|
-
}));
|
|
1378
|
-
},
|
|
1379
|
-
setResources: (sessionId, resources) => {
|
|
1380
|
-
set((state) => ({
|
|
1381
|
-
resourcesBySession: { ...state.resourcesBySession, [sessionId]: resources }
|
|
1382
|
-
}));
|
|
1383
|
-
},
|
|
1384
|
-
setTargets: (sessionId, targets) => {
|
|
1385
|
-
set((state) => ({
|
|
1386
|
-
targetsBySession: { ...state.targetsBySession, [sessionId]: targets }
|
|
1387
|
-
}));
|
|
1388
|
-
},
|
|
1389
|
-
pushMapCommand: (sessionId, command) => {
|
|
1390
|
-
set((state) => ({
|
|
1391
|
-
pendingMapCommandsBySession: {
|
|
1392
|
-
...state.pendingMapCommandsBySession,
|
|
1393
|
-
[sessionId]: [
|
|
1394
|
-
...state.pendingMapCommandsBySession[sessionId] ?? EMPTY_COMMANDS,
|
|
1395
|
-
{
|
|
1396
|
-
...command,
|
|
1397
|
-
id: newCommandId(),
|
|
1398
|
-
createdAt: Date.now()
|
|
1399
|
-
}
|
|
1400
|
-
]
|
|
1401
|
-
}
|
|
1402
|
-
}));
|
|
1403
|
-
},
|
|
1404
|
-
consumeMapCommand: (sessionId, commandId) => {
|
|
1405
|
-
set((state) => ({
|
|
1406
|
-
pendingMapCommandsBySession: {
|
|
1407
|
-
...state.pendingMapCommandsBySession,
|
|
1408
|
-
[sessionId]: (state.pendingMapCommandsBySession[sessionId] ?? EMPTY_COMMANDS).filter(
|
|
1409
|
-
(command) => command.id !== commandId
|
|
1410
|
-
)
|
|
1411
|
-
}
|
|
1412
|
-
}));
|
|
1413
|
-
},
|
|
1414
|
-
getGoals: (sessionId) => get().goalsBySession[sessionId] ?? EMPTY_GOALS,
|
|
1415
|
-
getResources: (sessionId) => get().resourcesBySession[sessionId] ?? EMPTY_RESOURCES,
|
|
1416
|
-
getTargets: (sessionId) => get().targetsBySession[sessionId] ?? EMPTY_TARGETS,
|
|
1417
|
-
getPendingMapCommands: (sessionId) => get().pendingMapCommandsBySession[sessionId] ?? EMPTY_COMMANDS
|
|
1418
|
-
}));
|
|
1419
|
-
|
|
1420
|
-
// src/react/stores/answer-callback-store.ts
|
|
1421
|
-
import { create as create12 } from "zustand";
|
|
1422
|
-
var useAnswerCallbackStore = create12()((set) => ({
|
|
1423
|
-
...createClientActions(set),
|
|
1424
|
-
callbacks: {},
|
|
1425
|
-
setAnswerCallback: (sessionId, callback) => {
|
|
1426
|
-
set((state) => ({
|
|
1427
|
-
callbacks: {
|
|
1428
|
-
...state.callbacks,
|
|
1429
|
-
[sessionId]: callback
|
|
1430
|
-
}
|
|
1431
|
-
}));
|
|
1432
|
-
}
|
|
1433
|
-
}));
|
|
1434
|
-
|
|
1435
|
-
// src/react/stores/runtime-features-store.ts
|
|
1436
|
-
import { create as create13 } from "zustand";
|
|
1437
|
-
var useRuntimeFeaturesStore = create13((set) => ({
|
|
1438
|
-
...createClientActions(set),
|
|
1439
|
-
asrEnabled: false,
|
|
1440
|
-
asrProvider: "volcengine",
|
|
1441
|
-
publicSharingEnabled: false,
|
|
1442
|
-
memoryEnabled: false,
|
|
1443
|
-
setFeatures: (features) => set((prev) => ({
|
|
1444
|
-
asrEnabled: features.asrEnabled ?? prev.asrEnabled,
|
|
1445
|
-
asrProvider: features.asrProvider ?? prev.asrProvider,
|
|
1446
|
-
publicSharingEnabled: features.publicSharingEnabled ?? prev.publicSharingEnabled,
|
|
1447
|
-
memoryEnabled: features.memoryEnabled ?? prev.memoryEnabled
|
|
1448
|
-
}))
|
|
1449
|
-
}));
|
|
1450
|
-
|
|
1451
|
-
// src/react/bootstrap.ts
|
|
1452
|
-
var bootstrappedClient = null;
|
|
1453
|
-
function getBootstrappedClient() {
|
|
1454
|
-
if (!bootstrappedClient) {
|
|
1455
|
-
throw new Error("bootstrapBladeClient() must be called before any SDK usage");
|
|
1456
|
-
}
|
|
1457
|
-
return bootstrappedClient;
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
// src/react/api/client.ts
|
|
1461
|
-
function getClient() {
|
|
1462
|
-
return getBootstrappedClient();
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
// src/react/api/licenses.ts
|
|
1466
|
-
var r3 = () => getClient().licenses;
|
|
1467
|
-
var getDeviceUuid = (...args) => r3().getDeviceUuid(...args);
|
|
1468
|
-
var validateLicense = (...args) => r3().validateLicense(...args);
|
|
1469
|
-
var getLicenseStatus = (...args) => r3().getLicenseStatus(...args);
|
|
1470
|
-
var uploadLicense = (...args) => r3().uploadLicense(...args);
|
|
1
|
+
import {
|
|
2
|
+
getDeviceUuid,
|
|
3
|
+
getLicenseStatus,
|
|
4
|
+
uploadLicense,
|
|
5
|
+
validateLicense
|
|
6
|
+
} from "../../chunk-TC5BBLWO.js";
|
|
7
|
+
import "../../chunk-4VWLTG5L.js";
|
|
8
|
+
import "../../chunk-J3XVFPOV.js";
|
|
9
|
+
import "../../chunk-OKQWPNE3.js";
|
|
10
|
+
import "../../chunk-JCJFFJ42.js";
|
|
11
|
+
import "../../chunk-PZ5AY32C.js";
|
|
1471
12
|
export {
|
|
1472
13
|
getDeviceUuid,
|
|
1473
14
|
getLicenseStatus,
|