@blade-hq/agent-react 2608.0.5-beta.0 → 2608.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -154
- package/dist/components/AssistantTurnBlock.d.ts +1 -1
- package/dist/components/ChatView.d.ts +39 -20
- package/dist/components/FileCard.d.ts +16 -0
- package/dist/components/MarkdownContent.d.ts +6 -3
- package/dist/components/MessageList.d.ts +3 -10
- package/dist/embed/entry.d.ts +0 -4
- package/dist/index.d.ts +1 -14
- package/dist/index.js +484 -1663
- package/dist/index.js.map +1 -1
- package/dist/lib/media-tags.d.ts +24 -0
- package/dist/style.full.css +1 -1
- package/package.json +2 -2
- package/public-api.md +4 -416
- package/dist/components/AgentChat.d.ts +0 -21
- package/dist/components/ChatSurface.d.ts +0 -68
- package/dist/components/LlmAdvancedSettings.d.ts +0 -40
- package/dist/components/LlmChat.d.ts +0 -29
- package/dist/components/PostChatFollowupBlock.d.ts +0 -59
- package/dist/components/ReplayBar.d.ts +0 -13
- package/dist/components/ReplayMismatchPrompt.d.ts +0 -8
- package/dist/hooks/use-llm-chat.d.ts +0 -57
- package/dist/hooks/use-replay.d.ts +0 -50
package/dist/index.js
CHANGED
|
@@ -99,453 +99,8 @@ function useAgentSession(sessionId, options = {}) {
|
|
|
99
99
|
return { session, state, error };
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
// src/
|
|
103
|
-
import {
|
|
104
|
-
import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";
|
|
105
|
-
var replayCreating = /* @__PURE__ */ new Set();
|
|
106
|
-
function useReplay(session) {
|
|
107
|
-
const client = useBladeClient();
|
|
108
|
-
const sessionId = session?.sessionId ?? null;
|
|
109
|
-
const [replay, setReplay] = useState2(null);
|
|
110
|
-
const [viewerRole, setViewerRole] = useState2(null);
|
|
111
|
-
const [sourceRunning, setSourceRunning] = useState2(false);
|
|
112
|
-
const [mismatch, setMismatch] = useState2(null);
|
|
113
|
-
const [preview, setPreview] = useState2({ status: "loading" });
|
|
114
|
-
const [isStarting, setIsStarting] = useState2(false);
|
|
115
|
-
const [error, setError] = useState2(null);
|
|
116
|
-
const [draftSpeed, setDraftSpeed] = useState2(DEFAULT_REPLAY_SPEED);
|
|
117
|
-
useEffect2(() => {
|
|
118
|
-
if (!session) {
|
|
119
|
-
setReplay(null);
|
|
120
|
-
setViewerRole(null);
|
|
121
|
-
setSourceRunning(false);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
const pull = () => {
|
|
125
|
-
const state = session.getState();
|
|
126
|
-
setReplay(state.replay);
|
|
127
|
-
setViewerRole(state.viewerRole);
|
|
128
|
-
setSourceRunning(state.isStreaming || state.status === "running");
|
|
129
|
-
};
|
|
130
|
-
pull();
|
|
131
|
-
return session.subscribe(pull);
|
|
132
|
-
}, [session]);
|
|
133
|
-
const [lastSessionId, setLastSessionId] = useState2(sessionId);
|
|
134
|
-
if (sessionId !== lastSessionId) {
|
|
135
|
-
setLastSessionId(sessionId);
|
|
136
|
-
setMismatch(null);
|
|
137
|
-
setError(null);
|
|
138
|
-
setDraftSpeed(DEFAULT_REPLAY_SPEED);
|
|
139
|
-
}
|
|
140
|
-
useEffect2(() => {
|
|
141
|
-
setPreview({ status: "loading" });
|
|
142
|
-
if (!sessionId) return;
|
|
143
|
-
let alive = true;
|
|
144
|
-
client.sessions.getReplayPreview(sessionId).then((result) => {
|
|
145
|
-
if (!alive) return;
|
|
146
|
-
setPreview({
|
|
147
|
-
status: "ready",
|
|
148
|
-
supported: result.supported,
|
|
149
|
-
reason: result.reason ?? null
|
|
150
|
-
});
|
|
151
|
-
}).catch(() => {
|
|
152
|
-
if (alive) setPreview({ status: "ready", supported: true, reason: null });
|
|
153
|
-
});
|
|
154
|
-
return () => {
|
|
155
|
-
alive = false;
|
|
156
|
-
};
|
|
157
|
-
}, [client, sessionId, sourceRunning]);
|
|
158
|
-
useEffect2(() => {
|
|
159
|
-
if (!session) return;
|
|
160
|
-
return session.on("replayMismatch", ({ actualMessage, expectedMessage, respond }) => {
|
|
161
|
-
setMismatch({
|
|
162
|
-
actualMessage: actualMessage ?? "",
|
|
163
|
-
expectedMessage: expectedMessage ?? "",
|
|
164
|
-
resolve: (decision) => {
|
|
165
|
-
setMismatch(null);
|
|
166
|
-
respond(decision);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
}, [session]);
|
|
171
|
-
const isReplay = replay?.isReplay ?? false;
|
|
172
|
-
const setSpeed = useCallback(
|
|
173
|
-
async (next) => {
|
|
174
|
-
setDraftSpeed(next);
|
|
175
|
-
if (!session) return;
|
|
176
|
-
setError(null);
|
|
177
|
-
try {
|
|
178
|
-
await session.setReplaySpeed(next);
|
|
179
|
-
} catch (err) {
|
|
180
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
[session]
|
|
184
|
-
);
|
|
185
|
-
const exitToAutonomous = useCallback(async () => {
|
|
186
|
-
if (!session) return;
|
|
187
|
-
setError(null);
|
|
188
|
-
const pending = mismatch;
|
|
189
|
-
if (pending) {
|
|
190
|
-
pending.resolve("continue_replay");
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
try {
|
|
194
|
-
await session.exitReplay();
|
|
195
|
-
} catch (err) {
|
|
196
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
197
|
-
}
|
|
198
|
-
}, [session, mismatch]);
|
|
199
|
-
const startReplay = useCallback(
|
|
200
|
-
async (speed) => {
|
|
201
|
-
if (!sessionId) throw new Error("\u5F53\u524D\u6CA1\u6709\u53EF\u56DE\u653E\u7684\u4F1A\u8BDD");
|
|
202
|
-
if (replayCreating.has(sessionId)) throw new Error("\u6B63\u5728\u521B\u5EFA\u56DE\u653E\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u5019");
|
|
203
|
-
replayCreating.add(sessionId);
|
|
204
|
-
setIsStarting(true);
|
|
205
|
-
setError(null);
|
|
206
|
-
try {
|
|
207
|
-
const result = await client.sessions.startReplaySession(sessionId, speed ?? draftSpeed);
|
|
208
|
-
return result.session_id;
|
|
209
|
-
} catch (err) {
|
|
210
|
-
const failure = err instanceof Error ? err : new Error(String(err));
|
|
211
|
-
setError(failure);
|
|
212
|
-
throw failure;
|
|
213
|
-
} finally {
|
|
214
|
-
replayCreating.delete(sessionId);
|
|
215
|
-
setIsStarting(false);
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
|
-
[client, sessionId, draftSpeed]
|
|
219
|
-
);
|
|
220
|
-
return {
|
|
221
|
-
isReplay,
|
|
222
|
-
speed: isReplay ? replay?.speed ?? 1 : draftSpeed,
|
|
223
|
-
setSpeed,
|
|
224
|
-
exitToAutonomous,
|
|
225
|
-
mismatch,
|
|
226
|
-
canControl: viewerRole !== "viewer",
|
|
227
|
-
canReplay: Boolean(sessionId) && preview.status === "ready" && preview.supported && viewerRole !== "viewer",
|
|
228
|
-
unsupportedReason: preview.status === "ready" && !preview.supported ? preview.reason : null,
|
|
229
|
-
startReplay,
|
|
230
|
-
isStarting,
|
|
231
|
-
error
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// src/hooks/use-llm-chat.ts
|
|
236
|
-
import { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2, useState as useState3 } from "react";
|
|
237
|
-
var DEFAULT_HISTORY_TURNS = 12;
|
|
238
|
-
var DEFAULT_MAX_TOOL_ROUNDS = 4;
|
|
239
|
-
var syntheticIdSeq = 0;
|
|
240
|
-
function useLlmChat(options) {
|
|
241
|
-
const [history, setHistory] = useState3([]);
|
|
242
|
-
const [streamingText, setStreamingText] = useState3(null);
|
|
243
|
-
const [streamingCalls, setStreamingCalls] = useState3([]);
|
|
244
|
-
const [failedToolIds, setFailedToolIds] = useState3([]);
|
|
245
|
-
const [error, setError] = useState3(null);
|
|
246
|
-
const [isStreaming, setIsStreaming] = useState3(false);
|
|
247
|
-
const abortRef = useRef2(null);
|
|
248
|
-
const generationRef = useRef2(0);
|
|
249
|
-
const historyRef = useRef2([]);
|
|
250
|
-
const optionsRef = useRef2(options);
|
|
251
|
-
optionsRef.current = options;
|
|
252
|
-
historyRef.current = history;
|
|
253
|
-
const stop = useCallback2(() => {
|
|
254
|
-
abortRef.current?.abort();
|
|
255
|
-
abortRef.current = null;
|
|
256
|
-
}, []);
|
|
257
|
-
const reset = useCallback2(() => {
|
|
258
|
-
generationRef.current += 1;
|
|
259
|
-
stop();
|
|
260
|
-
setHistory([]);
|
|
261
|
-
setStreamingText(null);
|
|
262
|
-
setStreamingCalls([]);
|
|
263
|
-
setFailedToolIds([]);
|
|
264
|
-
setError(null);
|
|
265
|
-
setIsStreaming(false);
|
|
266
|
-
}, [stop]);
|
|
267
|
-
const send = useCallback2(async (text) => {
|
|
268
|
-
const content = text.trim();
|
|
269
|
-
if (!content || abortRef.current) return false;
|
|
270
|
-
const opts = optionsRef.current;
|
|
271
|
-
const maxRounds = opts.maxToolRounds ?? DEFAULT_MAX_TOOL_ROUNDS;
|
|
272
|
-
const commit = (message) => {
|
|
273
|
-
historyRef.current = [...historyRef.current, message];
|
|
274
|
-
setHistory(historyRef.current);
|
|
275
|
-
};
|
|
276
|
-
setError(null);
|
|
277
|
-
setIsStreaming(true);
|
|
278
|
-
setStreamingText("");
|
|
279
|
-
setStreamingCalls([]);
|
|
280
|
-
commit({ role: "user", content });
|
|
281
|
-
let partial = "";
|
|
282
|
-
const controller = new AbortController();
|
|
283
|
-
abortRef.current = controller;
|
|
284
|
-
const generation = generationRef.current;
|
|
285
|
-
try {
|
|
286
|
-
for (let round = 0; ; round += 1) {
|
|
287
|
-
const result = await streamOnce(opts, historyRef.current, controller.signal, {
|
|
288
|
-
onText: (chunk) => {
|
|
289
|
-
partial += chunk;
|
|
290
|
-
setStreamingText((prev) => `${prev ?? ""}${chunk}`);
|
|
291
|
-
},
|
|
292
|
-
onToolCalls: (calls) => setStreamingCalls(calls)
|
|
293
|
-
});
|
|
294
|
-
const assistant = {
|
|
295
|
-
role: "assistant",
|
|
296
|
-
content: result.content,
|
|
297
|
-
...result.toolCalls.length ? { tool_calls: result.toolCalls } : {}
|
|
298
|
-
};
|
|
299
|
-
setStreamingText(null);
|
|
300
|
-
setStreamingCalls([]);
|
|
301
|
-
commit(assistant);
|
|
302
|
-
if (!result.toolCalls.length) return true;
|
|
303
|
-
const bail = (reason) => {
|
|
304
|
-
for (const call of result.toolCalls) {
|
|
305
|
-
commit({ role: "tool", tool_call_id: call.id, content: JSON.stringify({ error: reason }) });
|
|
306
|
-
}
|
|
307
|
-
setFailedToolIds((prev) => [...prev, ...result.toolCalls.map((call) => call.id)]);
|
|
308
|
-
};
|
|
309
|
-
if (!opts.onToolCall) {
|
|
310
|
-
bail("\u8FD9\u4E2A\u5E94\u7528\u6CA1\u6709\u63D0\u4F9B\u5DE5\u5177\u6267\u884C\u5165\u53E3");
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
if (round >= maxRounds) {
|
|
314
|
-
bail(`\u5DE5\u5177\u8C03\u7528\u5DF2\u8FBE\u4E0A\u9650 ${maxRounds} \u8F6E\uFF0C\u6CA1\u6709\u6267\u884C`);
|
|
315
|
-
setError(`\u5DE5\u5177\u8C03\u7528\u8D85\u8FC7 ${maxRounds} \u8F6E\u4ECD\u672A\u7ED9\u51FA\u7ED3\u8BBA\uFF0C\u5DF2\u505C\u4E0B\u3002`);
|
|
316
|
-
return false;
|
|
317
|
-
}
|
|
318
|
-
for (const call of result.toolCalls) {
|
|
319
|
-
let output;
|
|
320
|
-
try {
|
|
321
|
-
const value = await opts.onToolCall({
|
|
322
|
-
id: call.id,
|
|
323
|
-
name: call.function.name,
|
|
324
|
-
arguments: call.function.arguments
|
|
325
|
-
});
|
|
326
|
-
output = typeof value === "string" ? value : JSON.stringify(value ?? null);
|
|
327
|
-
} catch (err) {
|
|
328
|
-
output = JSON.stringify({ error: err instanceof Error ? err.message : String(err) });
|
|
329
|
-
setFailedToolIds((prev) => [...prev, call.id]);
|
|
330
|
-
}
|
|
331
|
-
commit({ role: "tool", tool_call_id: call.id, content: output });
|
|
332
|
-
}
|
|
333
|
-
setStreamingText("");
|
|
334
|
-
}
|
|
335
|
-
} catch (err) {
|
|
336
|
-
setStreamingText(null);
|
|
337
|
-
setStreamingCalls([]);
|
|
338
|
-
if (controller.signal.aborted) {
|
|
339
|
-
if (generation !== generationRef.current) return false;
|
|
340
|
-
commit({ role: "assistant", content: partial ? `${partial}\uFF08\u5DF2\u505C\u6B62\uFF09` : "\uFF08\u5DF2\u505C\u6B62\uFF09" });
|
|
341
|
-
return false;
|
|
342
|
-
}
|
|
343
|
-
if (partial && generation === generationRef.current) {
|
|
344
|
-
commit({ role: "assistant", content: partial });
|
|
345
|
-
}
|
|
346
|
-
setError(err instanceof Error && err.message ? err.message : "\u5BF9\u8BDD\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
|
|
347
|
-
return false;
|
|
348
|
-
} finally {
|
|
349
|
-
if (abortRef.current === controller) abortRef.current = null;
|
|
350
|
-
setIsStreaming(false);
|
|
351
|
-
}
|
|
352
|
-
}, []);
|
|
353
|
-
const messages = useMemo2(
|
|
354
|
-
() => toChatMessages(history, streamingText, streamingCalls, failedToolIds),
|
|
355
|
-
[history, streamingText, streamingCalls, failedToolIds]
|
|
356
|
-
);
|
|
357
|
-
return { messages, isStreaming, error, send, stop, reset };
|
|
358
|
-
}
|
|
359
|
-
async function streamOnce(options, history, signal, handlers) {
|
|
360
|
-
const {
|
|
361
|
-
baseURL,
|
|
362
|
-
model,
|
|
363
|
-
apiKey,
|
|
364
|
-
headers,
|
|
365
|
-
system,
|
|
366
|
-
historyTurns = DEFAULT_HISTORY_TURNS,
|
|
367
|
-
temperature,
|
|
368
|
-
extraBody,
|
|
369
|
-
tools,
|
|
370
|
-
fetchImpl
|
|
371
|
-
} = options;
|
|
372
|
-
const trimmed = trimHistory(history, historyTurns);
|
|
373
|
-
const payload = {
|
|
374
|
-
model,
|
|
375
|
-
stream: true,
|
|
376
|
-
messages: system ? [{ role: "system", content: system }, ...trimmed] : trimmed,
|
|
377
|
-
...tools?.length ? { tools } : {},
|
|
378
|
-
...temperature === void 0 ? {} : { temperature },
|
|
379
|
-
...extraBody
|
|
380
|
-
};
|
|
381
|
-
const doFetch = fetchImpl ?? globalThis.fetch;
|
|
382
|
-
const url = `${baseURL.replace(/\/$/, "")}/chat/completions`;
|
|
383
|
-
let response;
|
|
384
|
-
try {
|
|
385
|
-
response = await doFetch(url, {
|
|
386
|
-
method: "POST",
|
|
387
|
-
headers: {
|
|
388
|
-
"Content-Type": "application/json",
|
|
389
|
-
...apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
|
|
390
|
-
...headers
|
|
391
|
-
},
|
|
392
|
-
body: JSON.stringify(payload),
|
|
393
|
-
signal
|
|
394
|
-
});
|
|
395
|
-
} catch (err) {
|
|
396
|
-
if (signal.aborted) throw err;
|
|
397
|
-
throw new Error(`\u8FDE\u4E0D\u4E0A\u6A21\u578B\u670D\u52A1 ${url}\uFF1A${err instanceof Error ? err.message : String(err)}`);
|
|
398
|
-
}
|
|
399
|
-
if (!response.ok) {
|
|
400
|
-
throw new Error(await describeHttpError(response));
|
|
401
|
-
}
|
|
402
|
-
if (!response.body) {
|
|
403
|
-
throw new Error("\u6A21\u578B\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6D41\u5F0F\u54CD\u5E94");
|
|
404
|
-
}
|
|
405
|
-
let content = "";
|
|
406
|
-
const calls = [];
|
|
407
|
-
for await (const chunk of readSse(response.body, signal)) {
|
|
408
|
-
if (chunk.error) {
|
|
409
|
-
throw new Error(chunk.error);
|
|
410
|
-
}
|
|
411
|
-
if (chunk.text) {
|
|
412
|
-
content += chunk.text;
|
|
413
|
-
handlers.onText(chunk.text);
|
|
414
|
-
}
|
|
415
|
-
if (chunk.toolCallDeltas) {
|
|
416
|
-
for (const delta of chunk.toolCallDeltas) {
|
|
417
|
-
const index = delta.index ?? 0;
|
|
418
|
-
const existing = calls[index] ?? { id: "", type: "function", function: { name: "", arguments: "" } };
|
|
419
|
-
calls[index] = {
|
|
420
|
-
id: delta.id ?? existing.id,
|
|
421
|
-
type: "function",
|
|
422
|
-
function: {
|
|
423
|
-
name: delta.function?.name ?? existing.function.name,
|
|
424
|
-
arguments: `${existing.function.arguments}${delta.function?.arguments ?? ""}`
|
|
425
|
-
}
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
handlers.onToolCalls(calls.filter(Boolean).map((call) => ({ ...call })));
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
const normalized = calls.filter(Boolean).filter((call) => call.function.name).map((call) => {
|
|
432
|
-
if (call.id) return call;
|
|
433
|
-
syntheticIdSeq += 1;
|
|
434
|
-
return { ...call, id: `call_auto_${syntheticIdSeq}` };
|
|
435
|
-
});
|
|
436
|
-
return { content, toolCalls: normalized };
|
|
437
|
-
}
|
|
438
|
-
function trimHistory(history, historyTurns) {
|
|
439
|
-
const userIndexes = history.reduce((acc, msg, i) => {
|
|
440
|
-
if (msg.role === "user") acc.push(i);
|
|
441
|
-
return acc;
|
|
442
|
-
}, []);
|
|
443
|
-
if (userIndexes.length <= historyTurns) return history;
|
|
444
|
-
return history.slice(userIndexes[userIndexes.length - historyTurns]);
|
|
445
|
-
}
|
|
446
|
-
async function describeHttpError(response) {
|
|
447
|
-
const raw = await response.text().catch(() => "");
|
|
448
|
-
try {
|
|
449
|
-
const parsed = JSON.parse(raw);
|
|
450
|
-
const message = typeof parsed.error === "string" ? parsed.error : parsed.error?.message ?? (typeof parsed.detail === "string" ? parsed.detail : void 0);
|
|
451
|
-
if (message) return `\u6A21\u578B\u670D\u52A1\u8FD4\u56DE ${response.status}\uFF1A${message}`;
|
|
452
|
-
} catch {
|
|
453
|
-
}
|
|
454
|
-
const snippet = raw.trim().slice(0, 120);
|
|
455
|
-
return snippet ? `\u6A21\u578B\u670D\u52A1\u8FD4\u56DE ${response.status}\uFF1A${snippet}` : `\u6A21\u578B\u670D\u52A1\u8FD4\u56DE ${response.status}`;
|
|
456
|
-
}
|
|
457
|
-
async function* readSse(stream, signal) {
|
|
458
|
-
const reader = stream.getReader();
|
|
459
|
-
const decoder = new TextDecoder();
|
|
460
|
-
let buffer = "";
|
|
461
|
-
try {
|
|
462
|
-
while (!signal.aborted) {
|
|
463
|
-
const { done, value } = await reader.read();
|
|
464
|
-
if (done) {
|
|
465
|
-
const tail = parseSse(buffer);
|
|
466
|
-
if (tail && tail !== "done") yield tail;
|
|
467
|
-
break;
|
|
468
|
-
}
|
|
469
|
-
buffer = `${buffer}${decoder.decode(value, { stream: true })}`.replace(/\r\n/g, "\n");
|
|
470
|
-
let boundary = buffer.indexOf("\n\n");
|
|
471
|
-
while (boundary !== -1) {
|
|
472
|
-
const chunk = parseSse(buffer.slice(0, boundary));
|
|
473
|
-
buffer = buffer.slice(boundary + 2);
|
|
474
|
-
if (chunk === "done") return;
|
|
475
|
-
if (chunk) yield chunk;
|
|
476
|
-
boundary = buffer.indexOf("\n\n");
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
} finally {
|
|
480
|
-
reader.cancel().catch(() => {
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
function parseSse(raw) {
|
|
485
|
-
const dataLines = [];
|
|
486
|
-
for (const line of raw.split("\n")) {
|
|
487
|
-
if (line.startsWith("data:")) dataLines.push(line.slice(5).trim());
|
|
488
|
-
}
|
|
489
|
-
if (!dataLines.length) return null;
|
|
490
|
-
const data = dataLines.join("\n");
|
|
491
|
-
if (data === "[DONE]") return "done";
|
|
492
|
-
let parsed;
|
|
493
|
-
try {
|
|
494
|
-
parsed = JSON.parse(data);
|
|
495
|
-
} catch {
|
|
496
|
-
return null;
|
|
497
|
-
}
|
|
498
|
-
if (parsed.error) {
|
|
499
|
-
const message = typeof parsed.error === "string" ? parsed.error : parsed.error.message;
|
|
500
|
-
return { error: message || "\u6A21\u578B\u670D\u52A1\u8FD4\u56DE\u4E86\u9519\u8BEF" };
|
|
501
|
-
}
|
|
502
|
-
const delta = parsed.choices?.[0]?.delta;
|
|
503
|
-
if (!delta) return null;
|
|
504
|
-
return { text: delta.content, toolCallDeltas: delta.tool_calls };
|
|
505
|
-
}
|
|
506
|
-
function toChatMessages(history, streamingText, streamingCalls, failedToolIds) {
|
|
507
|
-
const results = /* @__PURE__ */ new Map();
|
|
508
|
-
for (const msg of history) {
|
|
509
|
-
if (msg.role === "tool") results.set(msg.tool_call_id, msg.content);
|
|
510
|
-
}
|
|
511
|
-
const messages = [];
|
|
512
|
-
for (const msg of history) {
|
|
513
|
-
if (msg.role === "tool") continue;
|
|
514
|
-
if (msg.role === "user") {
|
|
515
|
-
messages.push({ role: "user", content: msg.content, status: "completed" });
|
|
516
|
-
continue;
|
|
517
|
-
}
|
|
518
|
-
messages.push({
|
|
519
|
-
role: "assistant",
|
|
520
|
-
content: msg.content,
|
|
521
|
-
status: "completed",
|
|
522
|
-
...msg.tool_calls?.length ? { tool_calls: msg.tool_calls.map((call) => toToolCallInfo(call, results, failedToolIds)) } : {}
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
if (streamingText !== null) {
|
|
526
|
-
messages.push({
|
|
527
|
-
role: "assistant",
|
|
528
|
-
content: streamingText,
|
|
529
|
-
status: "streaming",
|
|
530
|
-
...streamingCalls.length ? { tool_calls: streamingCalls.map((call) => toToolCallInfo(call, results, failedToolIds)) } : {}
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
return messages;
|
|
534
|
-
}
|
|
535
|
-
function toToolCallInfo(call, results, failedToolIds) {
|
|
536
|
-
const result = results.get(call.id);
|
|
537
|
-
const failed = failedToolIds.includes(call.id);
|
|
538
|
-
return {
|
|
539
|
-
id: call.id,
|
|
540
|
-
name: call.function.name,
|
|
541
|
-
arguments: call.function.arguments,
|
|
542
|
-
...result === void 0 ? {} : { result },
|
|
543
|
-
status: result === void 0 ? "pending" : failed ? "error" : "done"
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// src/components/AgentChat.tsx
|
|
548
|
-
import { BladeApiError, latestPostChatFollowup } from "@blade-hq/agent-client";
|
|
102
|
+
// src/components/ChatView.tsx
|
|
103
|
+
import { BladeApiError } from "@blade-hq/agent-client";
|
|
549
104
|
|
|
550
105
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/createLucideIcon.js
|
|
551
106
|
import { forwardRef as forwardRef2, createElement as createElement2 } from "react";
|
|
@@ -618,16 +173,11 @@ var createLucideIcon = (iconName, iconNode) => {
|
|
|
618
173
|
return Component2;
|
|
619
174
|
};
|
|
620
175
|
|
|
621
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/
|
|
622
|
-
var
|
|
623
|
-
["
|
|
624
|
-
["path", { d: "
|
|
625
|
-
]
|
|
626
|
-
|
|
627
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/arrow-up-right.js
|
|
628
|
-
var ArrowUpRight = createLucideIcon("ArrowUpRight", [
|
|
629
|
-
["path", { d: "M7 7h10v10", key: "1tivn9" }],
|
|
630
|
-
["path", { d: "M7 17 17 7", key: "1vkiza" }]
|
|
176
|
+
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/archive.js
|
|
177
|
+
var Archive = createLucideIcon("Archive", [
|
|
178
|
+
["rect", { width: "20", height: "5", x: "2", y: "3", rx: "1", key: "1wp1u1" }],
|
|
179
|
+
["path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8", key: "1s80jp" }],
|
|
180
|
+
["path", { d: "M10 12h4", key: "a56b0p" }]
|
|
631
181
|
]);
|
|
632
182
|
|
|
633
183
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/arrow-up.js
|
|
@@ -704,6 +254,24 @@ var Download = createLucideIcon("Download", [
|
|
|
704
254
|
["line", { x1: "12", x2: "12", y1: "15", y2: "3", key: "1vk2je" }]
|
|
705
255
|
]);
|
|
706
256
|
|
|
257
|
+
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-code-2.js
|
|
258
|
+
var FileCode2 = createLucideIcon("FileCode2", [
|
|
259
|
+
["path", { d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4", key: "1pf5j1" }],
|
|
260
|
+
["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
|
|
261
|
+
["path", { d: "m5 12-3 3 3 3", key: "oke12k" }],
|
|
262
|
+
["path", { d: "m9 18 3-3-3-3", key: "112psh" }]
|
|
263
|
+
]);
|
|
264
|
+
|
|
265
|
+
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-spreadsheet.js
|
|
266
|
+
var FileSpreadsheet = createLucideIcon("FileSpreadsheet", [
|
|
267
|
+
["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
|
|
268
|
+
["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
|
|
269
|
+
["path", { d: "M8 13h2", key: "yr2amv" }],
|
|
270
|
+
["path", { d: "M14 13h2", key: "un5t4a" }],
|
|
271
|
+
["path", { d: "M8 17h2", key: "2yhykz" }],
|
|
272
|
+
["path", { d: "M14 17h2", key: "10kma7" }]
|
|
273
|
+
]);
|
|
274
|
+
|
|
707
275
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-text.js
|
|
708
276
|
var FileText = createLucideIcon("FileText", [
|
|
709
277
|
["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
|
|
@@ -731,11 +299,11 @@ var Film = createLucideIcon("Film", [
|
|
|
731
299
|
["path", { d: "M17 16.5h4", key: "go4c1d" }]
|
|
732
300
|
]);
|
|
733
301
|
|
|
734
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/
|
|
735
|
-
var
|
|
736
|
-
["
|
|
737
|
-
["
|
|
738
|
-
["path", { d: "
|
|
302
|
+
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/image.js
|
|
303
|
+
var Image = createLucideIcon("Image", [
|
|
304
|
+
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
|
|
305
|
+
["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
|
|
306
|
+
["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
|
|
739
307
|
]);
|
|
740
308
|
|
|
741
309
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/layers.js
|
|
@@ -801,32 +369,11 @@ var MessageSquare = createLucideIcon("MessageSquare", [
|
|
|
801
369
|
["path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z", key: "1lielz" }]
|
|
802
370
|
]);
|
|
803
371
|
|
|
804
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/
|
|
805
|
-
var
|
|
806
|
-
["
|
|
807
|
-
]
|
|
808
|
-
|
|
809
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/settings-2.js
|
|
810
|
-
var Settings2 = createLucideIcon("Settings2", [
|
|
811
|
-
["path", { d: "M20 7h-9", key: "3s1dr2" }],
|
|
812
|
-
["path", { d: "M14 17H5", key: "gfn3mx" }],
|
|
813
|
-
["circle", { cx: "17", cy: "17", r: "3", key: "18b49y" }],
|
|
814
|
-
["circle", { cx: "7", cy: "7", r: "3", key: "dfmy0x" }]
|
|
815
|
-
]);
|
|
816
|
-
|
|
817
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/sparkles.js
|
|
818
|
-
var Sparkles = createLucideIcon("Sparkles", [
|
|
819
|
-
[
|
|
820
|
-
"path",
|
|
821
|
-
{
|
|
822
|
-
d: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",
|
|
823
|
-
key: "4pj2yx"
|
|
824
|
-
}
|
|
825
|
-
],
|
|
826
|
-
["path", { d: "M20 3v4", key: "1olli1" }],
|
|
827
|
-
["path", { d: "M22 5h-4", key: "1gvqau" }],
|
|
828
|
-
["path", { d: "M4 17v2", key: "vumght" }],
|
|
829
|
-
["path", { d: "M5 18H3", key: "zchphs" }]
|
|
372
|
+
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/music.js
|
|
373
|
+
var Music = createLucideIcon("Music", [
|
|
374
|
+
["path", { d: "M9 18V5l12-2v13", key: "1jmyc2" }],
|
|
375
|
+
["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
|
|
376
|
+
["circle", { cx: "18", cy: "16", r: "3", key: "1hluhg" }]
|
|
830
377
|
]);
|
|
831
378
|
|
|
832
379
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/square.js
|
|
@@ -853,8 +400,8 @@ var X = createLucideIcon("X", [
|
|
|
853
400
|
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
854
401
|
]);
|
|
855
402
|
|
|
856
|
-
// src/components/
|
|
857
|
-
import {
|
|
403
|
+
// src/components/ChatView.tsx
|
|
404
|
+
import { useEffect as useEffect6, useState as useState10 } from "react";
|
|
858
405
|
|
|
859
406
|
// src/lib/utils.ts
|
|
860
407
|
function cn(...inputs) {
|
|
@@ -869,120 +416,8 @@ async function copyToClipboard(text) {
|
|
|
869
416
|
}
|
|
870
417
|
}
|
|
871
418
|
|
|
872
|
-
// src/components/ReplayBar.tsx
|
|
873
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
874
|
-
var SPEED_OPTIONS = [1, 2, 5];
|
|
875
|
-
function ReplayBar({
|
|
876
|
-
isReplay,
|
|
877
|
-
speed,
|
|
878
|
-
onSpeedChange,
|
|
879
|
-
onExit,
|
|
880
|
-
canControl = true,
|
|
881
|
-
className
|
|
882
|
-
}) {
|
|
883
|
-
if (!isReplay) return null;
|
|
884
|
-
return /* @__PURE__ */ jsxs(
|
|
885
|
-
"div",
|
|
886
|
-
{
|
|
887
|
-
className: cn(
|
|
888
|
-
"flex flex-wrap items-center gap-2 border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))]/40 px-4 py-2 text-xs",
|
|
889
|
-
className
|
|
890
|
-
),
|
|
891
|
-
children: [
|
|
892
|
-
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 font-medium text-[hsl(var(--foreground))]", children: [
|
|
893
|
-
/* @__PURE__ */ jsx2(Play, { size: 13 }),
|
|
894
|
-
"\u56DE\u653E\u6A21\u5F0F"
|
|
895
|
-
] }),
|
|
896
|
-
/* @__PURE__ */ jsx2("span", { className: "text-[hsl(var(--muted-foreground))]", children: "\u6B63\u5728\u91CD\u73B0\u4E4B\u524D\u7684\u5BF9\u8BDD" }),
|
|
897
|
-
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2", children: [
|
|
898
|
-
/* @__PURE__ */ jsx2("div", { className: "flex items-center gap-0.5 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-0.5", children: SPEED_OPTIONS.map((option) => /* @__PURE__ */ jsxs(
|
|
899
|
-
"button",
|
|
900
|
-
{
|
|
901
|
-
type: "button",
|
|
902
|
-
onClick: () => onSpeedChange(option),
|
|
903
|
-
"aria-pressed": speed === option,
|
|
904
|
-
disabled: !canControl,
|
|
905
|
-
className: cn(
|
|
906
|
-
"h-6 rounded px-2 font-medium transition-colors",
|
|
907
|
-
speed === option ? "bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
|
|
908
|
-
!canControl && "cursor-not-allowed opacity-50"
|
|
909
|
-
),
|
|
910
|
-
children: [
|
|
911
|
-
option,
|
|
912
|
-
"x"
|
|
913
|
-
]
|
|
914
|
-
},
|
|
915
|
-
option
|
|
916
|
-
)) }),
|
|
917
|
-
/* @__PURE__ */ jsx2(
|
|
918
|
-
"button",
|
|
919
|
-
{
|
|
920
|
-
type: "button",
|
|
921
|
-
onClick: onExit,
|
|
922
|
-
disabled: !canControl,
|
|
923
|
-
className: cn(
|
|
924
|
-
"h-7 rounded-md border border-[hsl(var(--border))] px-2.5 text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
|
|
925
|
-
!canControl && "cursor-not-allowed opacity-50 hover:bg-transparent"
|
|
926
|
-
),
|
|
927
|
-
children: "\u9000\u51FA\u56DE\u653E"
|
|
928
|
-
}
|
|
929
|
-
)
|
|
930
|
-
] })
|
|
931
|
-
]
|
|
932
|
-
}
|
|
933
|
-
);
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
// src/components/ReplayMismatchPrompt.tsx
|
|
937
|
-
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
938
|
-
function ReplayMismatchPrompt({ mismatch, className }) {
|
|
939
|
-
if (!mismatch) return null;
|
|
940
|
-
return /* @__PURE__ */ jsxs2(
|
|
941
|
-
"div",
|
|
942
|
-
{
|
|
943
|
-
className: cn(
|
|
944
|
-
"mx-auto my-3 max-w-3xl rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-4 py-3 text-sm",
|
|
945
|
-
className
|
|
946
|
-
),
|
|
947
|
-
children: [
|
|
948
|
-
/* @__PURE__ */ jsx3("div", { className: "font-medium text-[hsl(var(--foreground))]", children: "\u8FD9\u53E5\u8BDD\u548C\u4E4B\u524D\u5F55\u5236\u7684\u4E0D\u4E00\u6837" }),
|
|
949
|
-
/* @__PURE__ */ jsxs2("dl", { className: "mt-2 space-y-1 text-xs text-[hsl(var(--muted-foreground))]", children: [
|
|
950
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex gap-2", children: [
|
|
951
|
-
/* @__PURE__ */ jsx3("dt", { className: "shrink-0", children: "\u5F55\u5236\u7684\u662F" }),
|
|
952
|
-
/* @__PURE__ */ jsx3("dd", { className: "min-w-0 break-words text-[hsl(var(--foreground))]", children: mismatch.expectedMessage || "\uFF08\u7A7A\uFF09" })
|
|
953
|
-
] }),
|
|
954
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex gap-2", children: [
|
|
955
|
-
/* @__PURE__ */ jsx3("dt", { className: "shrink-0", children: "\u4F60\u8F93\u5165\u7684" }),
|
|
956
|
-
/* @__PURE__ */ jsx3("dd", { className: "min-w-0 break-words text-[hsl(var(--foreground))]", children: mismatch.actualMessage || "\uFF08\u7A7A\uFF09" })
|
|
957
|
-
] })
|
|
958
|
-
] }),
|
|
959
|
-
/* @__PURE__ */ jsxs2("div", { className: "mt-3 flex flex-wrap gap-2", children: [
|
|
960
|
-
/* @__PURE__ */ jsx3(
|
|
961
|
-
"button",
|
|
962
|
-
{
|
|
963
|
-
type: "button",
|
|
964
|
-
onClick: () => mismatch.resolve("keep_replay"),
|
|
965
|
-
className: "h-8 rounded-md bg-[hsl(var(--primary))] px-3 text-xs font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90",
|
|
966
|
-
children: "\u6309\u5F55\u5236\u5185\u5BB9\u7EE7\u7EED"
|
|
967
|
-
}
|
|
968
|
-
),
|
|
969
|
-
/* @__PURE__ */ jsx3(
|
|
970
|
-
"button",
|
|
971
|
-
{
|
|
972
|
-
type: "button",
|
|
973
|
-
onClick: () => mismatch.resolve("continue_replay"),
|
|
974
|
-
className: "h-8 rounded-md border border-[hsl(var(--border))] px-3 text-xs text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
|
|
975
|
-
children: "\u4ECE\u8FD9\u91CC\u5F00\u59CB\u771F\u7684\u8FD0\u884C"
|
|
976
|
-
}
|
|
977
|
-
)
|
|
978
|
-
] })
|
|
979
|
-
]
|
|
980
|
-
}
|
|
981
|
-
);
|
|
982
|
-
}
|
|
983
|
-
|
|
984
419
|
// src/components/ChatInput.tsx
|
|
985
|
-
import { jsx as
|
|
420
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
986
421
|
function ChatInput({
|
|
987
422
|
value,
|
|
988
423
|
onValueChange,
|
|
@@ -1007,8 +442,8 @@ function ChatInput({
|
|
|
1007
442
|
void handleSend();
|
|
1008
443
|
}
|
|
1009
444
|
};
|
|
1010
|
-
return /* @__PURE__ */
|
|
1011
|
-
/* @__PURE__ */
|
|
445
|
+
return /* @__PURE__ */ jsx2("div", { className: cn("blade-chat-input border-t border-[hsl(var(--border))] py-3", className), children: /* @__PURE__ */ jsxs("div", { className: "blade-chat-input-inner mx-auto flex max-w-[748px] items-end gap-2 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2", children: [
|
|
446
|
+
/* @__PURE__ */ jsx2(
|
|
1012
447
|
"textarea",
|
|
1013
448
|
{
|
|
1014
449
|
value,
|
|
@@ -1025,7 +460,7 @@ function ChatInput({
|
|
|
1025
460
|
className: "blade-chat-textarea max-h-48 min-h-[28px] flex-1 resize-none bg-transparent py-1 text-sm leading-6 text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.6)]"
|
|
1026
461
|
}
|
|
1027
462
|
),
|
|
1028
|
-
isStreaming ? /* @__PURE__ */
|
|
463
|
+
isStreaming ? /* @__PURE__ */ jsx2(
|
|
1029
464
|
"button",
|
|
1030
465
|
{
|
|
1031
466
|
type: "button",
|
|
@@ -1034,9 +469,9 @@ function ChatInput({
|
|
|
1034
469
|
"aria-label": isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D",
|
|
1035
470
|
title: isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D",
|
|
1036
471
|
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--muted))] text-[hsl(var(--foreground))] transition-opacity hover:opacity-90 disabled:opacity-60",
|
|
1037
|
-
children: isStopping ? /* @__PURE__ */
|
|
472
|
+
children: isStopping ? /* @__PURE__ */ jsx2(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Square, { size: 12, fill: "currentColor" })
|
|
1038
473
|
}
|
|
1039
|
-
) : /* @__PURE__ */
|
|
474
|
+
) : /* @__PURE__ */ jsx2(
|
|
1040
475
|
"button",
|
|
1041
476
|
{
|
|
1042
477
|
type: "button",
|
|
@@ -1045,20 +480,20 @@ function ChatInput({
|
|
|
1045
480
|
"aria-label": "\u53D1\u9001\u6D88\u606F",
|
|
1046
481
|
title: "\u53D1\u9001\u6D88\u606F",
|
|
1047
482
|
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40",
|
|
1048
|
-
children: /* @__PURE__ */
|
|
483
|
+
children: /* @__PURE__ */ jsx2(ArrowUp, { size: 15 })
|
|
1049
484
|
}
|
|
1050
485
|
)
|
|
1051
486
|
] }) });
|
|
1052
487
|
}
|
|
1053
488
|
|
|
1054
489
|
// src/components/ConnectionBanner.tsx
|
|
1055
|
-
import { jsx as
|
|
490
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1056
491
|
function ConnectionBanner({ connection, className }) {
|
|
1057
492
|
if (connection === "connected" || connection === "connecting") {
|
|
1058
493
|
return null;
|
|
1059
494
|
}
|
|
1060
495
|
const reconnecting = connection === "reconnecting";
|
|
1061
|
-
return /* @__PURE__ */
|
|
496
|
+
return /* @__PURE__ */ jsx3("div", { className: cn("blade-chat-banner bg-[hsl(var(--background))] px-5 pt-3", className), children: /* @__PURE__ */ jsxs2(
|
|
1062
497
|
"div",
|
|
1063
498
|
{
|
|
1064
499
|
className: cn(
|
|
@@ -1066,10 +501,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1066
501
|
reconnecting ? "border-amber-500/25 bg-amber-500/10 text-amber-100" : "border-rose-500/25 bg-rose-500/10 text-rose-100"
|
|
1067
502
|
),
|
|
1068
503
|
children: [
|
|
1069
|
-
/* @__PURE__ */
|
|
1070
|
-
/* @__PURE__ */
|
|
1071
|
-
/* @__PURE__ */
|
|
1072
|
-
/* @__PURE__ */
|
|
504
|
+
/* @__PURE__ */ jsx3("span", { className: "mt-0.5 shrink-0", children: reconnecting ? /* @__PURE__ */ jsx3(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx3(TriangleAlert, { size: 14 }) }),
|
|
505
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
|
|
506
|
+
/* @__PURE__ */ jsx3("div", { className: "text-sm font-medium", children: reconnecting ? "\u8FDE\u63A5\u5DF2\u65AD\u5F00\uFF0C\u6B63\u5728\u91CD\u8FDE\u2026" : "\u8FDE\u63A5\u5DF2\u65AD\u5F00" }),
|
|
507
|
+
/* @__PURE__ */ jsx3("div", { className: "text-xs opacity-80", children: "\u6D88\u606F\u540C\u6B65\u53EF\u80FD\u4F1A\u5EF6\u8FDF\uFF0C\u7CFB\u7EDF\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5" })
|
|
1073
508
|
] })
|
|
1074
509
|
]
|
|
1075
510
|
}
|
|
@@ -1078,10 +513,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1078
513
|
|
|
1079
514
|
// src/components/MessageList.tsx
|
|
1080
515
|
import { isHiddenInternalMessage } from "@blade-hq/agent-client";
|
|
1081
|
-
import { useCallback as
|
|
516
|
+
import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo6, useRef as useRef5, useState as useState9 } from "react";
|
|
1082
517
|
|
|
1083
518
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js
|
|
1084
|
-
import { useCallback
|
|
519
|
+
import { useCallback, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
1085
520
|
var DEFAULT_SPRING_ANIMATION = {
|
|
1086
521
|
/**
|
|
1087
522
|
* A value from 0 to 1, on how much to damp the animation.
|
|
@@ -1118,12 +553,12 @@ globalThis.document?.addEventListener("click", () => {
|
|
|
1118
553
|
mouseDown = false;
|
|
1119
554
|
});
|
|
1120
555
|
var useStickToBottom = (options = {}) => {
|
|
1121
|
-
const [escapedFromLock, updateEscapedFromLock] =
|
|
1122
|
-
const [isAtBottom, updateIsAtBottom] =
|
|
1123
|
-
const [isNearBottom, setIsNearBottom] =
|
|
1124
|
-
const optionsRef =
|
|
556
|
+
const [escapedFromLock, updateEscapedFromLock] = useState2(false);
|
|
557
|
+
const [isAtBottom, updateIsAtBottom] = useState2(options.initial !== false);
|
|
558
|
+
const [isNearBottom, setIsNearBottom] = useState2(false);
|
|
559
|
+
const optionsRef = useRef2(null);
|
|
1125
560
|
optionsRef.current = options;
|
|
1126
|
-
const isSelecting =
|
|
561
|
+
const isSelecting = useCallback(() => {
|
|
1127
562
|
if (!mouseDown) {
|
|
1128
563
|
return false;
|
|
1129
564
|
}
|
|
@@ -1134,15 +569,15 @@ var useStickToBottom = (options = {}) => {
|
|
|
1134
569
|
const range = selection.getRangeAt(0);
|
|
1135
570
|
return range.commonAncestorContainer.contains(scrollRef.current) || scrollRef.current?.contains(range.commonAncestorContainer);
|
|
1136
571
|
}, []);
|
|
1137
|
-
const setIsAtBottom =
|
|
572
|
+
const setIsAtBottom = useCallback((isAtBottom2) => {
|
|
1138
573
|
state.isAtBottom = isAtBottom2;
|
|
1139
574
|
updateIsAtBottom(isAtBottom2);
|
|
1140
575
|
}, []);
|
|
1141
|
-
const setEscapedFromLock =
|
|
576
|
+
const setEscapedFromLock = useCallback((escapedFromLock2) => {
|
|
1142
577
|
state.escapedFromLock = escapedFromLock2;
|
|
1143
578
|
updateEscapedFromLock(escapedFromLock2);
|
|
1144
579
|
}, []);
|
|
1145
|
-
const state =
|
|
580
|
+
const state = useMemo2(() => {
|
|
1146
581
|
let lastCalculation;
|
|
1147
582
|
return {
|
|
1148
583
|
escapedFromLock,
|
|
@@ -1195,7 +630,7 @@ var useStickToBottom = (options = {}) => {
|
|
|
1195
630
|
}
|
|
1196
631
|
};
|
|
1197
632
|
}, []);
|
|
1198
|
-
const scrollToBottom =
|
|
633
|
+
const scrollToBottom = useCallback((scrollOptions = {}) => {
|
|
1199
634
|
if (typeof scrollOptions === "string") {
|
|
1200
635
|
scrollOptions = { animation: scrollOptions };
|
|
1201
636
|
}
|
|
@@ -1280,11 +715,11 @@ var useStickToBottom = (options = {}) => {
|
|
|
1280
715
|
}
|
|
1281
716
|
return next();
|
|
1282
717
|
}, [setIsAtBottom, isSelecting, state]);
|
|
1283
|
-
const stopScroll =
|
|
718
|
+
const stopScroll = useCallback(() => {
|
|
1284
719
|
setEscapedFromLock(true);
|
|
1285
720
|
setIsAtBottom(false);
|
|
1286
721
|
}, [setEscapedFromLock, setIsAtBottom]);
|
|
1287
|
-
const handleScroll =
|
|
722
|
+
const handleScroll = useCallback(({ target }) => {
|
|
1288
723
|
if (target !== scrollRef.current) {
|
|
1289
724
|
return;
|
|
1290
725
|
}
|
|
@@ -1323,7 +758,7 @@ var useStickToBottom = (options = {}) => {
|
|
|
1323
758
|
}
|
|
1324
759
|
}, 1);
|
|
1325
760
|
}, [setEscapedFromLock, setIsAtBottom, isSelecting, state]);
|
|
1326
|
-
const handleWheel =
|
|
761
|
+
const handleWheel = useCallback(({ target, deltaY }) => {
|
|
1327
762
|
let element = target;
|
|
1328
763
|
while (!["scroll", "auto"].includes(getComputedStyle(element).overflow)) {
|
|
1329
764
|
if (!element.parentElement) {
|
|
@@ -1393,7 +828,7 @@ var useStickToBottom = (options = {}) => {
|
|
|
1393
828
|
};
|
|
1394
829
|
};
|
|
1395
830
|
function useRefCallback(callback, deps) {
|
|
1396
|
-
const result =
|
|
831
|
+
const result = useCallback((ref) => {
|
|
1397
832
|
result.current = ref;
|
|
1398
833
|
return callback(ref);
|
|
1399
834
|
}, deps);
|
|
@@ -1425,11 +860,11 @@ function mergeAnimations(...animations) {
|
|
|
1425
860
|
|
|
1426
861
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/StickToBottom.js
|
|
1427
862
|
import * as React from "react";
|
|
1428
|
-
import { createContext as createContext2, useContext as useContext2, useEffect as
|
|
863
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useImperativeHandle, useLayoutEffect, useMemo as useMemo3, useRef as useRef3 } from "react";
|
|
1429
864
|
var StickToBottomContext = createContext2(null);
|
|
1430
|
-
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect :
|
|
865
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect2;
|
|
1431
866
|
function StickToBottom({ instance, children, resize, initial, mass, damping, stiffness, targetScrollTop: currentTargetScrollTop, contextRef, ...props }) {
|
|
1432
|
-
const customTargetScrollTop =
|
|
867
|
+
const customTargetScrollTop = useRef3(null);
|
|
1433
868
|
const targetScrollTop = React.useCallback((target, elements) => {
|
|
1434
869
|
const get = context?.targetScrollTop ?? currentTargetScrollTop;
|
|
1435
870
|
return get?.(target, elements) ?? target;
|
|
@@ -1443,7 +878,7 @@ function StickToBottom({ instance, children, resize, initial, mass, damping, sti
|
|
|
1443
878
|
targetScrollTop
|
|
1444
879
|
});
|
|
1445
880
|
const { scrollRef, contentRef, scrollToBottom, stopScroll, isAtBottom, escapedFromLock, state } = instance ?? defaultInstance;
|
|
1446
|
-
const context =
|
|
881
|
+
const context = useMemo3(() => ({
|
|
1447
882
|
scrollToBottom,
|
|
1448
883
|
stopScroll,
|
|
1449
884
|
scrollRef,
|
|
@@ -1506,10 +941,10 @@ function useStickToBottomContext() {
|
|
|
1506
941
|
|
|
1507
942
|
// src/components/AssistantTurnBlock.tsx
|
|
1508
943
|
import { getTextContent, normalizeMessageContent } from "@blade-hq/agent-client";
|
|
1509
|
-
import { useState as
|
|
944
|
+
import { useState as useState8 } from "react";
|
|
1510
945
|
|
|
1511
946
|
// src/components/AgentLoopBlock.tsx
|
|
1512
|
-
import { useState as
|
|
947
|
+
import { useState as useState3 } from "react";
|
|
1513
948
|
|
|
1514
949
|
// src/components/display-utils.ts
|
|
1515
950
|
var TOOL_NAME_ALIASES = {
|
|
@@ -1631,7 +1066,7 @@ function formatToolResult(result) {
|
|
|
1631
1066
|
}
|
|
1632
1067
|
|
|
1633
1068
|
// src/components/AgentLoopBlock.tsx
|
|
1634
|
-
import { jsx as
|
|
1069
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1635
1070
|
function parseAgentDescription(argumentsJson) {
|
|
1636
1071
|
try {
|
|
1637
1072
|
const parsed = JSON.parse(argumentsJson);
|
|
@@ -1641,12 +1076,12 @@ function parseAgentDescription(argumentsJson) {
|
|
|
1641
1076
|
}
|
|
1642
1077
|
}
|
|
1643
1078
|
function AgentLoopBlock({ toolCall }) {
|
|
1644
|
-
const [expanded, setExpanded] =
|
|
1079
|
+
const [expanded, setExpanded] = useState3(false);
|
|
1645
1080
|
const description = parseAgentDescription(toolCall.arguments);
|
|
1646
1081
|
const running = toolCall.status === "pending" || toolCall.status === "awaiting_answer";
|
|
1647
1082
|
const failed = toolCall.status === "error" || toolCall.status === "cancelled";
|
|
1648
|
-
return /* @__PURE__ */
|
|
1649
|
-
/* @__PURE__ */
|
|
1083
|
+
return /* @__PURE__ */ jsxs3("div", { className: "blade-chat-agent-loop ml-4 text-xs", children: [
|
|
1084
|
+
/* @__PURE__ */ jsxs3(
|
|
1650
1085
|
"div",
|
|
1651
1086
|
{
|
|
1652
1087
|
className: cn(
|
|
@@ -1654,7 +1089,7 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1654
1089
|
failed ? "border-l-[hsl(var(--muted-foreground)/0.5)]" : running ? "border-l-blue-500" : "border-l-[hsl(var(--primary))]"
|
|
1655
1090
|
),
|
|
1656
1091
|
children: [
|
|
1657
|
-
/* @__PURE__ */
|
|
1092
|
+
/* @__PURE__ */ jsxs3(
|
|
1658
1093
|
"button",
|
|
1659
1094
|
{
|
|
1660
1095
|
type: "button",
|
|
@@ -1662,7 +1097,7 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1662
1097
|
className: "flex min-w-0 flex-1 items-center gap-2 text-left transition-colors hover:bg-white/3 focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none",
|
|
1663
1098
|
"aria-expanded": expanded,
|
|
1664
1099
|
children: [
|
|
1665
|
-
/* @__PURE__ */
|
|
1100
|
+
/* @__PURE__ */ jsx4(
|
|
1666
1101
|
ChevronRight,
|
|
1667
1102
|
{
|
|
1668
1103
|
size: 11,
|
|
@@ -1672,8 +1107,8 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1672
1107
|
)
|
|
1673
1108
|
}
|
|
1674
1109
|
),
|
|
1675
|
-
/* @__PURE__ */
|
|
1676
|
-
/* @__PURE__ */
|
|
1110
|
+
/* @__PURE__ */ jsx4(Bot, { size: 12, className: "shrink-0 text-[hsl(var(--muted-foreground))]" }),
|
|
1111
|
+
/* @__PURE__ */ jsxs3(
|
|
1677
1112
|
"span",
|
|
1678
1113
|
{
|
|
1679
1114
|
className: cn(
|
|
@@ -1681,43 +1116,171 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1681
1116
|
failed ? "text-[hsl(var(--muted-foreground))]" : running ? "text-blue-300" : "text-[hsl(var(--primary))]"
|
|
1682
1117
|
),
|
|
1683
1118
|
children: [
|
|
1684
|
-
running ? /* @__PURE__ */
|
|
1685
|
-
/* @__PURE__ */
|
|
1119
|
+
running ? /* @__PURE__ */ jsx4(LoaderCircle, { size: 11, className: "animate-spin" }) : failed ? /* @__PURE__ */ jsx4(X, { size: 11 }) : /* @__PURE__ */ jsx4(Check, { size: 11 }),
|
|
1120
|
+
/* @__PURE__ */ jsx4("span", { children: running ? "\u6267\u884C\u4E2D" : failed ? "\u5DF2\u7EC8\u6B62" : "\u5B8C\u6210" })
|
|
1686
1121
|
]
|
|
1687
1122
|
}
|
|
1688
1123
|
),
|
|
1689
|
-
/* @__PURE__ */
|
|
1124
|
+
/* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: [
|
|
1690
1125
|
"\u5B50\u667A\u80FD\u4F53\uFF1A",
|
|
1691
1126
|
description
|
|
1692
1127
|
] })
|
|
1693
1128
|
]
|
|
1694
1129
|
}
|
|
1695
1130
|
),
|
|
1696
|
-
typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */
|
|
1131
|
+
typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */ jsx4("span", { className: "shrink-0 font-mono text-[10px] text-[hsl(var(--muted-foreground))]", children: formatToolDuration(toolCall.duration_ms) })
|
|
1697
1132
|
]
|
|
1698
1133
|
}
|
|
1699
1134
|
),
|
|
1700
|
-
expanded && toolCall.result != null && /* @__PURE__ */
|
|
1701
|
-
/* @__PURE__ */
|
|
1702
|
-
/* @__PURE__ */
|
|
1135
|
+
expanded && toolCall.result != null && /* @__PURE__ */ jsxs3("div", { className: "ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3", children: [
|
|
1136
|
+
/* @__PURE__ */ jsx4("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
|
|
1137
|
+
/* @__PURE__ */ jsx4("pre", { className: "max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolResult(toolCall.result) })
|
|
1703
1138
|
] })
|
|
1704
1139
|
] });
|
|
1705
1140
|
}
|
|
1706
1141
|
|
|
1707
1142
|
// src/components/MarkdownContent.tsx
|
|
1708
1143
|
import {
|
|
1709
|
-
useEffect as
|
|
1710
|
-
useMemo as
|
|
1711
|
-
useRef as
|
|
1712
|
-
useState as
|
|
1144
|
+
useEffect as useEffect3,
|
|
1145
|
+
useMemo as useMemo4,
|
|
1146
|
+
useRef as useRef4,
|
|
1147
|
+
useState as useState5
|
|
1713
1148
|
} from "react";
|
|
1714
|
-
|
|
1149
|
+
|
|
1150
|
+
// src/lib/media-tags.ts
|
|
1151
|
+
var FILE_CARD_TAG = "blade-file-card";
|
|
1152
|
+
var MEDIA_LINE_RE = /^[ \t]*(?:[-*+][ \t]+|\d+\.[ \t]+)?(?<wrap>[`"'*_]*)MEDIA:[ \t]*(?<path>.+?)\k<wrap>[ \t]*[。,、;;,]?[ \t]*\r?$/gm;
|
|
1153
|
+
var MEDIA_LINE_START_RE = /^[ \t]*(?:[-*+][ \t]+|\d+\.[ \t]+)?[`"'*_]*MEDIA:/;
|
|
1154
|
+
function basename(path) {
|
|
1155
|
+
return path.split(/[/\\]/).filter(Boolean).pop() || path;
|
|
1156
|
+
}
|
|
1157
|
+
function unwrapMediaPath(path) {
|
|
1158
|
+
if (!path.startsWith("<")) return path;
|
|
1159
|
+
const closingBracket = path.indexOf(">");
|
|
1160
|
+
if (closingBracket < 0) return null;
|
|
1161
|
+
return `${path.slice(1, closingBracket)}${path.slice(closingBracket + 1)}`;
|
|
1162
|
+
}
|
|
1163
|
+
function isSafeMediaPath(path) {
|
|
1164
|
+
if (!path) return false;
|
|
1165
|
+
return !path.split(/[/\\]/).includes("..");
|
|
1166
|
+
}
|
|
1167
|
+
function escapeAttribute(value) {
|
|
1168
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
1169
|
+
}
|
|
1170
|
+
function foldMediaLines(text) {
|
|
1171
|
+
return text.replace(MEDIA_LINE_RE, (match, _wrap, rawPath) => {
|
|
1172
|
+
const path = unwrapMediaPath(rawPath);
|
|
1173
|
+
if (path === null) return match;
|
|
1174
|
+
const name = basename(path);
|
|
1175
|
+
if (!isSafeMediaPath(path)) {
|
|
1176
|
+
return `\`${name}\``;
|
|
1177
|
+
}
|
|
1178
|
+
return `<${FILE_CARD_TAG} data-path="${escapeAttribute(path)}" data-name="${escapeAttribute(name)}">${escapeAttribute(name)}</${FILE_CARD_TAG}>`;
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
function collapseMediaTags(text, options) {
|
|
1182
|
+
if (!text.includes("MEDIA:")) return text;
|
|
1183
|
+
if (!options?.streaming) return foldMediaLines(text);
|
|
1184
|
+
const newlineIndex = text.lastIndexOf("\n");
|
|
1185
|
+
const head = newlineIndex < 0 ? "" : text.slice(0, newlineIndex + 1);
|
|
1186
|
+
const lastLine = newlineIndex < 0 ? text : text.slice(newlineIndex + 1);
|
|
1187
|
+
if (MEDIA_LINE_START_RE.test(lastLine)) {
|
|
1188
|
+
return foldMediaLines(head);
|
|
1189
|
+
}
|
|
1190
|
+
return foldMediaLines(head) + lastLine;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// src/components/FileCard.tsx
|
|
1194
|
+
import { useState as useState4 } from "react";
|
|
1195
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1196
|
+
var IMAGE_EXTS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "svg", "webp", "ico", "bmp"]);
|
|
1197
|
+
var SHEET_EXTS = /* @__PURE__ */ new Set(["xlsx", "xls", "xlsm", "xlsb", "csv"]);
|
|
1198
|
+
var TEXT_EXTS = /* @__PURE__ */ new Set(["txt", "md", "markdown", "pdf", "doc", "docx", "rtf"]);
|
|
1199
|
+
var CODE_EXTS = /* @__PURE__ */ new Set(["js", "jsx", "ts", "tsx", "py", "go", "json", "yaml", "yml", "html", "css"]);
|
|
1200
|
+
var VIDEO_EXTS = /* @__PURE__ */ new Set(["mp4", "webm", "mov", "mkv", "avi"]);
|
|
1201
|
+
var AUDIO_EXTS = /* @__PURE__ */ new Set(["mp3", "wav", "ogg", "m4a", "flac"]);
|
|
1202
|
+
var ARCHIVE_EXTS = /* @__PURE__ */ new Set(["zip", "tar", "gz", "tgz", "rar", "7z"]);
|
|
1203
|
+
function getFileIcon(name) {
|
|
1204
|
+
const ext = name.split(".").pop()?.toLowerCase() ?? "";
|
|
1205
|
+
if (IMAGE_EXTS.has(ext)) return Image;
|
|
1206
|
+
if (SHEET_EXTS.has(ext)) return FileSpreadsheet;
|
|
1207
|
+
if (TEXT_EXTS.has(ext)) return FileText;
|
|
1208
|
+
if (CODE_EXTS.has(ext)) return FileCode2;
|
|
1209
|
+
if (VIDEO_EXTS.has(ext)) return Film;
|
|
1210
|
+
if (AUDIO_EXTS.has(ext)) return Music;
|
|
1211
|
+
if (ARCHIVE_EXTS.has(ext)) return Archive;
|
|
1212
|
+
return File;
|
|
1213
|
+
}
|
|
1214
|
+
function stringValue(value) {
|
|
1215
|
+
return typeof value === "string" ? value : void 0;
|
|
1216
|
+
}
|
|
1217
|
+
function extractChildrenText(children) {
|
|
1218
|
+
if (typeof children === "string") return children;
|
|
1219
|
+
if (Array.isArray(children)) return children.map(extractChildrenText).join("");
|
|
1220
|
+
if (children && typeof children === "object" && "props" in children) {
|
|
1221
|
+
return extractChildrenText(children.props?.children);
|
|
1222
|
+
}
|
|
1223
|
+
return "";
|
|
1224
|
+
}
|
|
1225
|
+
function FileCard({
|
|
1226
|
+
node,
|
|
1227
|
+
"data-path": pathAttribute,
|
|
1228
|
+
"data-name": nameAttribute,
|
|
1229
|
+
dataPath,
|
|
1230
|
+
dataName,
|
|
1231
|
+
sessionId,
|
|
1232
|
+
children,
|
|
1233
|
+
className,
|
|
1234
|
+
...props
|
|
1235
|
+
}) {
|
|
1236
|
+
const client = useBladeClient();
|
|
1237
|
+
const [downloading, setDownloading] = useState4(false);
|
|
1238
|
+
const [failed, setFailed] = useState4(false);
|
|
1239
|
+
const nodeProperties = node && typeof node === "object" && "properties" in node ? node.properties : void 0;
|
|
1240
|
+
const path = pathAttribute ?? dataPath ?? stringValue(nodeProperties?.["data-path"]) ?? stringValue(nodeProperties?.dataPath) ?? "";
|
|
1241
|
+
const name = nameAttribute ?? dataName ?? stringValue(nodeProperties?.["data-name"]) ?? stringValue(nodeProperties?.dataName) ?? extractChildrenText(children) ?? "";
|
|
1242
|
+
const disabled = !sessionId || !isSafeMediaPath(path);
|
|
1243
|
+
const Icon2 = getFileIcon(name);
|
|
1244
|
+
const handleDownload = async () => {
|
|
1245
|
+
if (disabled || downloading || !sessionId) return;
|
|
1246
|
+
setDownloading(true);
|
|
1247
|
+
setFailed(false);
|
|
1248
|
+
try {
|
|
1249
|
+
await client.sessions.downloadFile(sessionId, path, name);
|
|
1250
|
+
} catch {
|
|
1251
|
+
setFailed(true);
|
|
1252
|
+
} finally {
|
|
1253
|
+
setDownloading(false);
|
|
1254
|
+
}
|
|
1255
|
+
};
|
|
1256
|
+
return /* @__PURE__ */ jsxs4("span", { ...props, className: cn("blade-chat-file-card", className), children: [
|
|
1257
|
+
/* @__PURE__ */ jsxs4(
|
|
1258
|
+
"button",
|
|
1259
|
+
{
|
|
1260
|
+
type: "button",
|
|
1261
|
+
onClick: handleDownload,
|
|
1262
|
+
disabled: disabled || downloading,
|
|
1263
|
+
"aria-label": `\u4E0B\u8F7D\u6587\u4EF6\uFF1A${name}`,
|
|
1264
|
+
title: failed ? "\u4E0B\u8F7D\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5" : `\u4E0B\u8F7D ${name}`,
|
|
1265
|
+
children: [
|
|
1266
|
+
/* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-icon", children: downloading ? /* @__PURE__ */ jsx5(LoaderCircle, { size: 15, className: "animate-spin" }) : /* @__PURE__ */ jsx5(Icon2, { size: 15 }) }),
|
|
1267
|
+
/* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-name", children: name }),
|
|
1268
|
+
/* @__PURE__ */ jsx5(Download, { size: 13, className: "blade-chat-file-card-action" })
|
|
1269
|
+
]
|
|
1270
|
+
}
|
|
1271
|
+
),
|
|
1272
|
+
failed && /* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-error", children: "\u4E0B\u8F7D\u5931\u8D25" })
|
|
1273
|
+
] });
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// src/components/MarkdownContent.tsx
|
|
1277
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1715
1278
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
1716
1279
|
function CodeBlockPre({ children, node: _node, ...props }) {
|
|
1717
|
-
const preRef =
|
|
1718
|
-
const [copied, setCopied] =
|
|
1719
|
-
const [language, setLanguage] =
|
|
1720
|
-
|
|
1280
|
+
const preRef = useRef4(null);
|
|
1281
|
+
const [copied, setCopied] = useState5(false);
|
|
1282
|
+
const [language, setLanguage] = useState5("");
|
|
1283
|
+
useEffect3(() => {
|
|
1721
1284
|
const codeEl = preRef.current?.querySelector("code");
|
|
1722
1285
|
setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
|
|
1723
1286
|
}, []);
|
|
@@ -1728,10 +1291,10 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
1728
1291
|
setTimeout(() => setCopied(false), 2e3);
|
|
1729
1292
|
}
|
|
1730
1293
|
};
|
|
1731
|
-
return /* @__PURE__ */
|
|
1732
|
-
/* @__PURE__ */
|
|
1733
|
-
/* @__PURE__ */
|
|
1734
|
-
/* @__PURE__ */
|
|
1294
|
+
return /* @__PURE__ */ jsxs5("div", { className: "blade-chat-codeblock not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]", children: [
|
|
1295
|
+
/* @__PURE__ */ jsxs5("div", { className: "blade-chat-codeblock-header flex h-[34px] items-center justify-between border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))/0.5] pl-3.5 pr-1.5", children: [
|
|
1296
|
+
/* @__PURE__ */ jsx6("span", { className: "font-mono text-[12px] text-[hsl(var(--muted-foreground))]", children: language || "code" }),
|
|
1297
|
+
/* @__PURE__ */ jsxs5(
|
|
1735
1298
|
"button",
|
|
1736
1299
|
{
|
|
1737
1300
|
type: "button",
|
|
@@ -1741,13 +1304,13 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
1741
1304
|
copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"
|
|
1742
1305
|
),
|
|
1743
1306
|
children: [
|
|
1744
|
-
copied ? /* @__PURE__ */
|
|
1745
|
-
/* @__PURE__ */
|
|
1307
|
+
copied ? /* @__PURE__ */ jsx6(Check, { size: 12 }) : /* @__PURE__ */ jsx6(Copy, { size: 12 }),
|
|
1308
|
+
/* @__PURE__ */ jsx6("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
|
|
1746
1309
|
]
|
|
1747
1310
|
}
|
|
1748
1311
|
)
|
|
1749
1312
|
] }),
|
|
1750
|
-
/* @__PURE__ */
|
|
1313
|
+
/* @__PURE__ */ jsx6(
|
|
1751
1314
|
"pre",
|
|
1752
1315
|
{
|
|
1753
1316
|
ref: preRef,
|
|
@@ -1759,22 +1322,36 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
1759
1322
|
] });
|
|
1760
1323
|
}
|
|
1761
1324
|
function ExternalAnchor({ node: _node, children, ...props }) {
|
|
1762
|
-
return /* @__PURE__ */
|
|
1325
|
+
return /* @__PURE__ */ jsx6("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
|
|
1763
1326
|
}
|
|
1764
1327
|
var MARKDOWN_COMPONENTS = {
|
|
1765
1328
|
pre: CodeBlockPre,
|
|
1766
1329
|
a: ExternalAnchor
|
|
1767
1330
|
};
|
|
1331
|
+
var CUSTOM_ALLOWED_TAGS = {
|
|
1332
|
+
[FILE_CARD_TAG]: ["dataPath", "dataName", "data-path", "data-name"]
|
|
1333
|
+
};
|
|
1768
1334
|
function MarkdownContent({ children, className, mode, sessionId }) {
|
|
1769
|
-
const
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1335
|
+
const streaming = mode === "streaming";
|
|
1336
|
+
const resolvedChildren = useMemo4(() => {
|
|
1337
|
+
const withoutReminders = children.replace(SYSTEM_REMINDER_RE, "");
|
|
1338
|
+
if (!sessionId) return withoutReminders;
|
|
1339
|
+
return collapseMediaTags(withoutReminders, { streaming });
|
|
1340
|
+
}, [children, sessionId, streaming]);
|
|
1341
|
+
const components = useMemo4(
|
|
1342
|
+
() => ({
|
|
1343
|
+
...MARKDOWN_COMPONENTS,
|
|
1344
|
+
[FILE_CARD_TAG]: (fileCardProps) => /* @__PURE__ */ jsx6(FileCard, { ...fileCardProps, sessionId })
|
|
1345
|
+
}),
|
|
1346
|
+
[sessionId]
|
|
1347
|
+
);
|
|
1348
|
+
return /* @__PURE__ */ jsx6(
|
|
1773
1349
|
_r,
|
|
1774
1350
|
{
|
|
1775
1351
|
className: cn("blade-chat-markdown break-words", className),
|
|
1776
1352
|
mode: mode ?? "static",
|
|
1777
|
-
components
|
|
1353
|
+
components,
|
|
1354
|
+
allowedTags: CUSTOM_ALLOWED_TAGS,
|
|
1778
1355
|
children: resolvedChildren
|
|
1779
1356
|
},
|
|
1780
1357
|
sessionId ?? "no-session"
|
|
@@ -1782,17 +1359,17 @@ function MarkdownContent({ children, className, mode, sessionId }) {
|
|
|
1782
1359
|
}
|
|
1783
1360
|
|
|
1784
1361
|
// src/components/Shimmer.tsx
|
|
1785
|
-
import { jsx as
|
|
1362
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1786
1363
|
function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
|
|
1787
|
-
return /* @__PURE__ */
|
|
1364
|
+
return /* @__PURE__ */ jsx7("span", { className: cn("blade-shimmer-text text-sm font-medium", className), children });
|
|
1788
1365
|
}
|
|
1789
1366
|
|
|
1790
1367
|
// src/components/ToolCallBlock.tsx
|
|
1791
|
-
import { useState as
|
|
1368
|
+
import { useState as useState7 } from "react";
|
|
1792
1369
|
|
|
1793
1370
|
// src/components/AskUserQuestionBlock.tsx
|
|
1794
|
-
import { useEffect as
|
|
1795
|
-
import { jsx as
|
|
1371
|
+
import { useEffect as useEffect4, useMemo as useMemo5, useState as useState6 } from "react";
|
|
1372
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1796
1373
|
function AskUserQuestionBlock({
|
|
1797
1374
|
data,
|
|
1798
1375
|
answered,
|
|
@@ -1801,16 +1378,16 @@ function AskUserQuestionBlock({
|
|
|
1801
1378
|
answerData,
|
|
1802
1379
|
onAnswer
|
|
1803
1380
|
}) {
|
|
1804
|
-
const [selections, setSelections] =
|
|
1805
|
-
const [customTexts, setCustomTexts] =
|
|
1806
|
-
const [usingCustom, setUsingCustom] =
|
|
1807
|
-
const [submitted, setSubmitted] =
|
|
1808
|
-
|
|
1381
|
+
const [selections, setSelections] = useState6(/* @__PURE__ */ new Map());
|
|
1382
|
+
const [customTexts, setCustomTexts] = useState6(/* @__PURE__ */ new Map());
|
|
1383
|
+
const [usingCustom, setUsingCustom] = useState6(/* @__PURE__ */ new Set());
|
|
1384
|
+
const [submitted, setSubmitted] = useState6(false);
|
|
1385
|
+
useEffect4(() => {
|
|
1809
1386
|
if (sessionStatus === "failed" || sessionStatus === "interrupted") {
|
|
1810
1387
|
setSubmitted(false);
|
|
1811
1388
|
}
|
|
1812
1389
|
}, [sessionStatus]);
|
|
1813
|
-
const displayAnswerState =
|
|
1390
|
+
const displayAnswerState = useMemo5(() => {
|
|
1814
1391
|
if (!(answered && answerData)) {
|
|
1815
1392
|
return { selections, customTexts, usingCustom };
|
|
1816
1393
|
}
|
|
@@ -1895,7 +1472,7 @@ ${parts.join("\n")}`;
|
|
|
1895
1472
|
setSubmitted(true);
|
|
1896
1473
|
onAnswer(text, toolCallId, nextAnswerData);
|
|
1897
1474
|
};
|
|
1898
|
-
return /* @__PURE__ */
|
|
1475
|
+
return /* @__PURE__ */ jsxs6(
|
|
1899
1476
|
"div",
|
|
1900
1477
|
{
|
|
1901
1478
|
className: cn(
|
|
@@ -1903,12 +1480,12 @@ ${parts.join("\n")}`;
|
|
|
1903
1480
|
answered ? "max-w-2xl space-y-3 p-3 text-xs text-[hsl(var(--muted-foreground))] opacity-80" : "max-w-lg space-y-5 p-4 text-sm"
|
|
1904
1481
|
),
|
|
1905
1482
|
children: [
|
|
1906
|
-
data.source_loop?.description && /* @__PURE__ */
|
|
1483
|
+
data.source_loop?.description && /* @__PURE__ */ jsxs6("div", { className: "rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
|
|
1907
1484
|
"\u5B50\u667A\u80FD\u4F53\u300C",
|
|
1908
1485
|
data.source_loop.description,
|
|
1909
1486
|
"\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
|
|
1910
1487
|
] }),
|
|
1911
|
-
data.questions.map((q, qIdx) => /* @__PURE__ */
|
|
1488
|
+
data.questions.map((q, qIdx) => /* @__PURE__ */ jsx8(
|
|
1912
1489
|
QuestionCard,
|
|
1913
1490
|
{
|
|
1914
1491
|
question: q,
|
|
@@ -1923,7 +1500,7 @@ ${parts.join("\n")}`;
|
|
|
1923
1500
|
},
|
|
1924
1501
|
q.question
|
|
1925
1502
|
)),
|
|
1926
|
-
!answered && !submitted && onAnswer && /* @__PURE__ */
|
|
1503
|
+
!answered && !submitted && onAnswer && /* @__PURE__ */ jsx8(
|
|
1927
1504
|
"button",
|
|
1928
1505
|
{
|
|
1929
1506
|
type: "button",
|
|
@@ -1933,14 +1510,14 @@ ${parts.join("\n")}`;
|
|
|
1933
1510
|
children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
|
|
1934
1511
|
}
|
|
1935
1512
|
),
|
|
1936
|
-
submitted && !answered && /* @__PURE__ */
|
|
1513
|
+
submitted && !answered && /* @__PURE__ */ jsxs6(
|
|
1937
1514
|
"button",
|
|
1938
1515
|
{
|
|
1939
1516
|
type: "button",
|
|
1940
1517
|
disabled: true,
|
|
1941
1518
|
className: "flex w-full items-center justify-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] opacity-80",
|
|
1942
1519
|
children: [
|
|
1943
|
-
/* @__PURE__ */
|
|
1520
|
+
/* @__PURE__ */ jsx8(LoaderCircle, { size: 14, className: "animate-spin" }),
|
|
1944
1521
|
"\u786E\u8BA4\u4E2D"
|
|
1945
1522
|
]
|
|
1946
1523
|
}
|
|
@@ -1961,30 +1538,30 @@ function QuestionCard({
|
|
|
1961
1538
|
onCustomChange
|
|
1962
1539
|
}) {
|
|
1963
1540
|
const multi = question.multiSelect ?? false;
|
|
1964
|
-
return /* @__PURE__ */
|
|
1965
|
-
/* @__PURE__ */
|
|
1966
|
-
/* @__PURE__ */
|
|
1541
|
+
return /* @__PURE__ */ jsxs6("div", { children: [
|
|
1542
|
+
/* @__PURE__ */ jsxs6("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
|
|
1543
|
+
/* @__PURE__ */ jsx8(
|
|
1967
1544
|
MessageSquareMore,
|
|
1968
1545
|
{
|
|
1969
1546
|
size: answered ? 12 : 13,
|
|
1970
1547
|
className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
|
|
1971
1548
|
}
|
|
1972
1549
|
),
|
|
1973
|
-
/* @__PURE__ */
|
|
1550
|
+
/* @__PURE__ */ jsx8(
|
|
1974
1551
|
"div",
|
|
1975
1552
|
{
|
|
1976
1553
|
className: cn(
|
|
1977
1554
|
"min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
|
|
1978
1555
|
answered ? "text-xs" : "text-sm"
|
|
1979
1556
|
),
|
|
1980
|
-
children: /* @__PURE__ */
|
|
1557
|
+
children: /* @__PURE__ */ jsx8(MarkdownContent, { className: "blade-chat-prose", children: question.question })
|
|
1981
1558
|
}
|
|
1982
1559
|
)
|
|
1983
1560
|
] }),
|
|
1984
|
-
/* @__PURE__ */
|
|
1561
|
+
/* @__PURE__ */ jsxs6("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
|
|
1985
1562
|
question.options.map((opt, optIdx) => {
|
|
1986
1563
|
const isSel = selected.has(optIdx);
|
|
1987
|
-
return /* @__PURE__ */
|
|
1564
|
+
return /* @__PURE__ */ jsxs6(
|
|
1988
1565
|
"button",
|
|
1989
1566
|
{
|
|
1990
1567
|
type: "button",
|
|
@@ -1998,14 +1575,14 @@ function QuestionCard({
|
|
|
1998
1575
|
answered && "cursor-default opacity-70"
|
|
1999
1576
|
),
|
|
2000
1577
|
children: [
|
|
2001
|
-
multi && /* @__PURE__ */
|
|
1578
|
+
multi && /* @__PURE__ */ jsx8(
|
|
2002
1579
|
"div",
|
|
2003
1580
|
{
|
|
2004
1581
|
className: cn(
|
|
2005
1582
|
"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
|
|
2006
1583
|
isSel && !answered ? "border-[hsl(var(--primary-foreground)/0.6)] bg-[hsl(var(--primary-foreground)/0.2)]" : isSel ? "border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.12)]" : "border-[hsl(var(--border))]"
|
|
2007
1584
|
),
|
|
2008
|
-
children: isSel && /* @__PURE__ */
|
|
1585
|
+
children: isSel && /* @__PURE__ */ jsx8(
|
|
2009
1586
|
Check,
|
|
2010
1587
|
{
|
|
2011
1588
|
size: 9,
|
|
@@ -2014,9 +1591,9 @@ function QuestionCard({
|
|
|
2014
1591
|
)
|
|
2015
1592
|
}
|
|
2016
1593
|
),
|
|
2017
|
-
/* @__PURE__ */
|
|
2018
|
-
/* @__PURE__ */
|
|
2019
|
-
opt.description && /* @__PURE__ */
|
|
1594
|
+
/* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
|
|
1595
|
+
/* @__PURE__ */ jsx8("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
|
|
1596
|
+
opt.description && /* @__PURE__ */ jsx8(
|
|
2020
1597
|
"div",
|
|
2021
1598
|
{
|
|
2022
1599
|
className: cn(
|
|
@@ -2033,7 +1610,7 @@ function QuestionCard({
|
|
|
2033
1610
|
opt.label
|
|
2034
1611
|
);
|
|
2035
1612
|
}),
|
|
2036
|
-
answered && !isCustom ? null : /* @__PURE__ */
|
|
1613
|
+
answered && !isCustom ? null : /* @__PURE__ */ jsxs6(
|
|
2037
1614
|
"div",
|
|
2038
1615
|
{
|
|
2039
1616
|
className: cn(
|
|
@@ -2043,8 +1620,8 @@ function QuestionCard({
|
|
|
2043
1620
|
answered && "cursor-default opacity-70"
|
|
2044
1621
|
),
|
|
2045
1622
|
children: [
|
|
2046
|
-
/* @__PURE__ */
|
|
2047
|
-
/* @__PURE__ */
|
|
1623
|
+
/* @__PURE__ */ jsx8("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
|
|
1624
|
+
/* @__PURE__ */ jsx8(
|
|
2048
1625
|
"input",
|
|
2049
1626
|
{
|
|
2050
1627
|
type: "text",
|
|
@@ -2112,7 +1689,7 @@ function normalizeOptionItem(value) {
|
|
|
2112
1689
|
}
|
|
2113
1690
|
|
|
2114
1691
|
// src/components/ToolCallBlock.tsx
|
|
2115
|
-
import { Fragment, jsx as
|
|
1692
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2116
1693
|
function resolveAskQuestionState({
|
|
2117
1694
|
toolStatus,
|
|
2118
1695
|
hasAnswerData,
|
|
@@ -2132,12 +1709,12 @@ function ToolCallBlock({
|
|
|
2132
1709
|
sessionStatus,
|
|
2133
1710
|
renderer
|
|
2134
1711
|
}) {
|
|
2135
|
-
const [expanded, setExpanded] =
|
|
1712
|
+
const [expanded, setExpanded] = useState7(false);
|
|
2136
1713
|
const normalizedName = formatToolName(toolCall.name);
|
|
2137
1714
|
if (renderer) {
|
|
2138
1715
|
const custom = renderer(toolCall);
|
|
2139
1716
|
if (custom !== null && custom !== void 0) {
|
|
2140
|
-
return /* @__PURE__ */
|
|
1717
|
+
return /* @__PURE__ */ jsx9(Fragment, { children: custom });
|
|
2141
1718
|
}
|
|
2142
1719
|
}
|
|
2143
1720
|
if (normalizedName === "AskUserQuestion") {
|
|
@@ -2149,7 +1726,7 @@ function ToolCallBlock({
|
|
|
2149
1726
|
});
|
|
2150
1727
|
const canAnswer = questionState.awaitingAnswer && Boolean(onAnswer);
|
|
2151
1728
|
if (askData) {
|
|
2152
|
-
return /* @__PURE__ */
|
|
1729
|
+
return /* @__PURE__ */ jsx9(
|
|
2153
1730
|
AskUserQuestionBlock,
|
|
2154
1731
|
{
|
|
2155
1732
|
data: askData,
|
|
@@ -2162,24 +1739,24 @@ function ToolCallBlock({
|
|
|
2162
1739
|
);
|
|
2163
1740
|
}
|
|
2164
1741
|
if (toolCall.status === "pending") {
|
|
2165
|
-
return /* @__PURE__ */
|
|
2166
|
-
/* @__PURE__ */
|
|
2167
|
-
/* @__PURE__ */
|
|
1742
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ml-4 flex max-w-lg items-center gap-2 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-4 text-sm text-[hsl(var(--muted-foreground))]", children: [
|
|
1743
|
+
/* @__PURE__ */ jsx9(LoaderCircle, { size: 14, className: "animate-spin" }),
|
|
1744
|
+
/* @__PURE__ */ jsx9("span", { children: "\u6B63\u5728\u51C6\u5907\u95EE\u9898\u2026" })
|
|
2168
1745
|
] });
|
|
2169
1746
|
}
|
|
2170
|
-
return /* @__PURE__ */
|
|
2171
|
-
/* @__PURE__ */
|
|
2172
|
-
/* @__PURE__ */
|
|
1747
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ml-4 max-w-lg rounded-xl border border-amber-500/35 bg-amber-500/10 p-4 text-sm text-[hsl(var(--foreground))]", children: [
|
|
1748
|
+
/* @__PURE__ */ jsx9("div", { className: "font-semibold", children: "\u9009\u62E9\u9898\u5185\u5BB9\u6682\u65F6\u65E0\u6CD5\u663E\u793A" }),
|
|
1749
|
+
/* @__PURE__ */ jsx9("div", { className: "mt-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: "\u6536\u5230\u7684\u4EA4\u4E92\u6570\u636E\u4E0D\u5B8C\u6574\u3002\u8BF7\u8BA9\u667A\u80FD\u4F53\u91CD\u65B0\u63D0\u95EE\u3002" })
|
|
2173
1750
|
] });
|
|
2174
1751
|
}
|
|
2175
1752
|
const tone = getToolTone(toolCall.status);
|
|
2176
1753
|
const displayName = getToolDisplayLabel(toolCall);
|
|
2177
1754
|
const toneClass = tone === "red" ? "border-l-[hsl(var(--muted-foreground)/0.5)]" : tone === "amber" ? "border-l-amber-400" : tone === "blue" ? "border-l-blue-500" : "border-l-[hsl(var(--primary))]";
|
|
2178
|
-
const statusIcon = toolCall.status === "pending" ? /* @__PURE__ */
|
|
1755
|
+
const statusIcon = toolCall.status === "pending" ? /* @__PURE__ */ jsx9(LoaderCircle, { size: 11, className: "animate-spin" }) : toolCall.status === "awaiting_answer" ? /* @__PURE__ */ jsx9(MessageSquareMore, { size: 11 }) : toolCall.status === "cancelled" || toolCall.status === "error" ? /* @__PURE__ */ jsx9(X, { size: 11 }) : /* @__PURE__ */ jsx9(Check, { size: 11 });
|
|
2179
1756
|
const statusTextClass = tone === "red" ? "text-[hsl(var(--muted-foreground))]" : tone === "amber" ? "text-amber-300" : tone === "blue" ? "text-blue-300" : "text-[hsl(var(--primary))]";
|
|
2180
|
-
return /* @__PURE__ */
|
|
2181
|
-
/* @__PURE__ */
|
|
2182
|
-
/* @__PURE__ */
|
|
1757
|
+
return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-tool ml-4 text-xs", children: [
|
|
1758
|
+
/* @__PURE__ */ jsxs7("div", { className: cn("border-l-[3px] flex items-center gap-2 px-3 py-2", toneClass), children: [
|
|
1759
|
+
/* @__PURE__ */ jsxs7(
|
|
2183
1760
|
"button",
|
|
2184
1761
|
{
|
|
2185
1762
|
type: "button",
|
|
@@ -2187,7 +1764,7 @@ function ToolCallBlock({
|
|
|
2187
1764
|
className: "flex min-w-0 flex-1 items-center gap-2 text-left transition-colors hover:bg-white/3 focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none",
|
|
2188
1765
|
"aria-expanded": expanded,
|
|
2189
1766
|
children: [
|
|
2190
|
-
/* @__PURE__ */
|
|
1767
|
+
/* @__PURE__ */ jsx9(
|
|
2191
1768
|
ChevronRight,
|
|
2192
1769
|
{
|
|
2193
1770
|
size: 11,
|
|
@@ -2197,24 +1774,24 @@ function ToolCallBlock({
|
|
|
2197
1774
|
)
|
|
2198
1775
|
}
|
|
2199
1776
|
),
|
|
2200
|
-
/* @__PURE__ */
|
|
1777
|
+
/* @__PURE__ */ jsxs7("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
|
|
2201
1778
|
statusIcon,
|
|
2202
|
-
/* @__PURE__ */
|
|
1779
|
+
/* @__PURE__ */ jsx9("span", { children: getToolStatusLabel(toolCall.status) })
|
|
2203
1780
|
] }),
|
|
2204
|
-
/* @__PURE__ */
|
|
1781
|
+
/* @__PURE__ */ jsx9("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: displayName })
|
|
2205
1782
|
]
|
|
2206
1783
|
}
|
|
2207
1784
|
),
|
|
2208
|
-
typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */
|
|
1785
|
+
typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */ jsx9("span", { className: "shrink-0 font-mono text-[10px] text-[hsl(var(--muted-foreground))]", children: formatToolDuration(toolCall.duration_ms) })
|
|
2209
1786
|
] }),
|
|
2210
|
-
expanded && /* @__PURE__ */
|
|
2211
|
-
/* @__PURE__ */
|
|
2212
|
-
/* @__PURE__ */
|
|
2213
|
-
/* @__PURE__ */
|
|
2214
|
-
/* @__PURE__ */
|
|
2215
|
-
toolCall.result != null && /* @__PURE__ */
|
|
2216
|
-
/* @__PURE__ */
|
|
2217
|
-
/* @__PURE__ */
|
|
1787
|
+
expanded && /* @__PURE__ */ jsxs7("div", { className: "blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3", children: [
|
|
1788
|
+
/* @__PURE__ */ jsx9("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u5DE5\u5177" }),
|
|
1789
|
+
/* @__PURE__ */ jsx9("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
|
|
1790
|
+
/* @__PURE__ */ jsx9("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
|
|
1791
|
+
/* @__PURE__ */ jsx9("pre", { className: "overflow-x-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolArgs(toolCall.arguments) }),
|
|
1792
|
+
toolCall.result != null && /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
1793
|
+
/* @__PURE__ */ jsx9("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
|
|
1794
|
+
/* @__PURE__ */ jsx9("pre", { className: "max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolResult(toolCall.result) })
|
|
2218
1795
|
] })
|
|
2219
1796
|
] })
|
|
2220
1797
|
] });
|
|
@@ -2232,11 +1809,11 @@ function buildAskUserPayload(argumentsJson) {
|
|
|
2232
1809
|
}
|
|
2233
1810
|
|
|
2234
1811
|
// src/components/AssistantTurnBlock.tsx
|
|
2235
|
-
import { jsx as
|
|
1812
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2236
1813
|
function ThinkingBlock({ reasoning, isStreaming }) {
|
|
2237
|
-
const [open, setOpen] =
|
|
2238
|
-
return /* @__PURE__ */
|
|
2239
|
-
/* @__PURE__ */
|
|
1814
|
+
const [open, setOpen] = useState8(false);
|
|
1815
|
+
return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
|
|
1816
|
+
/* @__PURE__ */ jsxs8(
|
|
2240
1817
|
"button",
|
|
2241
1818
|
{
|
|
2242
1819
|
type: "button",
|
|
@@ -2244,14 +1821,14 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
2244
1821
|
"aria-expanded": open,
|
|
2245
1822
|
className: "inline-flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
|
|
2246
1823
|
children: [
|
|
2247
|
-
/* @__PURE__ */
|
|
2248
|
-
isStreaming ? /* @__PURE__ */
|
|
2249
|
-
/* @__PURE__ */
|
|
1824
|
+
/* @__PURE__ */ jsx10(Brain, { size: 12, className: "shrink-0" }),
|
|
1825
|
+
isStreaming ? /* @__PURE__ */ jsx10(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }) : /* @__PURE__ */ jsx10("span", { children: "\u601D\u8003\u8FC7\u7A0B" }),
|
|
1826
|
+
/* @__PURE__ */ jsxs8("span", { className: "text-[hsl(var(--muted-foreground))]/70", children: [
|
|
2250
1827
|
"\xB7 ",
|
|
2251
1828
|
new Intl.NumberFormat("zh-CN").format(reasoning.length),
|
|
2252
1829
|
" \u5B57"
|
|
2253
1830
|
] }),
|
|
2254
|
-
/* @__PURE__ */
|
|
1831
|
+
/* @__PURE__ */ jsx10(
|
|
2255
1832
|
ChevronDown,
|
|
2256
1833
|
{
|
|
2257
1834
|
size: 12,
|
|
@@ -2261,7 +1838,7 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
2261
1838
|
]
|
|
2262
1839
|
}
|
|
2263
1840
|
),
|
|
2264
|
-
open && /* @__PURE__ */
|
|
1841
|
+
open && /* @__PURE__ */ jsx10("div", { className: "mt-1.5 whitespace-pre-wrap border-l-2 border-[hsl(var(--border))] pl-3 text-[11px] leading-5 text-[hsl(var(--muted-foreground))]", children: reasoning })
|
|
2265
1842
|
] });
|
|
2266
1843
|
}
|
|
2267
1844
|
function getMessageText(message) {
|
|
@@ -2287,21 +1864,21 @@ function AssistantTurnBlock({
|
|
|
2287
1864
|
(message) => getMessageText(message) || message.reasoning || (message.tool_calls?.length ?? 0) > 0
|
|
2288
1865
|
);
|
|
2289
1866
|
const latestReasoningIndex = isStreaming ? findLatestReasoningMessageIndex(messages) : -1;
|
|
2290
|
-
return /* @__PURE__ */
|
|
2291
|
-
hasInterrupted && /* @__PURE__ */
|
|
1867
|
+
return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
|
|
1868
|
+
hasInterrupted && /* @__PURE__ */ jsx10("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
|
|
2292
1869
|
messages.map((message, index) => {
|
|
2293
1870
|
const isLast = index === messages.length - 1;
|
|
2294
1871
|
const streamingThis = isStreaming && isLast;
|
|
2295
1872
|
const text = getMessageText(message);
|
|
2296
1873
|
const toolCalls = message.tool_calls ?? [];
|
|
2297
1874
|
const showReasoning = !!message.reasoning && (!isStreaming || index === latestReasoningIndex);
|
|
2298
|
-
return /* @__PURE__ */
|
|
1875
|
+
return /* @__PURE__ */ jsxs8(
|
|
2299
1876
|
"div",
|
|
2300
1877
|
{
|
|
2301
1878
|
className: "flex flex-col gap-3",
|
|
2302
1879
|
children: [
|
|
2303
|
-
showReasoning && message.reasoning && /* @__PURE__ */
|
|
2304
|
-
text && /* @__PURE__ */
|
|
1880
|
+
showReasoning && message.reasoning && /* @__PURE__ */ jsx10(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }),
|
|
1881
|
+
text && /* @__PURE__ */ jsx10("div", { className: "blade-chat-assistant-text text-[15px] leading-8 text-[hsl(var(--foreground))]", children: /* @__PURE__ */ jsx10(
|
|
2305
1882
|
MarkdownContent,
|
|
2306
1883
|
{
|
|
2307
1884
|
mode: streamingThis ? "streaming" : "static",
|
|
@@ -2310,8 +1887,8 @@ function AssistantTurnBlock({
|
|
|
2310
1887
|
children: text
|
|
2311
1888
|
}
|
|
2312
1889
|
) }),
|
|
2313
|
-
toolCalls.length > 0 && /* @__PURE__ */
|
|
2314
|
-
(toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */
|
|
1890
|
+
toolCalls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "flex flex-col gap-2", children: toolCalls.map(
|
|
1891
|
+
(toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx10(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx10(
|
|
2315
1892
|
ToolCallBlock,
|
|
2316
1893
|
{
|
|
2317
1894
|
toolCall,
|
|
@@ -2329,13 +1906,13 @@ function AssistantTurnBlock({
|
|
|
2329
1906
|
message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
|
|
2330
1907
|
);
|
|
2331
1908
|
}),
|
|
2332
|
-
isStreaming && !hasAnyContent && /* @__PURE__ */
|
|
1909
|
+
isStreaming && !hasAnyContent && /* @__PURE__ */ jsx10(Shimmer, { className: "ml-4", children: "\u6B63\u5728\u751F\u6210..." })
|
|
2333
1910
|
] });
|
|
2334
1911
|
}
|
|
2335
1912
|
|
|
2336
1913
|
// src/components/RenderErrorBoundary.tsx
|
|
2337
1914
|
import { Component } from "react";
|
|
2338
|
-
import { jsx as
|
|
1915
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2339
1916
|
function getFirstComponentName(componentStack) {
|
|
2340
1917
|
const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
|
|
2341
1918
|
return match?.[1] ?? null;
|
|
@@ -2368,447 +1945,62 @@ var RenderErrorBoundary = class extends Component {
|
|
|
2368
1945
|
return children;
|
|
2369
1946
|
}
|
|
2370
1947
|
const componentName = getFirstComponentName(componentStack);
|
|
2371
|
-
return /* @__PURE__ */
|
|
2372
|
-
/* @__PURE__ */
|
|
2373
|
-
/* @__PURE__ */
|
|
2374
|
-
/* @__PURE__ */
|
|
1948
|
+
return /* @__PURE__ */ jsx11("div", { className: "blade-chat-render-error rounded-xl border border-amber-500/30 bg-amber-500/8 px-4 py-3 text-sm text-amber-100", children: /* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-2", children: [
|
|
1949
|
+
/* @__PURE__ */ jsx11(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
|
|
1950
|
+
/* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
|
|
1951
|
+
/* @__PURE__ */ jsxs9("div", { className: "font-medium", children: [
|
|
2375
1952
|
label,
|
|
2376
1953
|
"\u6E32\u67D3\u5931\u8D25"
|
|
2377
1954
|
] }),
|
|
2378
|
-
/* @__PURE__ */
|
|
1955
|
+
/* @__PURE__ */ jsxs9("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
|
|
2379
1956
|
componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
|
|
2380
1957
|
error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
|
|
2381
1958
|
] }),
|
|
2382
|
-
details ? /* @__PURE__ */
|
|
1959
|
+
details ? /* @__PURE__ */ jsx11("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
|
|
2383
1960
|
] })
|
|
2384
1961
|
] }) });
|
|
2385
1962
|
}
|
|
2386
1963
|
};
|
|
2387
1964
|
|
|
2388
|
-
// src/components/
|
|
2389
|
-
import {
|
|
2390
|
-
import {
|
|
2391
|
-
function
|
|
2392
|
-
|
|
2393
|
-
callback?.(event);
|
|
2394
|
-
} catch {
|
|
2395
|
-
}
|
|
2396
|
-
}
|
|
2397
|
-
function basename(path) {
|
|
2398
|
-
return path.split(/[\\/]/).filter(Boolean).pop() || path;
|
|
1965
|
+
// src/components/UserMessageBubble.tsx
|
|
1966
|
+
import { getFileParts, getImageParts, getTextContent as getTextContent2 } from "@blade-hq/agent-client";
|
|
1967
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1968
|
+
function isUserMessage(message) {
|
|
1969
|
+
return message.role === "user";
|
|
2399
1970
|
}
|
|
2400
|
-
function
|
|
2401
|
-
return
|
|
1971
|
+
function isErrorMessage(message) {
|
|
1972
|
+
return message.role === "error";
|
|
2402
1973
|
}
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
1974
|
+
var isSending = (message) => message.status === "streaming";
|
|
1975
|
+
function UserMessageBubble({ message, className }) {
|
|
1976
|
+
const text = getTextContent2(message.content).trim();
|
|
1977
|
+
const fileParts = getFileParts(message.content);
|
|
1978
|
+
const imageParts = getImageParts(message.content);
|
|
1979
|
+
return /* @__PURE__ */ jsx12("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsxs10("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: [
|
|
1980
|
+
imageParts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx12(
|
|
1981
|
+
"img",
|
|
1982
|
+
{
|
|
1983
|
+
src: part.image_url.url,
|
|
1984
|
+
alt: "\u7528\u6237\u4E0A\u4F20\u7684\u56FE\u7247",
|
|
1985
|
+
className: "max-h-64 rounded-xl border border-[hsl(var(--user-msg-border))] object-cover"
|
|
1986
|
+
},
|
|
1987
|
+
part.image_url.url
|
|
1988
|
+
)) }),
|
|
1989
|
+
fileParts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs10(
|
|
1990
|
+
"div",
|
|
2417
1991
|
{
|
|
2418
|
-
|
|
2419
|
-
target: "_blank",
|
|
2420
|
-
rel: "noopener noreferrer",
|
|
2421
|
-
onClick: () => onArtifactOpened(artifactIndex, "link"),
|
|
2422
|
-
title: `${name}
|
|
2423
|
-
${artifact.target}`,
|
|
2424
|
-
className: "group relative flex min-w-0 items-center gap-1.5 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-2 py-1.5 text-xs text-[hsl(var(--card-foreground))] hover:bg-[hsl(var(--accent))]",
|
|
1992
|
+
className: "flex items-center gap-1.5 rounded-lg border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--muted)/0.3)] px-2.5 py-1.5 text-xs text-[hsl(var(--muted-foreground))]",
|
|
2425
1993
|
children: [
|
|
2426
|
-
/* @__PURE__ */
|
|
2427
|
-
/* @__PURE__ */
|
|
2428
|
-
/* @__PURE__ */ jsx13(ArrowUpRight, { size: 13, className: "absolute right-2 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" })
|
|
2429
|
-
]
|
|
2430
|
-
}
|
|
2431
|
-
);
|
|
2432
|
-
}
|
|
2433
|
-
const Icon2 = isVideo(artifact.target) ? Film : File;
|
|
2434
|
-
return /* @__PURE__ */ jsxs11(
|
|
2435
|
-
"button",
|
|
2436
|
-
{
|
|
2437
|
-
type: "button",
|
|
2438
|
-
disabled: !sessionId || downloading,
|
|
2439
|
-
onClick: async () => {
|
|
2440
|
-
if (!sessionId || downloading) return;
|
|
2441
|
-
setDownloading(true);
|
|
2442
|
-
emitInteraction(onInteraction, {
|
|
2443
|
-
type: "artifact_download_started",
|
|
2444
|
-
sessionId,
|
|
2445
|
-
assistantEntryId,
|
|
2446
|
-
artifactIndex,
|
|
2447
|
-
artifactKind: "file"
|
|
2448
|
-
});
|
|
2449
|
-
try {
|
|
2450
|
-
await client.sessions.downloadFile(sessionId, artifact.target, basename(artifact.target));
|
|
2451
|
-
emitInteraction(onInteraction, {
|
|
2452
|
-
type: "artifact_download_succeeded",
|
|
2453
|
-
sessionId,
|
|
2454
|
-
assistantEntryId,
|
|
2455
|
-
artifactIndex,
|
|
2456
|
-
artifactKind: "file"
|
|
2457
|
-
});
|
|
2458
|
-
} catch {
|
|
2459
|
-
} finally {
|
|
2460
|
-
setDownloading(false);
|
|
2461
|
-
}
|
|
2462
|
-
},
|
|
2463
|
-
title: name,
|
|
2464
|
-
"aria-label": `\u4E0B\u8F7D ${name}`,
|
|
2465
|
-
className: "group relative flex min-w-0 items-center gap-1.5 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-2 py-1.5 text-left text-xs text-[hsl(var(--card-foreground))] hover:bg-[hsl(var(--accent))] disabled:opacity-60",
|
|
2466
|
-
children: [
|
|
2467
|
-
/* @__PURE__ */ jsx13(Icon2, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }),
|
|
2468
|
-
/* @__PURE__ */ jsx13("span", { className: "min-w-0 flex-1 truncate font-medium", children: name }),
|
|
2469
|
-
/* @__PURE__ */ jsx13(Download, { size: 13, className: "absolute right-2 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" })
|
|
2470
|
-
]
|
|
2471
|
-
}
|
|
2472
|
-
);
|
|
2473
|
-
}
|
|
2474
|
-
var FEEDBACK_REASONS = [
|
|
2475
|
-
{ value: "not_solved", label: "\u6CA1\u89E3\u51B3\u95EE\u9898" },
|
|
2476
|
-
{ value: "inaccurate", label: "\u5185\u5BB9\u4E0D\u51C6\u786E" },
|
|
2477
|
-
{ value: "incomplete", label: "\u5185\u5BB9\u4E0D\u5B8C\u6574" },
|
|
2478
|
-
{ value: "needs_major_changes", label: "\u9700\u8981\u5927\u91CF\u4FEE\u6539" },
|
|
2479
|
-
{ value: "too_slow", label: "\u592A\u6162" },
|
|
2480
|
-
{ value: "other", label: "\u5176\u4ED6" }
|
|
2481
|
-
];
|
|
2482
|
-
function feedbackReasonLabel(reason) {
|
|
2483
|
-
return FEEDBACK_REASONS.find((item) => item.value === reason)?.label ?? null;
|
|
2484
|
-
}
|
|
2485
|
-
function HistoricalResultFeedback({ feedback }) {
|
|
2486
|
-
const label = feedbackReasonLabel(feedback.reason);
|
|
2487
|
-
return /* @__PURE__ */ jsxs11(
|
|
2488
|
-
"section",
|
|
2489
|
-
{
|
|
2490
|
-
"aria-label": "\u5386\u53F2\u7ED3\u679C\u53CD\u9988",
|
|
2491
|
-
className: "mt-3 w-fit max-w-full rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.2)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
2492
|
-
children: [
|
|
2493
|
-
/* @__PURE__ */ jsxs11("span", { children: [
|
|
2494
|
-
"\u4F60\u5BF9\u6B64\u8F6E\u7ED3\u679C\u7684\u8BC4\u4EF7\uFF1A",
|
|
2495
|
-
feedback.helpful ? "\u6709\u5E2E\u52A9" : "\u6CA1\u5E2E\u52A9"
|
|
2496
|
-
] }),
|
|
2497
|
-
label ? /* @__PURE__ */ jsxs11("span", { children: [
|
|
2498
|
-
" \xB7 ",
|
|
2499
|
-
label
|
|
2500
|
-
] }) : null
|
|
2501
|
-
]
|
|
2502
|
-
}
|
|
2503
|
-
);
|
|
2504
|
-
}
|
|
2505
|
-
function ResultFeedback({
|
|
2506
|
-
followup,
|
|
2507
|
-
sessionId,
|
|
2508
|
-
isViewer,
|
|
2509
|
-
onInteraction,
|
|
2510
|
-
savedFeedback,
|
|
2511
|
-
onFeedbackSaved
|
|
2512
|
-
}) {
|
|
2513
|
-
const client = useBladeClient();
|
|
2514
|
-
const [saved, setSaved] = useState10(savedFeedback ?? null);
|
|
2515
|
-
const [helpful, setHelpful] = useState10(savedFeedback?.helpful ?? null);
|
|
2516
|
-
const [reason, setReason] = useState10(savedFeedback?.reason ?? null);
|
|
2517
|
-
const [saving, setSaving] = useState10(false);
|
|
2518
|
-
const [saveError, setSaveError] = useState10(false);
|
|
2519
|
-
const reportedShown = useRef6(false);
|
|
2520
|
-
const latestChoice = useRef6(null);
|
|
2521
|
-
const eligible = followup.feedback_eligible === true && Boolean(sessionId) && !isViewer;
|
|
2522
|
-
useEffect6(() => {
|
|
2523
|
-
if (!eligible || reportedShown.current) return;
|
|
2524
|
-
reportedShown.current = true;
|
|
2525
|
-
emitInteraction(onInteraction, {
|
|
2526
|
-
type: "result_feedback_shown",
|
|
2527
|
-
sessionId,
|
|
2528
|
-
assistantEntryId: followup.assistant_entry_id
|
|
2529
|
-
});
|
|
2530
|
-
}, [eligible, followup.assistant_entry_id, onInteraction, sessionId]);
|
|
2531
|
-
useEffect6(() => {
|
|
2532
|
-
if (!savedFeedback || latestChoice.current) return;
|
|
2533
|
-
setSaved(savedFeedback);
|
|
2534
|
-
setHelpful(savedFeedback.helpful);
|
|
2535
|
-
setReason(savedFeedback.reason);
|
|
2536
|
-
}, [savedFeedback]);
|
|
2537
|
-
const submit = useCallback5(
|
|
2538
|
-
async (nextHelpful, nextReason) => {
|
|
2539
|
-
if (!sessionId) return;
|
|
2540
|
-
const choice = { helpful: nextHelpful, reason: nextReason };
|
|
2541
|
-
latestChoice.current = choice;
|
|
2542
|
-
setHelpful(nextHelpful);
|
|
2543
|
-
setReason(nextReason);
|
|
2544
|
-
setSaving(true);
|
|
2545
|
-
setSaveError(false);
|
|
2546
|
-
try {
|
|
2547
|
-
const result = await client.sessions.putResultFeedback(
|
|
2548
|
-
sessionId,
|
|
2549
|
-
followup.assistant_entry_id,
|
|
2550
|
-
choice
|
|
2551
|
-
);
|
|
2552
|
-
if (latestChoice.current !== choice) return;
|
|
2553
|
-
setSaved(result);
|
|
2554
|
-
onFeedbackSaved?.(result);
|
|
2555
|
-
emitInteraction(onInteraction, {
|
|
2556
|
-
type: "result_feedback_submitted",
|
|
2557
|
-
sessionId,
|
|
2558
|
-
assistantEntryId: followup.assistant_entry_id,
|
|
2559
|
-
helpful: result.helpful,
|
|
2560
|
-
reason: result.reason,
|
|
2561
|
-
updatedAt: result.updated_at
|
|
2562
|
-
});
|
|
2563
|
-
} catch {
|
|
2564
|
-
if (latestChoice.current === choice) setSaveError(true);
|
|
2565
|
-
} finally {
|
|
2566
|
-
if (latestChoice.current === choice) setSaving(false);
|
|
2567
|
-
}
|
|
2568
|
-
},
|
|
2569
|
-
[client, followup.assistant_entry_id, onFeedbackSaved, onInteraction, sessionId]
|
|
2570
|
-
);
|
|
2571
|
-
if (!eligible) return null;
|
|
2572
|
-
return /* @__PURE__ */ jsxs11(
|
|
2573
|
-
"section",
|
|
2574
|
-
{
|
|
2575
|
-
"aria-label": "\u7ED3\u679C\u53CD\u9988",
|
|
2576
|
-
className: "flex flex-col gap-2 border-t border-[hsl(var(--border))] pt-3",
|
|
2577
|
-
children: [
|
|
2578
|
-
/* @__PURE__ */ jsx13("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u76EE\u524D\u7684\u6574\u4F53\u7ED3\u679C\u6709\u5E2E\u52A9\u5417\uFF1F" }),
|
|
2579
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap gap-1.5", children: [
|
|
2580
|
-
/* @__PURE__ */ jsx13(
|
|
2581
|
-
"button",
|
|
2582
|
-
{
|
|
2583
|
-
type: "button",
|
|
2584
|
-
"aria-pressed": helpful === true,
|
|
2585
|
-
disabled: saving,
|
|
2586
|
-
onClick: () => void submit(true, null),
|
|
2587
|
-
className: "rounded-lg border border-[hsl(var(--border))] px-2.5 py-1.5 text-xs aria-pressed:bg-[hsl(var(--primary)/0.1)] disabled:opacity-60",
|
|
2588
|
-
children: "\u6709\u5E2E\u52A9"
|
|
2589
|
-
}
|
|
2590
|
-
),
|
|
2591
|
-
/* @__PURE__ */ jsx13(
|
|
2592
|
-
"button",
|
|
2593
|
-
{
|
|
2594
|
-
type: "button",
|
|
2595
|
-
"aria-pressed": helpful === false,
|
|
2596
|
-
disabled: saving,
|
|
2597
|
-
onClick: () => void submit(false, reason),
|
|
2598
|
-
className: "rounded-lg border border-[hsl(var(--border))] px-2.5 py-1.5 text-xs aria-pressed:bg-[hsl(var(--primary)/0.1)] disabled:opacity-60",
|
|
2599
|
-
children: "\u6CA1\u5E2E\u52A9"
|
|
2600
|
-
}
|
|
2601
|
-
)
|
|
2602
|
-
] }),
|
|
2603
|
-
helpful === false ? /* @__PURE__ */ jsx13("div", { className: "flex flex-wrap gap-1.5", "aria-label": "\u6CA1\u5E2E\u52A9\u7684\u4E3B\u8981\u539F\u56E0", children: FEEDBACK_REASONS.map((item) => /* @__PURE__ */ jsx13(
|
|
2604
|
-
"button",
|
|
2605
|
-
{
|
|
2606
|
-
type: "button",
|
|
2607
|
-
"aria-pressed": reason === item.value,
|
|
2608
|
-
disabled: saving,
|
|
2609
|
-
onClick: () => void submit(false, item.value),
|
|
2610
|
-
className: "rounded-full bg-[hsl(var(--muted)/0.62)] px-2.5 py-1 text-[11px] aria-pressed:bg-[hsl(var(--primary)/0.14)] disabled:opacity-60",
|
|
2611
|
-
children: item.label
|
|
2612
|
-
},
|
|
2613
|
-
item.value
|
|
2614
|
-
)) }) : null,
|
|
2615
|
-
saveError ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--destructive))]", children: [
|
|
2616
|
-
/* @__PURE__ */ jsx13("span", { children: "\u53CD\u9988\u6682\u672A\u4FDD\u5B58\uFF0C\u53EF\u91CD\u8BD5" }),
|
|
2617
|
-
/* @__PURE__ */ jsx13(
|
|
2618
|
-
"button",
|
|
2619
|
-
{
|
|
2620
|
-
type: "button",
|
|
2621
|
-
className: "underline",
|
|
2622
|
-
onClick: () => {
|
|
2623
|
-
const choice = latestChoice.current;
|
|
2624
|
-
if (choice) void submit(choice.helpful, choice.reason);
|
|
2625
|
-
},
|
|
2626
|
-
children: "\u91CD\u8BD5"
|
|
2627
|
-
}
|
|
2628
|
-
)
|
|
2629
|
-
] }) : saved ? /* @__PURE__ */ jsx13("div", { className: "text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u4FDD\u5B58\uFF0C\u53EF\u968F\u65F6\u4FEE\u6539" }) : null
|
|
2630
|
-
]
|
|
2631
|
-
}
|
|
2632
|
-
);
|
|
2633
|
-
}
|
|
2634
|
-
function PostChatFollowupBlock({
|
|
2635
|
-
followup,
|
|
2636
|
-
sessionId,
|
|
2637
|
-
onSuggestion,
|
|
2638
|
-
isViewer = false,
|
|
2639
|
-
onInteraction,
|
|
2640
|
-
savedFeedback,
|
|
2641
|
-
onFeedbackSaved
|
|
2642
|
-
}) {
|
|
2643
|
-
const [expanded, setExpanded] = useState10(false);
|
|
2644
|
-
const adopted = useRef6(/* @__PURE__ */ new Set());
|
|
2645
|
-
const reportedSuggestions = useRef6(false);
|
|
2646
|
-
const reportedArtifacts = useRef6(/* @__PURE__ */ new Set());
|
|
2647
|
-
const openedArtifacts = useRef6(/* @__PURE__ */ new Set());
|
|
2648
|
-
const artifacts = followup.final_artifacts ?? [];
|
|
2649
|
-
const visibleArtifacts = expanded ? artifacts : artifacts.slice(0, 3);
|
|
2650
|
-
useEffect6(() => {
|
|
2651
|
-
if (!reportedSuggestions.current && followup.suggestions.length > 0) {
|
|
2652
|
-
reportedSuggestions.current = true;
|
|
2653
|
-
emitInteraction(onInteraction, {
|
|
2654
|
-
type: "suggestions_shown",
|
|
2655
|
-
sessionId,
|
|
2656
|
-
assistantEntryId: followup.assistant_entry_id,
|
|
2657
|
-
count: followup.suggestions.length
|
|
2658
|
-
});
|
|
2659
|
-
}
|
|
2660
|
-
for (let artifactIndex = 0; artifactIndex < visibleArtifacts.length; artifactIndex += 1) {
|
|
2661
|
-
if (reportedArtifacts.current.has(artifactIndex)) continue;
|
|
2662
|
-
const artifact = visibleArtifacts[artifactIndex];
|
|
2663
|
-
if (!artifact) continue;
|
|
2664
|
-
reportedArtifacts.current.add(artifactIndex);
|
|
2665
|
-
emitInteraction(onInteraction, {
|
|
2666
|
-
type: "artifact_shown",
|
|
2667
|
-
sessionId,
|
|
2668
|
-
assistantEntryId: followup.assistant_entry_id,
|
|
2669
|
-
artifactIndex,
|
|
2670
|
-
artifactKind: artifact.kind
|
|
2671
|
-
});
|
|
2672
|
-
}
|
|
2673
|
-
}, [
|
|
2674
|
-
followup.assistant_entry_id,
|
|
2675
|
-
followup.suggestions.length,
|
|
2676
|
-
onInteraction,
|
|
2677
|
-
sessionId,
|
|
2678
|
-
visibleArtifacts
|
|
2679
|
-
]);
|
|
2680
|
-
const reportArtifactOpened = useCallback5(
|
|
2681
|
-
(artifactIndex, artifactKind) => {
|
|
2682
|
-
if (openedArtifacts.current.has(artifactIndex)) return;
|
|
2683
|
-
openedArtifacts.current.add(artifactIndex);
|
|
2684
|
-
emitInteraction(onInteraction, {
|
|
2685
|
-
type: "artifact_opened",
|
|
2686
|
-
sessionId,
|
|
2687
|
-
assistantEntryId: followup.assistant_entry_id,
|
|
2688
|
-
artifactIndex,
|
|
2689
|
-
artifactKind
|
|
2690
|
-
});
|
|
2691
|
-
},
|
|
2692
|
-
[followup.assistant_entry_id, onInteraction, sessionId]
|
|
2693
|
-
);
|
|
2694
|
-
if (!followup.recaption && artifacts.length === 0 && followup.suggestions.length === 0 && !followup.feedback_eligible)
|
|
2695
|
-
return null;
|
|
2696
|
-
return /* @__PURE__ */ jsxs11("div", { className: "mt-3 flex w-fit max-w-full flex-col gap-3 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.28)] p-3 sm:max-w-[680px]", children: [
|
|
2697
|
-
followup.recaption || artifacts.length > 0 ? /* @__PURE__ */ jsxs11("section", { "aria-label": "\u672C\u8F6E\u5C0F\u7ED3", className: "flex flex-col gap-2", children: [
|
|
2698
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 text-xs font-medium text-[hsl(var(--muted-foreground))]", children: [
|
|
2699
|
-
/* @__PURE__ */ jsx13(Sparkles, { size: 14 }),
|
|
2700
|
-
"\u672C\u8F6E\u5C0F\u7ED3"
|
|
2701
|
-
] }),
|
|
2702
|
-
followup.recaption ? /* @__PURE__ */ jsx13("p", { className: "text-[13px] leading-5", children: followup.recaption }) : null,
|
|
2703
|
-
artifacts.length > 0 ? /* @__PURE__ */ jsxs11(Fragment2, { children: [
|
|
2704
|
-
/* @__PURE__ */ jsx13("div", { className: "grid max-w-full grid-cols-3 gap-1.5", children: visibleArtifacts.map((artifact, artifactIndex) => /* @__PURE__ */ jsx13(
|
|
2705
|
-
ArtifactCard,
|
|
2706
|
-
{
|
|
2707
|
-
artifact,
|
|
2708
|
-
sessionId,
|
|
2709
|
-
assistantEntryId: followup.assistant_entry_id,
|
|
2710
|
-
artifactIndex,
|
|
2711
|
-
onInteraction,
|
|
2712
|
-
onArtifactOpened: reportArtifactOpened
|
|
2713
|
-
},
|
|
2714
|
-
`${artifact.kind}:${artifactIndex}`
|
|
2715
|
-
)) }),
|
|
2716
|
-
artifacts.length > 3 ? /* @__PURE__ */ jsxs11(
|
|
2717
|
-
"button",
|
|
2718
|
-
{
|
|
2719
|
-
type: "button",
|
|
2720
|
-
onClick: () => setExpanded((value) => !value),
|
|
2721
|
-
"aria-expanded": expanded,
|
|
2722
|
-
className: "flex w-fit items-center gap-0.5 text-[11px] text-[hsl(var(--muted-foreground))]",
|
|
2723
|
-
children: [
|
|
2724
|
-
expanded ? "\u6536\u8D77" : `\u5C55\u5F00 ${artifacts.length - 3} \u4E2A`,
|
|
2725
|
-
/* @__PURE__ */ jsx13(ChevronDown, { size: 13, className: expanded ? "rotate-180" : void 0 })
|
|
2726
|
-
]
|
|
2727
|
-
}
|
|
2728
|
-
) : null
|
|
2729
|
-
] }) : null
|
|
2730
|
-
] }) : null,
|
|
2731
|
-
followup.suggestions.length > 0 ? /* @__PURE__ */ jsxs11("section", { "aria-label": "\u4E0B\u4E00\u6B65\u5EFA\u8BAE", className: "flex flex-col gap-1.5", children: [
|
|
2732
|
-
/* @__PURE__ */ jsx13("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u4E0B\u4E00\u6B65\u53EF\u4EE5" }),
|
|
2733
|
-
followup.suggestions.map((suggestion, suggestionIndex) => /* @__PURE__ */ jsxs11(
|
|
2734
|
-
"button",
|
|
2735
|
-
{
|
|
2736
|
-
type: "button",
|
|
2737
|
-
disabled: isViewer,
|
|
2738
|
-
onClick: () => {
|
|
2739
|
-
if (!adopted.current.has(suggestionIndex)) {
|
|
2740
|
-
adopted.current.add(suggestionIndex);
|
|
2741
|
-
emitInteraction(onInteraction, {
|
|
2742
|
-
type: "suggestion_adopted",
|
|
2743
|
-
sessionId,
|
|
2744
|
-
assistantEntryId: followup.assistant_entry_id,
|
|
2745
|
-
suggestionIndex
|
|
2746
|
-
});
|
|
2747
|
-
}
|
|
2748
|
-
onSuggestion?.(suggestion);
|
|
2749
|
-
},
|
|
2750
|
-
className: "group flex items-center gap-2 rounded-xl bg-[hsl(var(--muted)/0.62)] px-3 py-2 text-left text-[13px] disabled:cursor-default disabled:opacity-60",
|
|
2751
|
-
children: [
|
|
2752
|
-
/* @__PURE__ */ jsx13("span", { children: suggestion }),
|
|
2753
|
-
/* @__PURE__ */ jsx13(ArrowRight, { size: 14, className: "ml-auto shrink-0" })
|
|
2754
|
-
]
|
|
2755
|
-
},
|
|
2756
|
-
suggestion
|
|
2757
|
-
))
|
|
2758
|
-
] }) : null,
|
|
2759
|
-
/* @__PURE__ */ jsx13(
|
|
2760
|
-
ResultFeedback,
|
|
2761
|
-
{
|
|
2762
|
-
followup,
|
|
2763
|
-
sessionId,
|
|
2764
|
-
isViewer,
|
|
2765
|
-
onInteraction,
|
|
2766
|
-
savedFeedback,
|
|
2767
|
-
onFeedbackSaved
|
|
2768
|
-
}
|
|
2769
|
-
)
|
|
2770
|
-
] });
|
|
2771
|
-
}
|
|
2772
|
-
|
|
2773
|
-
// src/components/UserMessageBubble.tsx
|
|
2774
|
-
import { getFileParts, getImageParts, getTextContent as getTextContent2 } from "@blade-hq/agent-client";
|
|
2775
|
-
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2776
|
-
function isUserMessage(message) {
|
|
2777
|
-
return message.role === "user";
|
|
2778
|
-
}
|
|
2779
|
-
function isErrorMessage(message) {
|
|
2780
|
-
return message.role === "error";
|
|
2781
|
-
}
|
|
2782
|
-
var isSending = (message) => message.status === "streaming";
|
|
2783
|
-
function UserMessageBubble({ message, className }) {
|
|
2784
|
-
const text = getTextContent2(message.content).trim();
|
|
2785
|
-
const fileParts = getFileParts(message.content);
|
|
2786
|
-
const imageParts = getImageParts(message.content);
|
|
2787
|
-
return /* @__PURE__ */ jsx14("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsxs12("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: [
|
|
2788
|
-
imageParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx14(
|
|
2789
|
-
"img",
|
|
2790
|
-
{
|
|
2791
|
-
src: part.image_url.url,
|
|
2792
|
-
alt: "\u7528\u6237\u4E0A\u4F20\u7684\u56FE\u7247",
|
|
2793
|
-
className: "max-h-64 rounded-xl border border-[hsl(var(--user-msg-border))] object-cover"
|
|
2794
|
-
},
|
|
2795
|
-
part.image_url.url
|
|
2796
|
-
)) }),
|
|
2797
|
-
fileParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs12(
|
|
2798
|
-
"div",
|
|
2799
|
-
{
|
|
2800
|
-
className: "flex items-center gap-1.5 rounded-lg border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--muted)/0.3)] px-2.5 py-1.5 text-xs text-[hsl(var(--muted-foreground))]",
|
|
2801
|
-
children: [
|
|
2802
|
-
/* @__PURE__ */ jsx14(FileText, { size: 12, className: "shrink-0" }),
|
|
2803
|
-
/* @__PURE__ */ jsx14("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
|
|
1994
|
+
/* @__PURE__ */ jsx12(FileText, { size: 12, className: "shrink-0" }),
|
|
1995
|
+
/* @__PURE__ */ jsx12("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
|
|
2804
1996
|
]
|
|
2805
1997
|
},
|
|
2806
1998
|
`${part.name}-${part.data.length}`
|
|
2807
1999
|
)) }),
|
|
2808
|
-
text && /* @__PURE__ */
|
|
2809
|
-
text && isSending(message) && /* @__PURE__ */
|
|
2810
|
-
/* @__PURE__ */
|
|
2811
|
-
/* @__PURE__ */
|
|
2000
|
+
text && /* @__PURE__ */ jsx12("div", { className: "blade-chat-user-bubble max-w-full rounded-[20px] rounded-br-[6px] border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-[18px] py-[13px] text-sm leading-[1.65] text-[hsl(var(--user-msg-fg))]", children: /* @__PURE__ */ jsx12(MarkdownContent, { className: "blade-chat-prose", children: text }) }),
|
|
2001
|
+
text && isSending(message) && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]", children: [
|
|
2002
|
+
/* @__PURE__ */ jsx12(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
|
|
2003
|
+
/* @__PURE__ */ jsx12("span", { children: "\u53D1\u9001\u4E2D" })
|
|
2812
2004
|
] })
|
|
2813
2005
|
] }) });
|
|
2814
2006
|
}
|
|
@@ -2817,11 +2009,11 @@ function ErrorMessageBlock({
|
|
|
2817
2009
|
className
|
|
2818
2010
|
}) {
|
|
2819
2011
|
const text = getTextContent2(message.content);
|
|
2820
|
-
return /* @__PURE__ */
|
|
2012
|
+
return /* @__PURE__ */ jsx12("div", { className: cn("blade-chat-error-row flex justify-center", className), children: /* @__PURE__ */ jsx12("div", { className: "blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--border))] px-4 py-1 text-sm leading-7 text-[hsl(var(--muted-foreground))]", children: text }) });
|
|
2821
2013
|
}
|
|
2822
2014
|
|
|
2823
2015
|
// src/components/MessageList.tsx
|
|
2824
|
-
import { jsx as
|
|
2016
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2825
2017
|
function parseModeChange(message) {
|
|
2826
2018
|
if (message.kind !== "mode_change" || typeof message.content !== "string") {
|
|
2827
2019
|
return null;
|
|
@@ -2855,8 +2047,6 @@ function getMessageResetSignature(messages) {
|
|
|
2855
2047
|
}
|
|
2856
2048
|
function MessageList({
|
|
2857
2049
|
messages,
|
|
2858
|
-
postChatFollowup,
|
|
2859
|
-
onSuggestion,
|
|
2860
2050
|
isStreaming,
|
|
2861
2051
|
sessionStatus,
|
|
2862
2052
|
askAnswers,
|
|
@@ -2864,13 +2054,9 @@ function MessageList({
|
|
|
2864
2054
|
toolCallRenderer,
|
|
2865
2055
|
emptyState,
|
|
2866
2056
|
className,
|
|
2867
|
-
sessionId
|
|
2868
|
-
isViewer = false,
|
|
2869
|
-
onFollowupInteraction,
|
|
2870
|
-
resultFeedbackByEntry = /* @__PURE__ */ new Map(),
|
|
2871
|
-
onResultFeedbackSaved
|
|
2057
|
+
sessionId
|
|
2872
2058
|
}) {
|
|
2873
|
-
const renderBlocks =
|
|
2059
|
+
const renderBlocks = useMemo6(() => {
|
|
2874
2060
|
const visible = messages.filter((message) => {
|
|
2875
2061
|
if ((message.loop_name ?? "root") !== "root") return false;
|
|
2876
2062
|
if (isHiddenInternalMessage(message)) return false;
|
|
@@ -2943,86 +2129,63 @@ function MessageList({
|
|
|
2943
2129
|
}
|
|
2944
2130
|
return blocks;
|
|
2945
2131
|
}, [messages, isStreaming]);
|
|
2946
|
-
return /* @__PURE__ */
|
|
2947
|
-
/* @__PURE__ */
|
|
2948
|
-
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */
|
|
2949
|
-
/* @__PURE__ */
|
|
2950
|
-
/* @__PURE__ */
|
|
2951
|
-
/* @__PURE__ */
|
|
2132
|
+
return /* @__PURE__ */ jsx13("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: /* @__PURE__ */ jsxs11(StickToBottom, { className: "h-full overflow-y-hidden", initial: "instant", resize: "instant", children: [
|
|
2133
|
+
/* @__PURE__ */ jsx13(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */ jsx13("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: /* @__PURE__ */ jsxs11("div", { className: "flex min-w-0 flex-col", children: [
|
|
2134
|
+
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs11("div", { className: "blade-chat-empty", children: [
|
|
2135
|
+
/* @__PURE__ */ jsx13(MessageSquare, { size: 40, strokeWidth: 1.5 }),
|
|
2136
|
+
/* @__PURE__ */ jsx13("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
|
|
2137
|
+
/* @__PURE__ */ jsx13("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
|
|
2952
2138
|
] }) : renderBlocks.map((block) => {
|
|
2953
2139
|
if (block.type === "message") {
|
|
2954
|
-
return /* @__PURE__ */
|
|
2140
|
+
return /* @__PURE__ */ jsx13("div", { "data-entry-id": block.message.entry_id, children: isUserMessage(block.message) ? /* @__PURE__ */ jsx13(UserMessageBubble, { message: block.message }) : isErrorMessage(block.message) ? /* @__PURE__ */ jsx13(ErrorMessageBlock, { message: block.message }) : null }, block.key);
|
|
2955
2141
|
}
|
|
2956
2142
|
if (block.type === "assistant_turn") {
|
|
2957
|
-
|
|
2958
|
-
(message) => message.entry_id ? resultFeedbackByEntry.get(message.entry_id) : void 0
|
|
2959
|
-
).find((feedback) => feedback != null);
|
|
2960
|
-
const hasActiveFollowup = Boolean(
|
|
2961
|
-
postChatFollowup && block.messages.some(
|
|
2962
|
-
(message) => message.entry_id === postChatFollowup.assistant_entry_id
|
|
2963
|
-
)
|
|
2964
|
-
);
|
|
2965
|
-
return /* @__PURE__ */ jsx15("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs13(
|
|
2143
|
+
return /* @__PURE__ */ jsx13("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsx13(
|
|
2966
2144
|
RenderErrorBoundary,
|
|
2967
2145
|
{
|
|
2968
2146
|
label: "\u52A9\u624B\u6D88\u606F",
|
|
2969
2147
|
details: block.key,
|
|
2970
2148
|
resetKey: getMessageResetSignature(block.messages),
|
|
2971
|
-
children:
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
),
|
|
2984
|
-
blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx15(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
|
|
2985
|
-
hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx15(
|
|
2986
|
-
PostChatFollowupBlock,
|
|
2987
|
-
{
|
|
2988
|
-
followup: postChatFollowup,
|
|
2989
|
-
sessionId,
|
|
2990
|
-
onSuggestion,
|
|
2991
|
-
isViewer,
|
|
2992
|
-
onInteraction: onFollowupInteraction,
|
|
2993
|
-
savedFeedback: blockFeedback,
|
|
2994
|
-
onFeedbackSaved: onResultFeedbackSaved
|
|
2995
|
-
}
|
|
2996
|
-
) : null
|
|
2997
|
-
]
|
|
2149
|
+
children: /* @__PURE__ */ jsx13(
|
|
2150
|
+
AssistantTurnBlock,
|
|
2151
|
+
{
|
|
2152
|
+
messages: block.messages,
|
|
2153
|
+
isStreaming: block.isStreaming,
|
|
2154
|
+
askAnswers,
|
|
2155
|
+
onAnswer,
|
|
2156
|
+
sessionStatus,
|
|
2157
|
+
toolCallRenderer,
|
|
2158
|
+
sessionId
|
|
2159
|
+
}
|
|
2160
|
+
)
|
|
2998
2161
|
}
|
|
2999
2162
|
) }, block.key);
|
|
3000
2163
|
}
|
|
3001
2164
|
if (block.type === "compaction") {
|
|
3002
|
-
return /* @__PURE__ */
|
|
2165
|
+
return /* @__PURE__ */ jsxs11(
|
|
3003
2166
|
"div",
|
|
3004
2167
|
{
|
|
3005
2168
|
className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
3006
2169
|
children: [
|
|
3007
|
-
/* @__PURE__ */
|
|
3008
|
-
/* @__PURE__ */
|
|
2170
|
+
/* @__PURE__ */ jsx13(Layers, { size: 12 }),
|
|
2171
|
+
/* @__PURE__ */ jsx13("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
|
|
3009
2172
|
]
|
|
3010
2173
|
},
|
|
3011
2174
|
block.key
|
|
3012
2175
|
);
|
|
3013
2176
|
}
|
|
3014
|
-
return /* @__PURE__ */
|
|
2177
|
+
return /* @__PURE__ */ jsx13(PlanningDivider, { kind: block.kind }, block.key);
|
|
3015
2178
|
}),
|
|
3016
|
-
sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */
|
|
2179
|
+
sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */ jsx13("div", { className: "flex", children: /* @__PURE__ */ jsx13("div", { className: "rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }) }) : null
|
|
3017
2180
|
] }) }) }),
|
|
3018
|
-
/* @__PURE__ */
|
|
3019
|
-
/* @__PURE__ */
|
|
2181
|
+
/* @__PURE__ */ jsx13(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
|
|
2182
|
+
/* @__PURE__ */ jsx13(ScrollToBottomButton, {})
|
|
3020
2183
|
] }) });
|
|
3021
2184
|
}
|
|
3022
2185
|
function AutoScrollOnUserSend({ userMessageCount }) {
|
|
3023
2186
|
const { scrollToBottom } = useStickToBottomContext();
|
|
3024
|
-
const previousCountRef =
|
|
3025
|
-
|
|
2187
|
+
const previousCountRef = useRef5(userMessageCount);
|
|
2188
|
+
useEffect5(() => {
|
|
3026
2189
|
if (userMessageCount > previousCountRef.current) {
|
|
3027
2190
|
scrollToBottom("instant");
|
|
3028
2191
|
}
|
|
@@ -3032,9 +2195,9 @@ function AutoScrollOnUserSend({ userMessageCount }) {
|
|
|
3032
2195
|
}
|
|
3033
2196
|
function ScrollToBottomButton() {
|
|
3034
2197
|
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
|
3035
|
-
const [visible, setVisible] =
|
|
3036
|
-
const hideTimerRef =
|
|
3037
|
-
|
|
2198
|
+
const [visible, setVisible] = useState9(false);
|
|
2199
|
+
const hideTimerRef = useRef5(null);
|
|
2200
|
+
useEffect5(() => {
|
|
3038
2201
|
if (isAtBottom) {
|
|
3039
2202
|
if (!hideTimerRef.current) {
|
|
3040
2203
|
hideTimerRef.current = setTimeout(() => {
|
|
@@ -3056,7 +2219,7 @@ function ScrollToBottomButton() {
|
|
|
3056
2219
|
}
|
|
3057
2220
|
};
|
|
3058
2221
|
}, [isAtBottom]);
|
|
3059
|
-
const handleClick =
|
|
2222
|
+
const handleClick = useCallback3(() => {
|
|
3060
2223
|
if (hideTimerRef.current) {
|
|
3061
2224
|
clearTimeout(hideTimerRef.current);
|
|
3062
2225
|
hideTimerRef.current = null;
|
|
@@ -3065,7 +2228,7 @@ function ScrollToBottomButton() {
|
|
|
3065
2228
|
scrollToBottom();
|
|
3066
2229
|
}, [scrollToBottom]);
|
|
3067
2230
|
if (!visible) return null;
|
|
3068
|
-
return /* @__PURE__ */
|
|
2231
|
+
return /* @__PURE__ */ jsxs11(
|
|
3069
2232
|
"button",
|
|
3070
2233
|
{
|
|
3071
2234
|
type: "button",
|
|
@@ -3073,120 +2236,34 @@ function ScrollToBottomButton() {
|
|
|
3073
2236
|
"aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
|
|
3074
2237
|
className: "blade-chat-scroll-bottom absolute bottom-4 right-4 flex items-center gap-1 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-1.5 text-xs text-[hsl(var(--muted-foreground))] shadow-lg transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
|
|
3075
2238
|
children: [
|
|
3076
|
-
/* @__PURE__ */
|
|
3077
|
-
/* @__PURE__ */
|
|
2239
|
+
/* @__PURE__ */ jsx13(ChevronDown, { size: 14 }),
|
|
2240
|
+
/* @__PURE__ */ jsx13("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
|
|
3078
2241
|
]
|
|
3079
2242
|
}
|
|
3080
2243
|
);
|
|
3081
2244
|
}
|
|
3082
2245
|
function PlanningDivider({ kind }) {
|
|
3083
|
-
return /* @__PURE__ */
|
|
3084
|
-
/* @__PURE__ */
|
|
3085
|
-
/* @__PURE__ */
|
|
3086
|
-
/* @__PURE__ */
|
|
3087
|
-
/* @__PURE__ */
|
|
2246
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-3 py-1", children: [
|
|
2247
|
+
/* @__PURE__ */ jsx13("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
|
|
2248
|
+
/* @__PURE__ */ jsxs11("div", { className: "inline-flex items-center gap-1.5 rounded-full border border-amber-500/30 bg-amber-500/10 px-3 py-1 text-[11px] text-amber-300", children: [
|
|
2249
|
+
/* @__PURE__ */ jsx13(Lightbulb, { size: 12 }),
|
|
2250
|
+
/* @__PURE__ */ jsx13("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
|
|
3088
2251
|
] }),
|
|
3089
|
-
/* @__PURE__ */
|
|
2252
|
+
/* @__PURE__ */ jsx13("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
|
|
3090
2253
|
] });
|
|
3091
2254
|
}
|
|
3092
2255
|
|
|
3093
|
-
// src/components/
|
|
3094
|
-
import { jsx as
|
|
2256
|
+
// src/components/ChatView.tsx
|
|
2257
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3095
2258
|
function themeAttr(theme) {
|
|
3096
2259
|
return theme === "dark" ? "dark" : void 0;
|
|
3097
2260
|
}
|
|
3098
|
-
function ChatSurface({
|
|
3099
|
-
theme,
|
|
3100
|
-
classNames,
|
|
3101
|
-
renderers,
|
|
3102
|
-
slots,
|
|
3103
|
-
placeholder,
|
|
3104
|
-
connection,
|
|
3105
|
-
errorMessage,
|
|
3106
|
-
messages,
|
|
3107
|
-
postChatFollowup,
|
|
3108
|
-
isStreaming,
|
|
3109
|
-
isStopping,
|
|
3110
|
-
inputText,
|
|
3111
|
-
onInputChange,
|
|
3112
|
-
onSuggestion,
|
|
3113
|
-
onSend,
|
|
3114
|
-
onStop,
|
|
3115
|
-
sessionStatus,
|
|
3116
|
-
askAnswers,
|
|
3117
|
-
onAnswer,
|
|
3118
|
-
sessionId,
|
|
3119
|
-
isViewer,
|
|
3120
|
-
resultFeedbackByEntry,
|
|
3121
|
-
onResultFeedbackSaved,
|
|
3122
|
-
onFollowupInteraction,
|
|
3123
|
-
beforeInput,
|
|
3124
|
-
banner
|
|
3125
|
-
}) {
|
|
3126
|
-
return /* @__PURE__ */ jsxs14(
|
|
3127
|
-
"div",
|
|
3128
|
-
{
|
|
3129
|
-
"data-theme": themeAttr(theme),
|
|
3130
|
-
className: cn(
|
|
3131
|
-
"blade-chat flex min-h-0 flex-1 flex-col overflow-hidden",
|
|
3132
|
-
classNames?.root
|
|
3133
|
-
),
|
|
3134
|
-
children: [
|
|
3135
|
-
/* @__PURE__ */ jsx16(ConnectionBanner, { connection, className: classNames?.banner }),
|
|
3136
|
-
banner,
|
|
3137
|
-
errorMessage && /* @__PURE__ */ jsxs14("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
|
|
3138
|
-
/* @__PURE__ */ jsx16(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
|
|
3139
|
-
/* @__PURE__ */ jsx16("span", { children: errorMessage })
|
|
3140
|
-
] }),
|
|
3141
|
-
slots?.header,
|
|
3142
|
-
/* @__PURE__ */ jsx16(
|
|
3143
|
-
MessageList,
|
|
3144
|
-
{
|
|
3145
|
-
messages,
|
|
3146
|
-
postChatFollowup,
|
|
3147
|
-
onSuggestion,
|
|
3148
|
-
isStreaming,
|
|
3149
|
-
sessionStatus,
|
|
3150
|
-
askAnswers,
|
|
3151
|
-
onAnswer,
|
|
3152
|
-
toolCallRenderer: renderers?.toolCall,
|
|
3153
|
-
emptyState: slots?.emptyState,
|
|
3154
|
-
className: classNames?.messageList,
|
|
3155
|
-
sessionId,
|
|
3156
|
-
isViewer,
|
|
3157
|
-
resultFeedbackByEntry,
|
|
3158
|
-
onResultFeedbackSaved,
|
|
3159
|
-
onFollowupInteraction
|
|
3160
|
-
}
|
|
3161
|
-
),
|
|
3162
|
-
beforeInput,
|
|
3163
|
-
/* @__PURE__ */ jsx16(
|
|
3164
|
-
ChatInput,
|
|
3165
|
-
{
|
|
3166
|
-
value: inputText,
|
|
3167
|
-
onValueChange: onInputChange,
|
|
3168
|
-
onSend,
|
|
3169
|
-
onStop,
|
|
3170
|
-
isStreaming,
|
|
3171
|
-
isStopping,
|
|
3172
|
-
placeholder,
|
|
3173
|
-
className: classNames?.chatInput
|
|
3174
|
-
}
|
|
3175
|
-
),
|
|
3176
|
-
slots?.footer
|
|
3177
|
-
]
|
|
3178
|
-
}
|
|
3179
|
-
);
|
|
3180
|
-
}
|
|
3181
|
-
|
|
3182
|
-
// src/components/AgentChat.tsx
|
|
3183
|
-
import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3184
2261
|
function isUnauthorizedError(error) {
|
|
3185
2262
|
return error instanceof BladeApiError && error.status === 401;
|
|
3186
2263
|
}
|
|
3187
2264
|
function LoginCard({ client, onLoggedIn }) {
|
|
3188
|
-
const [loggingIn, setLoggingIn] =
|
|
3189
|
-
const [loginError, setLoginError] =
|
|
2265
|
+
const [loggingIn, setLoggingIn] = useState10(false);
|
|
2266
|
+
const [loginError, setLoginError] = useState10(null);
|
|
3190
2267
|
const handleLogin = async () => {
|
|
3191
2268
|
setLoggingIn(true);
|
|
3192
2269
|
setLoginError(null);
|
|
@@ -3199,11 +2276,11 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
3199
2276
|
setLoggingIn(false);
|
|
3200
2277
|
}
|
|
3201
2278
|
};
|
|
3202
|
-
return /* @__PURE__ */
|
|
3203
|
-
/* @__PURE__ */
|
|
3204
|
-
/* @__PURE__ */
|
|
3205
|
-
/* @__PURE__ */
|
|
3206
|
-
/* @__PURE__ */
|
|
2279
|
+
return /* @__PURE__ */ jsx14("div", { className: "blade-chat-login flex flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsxs12("div", { className: "flex w-full max-w-sm flex-col items-center gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-6 py-8 text-center", children: [
|
|
2280
|
+
/* @__PURE__ */ jsx14(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
|
|
2281
|
+
/* @__PURE__ */ jsx14("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
|
|
2282
|
+
/* @__PURE__ */ jsx14("div", { className: "text-sm text-[hsl(var(--muted-foreground))]", children: "\u767B\u5F55\u540E\u5373\u53EF\u4E0E\u667A\u80FD\u4F53\u5BF9\u8BDD\uFF0C\u4F60\u7684\u4F1A\u8BDD\u5185\u5BB9\u4EC5\u81EA\u5DF1\u53EF\u89C1\u3002" }),
|
|
2283
|
+
/* @__PURE__ */ jsx14(
|
|
3207
2284
|
"button",
|
|
3208
2285
|
{
|
|
3209
2286
|
type: "button",
|
|
@@ -3213,20 +2290,20 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
3213
2290
|
children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
|
|
3214
2291
|
}
|
|
3215
2292
|
),
|
|
3216
|
-
loginError && /* @__PURE__ */
|
|
2293
|
+
loginError && /* @__PURE__ */ jsx14("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
|
|
3217
2294
|
] }) });
|
|
3218
2295
|
}
|
|
3219
|
-
function
|
|
2296
|
+
function ChatView(props) {
|
|
3220
2297
|
const client = useBladeClient();
|
|
3221
|
-
const [attempt, setAttempt] =
|
|
3222
|
-
const [needLogin, setNeedLogin] =
|
|
2298
|
+
const [attempt, setAttempt] = useState10(0);
|
|
2299
|
+
const [needLogin, setNeedLogin] = useState10(() => !client.hasToken());
|
|
3223
2300
|
if (needLogin) {
|
|
3224
|
-
return /* @__PURE__ */
|
|
2301
|
+
return /* @__PURE__ */ jsx14(
|
|
3225
2302
|
"div",
|
|
3226
2303
|
{
|
|
3227
2304
|
"data-theme": themeAttr(props.theme),
|
|
3228
2305
|
className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
|
|
3229
|
-
children: /* @__PURE__ */
|
|
2306
|
+
children: /* @__PURE__ */ jsx14(
|
|
3230
2307
|
LoginCard,
|
|
3231
2308
|
{
|
|
3232
2309
|
client,
|
|
@@ -3239,7 +2316,7 @@ function AgentChat(props) {
|
|
|
3239
2316
|
}
|
|
3240
2317
|
);
|
|
3241
2318
|
}
|
|
3242
|
-
return /* @__PURE__ */
|
|
2319
|
+
return /* @__PURE__ */ jsx14(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
|
|
3243
2320
|
}
|
|
3244
2321
|
function ChatSessionView({
|
|
3245
2322
|
sessionId,
|
|
@@ -3252,61 +2329,20 @@ function ChatSessionView({
|
|
|
3252
2329
|
slots,
|
|
3253
2330
|
placeholder,
|
|
3254
2331
|
theme,
|
|
3255
|
-
onFollowupInteraction,
|
|
3256
2332
|
onUnauthorized
|
|
3257
2333
|
}) {
|
|
3258
|
-
const client = useBladeClient();
|
|
3259
2334
|
const { session, state, error } = useAgentSession(sessionId, {
|
|
3260
2335
|
createOptions,
|
|
3261
2336
|
onSessionCreated
|
|
3262
2337
|
});
|
|
3263
|
-
const
|
|
3264
|
-
const [
|
|
3265
|
-
|
|
3266
|
-
const [resultFeedback, setResultFeedback] = useState12([]);
|
|
3267
|
-
const resolvedSessionId = session?.sessionId;
|
|
3268
|
-
const isViewer = state?.viewerRole === "viewer";
|
|
3269
|
-
useEffect8(() => {
|
|
3270
|
-
setResultFeedback([]);
|
|
3271
|
-
if (!resolvedSessionId || isViewer) return;
|
|
3272
|
-
let cancelled = false;
|
|
3273
|
-
void client.sessions.listResultFeedback(resolvedSessionId).then(
|
|
3274
|
-
(items) => {
|
|
3275
|
-
if (cancelled) return;
|
|
3276
|
-
setResultFeedback((current) => {
|
|
3277
|
-
const merged = new Map(items.map((item) => [item.assistant_entry_id, item]));
|
|
3278
|
-
for (const item of current) {
|
|
3279
|
-
const fetched = merged.get(item.assistant_entry_id);
|
|
3280
|
-
if (!fetched || fetched.updated_at < item.updated_at) {
|
|
3281
|
-
merged.set(item.assistant_entry_id, item);
|
|
3282
|
-
}
|
|
3283
|
-
}
|
|
3284
|
-
return [...merged.values()];
|
|
3285
|
-
});
|
|
3286
|
-
},
|
|
3287
|
-
() => {
|
|
3288
|
-
}
|
|
3289
|
-
);
|
|
3290
|
-
return () => {
|
|
3291
|
-
cancelled = true;
|
|
3292
|
-
};
|
|
3293
|
-
}, [client, isViewer, resolvedSessionId]);
|
|
3294
|
-
const resultFeedbackByEntry = useMemo8(
|
|
3295
|
-
() => new Map(resultFeedback.map((item) => [item.assistant_entry_id, item])),
|
|
3296
|
-
[resultFeedback]
|
|
3297
|
-
);
|
|
3298
|
-
const handleResultFeedbackSaved = useCallback7((saved) => {
|
|
3299
|
-
setResultFeedback((current) => [
|
|
3300
|
-
...current.filter((item) => item.assistant_entry_id !== saved.assistant_entry_id),
|
|
3301
|
-
saved
|
|
3302
|
-
]);
|
|
3303
|
-
}, []);
|
|
3304
|
-
useEffect8(() => {
|
|
2338
|
+
const [stopRequested, setStopRequested] = useState10(false);
|
|
2339
|
+
const [inputText, setInputText] = useState10("");
|
|
2340
|
+
useEffect6(() => {
|
|
3305
2341
|
if (session) {
|
|
3306
2342
|
onSessionReady?.(session);
|
|
3307
2343
|
}
|
|
3308
2344
|
}, [session, onSessionReady]);
|
|
3309
|
-
|
|
2345
|
+
useEffect6(() => {
|
|
3310
2346
|
if (!session) return;
|
|
3311
2347
|
const offAttach = session.on("attachRequested", ({ label, content }) => {
|
|
3312
2348
|
setInputText((prev) => `${prev ? `${prev}
|
|
@@ -3322,12 +2358,12 @@ ${content}`);
|
|
|
3322
2358
|
offInsert();
|
|
3323
2359
|
};
|
|
3324
2360
|
}, [session]);
|
|
3325
|
-
|
|
2361
|
+
useEffect6(() => {
|
|
3326
2362
|
if (isUnauthorizedError(error)) {
|
|
3327
2363
|
onUnauthorized();
|
|
3328
2364
|
}
|
|
3329
2365
|
}, [error, onUnauthorized]);
|
|
3330
|
-
|
|
2366
|
+
useEffect6(() => {
|
|
3331
2367
|
if (!session || !commands) return;
|
|
3332
2368
|
const unsubscribes = Object.entries(commands).map(
|
|
3333
2369
|
([action, handler]) => session.onCommand(action, (payload) => handler(payload))
|
|
@@ -3339,7 +2375,7 @@ ${content}`);
|
|
|
3339
2375
|
const isStreaming = state?.isStreaming ?? false;
|
|
3340
2376
|
const isStopping = stopRequested && isStreaming;
|
|
3341
2377
|
const connectError = error && !isUnauthorizedError(error) ? error.message || "\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5" : null;
|
|
3342
|
-
const errorMessage = connectError ?? state?.errorMessage ??
|
|
2378
|
+
const errorMessage = connectError ?? state?.errorMessage ?? null;
|
|
3343
2379
|
const handleSend = (text) => {
|
|
3344
2380
|
setStopRequested(false);
|
|
3345
2381
|
return session?.send(text, { mode: state?.mode ?? void 0 }) ?? Promise.resolve(false);
|
|
@@ -3348,287 +2384,73 @@ ${content}`);
|
|
|
3348
2384
|
setStopRequested(true);
|
|
3349
2385
|
void session?.stop();
|
|
3350
2386
|
};
|
|
3351
|
-
return /* @__PURE__ */
|
|
3352
|
-
|
|
2387
|
+
return /* @__PURE__ */ jsxs12(
|
|
2388
|
+
"div",
|
|
3353
2389
|
{
|
|
3354
|
-
theme,
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
/* @__PURE__ */ jsx17(
|
|
3363
|
-
ReplayBar,
|
|
2390
|
+
"data-theme": themeAttr(theme),
|
|
2391
|
+
className: cn(
|
|
2392
|
+
"blade-chat flex min-h-0 flex-1 flex-col overflow-hidden",
|
|
2393
|
+
classNames?.root
|
|
2394
|
+
),
|
|
2395
|
+
children: [
|
|
2396
|
+
/* @__PURE__ */ jsx14(
|
|
2397
|
+
ConnectionBanner,
|
|
3364
2398
|
{
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
canControl: replay.canControl,
|
|
3368
|
-
onSpeedChange: (next) => void replay.setSpeed(next),
|
|
3369
|
-
onExit: () => void replay.exitToAutonomous()
|
|
2399
|
+
connection: state?.connection ?? "connecting",
|
|
2400
|
+
className: classNames?.banner
|
|
3370
2401
|
}
|
|
3371
2402
|
),
|
|
3372
|
-
/* @__PURE__ */
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
isStreaming,
|
|
3380
|
-
isStopping,
|
|
3381
|
-
inputText,
|
|
3382
|
-
onInputChange: setInputText,
|
|
3383
|
-
onSuggestion: setInputText,
|
|
3384
|
-
onSend: handleSend,
|
|
3385
|
-
onStop: handleStop,
|
|
3386
|
-
sessionStatus: state?.status ?? void 0,
|
|
3387
|
-
askAnswers: state?.askAnswers,
|
|
3388
|
-
onAnswer: (answer, toolCallId, answerData) => {
|
|
3389
|
-
void session?.send(answer, {
|
|
3390
|
-
mode: state?.mode ?? void 0,
|
|
3391
|
-
askUserAnswer: { tool_call_id: toolCallId, ...answerData }
|
|
3392
|
-
});
|
|
3393
|
-
},
|
|
3394
|
-
sessionId: resolvedSessionId,
|
|
3395
|
-
isViewer
|
|
3396
|
-
}
|
|
3397
|
-
);
|
|
3398
|
-
}
|
|
3399
|
-
|
|
3400
|
-
// src/components/LlmChat.tsx
|
|
3401
|
-
import { useEffect as useEffect9, useMemo as useMemo9, useState as useState14 } from "react";
|
|
3402
|
-
|
|
3403
|
-
// src/components/LlmAdvancedSettings.tsx
|
|
3404
|
-
import { useState as useState13 } from "react";
|
|
3405
|
-
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3406
|
-
var FIELDS = [
|
|
3407
|
-
{ id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
|
|
3408
|
-
{ id: "model", label: "\u6A21\u578B", placeholder: "\u6A21\u578B\u540D\u79F0" },
|
|
3409
|
-
{ id: "apiKey", label: "\u5BC6\u94A5", placeholder: "\u7559\u7A7A\u8868\u793A\u4E0D\u6539", secret: true }
|
|
3410
|
-
];
|
|
3411
|
-
function normalizeAdvanced(value) {
|
|
3412
|
-
if (!value) return null;
|
|
3413
|
-
const config = value === true ? {} : value;
|
|
3414
|
-
return {
|
|
3415
|
-
baseURL: config.baseURL ?? true,
|
|
3416
|
-
model: config.model ?? true,
|
|
3417
|
-
apiKey: config.apiKey ?? false,
|
|
3418
|
-
storage: config.storage ?? "local"
|
|
3419
|
-
};
|
|
3420
|
-
}
|
|
3421
|
-
function storageKeyFor(settings, baseURL) {
|
|
3422
|
-
const explicit = typeof settings === "object" ? settings.storageKey : void 0;
|
|
3423
|
-
return `blade-llm-override:${explicit ?? baseURL}`;
|
|
3424
|
-
}
|
|
3425
|
-
function readOverride(settings, baseURL) {
|
|
3426
|
-
const normalized = normalizeAdvanced(settings);
|
|
3427
|
-
if (!normalized || normalized.storage !== "local" || typeof localStorage === "undefined") return {};
|
|
3428
|
-
try {
|
|
3429
|
-
const raw = localStorage.getItem(storageKeyFor(settings, baseURL));
|
|
3430
|
-
if (!raw) return {};
|
|
3431
|
-
const stored = JSON.parse(raw);
|
|
3432
|
-
return Object.fromEntries(
|
|
3433
|
-
Object.entries(stored).filter(([key]) => normalized[key])
|
|
3434
|
-
);
|
|
3435
|
-
} catch {
|
|
3436
|
-
return {};
|
|
3437
|
-
}
|
|
3438
|
-
}
|
|
3439
|
-
function writeOverride(settings, baseURL, override) {
|
|
3440
|
-
const normalized = normalizeAdvanced(settings);
|
|
3441
|
-
if (!normalized || normalized.storage !== "local" || typeof localStorage === "undefined") return;
|
|
3442
|
-
try {
|
|
3443
|
-
const key = storageKeyFor(settings, baseURL);
|
|
3444
|
-
if (Object.keys(override).length === 0) localStorage.removeItem(key);
|
|
3445
|
-
else localStorage.setItem(key, JSON.stringify(override));
|
|
3446
|
-
} catch {
|
|
3447
|
-
}
|
|
3448
|
-
}
|
|
3449
|
-
function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
3450
|
-
const normalized = normalizeAdvanced(settings);
|
|
3451
|
-
const [open, setOpen] = useState13(false);
|
|
3452
|
-
const [draft, setDraft] = useState13(override);
|
|
3453
|
-
if (!normalized) return null;
|
|
3454
|
-
const fields = FIELDS.filter((field) => normalized[field.id]);
|
|
3455
|
-
const dirty = Object.keys(override).length > 0;
|
|
3456
|
-
return /* @__PURE__ */ jsxs16("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
|
|
3457
|
-
/* @__PURE__ */ jsxs16(
|
|
3458
|
-
"button",
|
|
3459
|
-
{
|
|
3460
|
-
type: "button",
|
|
3461
|
-
onClick: () => {
|
|
3462
|
-
setDraft(override);
|
|
3463
|
-
setOpen((value) => !value);
|
|
3464
|
-
},
|
|
3465
|
-
className: "flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
|
|
3466
|
-
children: [
|
|
3467
|
-
/* @__PURE__ */ jsx18(Settings2, { size: 13 }),
|
|
3468
|
-
"\u9AD8\u7EA7\u8BBE\u7F6E",
|
|
3469
|
-
dirty && /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
|
|
3470
|
-
]
|
|
3471
|
-
}
|
|
3472
|
-
),
|
|
3473
|
-
open && /* @__PURE__ */ jsxs16("div", { className: "mt-2 flex flex-col gap-2", children: [
|
|
3474
|
-
fields.map((field) => /* @__PURE__ */ jsxs16("label", { className: "flex flex-col gap-1", children: [
|
|
3475
|
-
/* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
|
|
3476
|
-
/* @__PURE__ */ jsx18(
|
|
3477
|
-
"input",
|
|
3478
|
-
{
|
|
3479
|
-
type: field.secret ? "password" : "text",
|
|
3480
|
-
value: draft[field.id] ?? "",
|
|
3481
|
-
placeholder: field.id === "apiKey" ? field.placeholder : defaults[field.id] || field.placeholder,
|
|
3482
|
-
onChange: (event) => setDraft({ ...draft, [field.id]: event.target.value }),
|
|
3483
|
-
className: "rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))] px-2 py-1 text-xs text-[hsl(var(--foreground))] outline-none"
|
|
3484
|
-
}
|
|
3485
|
-
)
|
|
3486
|
-
] }, field.id)),
|
|
3487
|
-
normalized.apiKey && /* @__PURE__ */ jsx18("p", { className: "text-[hsl(var(--muted-foreground))]", children: "\u5BC6\u94A5\u4F1A\u5B58\u5728\u8FD9\u53F0\u6D4F\u89C8\u5668\u91CC\u3002\u53EA\u5728\u4F60\u4FE1\u5F97\u8FC7\u8FD9\u53F0\u673A\u5668\u65F6\u586B\u3002" }),
|
|
3488
|
-
/* @__PURE__ */ jsxs16("div", { className: "flex gap-2", children: [
|
|
3489
|
-
/* @__PURE__ */ jsx18(
|
|
3490
|
-
"button",
|
|
2403
|
+
errorMessage && /* @__PURE__ */ jsxs12("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
|
|
2404
|
+
/* @__PURE__ */ jsx14(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
|
|
2405
|
+
/* @__PURE__ */ jsx14("span", { children: errorMessage })
|
|
2406
|
+
] }),
|
|
2407
|
+
slots?.header,
|
|
2408
|
+
/* @__PURE__ */ jsx14(
|
|
2409
|
+
MessageList,
|
|
3491
2410
|
{
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
2411
|
+
messages: state?.messages ?? [],
|
|
2412
|
+
isStreaming,
|
|
2413
|
+
sessionStatus: state?.status ?? void 0,
|
|
2414
|
+
askAnswers: state?.askAnswers,
|
|
2415
|
+
onAnswer: (answer, toolCallId, answerData) => {
|
|
2416
|
+
void session?.send(answer, {
|
|
2417
|
+
mode: state?.mode ?? void 0,
|
|
2418
|
+
askUserAnswer: { tool_call_id: toolCallId, ...answerData }
|
|
2419
|
+
});
|
|
3499
2420
|
},
|
|
3500
|
-
|
|
3501
|
-
|
|
2421
|
+
toolCallRenderer: renderers?.toolCall,
|
|
2422
|
+
emptyState: slots?.emptyState,
|
|
2423
|
+
className: classNames?.messageList,
|
|
2424
|
+
sessionId: session?.sessionId
|
|
3502
2425
|
}
|
|
3503
2426
|
),
|
|
3504
|
-
/* @__PURE__ */
|
|
3505
|
-
|
|
2427
|
+
/* @__PURE__ */ jsx14(
|
|
2428
|
+
ChatInput,
|
|
3506
2429
|
{
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
}
|
|
3516
|
-
)
|
|
3517
|
-
] })
|
|
3518
|
-
] })
|
|
3519
|
-
] });
|
|
3520
|
-
}
|
|
3521
|
-
|
|
3522
|
-
// src/components/LlmChat.tsx
|
|
3523
|
-
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
3524
|
-
function LlmChat({
|
|
3525
|
-
classNames,
|
|
3526
|
-
renderers,
|
|
3527
|
-
slots,
|
|
3528
|
-
placeholder,
|
|
3529
|
-
theme,
|
|
3530
|
-
onReady,
|
|
3531
|
-
advanced,
|
|
3532
|
-
onOverrideChange,
|
|
3533
|
-
...options
|
|
3534
|
-
}) {
|
|
3535
|
-
const [override, setOverride] = useState14(() => readOverride(advanced, options.baseURL));
|
|
3536
|
-
const effective = { ...options, ...override };
|
|
3537
|
-
const { messages, isStreaming, error, send, stop, reset } = useLlmChat(effective);
|
|
3538
|
-
const [inputText, setInputText] = useState14("");
|
|
3539
|
-
const [stopRequested, setStopRequested] = useState14(false);
|
|
3540
|
-
const handle = useMemo9(
|
|
3541
|
-
() => ({
|
|
3542
|
-
insertText: (text) => setInputText((prev) => prev ? `${prev}
|
|
3543
|
-
${text}` : text),
|
|
3544
|
-
send,
|
|
3545
|
-
reset
|
|
3546
|
-
}),
|
|
3547
|
-
[send, reset]
|
|
3548
|
-
);
|
|
3549
|
-
useEffect9(() => {
|
|
3550
|
-
onReady?.(handle);
|
|
3551
|
-
}, [handle, onReady]);
|
|
3552
|
-
return /* @__PURE__ */ jsx19(
|
|
3553
|
-
ChatSurface,
|
|
3554
|
-
{
|
|
3555
|
-
theme,
|
|
3556
|
-
classNames,
|
|
3557
|
-
renderers,
|
|
3558
|
-
slots,
|
|
3559
|
-
placeholder,
|
|
3560
|
-
connection: "connected",
|
|
3561
|
-
errorMessage: error,
|
|
3562
|
-
messages,
|
|
3563
|
-
isStreaming,
|
|
3564
|
-
isStopping: stopRequested && isStreaming,
|
|
3565
|
-
inputText,
|
|
3566
|
-
onInputChange: setInputText,
|
|
3567
|
-
onSend: async (text) => {
|
|
3568
|
-
setStopRequested(false);
|
|
3569
|
-
if (!text.trim() || isStreaming) return false;
|
|
3570
|
-
void send(text);
|
|
3571
|
-
return true;
|
|
3572
|
-
},
|
|
3573
|
-
onStop: () => {
|
|
3574
|
-
setStopRequested(true);
|
|
3575
|
-
stop();
|
|
3576
|
-
},
|
|
3577
|
-
beforeInput: advanced ? /* @__PURE__ */ jsx19(
|
|
3578
|
-
LlmAdvancedSettingsBar,
|
|
3579
|
-
{
|
|
3580
|
-
settings: advanced,
|
|
3581
|
-
defaults: { baseURL: options.baseURL, model: options.model },
|
|
3582
|
-
override,
|
|
3583
|
-
onChange: (next) => {
|
|
3584
|
-
setOverride(next);
|
|
3585
|
-
writeOverride(advanced, options.baseURL, next);
|
|
3586
|
-
onOverrideChange?.(next);
|
|
2430
|
+
value: inputText,
|
|
2431
|
+
onValueChange: setInputText,
|
|
2432
|
+
onSend: handleSend,
|
|
2433
|
+
onStop: handleStop,
|
|
2434
|
+
isStreaming,
|
|
2435
|
+
isStopping,
|
|
2436
|
+
placeholder,
|
|
2437
|
+
className: classNames?.chatInput
|
|
3587
2438
|
}
|
|
3588
|
-
|
|
3589
|
-
|
|
2439
|
+
),
|
|
2440
|
+
slots?.footer
|
|
2441
|
+
]
|
|
3590
2442
|
}
|
|
3591
2443
|
);
|
|
3592
2444
|
}
|
|
3593
2445
|
|
|
3594
|
-
// src/components/ChatView.tsx
|
|
3595
|
-
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
3596
|
-
function ChatView(props) {
|
|
3597
|
-
const { mode, llm, onLlmReady, ...rest } = props;
|
|
3598
|
-
if (mode === "llm") {
|
|
3599
|
-
if (!llm) {
|
|
3600
|
-
throw new Error('ChatView: mode="llm" \u9700\u8981\u540C\u65F6\u4F20 llm={{ baseURL, model }}');
|
|
3601
|
-
}
|
|
3602
|
-
return /* @__PURE__ */ jsx20(
|
|
3603
|
-
LlmChat,
|
|
3604
|
-
{
|
|
3605
|
-
...llm,
|
|
3606
|
-
classNames: rest.classNames,
|
|
3607
|
-
renderers: rest.renderers,
|
|
3608
|
-
slots: rest.slots,
|
|
3609
|
-
placeholder: rest.placeholder,
|
|
3610
|
-
theme: rest.theme,
|
|
3611
|
-
onReady: onLlmReady
|
|
3612
|
-
}
|
|
3613
|
-
);
|
|
3614
|
-
}
|
|
3615
|
-
return /* @__PURE__ */ jsx20(AgentChat, { ...rest });
|
|
3616
|
-
}
|
|
3617
|
-
|
|
3618
2446
|
// src/index.ts
|
|
3619
2447
|
export * from "@blade-hq/agent-client";
|
|
3620
2448
|
export {
|
|
3621
|
-
AgentChat,
|
|
3622
2449
|
BladeProvider,
|
|
3623
2450
|
ChatView,
|
|
3624
|
-
LlmChat,
|
|
3625
2451
|
MarkdownContent,
|
|
3626
|
-
ReplayBar,
|
|
3627
|
-
ReplayMismatchPrompt,
|
|
3628
2452
|
useAgentSession,
|
|
3629
|
-
useBladeClient
|
|
3630
|
-
useLlmChat,
|
|
3631
|
-
useReplay
|
|
2453
|
+
useBladeClient
|
|
3632
2454
|
};
|
|
3633
2455
|
/*! Bundled license information:
|
|
3634
2456
|
|
|
@@ -3636,8 +2458,7 @@ lucide-react/dist/esm/shared/src/utils.js:
|
|
|
3636
2458
|
lucide-react/dist/esm/defaultAttributes.js:
|
|
3637
2459
|
lucide-react/dist/esm/Icon.js:
|
|
3638
2460
|
lucide-react/dist/esm/createLucideIcon.js:
|
|
3639
|
-
lucide-react/dist/esm/icons/
|
|
3640
|
-
lucide-react/dist/esm/icons/arrow-up-right.js:
|
|
2461
|
+
lucide-react/dist/esm/icons/archive.js:
|
|
3641
2462
|
lucide-react/dist/esm/icons/arrow-up.js:
|
|
3642
2463
|
lucide-react/dist/esm/icons/bot.js:
|
|
3643
2464
|
lucide-react/dist/esm/icons/brain.js:
|
|
@@ -3647,19 +2468,19 @@ lucide-react/dist/esm/icons/chevron-right.js:
|
|
|
3647
2468
|
lucide-react/dist/esm/icons/circle-alert.js:
|
|
3648
2469
|
lucide-react/dist/esm/icons/copy.js:
|
|
3649
2470
|
lucide-react/dist/esm/icons/download.js:
|
|
2471
|
+
lucide-react/dist/esm/icons/file-code-2.js:
|
|
2472
|
+
lucide-react/dist/esm/icons/file-spreadsheet.js:
|
|
3650
2473
|
lucide-react/dist/esm/icons/file-text.js:
|
|
3651
2474
|
lucide-react/dist/esm/icons/file.js:
|
|
3652
2475
|
lucide-react/dist/esm/icons/film.js:
|
|
3653
|
-
lucide-react/dist/esm/icons/
|
|
2476
|
+
lucide-react/dist/esm/icons/image.js:
|
|
3654
2477
|
lucide-react/dist/esm/icons/layers.js:
|
|
3655
2478
|
lucide-react/dist/esm/icons/lightbulb.js:
|
|
3656
2479
|
lucide-react/dist/esm/icons/loader-circle.js:
|
|
3657
2480
|
lucide-react/dist/esm/icons/lock-keyhole.js:
|
|
3658
2481
|
lucide-react/dist/esm/icons/message-square-more.js:
|
|
3659
2482
|
lucide-react/dist/esm/icons/message-square.js:
|
|
3660
|
-
lucide-react/dist/esm/icons/
|
|
3661
|
-
lucide-react/dist/esm/icons/settings-2.js:
|
|
3662
|
-
lucide-react/dist/esm/icons/sparkles.js:
|
|
2483
|
+
lucide-react/dist/esm/icons/music.js:
|
|
3663
2484
|
lucide-react/dist/esm/icons/square.js:
|
|
3664
2485
|
lucide-react/dist/esm/icons/triangle-alert.js:
|
|
3665
2486
|
lucide-react/dist/esm/icons/x.js:
|