@nextclaw/ui 0.11.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -2
- package/dist/assets/{ChannelsList-BqsOYnXz.js → ChannelsList-CVPqrxns.js} +4 -4
- package/dist/assets/ChatPage-BO1VUrAY.js +37 -0
- package/dist/assets/{DocBrowser-BmL0QXBZ.js → DocBrowser-FBwg8iji.js} +1 -1
- package/dist/assets/{LogoBadge-C1HiPZPf.js → LogoBadge-BCmJfRT8.js} +1 -1
- package/dist/assets/MarketplacePage-DWxXUOCx.js +49 -0
- package/dist/assets/{McpMarketplacePage-CLHFnNBd.js → McpMarketplacePage-Bth9X_hu.js} +2 -2
- package/dist/assets/{ModelConfig-LQSR58tc.js → ModelConfig-PkSp_ioc.js} +1 -1
- package/dist/assets/ProvidersList-DVDge8wa.js +1 -0
- package/dist/assets/RemoteAccessPage-BVkzfEaL.js +1 -0
- package/dist/assets/RuntimeConfig-ByJs3khh.js +1 -0
- package/dist/assets/{SearchConfig-Chzo_JGs.js → SearchConfig-KZUAqYJN.js} +1 -1
- package/dist/assets/{SecretsConfig-CEIbjZYA.js → SecretsConfig-qwB_Y_Ka.js} +2 -2
- package/dist/assets/SessionsConfig-CGCl4UTr.js +2 -0
- package/dist/assets/index-CrilScMo.css +1 -0
- package/dist/assets/{index-j6A_-1b6.js → index-D41ntvb7.js} +6 -6
- package/dist/assets/{label-GACO2RzW.js → label-7JEFhkur.js} +1 -1
- package/dist/assets/ncp-session-adapter-BOqhkrc-.js +1 -0
- package/dist/assets/{page-layout-DjXaK3A3.js → page-layout-B7q511TE.js} +1 -1
- package/dist/assets/popover-CywJGmPr.js +1 -0
- package/dist/assets/security-config-zi2UxN5r.js +1 -0
- package/dist/assets/skeleton-qUJZQ03S.js +1 -0
- package/dist/assets/{status-dot-IWEBezqb.js → status-dot-BilwNdTT.js} +1 -1
- package/dist/assets/{switch-DCHAJSrA.js → switch-BLp2Pno1.js} +1 -1
- package/dist/assets/tabs-custom-CgIdQMGC.js +1 -0
- package/dist/assets/useConfirmDialog-BitswAkv.js +1 -0
- package/dist/assets/{vendor-CNhxtHCf.js → vendor-D_JxmsLV.js} +87 -87
- package/dist/index.html +3 -3
- package/package.json +4 -4
- package/src/App.test.tsx +42 -10
- package/src/App.tsx +5 -40
- package/src/api/api-base.test.ts +37 -0
- package/src/api/api-base.ts +0 -4
- package/src/api/config.ts +2 -270
- package/src/api/types.ts +0 -117
- package/src/components/chat/ChatPage.tsx +1 -11
- package/src/components/chat/ChatSidebar.test.tsx +1 -50
- package/src/components/chat/ChatSidebar.tsx +0 -5
- package/src/components/chat/README.md +2 -0
- package/src/components/chat/chat-attachment-upload-limit.test.ts +41 -0
- package/src/components/chat/chat-session-display.ts +9 -0
- package/src/components/chat/chat-session-label.service.ts +3 -12
- package/src/components/chat/chat-session-preference-sync.test.ts +10 -13
- package/src/components/chat/chat-stream/types.ts +4 -57
- package/src/components/chat/ncp/NcpChatPage.tsx +3 -3
- package/src/components/chat/useHydratedNcpAgent.test.tsx +77 -0
- package/src/components/config/README.md +2 -0
- package/src/components/config/SessionsConfig.tsx +152 -132
- package/src/hooks/use-auth.test.ts +3 -3
- package/src/hooks/use-auth.ts +16 -4
- package/src/hooks/use-realtime-query-bridge.ts +0 -24
- package/src/hooks/useConfig.ts +10 -137
- package/src/lib/session-run-status.ts +1 -63
- package/src/vite-env.d.ts +1 -0
- package/vite.config.ts +4 -4
- package/dist/assets/ChatPage-CJBYKR-Y.js +0 -38
- package/dist/assets/MarketplacePage-BIRP0NRS.js +0 -49
- package/dist/assets/ProvidersList-CwI-mxah.js +0 -1
- package/dist/assets/RemoteAccessPage-Cw5BqZb6.js +0 -1
- package/dist/assets/RuntimeConfig-DbowSRAb.js +0 -1
- package/dist/assets/SessionsConfig-BR8GfGWL.js +0 -2
- package/dist/assets/chat-message-CPG7zxRR.js +0 -3
- package/dist/assets/index-kaPUhd-8.css +0 -1
- package/dist/assets/popover-DTaFiTmU.js +0 -1
- package/dist/assets/security-config-Dk-yoKvK.js +0 -1
- package/dist/assets/skeleton-Dm2xOBSA.js +0 -1
- package/dist/assets/tabs-custom-DKSbDSB9.js +0 -1
- package/dist/assets/useConfirmDialog-ByJ8A8n7.js +0 -1
- package/src/api/config.stream.test.ts +0 -115
- package/src/components/chat/chat-chain.test.ts +0 -22
- package/src/components/chat/chat-chain.ts +0 -23
- package/src/components/chat/chat-page-data.ts +0 -171
- package/src/components/chat/chat-page-runtime.ts +0 -190
- package/src/components/chat/chat-stream/nextbot-parsers.ts +0 -52
- package/src/components/chat/chat-stream/nextbot-runtime-agent.ts +0 -413
- package/src/components/chat/chat-stream/stream-event-adapter.ts +0 -98
- package/src/components/chat/chat-stream/transport.ts +0 -253
- package/src/components/chat/legacy/LegacyChatPage.tsx +0 -223
- package/src/components/chat/managers/chat-input.manager.ts +0 -228
- package/src/components/chat/managers/chat-thread.manager.ts +0 -87
- package/src/components/chat/presenter/chat.presenter.ts +0 -32
- package/src/components/chat/useChatRuntimeController.ts +0 -134
|
@@ -1,413 +0,0 @@
|
|
|
1
|
-
import { EventType, type AgentEvent, type IAgent, type RunAgentInput } from '@nextclaw/agent-chat';
|
|
2
|
-
import { Observable, type Subscribable } from 'rxjs';
|
|
3
|
-
import {
|
|
4
|
-
buildDeltaEvents,
|
|
5
|
-
buildDeltaMessageId,
|
|
6
|
-
buildSessionEventEvents,
|
|
7
|
-
isAssistantSessionEvent,
|
|
8
|
-
shouldCloseDeltaOnSessionEvent
|
|
9
|
-
} from './stream-event-adapter';
|
|
10
|
-
import { openResumeRunStream, openSendTurnStream, requestStopRun } from './transport';
|
|
11
|
-
import type {
|
|
12
|
-
ActiveRunState,
|
|
13
|
-
NextbotAgentRunMetadata,
|
|
14
|
-
StreamDeltaEvent,
|
|
15
|
-
StreamReadyEvent,
|
|
16
|
-
StreamSessionEvent
|
|
17
|
-
} from './types';
|
|
18
|
-
import { isAbortLikeError } from '@/lib/chat-runtime-utils';
|
|
19
|
-
|
|
20
|
-
type SendRunMetadata = Extract<NextbotAgentRunMetadata, { mode: 'send' }>;
|
|
21
|
-
type ResumeRunMetadata = Extract<NextbotAgentRunMetadata, { mode: 'resume' }>;
|
|
22
|
-
type StreamResult = { sessionKey: string; reply: string };
|
|
23
|
-
type EmitEvent = (event: AgentEvent) => void;
|
|
24
|
-
type StreamRuntimeState = {
|
|
25
|
-
deltaMessageId: string;
|
|
26
|
-
deltaStarted: boolean;
|
|
27
|
-
deltaClosed: boolean;
|
|
28
|
-
hasAssistantSessionEvent: boolean;
|
|
29
|
-
hasAssistantOutput: boolean;
|
|
30
|
-
};
|
|
31
|
-
type RunObservableParams = {
|
|
32
|
-
metadata: NextbotAgentRunMetadata;
|
|
33
|
-
clientRunId: string;
|
|
34
|
-
abortController: AbortController;
|
|
35
|
-
runState: ActiveRunState;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
function createBackendRunId(): string {
|
|
39
|
-
const now = Date.now().toString(36);
|
|
40
|
-
const rand = Math.random().toString(36).slice(2, 10);
|
|
41
|
-
return `run-${now}-${rand}`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export type NextbotRunMetadataPayload =
|
|
45
|
-
| {
|
|
46
|
-
driver: 'nextbot-stream';
|
|
47
|
-
kind: 'ready';
|
|
48
|
-
sessionKey?: string;
|
|
49
|
-
backendRunId?: string;
|
|
50
|
-
stopSupported?: boolean;
|
|
51
|
-
stopReason?: string;
|
|
52
|
-
requestedAt?: string;
|
|
53
|
-
}
|
|
54
|
-
| {
|
|
55
|
-
driver: 'nextbot-stream';
|
|
56
|
-
kind: 'final';
|
|
57
|
-
sessionKey: string;
|
|
58
|
-
reply: string;
|
|
59
|
-
hasAssistantSessionEvent: boolean;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
function readRunMetadata(input: RunAgentInput): NextbotAgentRunMetadata | null {
|
|
63
|
-
const raw = input.metadata;
|
|
64
|
-
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
const record = raw as Record<string, unknown>;
|
|
68
|
-
if (record.driver !== 'nextbot-stream') {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
const mode = record.mode;
|
|
72
|
-
if (mode === 'send') {
|
|
73
|
-
const payload = record.payload;
|
|
74
|
-
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
const requestedSkills = Array.isArray(record.requestedSkills)
|
|
78
|
-
? record.requestedSkills.filter((item): item is string => typeof item === 'string')
|
|
79
|
-
: [];
|
|
80
|
-
return {
|
|
81
|
-
driver: 'nextbot-stream',
|
|
82
|
-
mode: 'send',
|
|
83
|
-
payload: payload as SendRunMetadata['payload'],
|
|
84
|
-
requestedSkills
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
if (mode === 'resume') {
|
|
88
|
-
const runId = typeof record.runId === 'string' ? record.runId.trim() : '';
|
|
89
|
-
if (!runId) {
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
const fromEventIndex =
|
|
93
|
-
typeof record.fromEventIndex === 'number' && Number.isFinite(record.fromEventIndex)
|
|
94
|
-
? Math.max(0, Math.trunc(record.fromEventIndex))
|
|
95
|
-
: undefined;
|
|
96
|
-
const sessionKey = typeof record.sessionKey === 'string' ? record.sessionKey.trim() : '';
|
|
97
|
-
const agentId = typeof record.agentId === 'string' ? record.agentId.trim() : '';
|
|
98
|
-
const stopSupported = typeof record.stopSupported === 'boolean' ? record.stopSupported : undefined;
|
|
99
|
-
const stopReason = typeof record.stopReason === 'string' ? record.stopReason.trim() : '';
|
|
100
|
-
return {
|
|
101
|
-
driver: 'nextbot-stream',
|
|
102
|
-
mode: 'resume',
|
|
103
|
-
runId,
|
|
104
|
-
...(typeof fromEventIndex === 'number' ? { fromEventIndex } : {}),
|
|
105
|
-
...(sessionKey ? { sessionKey } : {}),
|
|
106
|
-
...(agentId ? { agentId } : {}),
|
|
107
|
-
...(typeof stopSupported === 'boolean' ? { stopSupported } : {}),
|
|
108
|
-
...(stopReason ? { stopReason } : {})
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function buildInitialRunState(metadata: NextbotAgentRunMetadata): ActiveRunState {
|
|
115
|
-
if (metadata.mode === 'send') {
|
|
116
|
-
const backendRunId = metadata.payload.runId?.trim() || '';
|
|
117
|
-
return {
|
|
118
|
-
localRunId: 0,
|
|
119
|
-
sessionKey: metadata.payload.sessionKey,
|
|
120
|
-
...(metadata.payload.agentId ? { agentId: metadata.payload.agentId } : {}),
|
|
121
|
-
...(backendRunId ? { backendRunId } : {}),
|
|
122
|
-
backendStopSupported: Boolean(metadata.payload.stopSupported),
|
|
123
|
-
...(metadata.payload.stopReason ? { backendStopReason: metadata.payload.stopReason } : {})
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
localRunId: 0,
|
|
128
|
-
sessionKey: metadata.sessionKey ?? '',
|
|
129
|
-
...(metadata.agentId ? { agentId: metadata.agentId } : {}),
|
|
130
|
-
backendRunId: metadata.runId,
|
|
131
|
-
backendStopSupported: Boolean(metadata.stopSupported),
|
|
132
|
-
...(metadata.stopReason ? { backendStopReason: metadata.stopReason } : {})
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function withEnsuredSendRunId(metadata: NextbotAgentRunMetadata): NextbotAgentRunMetadata {
|
|
137
|
-
if (metadata.mode !== 'send') {
|
|
138
|
-
return metadata;
|
|
139
|
-
}
|
|
140
|
-
const runId = metadata.payload.runId?.trim();
|
|
141
|
-
if (runId) {
|
|
142
|
-
return metadata;
|
|
143
|
-
}
|
|
144
|
-
return {
|
|
145
|
-
...metadata,
|
|
146
|
-
payload: {
|
|
147
|
-
...metadata.payload,
|
|
148
|
-
runId: createBackendRunId()
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function updateRunStateFromReady(runState: ActiveRunState, event: {
|
|
154
|
-
sessionKey?: string;
|
|
155
|
-
runId?: string;
|
|
156
|
-
stopSupported?: boolean;
|
|
157
|
-
stopReason?: string;
|
|
158
|
-
}) {
|
|
159
|
-
runState.backendRunId = event.runId?.trim() || runState.backendRunId;
|
|
160
|
-
runState.backendStopSupported =
|
|
161
|
-
typeof event.stopSupported === 'boolean' ? event.stopSupported : runState.backendStopSupported;
|
|
162
|
-
if (event.stopReason?.trim()) {
|
|
163
|
-
runState.backendStopReason = event.stopReason.trim();
|
|
164
|
-
}
|
|
165
|
-
if (event.sessionKey?.trim()) {
|
|
166
|
-
runState.sessionKey = event.sessionKey.trim();
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function createStreamRuntimeState(): StreamRuntimeState {
|
|
171
|
-
return {
|
|
172
|
-
deltaMessageId: buildDeltaMessageId(),
|
|
173
|
-
deltaStarted: false,
|
|
174
|
-
deltaClosed: false,
|
|
175
|
-
hasAssistantSessionEvent: false,
|
|
176
|
-
hasAssistantOutput: false
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function buildReadyMetadata(event: StreamReadyEvent): NextbotRunMetadataPayload {
|
|
181
|
-
return {
|
|
182
|
-
driver: 'nextbot-stream',
|
|
183
|
-
kind: 'ready',
|
|
184
|
-
...(event.sessionKey?.trim() ? { sessionKey: event.sessionKey.trim() } : {}),
|
|
185
|
-
...(event.runId?.trim() ? { backendRunId: event.runId.trim() } : {}),
|
|
186
|
-
...(typeof event.stopSupported === 'boolean' ? { stopSupported: event.stopSupported } : {}),
|
|
187
|
-
...(event.stopReason?.trim() ? { stopReason: event.stopReason.trim() } : {}),
|
|
188
|
-
...(event.requestedAt ? { requestedAt: event.requestedAt } : {})
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function buildFinalMetadata(result: StreamResult, hasAssistantSessionEvent: boolean): NextbotRunMetadataPayload {
|
|
193
|
-
return {
|
|
194
|
-
driver: 'nextbot-stream',
|
|
195
|
-
kind: 'final',
|
|
196
|
-
sessionKey: result.sessionKey,
|
|
197
|
-
reply: result.reply,
|
|
198
|
-
hasAssistantSessionEvent
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function emitRunMetadata(emit: EmitEvent, clientRunId: string, metadata: NextbotRunMetadataPayload) {
|
|
203
|
-
emit({
|
|
204
|
-
type: EventType.RUN_METADATA,
|
|
205
|
-
runId: clientRunId,
|
|
206
|
-
metadata
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function closeDelta(runtime: StreamRuntimeState, emit: EmitEvent) {
|
|
211
|
-
if (!runtime.deltaStarted || runtime.deltaClosed) {
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
emit({ type: EventType.TEXT_END, messageId: runtime.deltaMessageId });
|
|
215
|
-
runtime.deltaClosed = true;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function handleDelta(runtime: StreamRuntimeState, emit: EmitEvent, event: StreamDeltaEvent) {
|
|
219
|
-
const events = buildDeltaEvents({
|
|
220
|
-
messageId: runtime.deltaMessageId,
|
|
221
|
-
delta: event.delta,
|
|
222
|
-
started: runtime.deltaStarted
|
|
223
|
-
});
|
|
224
|
-
if (events.length > 0) {
|
|
225
|
-
runtime.deltaStarted = true;
|
|
226
|
-
runtime.deltaClosed = false;
|
|
227
|
-
runtime.hasAssistantOutput = true;
|
|
228
|
-
}
|
|
229
|
-
for (const streamEvent of events) {
|
|
230
|
-
emit(streamEvent);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function handleSession(runtime: StreamRuntimeState, emit: EmitEvent, event: StreamSessionEvent) {
|
|
235
|
-
if (shouldCloseDeltaOnSessionEvent(event.data)) {
|
|
236
|
-
closeDelta(runtime, emit);
|
|
237
|
-
runtime.deltaMessageId = buildDeltaMessageId();
|
|
238
|
-
runtime.deltaStarted = false;
|
|
239
|
-
runtime.deltaClosed = false;
|
|
240
|
-
}
|
|
241
|
-
if (isAssistantSessionEvent(event.data)) {
|
|
242
|
-
runtime.hasAssistantSessionEvent = true;
|
|
243
|
-
}
|
|
244
|
-
for (const streamEvent of buildSessionEventEvents({
|
|
245
|
-
event: event.data,
|
|
246
|
-
messageId: runtime.deltaMessageId
|
|
247
|
-
})) {
|
|
248
|
-
emit(streamEvent);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function emitFallbackReplyIfNeeded(runtime: StreamRuntimeState, emit: EmitEvent, reply: string) {
|
|
253
|
-
const fallbackText = reply.trim();
|
|
254
|
-
if (runtime.hasAssistantOutput || !fallbackText) {
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
const fallbackMessageId = buildDeltaMessageId();
|
|
258
|
-
emit({ type: EventType.TEXT_START, messageId: fallbackMessageId });
|
|
259
|
-
emit({ type: EventType.TEXT_DELTA, messageId: fallbackMessageId, delta: fallbackText });
|
|
260
|
-
emit({ type: EventType.TEXT_END, messageId: fallbackMessageId });
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
export class NextbotRuntimeAgent implements IAgent {
|
|
264
|
-
private activeAbortController: AbortController | null = null;
|
|
265
|
-
private activeRunState: ActiveRunState | null = null;
|
|
266
|
-
|
|
267
|
-
private buildMissingMetadataObservable = (clientRunId: string): Observable<AgentEvent> =>
|
|
268
|
-
new Observable<AgentEvent>((subscriber) => {
|
|
269
|
-
subscriber.next({
|
|
270
|
-
type: EventType.RUN_ERROR,
|
|
271
|
-
runId: clientRunId,
|
|
272
|
-
error: 'nextbot runtime metadata is required'
|
|
273
|
-
});
|
|
274
|
-
subscriber.complete();
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
private openRunStream = (params: {
|
|
278
|
-
metadata: NextbotAgentRunMetadata;
|
|
279
|
-
signal: AbortSignal;
|
|
280
|
-
onReady: (event: StreamReadyEvent) => void;
|
|
281
|
-
onDelta: (event: StreamDeltaEvent) => void;
|
|
282
|
-
onSessionEvent: (event: StreamSessionEvent) => void;
|
|
283
|
-
}): Promise<StreamResult> => {
|
|
284
|
-
const { metadata, signal, onReady, onDelta, onSessionEvent } = params;
|
|
285
|
-
if (metadata.mode === 'send') {
|
|
286
|
-
return openSendTurnStream({
|
|
287
|
-
item: metadata.payload,
|
|
288
|
-
requestedSkills: metadata.requestedSkills,
|
|
289
|
-
signal,
|
|
290
|
-
onReady,
|
|
291
|
-
onDelta,
|
|
292
|
-
onSessionEvent
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
return openResumeRunStream({
|
|
296
|
-
runId: (metadata as ResumeRunMetadata).runId,
|
|
297
|
-
fromEventIndex: (metadata as ResumeRunMetadata).fromEventIndex,
|
|
298
|
-
signal,
|
|
299
|
-
onReady,
|
|
300
|
-
onDelta,
|
|
301
|
-
onSessionEvent
|
|
302
|
-
});
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
private finalizeRunState = (abortController: AbortController, runState: ActiveRunState) => {
|
|
306
|
-
if (this.activeAbortController === abortController) {
|
|
307
|
-
this.activeAbortController = null;
|
|
308
|
-
}
|
|
309
|
-
if (this.activeRunState === runState) {
|
|
310
|
-
this.activeRunState = null;
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
private createRunObservable = ({
|
|
315
|
-
metadata,
|
|
316
|
-
clientRunId,
|
|
317
|
-
abortController,
|
|
318
|
-
runState
|
|
319
|
-
}: RunObservableParams): Observable<AgentEvent> =>
|
|
320
|
-
new Observable<AgentEvent>((subscriber) => {
|
|
321
|
-
const runtime = createStreamRuntimeState();
|
|
322
|
-
let disposed = false;
|
|
323
|
-
const emit: EmitEvent = (event) => {
|
|
324
|
-
if (!disposed) {
|
|
325
|
-
subscriber.next(event);
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
emit({ type: EventType.RUN_STARTED, runId: clientRunId });
|
|
330
|
-
|
|
331
|
-
const streamTask = this.openRunStream({
|
|
332
|
-
metadata,
|
|
333
|
-
signal: abortController.signal,
|
|
334
|
-
onReady: (event) => {
|
|
335
|
-
if (this.activeRunState) {
|
|
336
|
-
updateRunStateFromReady(this.activeRunState, event);
|
|
337
|
-
}
|
|
338
|
-
emitRunMetadata(emit, clientRunId, buildReadyMetadata(event));
|
|
339
|
-
},
|
|
340
|
-
onDelta: (event) => {
|
|
341
|
-
handleDelta(runtime, emit, event);
|
|
342
|
-
},
|
|
343
|
-
onSessionEvent: (event) => {
|
|
344
|
-
handleSession(runtime, emit, event);
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
void streamTask
|
|
349
|
-
.then((result) => {
|
|
350
|
-
closeDelta(runtime, emit);
|
|
351
|
-
emitFallbackReplyIfNeeded(runtime, emit, result.reply);
|
|
352
|
-
emitRunMetadata(emit, clientRunId, buildFinalMetadata(result, runtime.hasAssistantSessionEvent));
|
|
353
|
-
emit({
|
|
354
|
-
type: EventType.RUN_FINISHED,
|
|
355
|
-
runId: clientRunId
|
|
356
|
-
});
|
|
357
|
-
subscriber.complete();
|
|
358
|
-
})
|
|
359
|
-
.catch((error) => {
|
|
360
|
-
closeDelta(runtime, emit);
|
|
361
|
-
if (!isAbortLikeError(error)) {
|
|
362
|
-
emit({
|
|
363
|
-
type: EventType.RUN_ERROR,
|
|
364
|
-
runId: clientRunId,
|
|
365
|
-
error: error instanceof Error ? error.message : String(error)
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
subscriber.complete();
|
|
369
|
-
})
|
|
370
|
-
.finally(() => {
|
|
371
|
-
this.finalizeRunState(abortController, runState);
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
return () => {
|
|
375
|
-
disposed = true;
|
|
376
|
-
abortController.abort();
|
|
377
|
-
if (this.activeAbortController === abortController) {
|
|
378
|
-
this.activeAbortController = null;
|
|
379
|
-
}
|
|
380
|
-
};
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
abortRun = () => {
|
|
384
|
-
const activeRunState = this.activeRunState;
|
|
385
|
-
if (activeRunState?.backendStopSupported) {
|
|
386
|
-
void requestStopRun(activeRunState);
|
|
387
|
-
}
|
|
388
|
-
this.activeAbortController?.abort();
|
|
389
|
-
this.activeAbortController = null;
|
|
390
|
-
this.activeRunState = null;
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
run = (input: RunAgentInput): Subscribable<AgentEvent> => {
|
|
394
|
-
const metadata = readRunMetadata(input);
|
|
395
|
-
const clientRunId = typeof input.runId === 'string' && input.runId.trim() ? input.runId : `run-${Date.now()}`;
|
|
396
|
-
if (!metadata) {
|
|
397
|
-
return this.buildMissingMetadataObservable(clientRunId);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
const normalizedMetadata = withEnsuredSendRunId(metadata);
|
|
401
|
-
this.abortRun();
|
|
402
|
-
const abortController = new AbortController();
|
|
403
|
-
this.activeAbortController = abortController;
|
|
404
|
-
const runState = buildInitialRunState(normalizedMetadata);
|
|
405
|
-
this.activeRunState = runState;
|
|
406
|
-
return this.createRunObservable({
|
|
407
|
-
metadata: normalizedMetadata,
|
|
408
|
-
clientRunId,
|
|
409
|
-
abortController,
|
|
410
|
-
runState
|
|
411
|
-
});
|
|
412
|
-
};
|
|
413
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { EventType, type AgentEvent } from '@nextclaw/agent-chat';
|
|
2
|
-
import type { SessionEventView } from '@/api/types';
|
|
3
|
-
|
|
4
|
-
export function buildDeltaEvents(params: { messageId: string; delta: string; started: boolean }): AgentEvent[] {
|
|
5
|
-
if (!params.delta) {
|
|
6
|
-
return [];
|
|
7
|
-
}
|
|
8
|
-
if (params.started) {
|
|
9
|
-
return [{ type: EventType.TEXT_DELTA, messageId: params.messageId, delta: params.delta }];
|
|
10
|
-
}
|
|
11
|
-
return [
|
|
12
|
-
{ type: EventType.TEXT_START, messageId: params.messageId },
|
|
13
|
-
{ type: EventType.TEXT_DELTA, messageId: params.messageId, delta: params.delta }
|
|
14
|
-
];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function shouldCloseDeltaOnSessionEvent(event: SessionEventView): boolean {
|
|
18
|
-
void event;
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function isAssistantSessionEvent(event: SessionEventView): boolean {
|
|
23
|
-
const role = event.message?.role?.toLowerCase().trim();
|
|
24
|
-
return role === 'assistant';
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function buildSessionEventEvents(params: { event: SessionEventView; messageId: string }): AgentEvent[] {
|
|
28
|
-
const { event, messageId } = params;
|
|
29
|
-
const message = event.message;
|
|
30
|
-
if (!message) {
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
const role = message.role?.toLowerCase().trim();
|
|
34
|
-
if (!role) {
|
|
35
|
-
return [];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const events: AgentEvent[] = [];
|
|
39
|
-
|
|
40
|
-
if (typeof message.reasoning_content === 'string' && message.reasoning_content.trim()) {
|
|
41
|
-
events.push({ type: EventType.REASONING_START, messageId });
|
|
42
|
-
events.push({
|
|
43
|
-
type: EventType.REASONING_DELTA,
|
|
44
|
-
messageId,
|
|
45
|
-
delta: message.reasoning_content.trim()
|
|
46
|
-
});
|
|
47
|
-
events.push({ type: EventType.REASONING_END, messageId });
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (Array.isArray(message.tool_calls)) {
|
|
51
|
-
for (let index = 0; index < message.tool_calls.length; index += 1) {
|
|
52
|
-
const call = message.tool_calls[index];
|
|
53
|
-
if (!call || typeof call !== 'object') {
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
const callRecord = call as Record<string, unknown>;
|
|
57
|
-
const fnValue = callRecord.function;
|
|
58
|
-
const fn = typeof fnValue === 'object' && fnValue ? (fnValue as { name?: unknown; arguments?: unknown }) : null;
|
|
59
|
-
const seqPrefix = typeof event.seq === 'number' ? String(event.seq) : 'unknown';
|
|
60
|
-
const toolCallId = typeof callRecord.id === 'string' ? callRecord.id : `tool-${seqPrefix}-${index}`;
|
|
61
|
-
const toolName = typeof fn?.name === 'string' ? fn.name : typeof callRecord.name === 'string' ? callRecord.name : 'tool';
|
|
62
|
-
const rawArgs = fn?.arguments ?? callRecord.arguments ?? '';
|
|
63
|
-
const args = typeof rawArgs === 'string' ? rawArgs : JSON.stringify(rawArgs ?? {});
|
|
64
|
-
events.push({
|
|
65
|
-
type: EventType.TOOL_CALL_START,
|
|
66
|
-
messageId,
|
|
67
|
-
toolCallId,
|
|
68
|
-
toolName
|
|
69
|
-
});
|
|
70
|
-
events.push({
|
|
71
|
-
type: EventType.TOOL_CALL_ARGS,
|
|
72
|
-
toolCallId,
|
|
73
|
-
args
|
|
74
|
-
});
|
|
75
|
-
events.push({
|
|
76
|
-
type: EventType.TOOL_CALL_END,
|
|
77
|
-
toolCallId
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (role === 'tool' || role === 'tool_result' || role === 'toolresult' || role === 'function') {
|
|
83
|
-
const toolCallId = typeof message.tool_call_id === 'string' ? message.tool_call_id.trim() : '';
|
|
84
|
-
if (toolCallId) {
|
|
85
|
-
events.push({
|
|
86
|
-
type: EventType.TOOL_CALL_RESULT,
|
|
87
|
-
toolCallId,
|
|
88
|
-
content: message.content
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return events;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export function buildDeltaMessageId(): string {
|
|
97
|
-
return `stream-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
98
|
-
}
|