@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.
Files changed (52) hide show
  1. package/README.md +39 -1
  2. package/dist/{SkillStatusBar-DItrW2vv.d.ts → SkillStatusBar-DQyipdzn.d.ts} +112 -8
  3. package/dist/chunk-2UP7MG3J.js +66 -0
  4. package/dist/chunk-2UP7MG3J.js.map +1 -0
  5. package/dist/chunk-4VWLTG5L.js +2984 -0
  6. package/dist/chunk-4VWLTG5L.js.map +1 -0
  7. package/dist/chunk-7LEKQI47.js +32 -0
  8. package/dist/chunk-7LEKQI47.js.map +1 -0
  9. package/dist/chunk-CGOQI7ZL.js +8124 -0
  10. package/dist/chunk-CGOQI7ZL.js.map +1 -0
  11. package/dist/chunk-DQCXSPHP.js +33 -0
  12. package/dist/chunk-DQCXSPHP.js.map +1 -0
  13. package/dist/chunk-I3FFV63W.js +30 -0
  14. package/dist/chunk-I3FFV63W.js.map +1 -0
  15. package/dist/chunk-J3XVFPOV.js +58 -0
  16. package/dist/chunk-J3XVFPOV.js.map +1 -0
  17. package/dist/chunk-JCJFFJ42.js +39 -0
  18. package/dist/chunk-JCJFFJ42.js.map +1 -0
  19. package/dist/chunk-OKQWPNE3.js +1077 -0
  20. package/dist/chunk-OKQWPNE3.js.map +1 -0
  21. package/dist/chunk-PZ5AY32C.js +10 -0
  22. package/dist/chunk-PZ5AY32C.js.map +1 -0
  23. package/dist/chunk-TC5BBLWO.js +29 -0
  24. package/dist/chunk-TC5BBLWO.js.map +1 -0
  25. package/dist/chunk-VD4CKRMT.js +127 -0
  26. package/dist/chunk-VD4CKRMT.js.map +1 -0
  27. package/dist/chunk-X6MEYCU7.js +1401 -0
  28. package/dist/chunk-X6MEYCU7.js.map +1 -0
  29. package/dist/client/index.js +24 -1052
  30. package/dist/client/index.js.map +1 -1
  31. package/dist/react/api/licenses.js +11 -1470
  32. package/dist/react/api/licenses.js.map +1 -1
  33. package/dist/react/api/vibe-coding.js +25 -1481
  34. package/dist/react/api/vibe-coding.js.map +1 -1
  35. package/dist/react/cards/register.js +45 -138
  36. package/dist/react/cards/register.js.map +1 -1
  37. package/dist/react/components/chat/index.d.ts +7 -21
  38. package/dist/react/components/chat/index.js +28 -11366
  39. package/dist/react/components/chat/index.js.map +1 -1
  40. package/dist/react/components/plan/index.js +135 -3054
  41. package/dist/react/components/plan/index.js.map +1 -1
  42. package/dist/react/components/session/index.js +21 -1499
  43. package/dist/react/components/session/index.js.map +1 -1
  44. package/dist/react/components/workspace/index.js +116 -1715
  45. package/dist/react/components/workspace/index.js.map +1 -1
  46. package/dist/react/devtools/bridge-devtools/index.js +8 -51
  47. package/dist/react/devtools/bridge-devtools/index.js.map +1 -1
  48. package/dist/react/index.d.ts +2 -2
  49. package/dist/react/index.js +625 -14035
  50. package/dist/react/index.js.map +1 -1
  51. package/dist/style.css +1 -1
  52. package/package.json +1 -1
@@ -1,1475 +1,19 @@
1
- // src/client/resources/models.ts
2
- import { type } from "arktype";
3
- var ModelOption = type({
4
- id: "string",
5
- label: "string"
6
- });
7
- var ModelsConfig = type({
8
- default: "string",
9
- models: ModelOption.array()
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/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 r3 = Math.min(5, Math.abs(toX - fromX), Math.abs(toY - fromY));
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 * r3}`,
1844
- `A ${r3} ${r3} 0 0 ${dx > 0 ? 1 : 0} ${toX} ${fromY + r3}`,
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: createSession2, activeSessionId } = useSession();
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 createSession2();
629
+ const sessionId = await createSession();
2108
630
  onSessionCreated?.(sessionId);
2109
631
  onSessionSelect(sessionId);
2110
632
  } catch (err) {