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