@nextclaw/ui 0.6.10 → 0.6.11
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/.eslintrc.cjs +10 -0
- package/CHANGELOG.md +9 -0
- package/dist/assets/{ChannelsList-TyMb5Mgz.js → ChannelsList-C49JQ-Zt.js} +1 -1
- package/dist/assets/ChatPage-DIx05c6s.js +36 -0
- package/dist/assets/{DocBrowser-CNtrA0ps.js → DocBrowser-CpOosDEI.js} +1 -1
- package/dist/assets/{LogoBadge-BLqiOM5D.js → LogoBadge-CL_8ZPXU.js} +1 -1
- package/dist/assets/MarketplacePage-BOzko5s9.js +49 -0
- package/dist/assets/{ModelConfig-CCsQ8KFq.js → ModelConfig-BZ4ZfaQB.js} +1 -1
- package/dist/assets/ProvidersList-fPpJ5gl6.js +1 -0
- package/dist/assets/{RuntimeConfig-BO6s-ls-.js → RuntimeConfig-Dt9pLB9P.js} +1 -1
- package/dist/assets/{SecretsConfig-mayFdxpM.js → SecretsConfig-C1PU0Yy8.js} +2 -2
- package/dist/assets/{SessionsConfig-DAIczdBj.js → SessionsConfig-EskBOofQ.js} +2 -2
- package/dist/assets/{card-BP5YnL-G.js → card-C7Gtw2Vs.js} +1 -1
- package/dist/assets/index-Cn6_2To7.js +8 -0
- package/dist/assets/{index-BUiahmWm.css → index-nEYGCJTC.css} +1 -1
- package/dist/assets/{input-B1D2QX0O.js → input-oBvxsnV9.js} +1 -1
- package/dist/assets/{label-DW0j-fXA.js → label-C7F8lMpQ.js} +1 -1
- package/dist/assets/{page-layout-Ch-H9gD-.js → page-layout-DO8BlScF.js} +1 -1
- package/dist/assets/session-run-status-Kg0FwAPn.js +3 -0
- package/dist/assets/{switch-_cZHlGKB.js → switch-C6a5GyZB.js} +1 -1
- package/dist/assets/{tabs-custom-ARxqYYjG.js → tabs-custom-BatFap5k.js} +1 -1
- package/dist/assets/{useConfirmDialog-BaU7nIat.js → useConfirmDialog-zJzVKMdu.js} +2 -2
- package/dist/assets/{vendor-C--HHaLf.js → vendor-TlME1INH.js} +84 -84
- package/dist/index.html +3 -3
- package/package.json +4 -2
- package/src/App.tsx +1 -2
- package/src/api/config.ts +199 -200
- package/src/api/types.ts +36 -24
- package/src/components/chat/ChatConversationPanel.tsx +102 -121
- package/src/components/chat/ChatPage.tsx +165 -437
- package/src/components/chat/ChatSidebar.tsx +30 -36
- package/src/components/chat/ChatThread.tsx +73 -131
- package/src/components/chat/chat-input/ChatInputBarView.tsx +82 -0
- package/src/components/chat/chat-input/ChatInputBottomToolbar.tsx +71 -0
- package/src/components/chat/chat-input/components/ChatInputModelStateHint.tsx +39 -0
- package/src/components/chat/chat-input/components/ChatInputSelectedSkillsSection.tsx +31 -0
- package/src/components/chat/chat-input/components/ChatInputSlashPanelSection.tsx +112 -0
- package/src/components/chat/chat-input/components/bottom-toolbar/ChatInputAttachButton.tsx +24 -0
- package/src/components/chat/chat-input/components/bottom-toolbar/ChatInputModelSelector.tsx +58 -0
- package/src/components/chat/chat-input/components/bottom-toolbar/ChatInputSendControls.tsx +56 -0
- package/src/components/chat/chat-input/components/bottom-toolbar/ChatInputSessionTypeSelector.tsx +40 -0
- package/src/components/chat/chat-input/useChatInputBarController.ts +313 -0
- package/src/components/chat/chat-input.types.ts +15 -0
- package/src/components/chat/chat-page-data.ts +121 -0
- package/src/components/chat/chat-page-runtime.ts +221 -0
- package/src/components/chat/chat-session-route.ts +59 -0
- package/src/components/chat/chat-stream/nextbot-parsers.ts +52 -0
- package/src/components/chat/chat-stream/nextbot-runtime-agent.ts +413 -0
- package/src/components/chat/chat-stream/stream-event-adapter.ts +98 -0
- package/src/components/chat/chat-stream/transport.ts +159 -0
- package/src/components/chat/chat-stream/types.ts +76 -0
- package/src/components/chat/managers/chat-input.manager.ts +142 -0
- package/src/components/chat/managers/chat-run-status.manager.ts +32 -0
- package/src/components/chat/managers/chat-session-list.manager.ts +77 -0
- package/src/components/chat/managers/chat-stream-actions.manager.ts +34 -0
- package/src/components/chat/managers/chat-thread.manager.ts +86 -0
- package/src/components/chat/managers/chat-ui.manager.ts +65 -0
- package/src/components/chat/presenter/chat-presenter-context.tsx +25 -0
- package/src/components/chat/presenter/chat.presenter.ts +32 -0
- package/src/components/chat/stores/chat-input.store.ts +62 -0
- package/src/components/chat/stores/chat-run-status.store.ts +30 -0
- package/src/components/chat/stores/chat-session-list.store.ts +34 -0
- package/src/components/chat/stores/chat-thread.store.ts +52 -0
- package/src/components/chat/useChatRuntimeController.ts +134 -0
- package/src/components/chat/useChatSessionTypeState.ts +148 -0
- package/src/components/common/MaskedInput.tsx +1 -1
- package/src/hooks/useConfig.ts +31 -1
- package/src/hooks/useObservable.ts +20 -0
- package/src/lib/chat-message.ts +2 -202
- package/src/lib/chat-runtime-utils.ts +250 -0
- package/src/lib/i18n.ts +9 -0
- package/tsconfig.json +2 -1
- package/vite.config.ts +2 -1
- package/dist/assets/ChatPage-CQerYqvy.js +0 -34
- package/dist/assets/MarketplacePage-CotZxxNe.js +0 -49
- package/dist/assets/ProvidersList-BYYX5K_g.js +0 -1
- package/dist/assets/index-D6_5HaDl.js +0 -7
- package/dist/assets/session-run-status-BUYsQeWs.js +0 -5
- package/src/components/chat/ChatInputBar.tsx +0 -590
- package/src/components/chat/useChatStreamController.ts +0 -591
package/dist/index.html
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
8
|
<title>NextClaw - 系统配置</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-Cn6_2To7.js"></script>
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-TlME1INH.js">
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/assets/index-nEYGCJTC.css">
|
|
12
12
|
</head>
|
|
13
13
|
|
|
14
14
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ui",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.11",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,10 +24,12 @@
|
|
|
24
24
|
"react-router-dom": "^7.13.0",
|
|
25
25
|
"rehype-sanitize": "^6.0.0",
|
|
26
26
|
"remark-gfm": "^4.0.1",
|
|
27
|
+
"rxjs": "^7.8.2",
|
|
27
28
|
"sonner": "^1.7.1",
|
|
28
29
|
"tailwind-merge": "^2.5.4",
|
|
29
30
|
"zod": "^3.23.8",
|
|
30
|
-
"zustand": "^5.0.2"
|
|
31
|
+
"zustand": "^5.0.2",
|
|
32
|
+
"@nextclaw/agent-chat": "0.1.1"
|
|
31
33
|
},
|
|
32
34
|
"devDependencies": {
|
|
33
35
|
"@types/react": "^18.3.12",
|
package/src/App.tsx
CHANGED
|
@@ -41,8 +41,7 @@ function AppContent() {
|
|
|
41
41
|
<Routes>
|
|
42
42
|
<Route path="/chat/skills" element={<Navigate to="/skills" replace />} />
|
|
43
43
|
<Route path="/chat/cron" element={<Navigate to="/cron" replace />} />
|
|
44
|
-
<Route path="/chat/:sessionId" element={<LazyRoute><ChatPage view="chat" /></LazyRoute>} />
|
|
45
|
-
<Route path="/chat" element={<LazyRoute><ChatPage view="chat" /></LazyRoute>} />
|
|
44
|
+
<Route path="/chat/:sessionId?" element={<LazyRoute><ChatPage view="chat" /></LazyRoute>} />
|
|
46
45
|
<Route path="/skills" element={<LazyRoute><ChatPage view="skills" /></LazyRoute>} />
|
|
47
46
|
<Route path="/cron" element={<LazyRoute><ChatPage view="cron" /></LazyRoute>} />
|
|
48
47
|
<Route path="/model" element={<LazyRoute><ModelConfigPage /></LazyRoute>} />
|
package/src/api/config.ts
CHANGED
|
@@ -27,7 +27,12 @@ import type {
|
|
|
27
27
|
SessionPatchUpdate,
|
|
28
28
|
ChatTurnRequest,
|
|
29
29
|
ChatTurnView,
|
|
30
|
+
ChatTurnStreamDeltaEvent,
|
|
31
|
+
ChatTurnStreamErrorEvent,
|
|
32
|
+
ChatTurnStreamReadyEvent,
|
|
33
|
+
ChatTurnStreamSessionEvent,
|
|
30
34
|
ChatCapabilitiesView,
|
|
35
|
+
ChatSessionTypesView,
|
|
31
36
|
ChatTurnStopRequest,
|
|
32
37
|
ChatTurnStopResult,
|
|
33
38
|
ChatRunListView,
|
|
@@ -36,10 +41,7 @@ import type {
|
|
|
36
41
|
CronListView,
|
|
37
42
|
CronEnableRequest,
|
|
38
43
|
CronRunRequest,
|
|
39
|
-
CronActionResult
|
|
40
|
-
ChatTurnStreamReadyEvent,
|
|
41
|
-
ChatTurnStreamDeltaEvent,
|
|
42
|
-
ChatTurnStreamSessionEvent
|
|
44
|
+
CronActionResult
|
|
43
45
|
} from './types';
|
|
44
46
|
|
|
45
47
|
// GET /api/app/meta
|
|
@@ -304,91 +306,24 @@ export async function sendChatTurn(data: ChatTurnRequest): Promise<ChatTurnView>
|
|
|
304
306
|
return response.data;
|
|
305
307
|
}
|
|
306
308
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (params?.sessionKey?.trim()) {
|
|
311
|
-
query.set('sessionKey', params.sessionKey.trim());
|
|
312
|
-
}
|
|
313
|
-
if (params?.agentId?.trim()) {
|
|
314
|
-
query.set('agentId', params.agentId.trim());
|
|
315
|
-
}
|
|
316
|
-
const suffix = query.toString();
|
|
317
|
-
const response = await api.get<ChatCapabilitiesView>(suffix ? `/api/chat/capabilities?${suffix}` : '/api/chat/capabilities');
|
|
318
|
-
if (!response.ok) {
|
|
319
|
-
throw new Error(response.error.message);
|
|
320
|
-
}
|
|
321
|
-
return response.data;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// POST /api/chat/turn/stop
|
|
325
|
-
export async function stopChatTurn(data: ChatTurnStopRequest): Promise<ChatTurnStopResult> {
|
|
326
|
-
const response = await api.post<ChatTurnStopResult>('/api/chat/turn/stop', data);
|
|
327
|
-
if (!response.ok) {
|
|
328
|
-
throw new Error(response.error.message);
|
|
329
|
-
}
|
|
330
|
-
return response.data;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// GET /api/chat/runs
|
|
334
|
-
export async function fetchChatRuns(params?: {
|
|
335
|
-
sessionKey?: string;
|
|
336
|
-
states?: ChatRunState[];
|
|
337
|
-
limit?: number;
|
|
338
|
-
}): Promise<ChatRunListView> {
|
|
339
|
-
const query = new URLSearchParams();
|
|
340
|
-
if (params?.sessionKey?.trim()) {
|
|
341
|
-
query.set('sessionKey', params.sessionKey.trim());
|
|
342
|
-
}
|
|
343
|
-
if (Array.isArray(params?.states) && params.states.length > 0) {
|
|
344
|
-
query.set('states', params.states.join(','));
|
|
345
|
-
}
|
|
346
|
-
if (typeof params?.limit === 'number' && Number.isFinite(params.limit)) {
|
|
347
|
-
query.set('limit', String(Math.max(0, Math.trunc(params.limit))));
|
|
348
|
-
}
|
|
349
|
-
const suffix = query.toString();
|
|
350
|
-
const response = await api.get<ChatRunListView>(suffix ? `/api/chat/runs?${suffix}` : '/api/chat/runs');
|
|
351
|
-
if (!response.ok) {
|
|
352
|
-
throw new Error(response.error.message);
|
|
353
|
-
}
|
|
354
|
-
return response.data;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// GET /api/chat/runs/:runId
|
|
358
|
-
export async function fetchChatRun(runId: string): Promise<ChatRunView> {
|
|
359
|
-
const response = await api.get<ChatRunView>(`/api/chat/runs/${encodeURIComponent(runId)}`);
|
|
360
|
-
if (!response.ok) {
|
|
361
|
-
throw new Error(response.error.message);
|
|
362
|
-
}
|
|
363
|
-
return response.data;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
type ChatTurnStreamOptions = {
|
|
367
|
-
signal?: AbortSignal;
|
|
368
|
-
onReady?: (event: ChatTurnStreamReadyEvent) => void;
|
|
369
|
-
onDelta?: (event: ChatTurnStreamDeltaEvent) => void;
|
|
370
|
-
onSessionEvent?: (event: ChatTurnStreamSessionEvent) => void;
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
type SseParsedEvent = {
|
|
374
|
-
event: string;
|
|
375
|
-
data: string;
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
function parseSseFrame(frame: string): SseParsedEvent | null {
|
|
379
|
-
const lines = frame.split(/\r?\n/);
|
|
380
|
-
let event = 'message';
|
|
309
|
+
function parseSseFrame(frame: string): { event: string; data: string } | null {
|
|
310
|
+
const lines = frame.split('\n');
|
|
311
|
+
let event = '';
|
|
381
312
|
const dataLines: string[] = [];
|
|
382
|
-
for (const
|
|
313
|
+
for (const raw of lines) {
|
|
314
|
+
const line = raw.trimEnd();
|
|
315
|
+
if (!line || line.startsWith(':')) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
383
318
|
if (line.startsWith('event:')) {
|
|
384
|
-
event = line.slice(
|
|
319
|
+
event = line.slice(6).trim();
|
|
385
320
|
continue;
|
|
386
321
|
}
|
|
387
322
|
if (line.startsWith('data:')) {
|
|
388
|
-
dataLines.push(line.slice(
|
|
323
|
+
dataLines.push(line.slice(5).trimStart());
|
|
389
324
|
}
|
|
390
325
|
}
|
|
391
|
-
if (
|
|
326
|
+
if (!event) {
|
|
392
327
|
return null;
|
|
393
328
|
}
|
|
394
329
|
return {
|
|
@@ -397,178 +332,242 @@ function parseSseFrame(frame: string): SseParsedEvent | null {
|
|
|
397
332
|
};
|
|
398
333
|
}
|
|
399
334
|
|
|
400
|
-
async function
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
335
|
+
async function readSseStream(params: {
|
|
336
|
+
path: string;
|
|
337
|
+
method: 'GET' | 'POST';
|
|
338
|
+
body?: unknown;
|
|
339
|
+
signal?: AbortSignal;
|
|
340
|
+
onReady: (event: ChatTurnStreamReadyEvent) => void;
|
|
341
|
+
onDelta: (event: ChatTurnStreamDeltaEvent) => void;
|
|
342
|
+
onSessionEvent: (event: ChatTurnStreamSessionEvent) => void;
|
|
343
|
+
}): Promise<{ sessionKey: string; reply: string }> {
|
|
344
|
+
const response = await fetch(`${API_BASE}${params.path}`, {
|
|
345
|
+
method: params.method,
|
|
346
|
+
headers: {
|
|
347
|
+
'Content-Type': 'application/json',
|
|
348
|
+
Accept: 'text/event-stream'
|
|
349
|
+
},
|
|
350
|
+
...(params.body !== undefined ? { body: JSON.stringify(params.body) } : {}),
|
|
351
|
+
...(params.signal ? { signal: params.signal } : {})
|
|
352
|
+
});
|
|
353
|
+
|
|
404
354
|
if (!response.ok) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
message = payload.error.message;
|
|
410
|
-
}
|
|
411
|
-
} catch {
|
|
412
|
-
const text = await response.text().catch(() => '');
|
|
413
|
-
if (text.trim()) {
|
|
414
|
-
message = text.trim();
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
throw new Error(message);
|
|
355
|
+
const text = await response.text();
|
|
356
|
+
const fallback = `HTTP ${response.status}`;
|
|
357
|
+
const trimmed = text.trim();
|
|
358
|
+
throw new Error(trimmed || fallback);
|
|
418
359
|
}
|
|
419
360
|
|
|
420
|
-
|
|
421
|
-
|
|
361
|
+
const reader = response.body?.getReader();
|
|
362
|
+
if (!reader) {
|
|
363
|
+
throw new Error('SSE response body unavailable');
|
|
422
364
|
}
|
|
423
365
|
|
|
424
|
-
const reader = response.body.getReader();
|
|
425
366
|
const decoder = new TextDecoder();
|
|
426
367
|
let buffer = '';
|
|
427
|
-
let
|
|
368
|
+
let finalResult: { sessionKey: string; reply: string } | null = null;
|
|
369
|
+
let readySessionKey: string | null = null;
|
|
428
370
|
|
|
429
|
-
const
|
|
371
|
+
const consumeFrame = (frame: string) => {
|
|
430
372
|
const parsed = parseSseFrame(frame);
|
|
431
373
|
if (!parsed) {
|
|
432
374
|
return;
|
|
433
375
|
}
|
|
434
|
-
|
|
376
|
+
|
|
377
|
+
let payload: unknown = undefined;
|
|
378
|
+
if (parsed.data) {
|
|
435
379
|
try {
|
|
436
|
-
|
|
437
|
-
sessionKey?: string;
|
|
438
|
-
requestedAt?: string;
|
|
439
|
-
runId?: string;
|
|
440
|
-
stopSupported?: boolean;
|
|
441
|
-
stopReason?: string;
|
|
442
|
-
};
|
|
443
|
-
options.onReady?.({
|
|
444
|
-
event: 'ready',
|
|
445
|
-
sessionKey: String(readyPayload.sessionKey ?? ''),
|
|
446
|
-
requestedAt: String(readyPayload.requestedAt ?? ''),
|
|
447
|
-
...(typeof readyPayload.runId === 'string' && readyPayload.runId.trim().length > 0
|
|
448
|
-
? { runId: readyPayload.runId.trim() }
|
|
449
|
-
: {}),
|
|
450
|
-
...(typeof readyPayload.stopSupported === 'boolean'
|
|
451
|
-
? { stopSupported: readyPayload.stopSupported }
|
|
452
|
-
: {}),
|
|
453
|
-
...(typeof readyPayload.stopReason === 'string' && readyPayload.stopReason.trim().length > 0
|
|
454
|
-
? { stopReason: readyPayload.stopReason.trim() }
|
|
455
|
-
: {})
|
|
456
|
-
});
|
|
380
|
+
payload = JSON.parse(parsed.data);
|
|
457
381
|
} catch {
|
|
458
|
-
|
|
382
|
+
payload = undefined;
|
|
459
383
|
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (parsed.event === 'ready') {
|
|
387
|
+
const ready = (payload ?? {}) as ChatTurnStreamReadyEvent;
|
|
388
|
+
readySessionKey = typeof ready.sessionKey === 'string' && ready.sessionKey.trim() ? ready.sessionKey : readySessionKey;
|
|
389
|
+
params.onReady(ready);
|
|
460
390
|
return;
|
|
461
391
|
}
|
|
392
|
+
|
|
462
393
|
if (parsed.event === 'delta') {
|
|
463
|
-
|
|
464
|
-
const deltaPayload = JSON.parse(parsed.data) as { delta?: string };
|
|
465
|
-
if (typeof deltaPayload.delta === 'string' && deltaPayload.delta.length > 0) {
|
|
466
|
-
options.onDelta?.({
|
|
467
|
-
event: 'delta',
|
|
468
|
-
delta: deltaPayload.delta
|
|
469
|
-
});
|
|
470
|
-
}
|
|
471
|
-
} catch {
|
|
472
|
-
// ignore malformed delta event payload
|
|
473
|
-
}
|
|
394
|
+
params.onDelta((payload ?? { delta: '' }) as ChatTurnStreamDeltaEvent);
|
|
474
395
|
return;
|
|
475
396
|
}
|
|
397
|
+
|
|
476
398
|
if (parsed.event === 'session_event') {
|
|
477
|
-
|
|
478
|
-
options.onSessionEvent?.({
|
|
479
|
-
event: 'session_event',
|
|
480
|
-
data: JSON.parse(parsed.data)
|
|
481
|
-
});
|
|
482
|
-
} catch {
|
|
483
|
-
// ignore malformed session_event payload
|
|
484
|
-
}
|
|
399
|
+
params.onSessionEvent({ data: payload as ChatTurnStreamSessionEvent['data'] });
|
|
485
400
|
return;
|
|
486
401
|
}
|
|
402
|
+
|
|
487
403
|
if (parsed.event === 'final') {
|
|
488
|
-
|
|
404
|
+
const result = payload as ChatTurnView;
|
|
405
|
+
finalResult = {
|
|
406
|
+
sessionKey: typeof result?.sessionKey === 'string' && result.sessionKey.trim()
|
|
407
|
+
? result.sessionKey
|
|
408
|
+
: (readySessionKey ?? ''),
|
|
409
|
+
reply: typeof result?.reply === 'string' ? result.reply : ''
|
|
410
|
+
};
|
|
489
411
|
return;
|
|
490
412
|
}
|
|
413
|
+
|
|
491
414
|
if (parsed.event === 'error') {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
throw new Error(typeof errPayload.message === 'string' && errPayload.message ? errPayload.message : 'chat stream failed');
|
|
495
|
-
} catch (error) {
|
|
496
|
-
if (error instanceof Error) {
|
|
497
|
-
throw error;
|
|
498
|
-
}
|
|
499
|
-
throw new Error('chat stream failed');
|
|
500
|
-
}
|
|
415
|
+
const errorPayload = (payload ?? {}) as ChatTurnStreamErrorEvent;
|
|
416
|
+
throw new Error((errorPayload.message ?? '').trim() || 'chat stream failed');
|
|
501
417
|
}
|
|
502
418
|
};
|
|
503
419
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
420
|
+
try {
|
|
421
|
+
let isReading = true;
|
|
422
|
+
while (isReading) {
|
|
423
|
+
const { value, done } = await reader.read();
|
|
424
|
+
if (done) {
|
|
425
|
+
isReading = false;
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
buffer += decoder.decode(value, { stream: true });
|
|
429
|
+
let boundary = buffer.indexOf('\n\n');
|
|
430
|
+
while (boundary !== -1) {
|
|
431
|
+
const frame = buffer.slice(0, boundary);
|
|
432
|
+
buffer = buffer.slice(boundary + 2);
|
|
433
|
+
consumeFrame(frame);
|
|
434
|
+
boundary = buffer.indexOf('\n\n');
|
|
519
435
|
}
|
|
520
|
-
boundary = buffer.indexOf('\n\n');
|
|
521
436
|
}
|
|
437
|
+
if (buffer.trim()) {
|
|
438
|
+
consumeFrame(buffer);
|
|
439
|
+
}
|
|
440
|
+
} finally {
|
|
441
|
+
reader.releaseLock();
|
|
522
442
|
}
|
|
523
443
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
handleFrame(trailing);
|
|
444
|
+
if (finalResult) {
|
|
445
|
+
return finalResult;
|
|
527
446
|
}
|
|
528
447
|
|
|
529
|
-
if (
|
|
530
|
-
|
|
448
|
+
if (readySessionKey) {
|
|
449
|
+
return { sessionKey: readySessionKey, reply: '' };
|
|
531
450
|
}
|
|
532
|
-
|
|
451
|
+
|
|
452
|
+
throw new Error('chat stream ended without final event');
|
|
533
453
|
}
|
|
534
454
|
|
|
455
|
+
// POST /api/chat/turn/stream
|
|
535
456
|
export async function sendChatTurnStream(
|
|
536
457
|
data: ChatTurnRequest,
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
458
|
+
params: {
|
|
459
|
+
signal?: AbortSignal;
|
|
460
|
+
onReady: (event: ChatTurnStreamReadyEvent) => void;
|
|
461
|
+
onDelta: (event: ChatTurnStreamDeltaEvent) => void;
|
|
462
|
+
onSessionEvent: (event: ChatTurnStreamSessionEvent) => void;
|
|
463
|
+
}
|
|
464
|
+
): Promise<{ sessionKey: string; reply: string }> {
|
|
465
|
+
return readSseStream({
|
|
466
|
+
path: '/api/chat/turn/stream',
|
|
540
467
|
method: 'POST',
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
signal: options.signal
|
|
468
|
+
body: data,
|
|
469
|
+
signal: params.signal,
|
|
470
|
+
onReady: params.onReady,
|
|
471
|
+
onDelta: params.onDelta,
|
|
472
|
+
onSessionEvent: params.onSessionEvent
|
|
547
473
|
});
|
|
548
|
-
return consumeChatTurnSseStream(response, options);
|
|
549
474
|
}
|
|
550
475
|
|
|
476
|
+
// GET /api/chat/runs/:runId/stream
|
|
551
477
|
export async function streamChatRun(
|
|
552
|
-
|
|
478
|
+
data: {
|
|
553
479
|
runId: string;
|
|
554
480
|
fromEventIndex?: number;
|
|
555
481
|
},
|
|
556
|
-
|
|
557
|
-
|
|
482
|
+
params: {
|
|
483
|
+
signal?: AbortSignal;
|
|
484
|
+
onReady: (event: ChatTurnStreamReadyEvent) => void;
|
|
485
|
+
onDelta: (event: ChatTurnStreamDeltaEvent) => void;
|
|
486
|
+
onSessionEvent: (event: ChatTurnStreamSessionEvent) => void;
|
|
487
|
+
}
|
|
488
|
+
): Promise<{ sessionKey: string; reply: string }> {
|
|
558
489
|
const query = new URLSearchParams();
|
|
559
|
-
if (typeof
|
|
560
|
-
query.set('fromEventIndex', String(Math.max(0, Math.trunc(
|
|
490
|
+
if (typeof data.fromEventIndex === 'number' && Number.isFinite(data.fromEventIndex)) {
|
|
491
|
+
query.set('fromEventIndex', String(Math.max(0, Math.trunc(data.fromEventIndex))));
|
|
561
492
|
}
|
|
562
493
|
const suffix = query.toString();
|
|
563
|
-
const
|
|
564
|
-
|
|
494
|
+
const path = `/api/chat/runs/${encodeURIComponent(data.runId)}/stream${suffix ? `?${suffix}` : ''}`;
|
|
495
|
+
return readSseStream({
|
|
496
|
+
path,
|
|
565
497
|
method: 'GET',
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
498
|
+
signal: params.signal,
|
|
499
|
+
onReady: params.onReady,
|
|
500
|
+
onDelta: params.onDelta,
|
|
501
|
+
onSessionEvent: params.onSessionEvent
|
|
570
502
|
});
|
|
571
|
-
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// GET /api/chat/capabilities
|
|
506
|
+
export async function fetchChatCapabilities(params?: { sessionKey?: string; agentId?: string }): Promise<ChatCapabilitiesView> {
|
|
507
|
+
const query = new URLSearchParams();
|
|
508
|
+
if (params?.sessionKey?.trim()) {
|
|
509
|
+
query.set('sessionKey', params.sessionKey.trim());
|
|
510
|
+
}
|
|
511
|
+
if (params?.agentId?.trim()) {
|
|
512
|
+
query.set('agentId', params.agentId.trim());
|
|
513
|
+
}
|
|
514
|
+
const suffix = query.toString();
|
|
515
|
+
const response = await api.get<ChatCapabilitiesView>(suffix ? `/api/chat/capabilities?${suffix}` : '/api/chat/capabilities');
|
|
516
|
+
if (!response.ok) {
|
|
517
|
+
throw new Error(response.error.message);
|
|
518
|
+
}
|
|
519
|
+
return response.data;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// GET /api/chat/session-types
|
|
523
|
+
export async function fetchChatSessionTypes(): Promise<ChatSessionTypesView> {
|
|
524
|
+
const response = await api.get<ChatSessionTypesView>('/api/chat/session-types');
|
|
525
|
+
if (!response.ok) {
|
|
526
|
+
throw new Error(response.error.message);
|
|
527
|
+
}
|
|
528
|
+
return response.data;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// POST /api/chat/turn/stop
|
|
532
|
+
export async function stopChatTurn(data: ChatTurnStopRequest): Promise<ChatTurnStopResult> {
|
|
533
|
+
const response = await api.post<ChatTurnStopResult>('/api/chat/turn/stop', data);
|
|
534
|
+
if (!response.ok) {
|
|
535
|
+
throw new Error(response.error.message);
|
|
536
|
+
}
|
|
537
|
+
return response.data;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// GET /api/chat/runs
|
|
541
|
+
export async function fetchChatRuns(params?: {
|
|
542
|
+
sessionKey?: string;
|
|
543
|
+
states?: ChatRunState[];
|
|
544
|
+
limit?: number;
|
|
545
|
+
}): Promise<ChatRunListView> {
|
|
546
|
+
const query = new URLSearchParams();
|
|
547
|
+
if (params?.sessionKey?.trim()) {
|
|
548
|
+
query.set('sessionKey', params.sessionKey.trim());
|
|
549
|
+
}
|
|
550
|
+
if (Array.isArray(params?.states) && params.states.length > 0) {
|
|
551
|
+
query.set('states', params.states.join(','));
|
|
552
|
+
}
|
|
553
|
+
if (typeof params?.limit === 'number' && Number.isFinite(params.limit)) {
|
|
554
|
+
query.set('limit', String(Math.max(0, Math.trunc(params.limit))));
|
|
555
|
+
}
|
|
556
|
+
const suffix = query.toString();
|
|
557
|
+
const response = await api.get<ChatRunListView>(suffix ? `/api/chat/runs?${suffix}` : '/api/chat/runs');
|
|
558
|
+
if (!response.ok) {
|
|
559
|
+
throw new Error(response.error.message);
|
|
560
|
+
}
|
|
561
|
+
return response.data;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// GET /api/chat/runs/:runId
|
|
565
|
+
export async function fetchChatRun(runId: string): Promise<ChatRunView> {
|
|
566
|
+
const response = await api.get<ChatRunView>(`/api/chat/runs/${encodeURIComponent(runId)}`);
|
|
567
|
+
if (!response.ok) {
|
|
568
|
+
throw new Error(response.error.message);
|
|
569
|
+
}
|
|
570
|
+
return response.data;
|
|
572
571
|
}
|
|
573
572
|
|
|
574
573
|
// GET /api/cron
|
package/src/api/types.ts
CHANGED
|
@@ -146,6 +146,8 @@ export type SessionEntryView = {
|
|
|
146
146
|
updatedAt: string;
|
|
147
147
|
label?: string;
|
|
148
148
|
preferredModel?: string;
|
|
149
|
+
sessionType: string;
|
|
150
|
+
sessionTypeMutable: boolean;
|
|
149
151
|
messageCount: number;
|
|
150
152
|
lastRole?: string;
|
|
151
153
|
lastTimestamp?: string;
|
|
@@ -177,6 +179,8 @@ export type SessionHistoryView = {
|
|
|
177
179
|
key: string;
|
|
178
180
|
totalMessages: number;
|
|
179
181
|
totalEvents: number;
|
|
182
|
+
sessionType: string;
|
|
183
|
+
sessionTypeMutable: boolean;
|
|
180
184
|
metadata: Record<string, unknown>;
|
|
181
185
|
messages: SessionMessageView[];
|
|
182
186
|
events: SessionEventView[];
|
|
@@ -185,6 +189,7 @@ export type SessionHistoryView = {
|
|
|
185
189
|
export type SessionPatchUpdate = {
|
|
186
190
|
label?: string | null;
|
|
187
191
|
preferredModel?: string | null;
|
|
192
|
+
sessionType?: string | null;
|
|
188
193
|
clearHistory?: boolean;
|
|
189
194
|
};
|
|
190
195
|
|
|
@@ -208,11 +213,42 @@ export type ChatTurnView = {
|
|
|
208
213
|
durationMs: number;
|
|
209
214
|
};
|
|
210
215
|
|
|
216
|
+
export type ChatTurnStreamReadyEvent = {
|
|
217
|
+
sessionKey: string;
|
|
218
|
+
requestedAt?: string;
|
|
219
|
+
runId?: string;
|
|
220
|
+
stopSupported?: boolean;
|
|
221
|
+
stopReason?: string;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export type ChatTurnStreamDeltaEvent = {
|
|
225
|
+
delta: string;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export type ChatTurnStreamSessionEvent = {
|
|
229
|
+
data: SessionEventView;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
export type ChatTurnStreamErrorEvent = {
|
|
233
|
+
code?: string;
|
|
234
|
+
message?: string;
|
|
235
|
+
};
|
|
236
|
+
|
|
211
237
|
export type ChatCapabilitiesView = {
|
|
212
238
|
stopSupported: boolean;
|
|
213
239
|
stopReason?: string;
|
|
214
240
|
};
|
|
215
241
|
|
|
242
|
+
export type ChatSessionTypeOptionView = {
|
|
243
|
+
value: string;
|
|
244
|
+
label: string;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
export type ChatSessionTypesView = {
|
|
248
|
+
defaultType: string;
|
|
249
|
+
options: ChatSessionTypeOptionView[];
|
|
250
|
+
};
|
|
251
|
+
|
|
216
252
|
export type ChatCommandOptionView = {
|
|
217
253
|
name: string;
|
|
218
254
|
description: string;
|
|
@@ -267,30 +303,6 @@ export type ChatRunListView = {
|
|
|
267
303
|
total: number;
|
|
268
304
|
};
|
|
269
305
|
|
|
270
|
-
export type ChatTurnStreamReadyEvent = {
|
|
271
|
-
event: "ready";
|
|
272
|
-
sessionKey: string;
|
|
273
|
-
requestedAt: string;
|
|
274
|
-
runId?: string;
|
|
275
|
-
stopSupported?: boolean;
|
|
276
|
-
stopReason?: string;
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
export type ChatTurnStreamDeltaEvent = {
|
|
280
|
-
event: "delta";
|
|
281
|
-
delta: string;
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
export type ChatTurnStreamSessionEvent = {
|
|
285
|
-
event: "session_event";
|
|
286
|
-
data: SessionEventView;
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
export type ChatTurnStreamFinalEvent = {
|
|
290
|
-
event: "final";
|
|
291
|
-
data: ChatTurnView;
|
|
292
|
-
};
|
|
293
|
-
|
|
294
306
|
export type CronScheduleView =
|
|
295
307
|
| { kind: "at"; atMs?: number | null }
|
|
296
308
|
| { kind: "every"; everyMs?: number | null }
|