@blade-hq/agent-react 2608.0.5-alpha.1 → 2608.0.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -150
- package/dist/components/ChatView.d.ts +39 -19
- package/dist/embed/entry.d.ts +0 -2
- package/dist/index.d.ts +0 -13
- package/dist/index.js +279 -1134
- package/dist/index.js.map +1 -1
- package/dist/style.full.css +1 -1
- package/package.json +5 -3
- package/public-api.md +4 -272
- package/dist/components/AgentChat.d.ts +0 -18
- package/dist/components/ChatSurface.d.ts +0 -59
- package/dist/components/LlmAdvancedSettings.d.ts +0 -40
- package/dist/components/LlmChat.d.ts +0 -29
- 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,452 +99,7 @@ function useAgentSession(sessionId, options = {}) {
|
|
|
99
99
|
return { session, state, error };
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
// src/
|
|
103
|
-
import { DEFAULT_REPLAY_SPEED } from "@blade-hq/agent-client";
|
|
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
|
|
102
|
+
// src/components/ChatView.tsx
|
|
548
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
|
|
@@ -821,19 +376,6 @@ var Music = createLucideIcon("Music", [
|
|
|
821
376
|
["circle", { cx: "18", cy: "16", r: "3", key: "1hluhg" }]
|
|
822
377
|
]);
|
|
823
378
|
|
|
824
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/play.js
|
|
825
|
-
var Play = createLucideIcon("Play", [
|
|
826
|
-
["polygon", { points: "6 3 20 12 6 21 6 3", key: "1oa8hb" }]
|
|
827
|
-
]);
|
|
828
|
-
|
|
829
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/settings-2.js
|
|
830
|
-
var Settings2 = createLucideIcon("Settings2", [
|
|
831
|
-
["path", { d: "M20 7h-9", key: "3s1dr2" }],
|
|
832
|
-
["path", { d: "M14 17H5", key: "gfn3mx" }],
|
|
833
|
-
["circle", { cx: "17", cy: "17", r: "3", key: "18b49y" }],
|
|
834
|
-
["circle", { cx: "7", cy: "7", r: "3", key: "dfmy0x" }]
|
|
835
|
-
]);
|
|
836
|
-
|
|
837
379
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/square.js
|
|
838
380
|
var Square = createLucideIcon("Square", [
|
|
839
381
|
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }]
|
|
@@ -858,8 +400,8 @@ var X = createLucideIcon("X", [
|
|
|
858
400
|
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
859
401
|
]);
|
|
860
402
|
|
|
861
|
-
// src/components/
|
|
862
|
-
import { useEffect as
|
|
403
|
+
// src/components/ChatView.tsx
|
|
404
|
+
import { useEffect as useEffect6, useState as useState10 } from "react";
|
|
863
405
|
|
|
864
406
|
// src/lib/utils.ts
|
|
865
407
|
function cn(...inputs) {
|
|
@@ -874,120 +416,8 @@ async function copyToClipboard(text) {
|
|
|
874
416
|
}
|
|
875
417
|
}
|
|
876
418
|
|
|
877
|
-
// src/components/ReplayBar.tsx
|
|
878
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
879
|
-
var SPEED_OPTIONS = [1, 2, 5];
|
|
880
|
-
function ReplayBar({
|
|
881
|
-
isReplay,
|
|
882
|
-
speed,
|
|
883
|
-
onSpeedChange,
|
|
884
|
-
onExit,
|
|
885
|
-
canControl = true,
|
|
886
|
-
className
|
|
887
|
-
}) {
|
|
888
|
-
if (!isReplay) return null;
|
|
889
|
-
return /* @__PURE__ */ jsxs(
|
|
890
|
-
"div",
|
|
891
|
-
{
|
|
892
|
-
className: cn(
|
|
893
|
-
"flex flex-wrap items-center gap-2 border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))]/40 px-4 py-2 text-xs",
|
|
894
|
-
className
|
|
895
|
-
),
|
|
896
|
-
children: [
|
|
897
|
-
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 font-medium text-[hsl(var(--foreground))]", children: [
|
|
898
|
-
/* @__PURE__ */ jsx2(Play, { size: 13 }),
|
|
899
|
-
"\u56DE\u653E\u6A21\u5F0F"
|
|
900
|
-
] }),
|
|
901
|
-
/* @__PURE__ */ jsx2("span", { className: "text-[hsl(var(--muted-foreground))]", children: "\u6B63\u5728\u91CD\u73B0\u4E4B\u524D\u7684\u5BF9\u8BDD" }),
|
|
902
|
-
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2", children: [
|
|
903
|
-
/* @__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(
|
|
904
|
-
"button",
|
|
905
|
-
{
|
|
906
|
-
type: "button",
|
|
907
|
-
onClick: () => onSpeedChange(option),
|
|
908
|
-
"aria-pressed": speed === option,
|
|
909
|
-
disabled: !canControl,
|
|
910
|
-
className: cn(
|
|
911
|
-
"h-6 rounded px-2 font-medium transition-colors",
|
|
912
|
-
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))]",
|
|
913
|
-
!canControl && "cursor-not-allowed opacity-50"
|
|
914
|
-
),
|
|
915
|
-
children: [
|
|
916
|
-
option,
|
|
917
|
-
"x"
|
|
918
|
-
]
|
|
919
|
-
},
|
|
920
|
-
option
|
|
921
|
-
)) }),
|
|
922
|
-
/* @__PURE__ */ jsx2(
|
|
923
|
-
"button",
|
|
924
|
-
{
|
|
925
|
-
type: "button",
|
|
926
|
-
onClick: onExit,
|
|
927
|
-
disabled: !canControl,
|
|
928
|
-
className: cn(
|
|
929
|
-
"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))]",
|
|
930
|
-
!canControl && "cursor-not-allowed opacity-50 hover:bg-transparent"
|
|
931
|
-
),
|
|
932
|
-
children: "\u9000\u51FA\u56DE\u653E"
|
|
933
|
-
}
|
|
934
|
-
)
|
|
935
|
-
] })
|
|
936
|
-
]
|
|
937
|
-
}
|
|
938
|
-
);
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
// src/components/ReplayMismatchPrompt.tsx
|
|
942
|
-
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
943
|
-
function ReplayMismatchPrompt({ mismatch, className }) {
|
|
944
|
-
if (!mismatch) return null;
|
|
945
|
-
return /* @__PURE__ */ jsxs2(
|
|
946
|
-
"div",
|
|
947
|
-
{
|
|
948
|
-
className: cn(
|
|
949
|
-
"mx-auto my-3 max-w-3xl rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-4 py-3 text-sm",
|
|
950
|
-
className
|
|
951
|
-
),
|
|
952
|
-
children: [
|
|
953
|
-
/* @__PURE__ */ jsx3("div", { className: "font-medium text-[hsl(var(--foreground))]", children: "\u8FD9\u53E5\u8BDD\u548C\u4E4B\u524D\u5F55\u5236\u7684\u4E0D\u4E00\u6837" }),
|
|
954
|
-
/* @__PURE__ */ jsxs2("dl", { className: "mt-2 space-y-1 text-xs text-[hsl(var(--muted-foreground))]", children: [
|
|
955
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex gap-2", children: [
|
|
956
|
-
/* @__PURE__ */ jsx3("dt", { className: "shrink-0", children: "\u5F55\u5236\u7684\u662F" }),
|
|
957
|
-
/* @__PURE__ */ jsx3("dd", { className: "min-w-0 break-words text-[hsl(var(--foreground))]", children: mismatch.expectedMessage || "\uFF08\u7A7A\uFF09" })
|
|
958
|
-
] }),
|
|
959
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex gap-2", children: [
|
|
960
|
-
/* @__PURE__ */ jsx3("dt", { className: "shrink-0", children: "\u4F60\u8F93\u5165\u7684" }),
|
|
961
|
-
/* @__PURE__ */ jsx3("dd", { className: "min-w-0 break-words text-[hsl(var(--foreground))]", children: mismatch.actualMessage || "\uFF08\u7A7A\uFF09" })
|
|
962
|
-
] })
|
|
963
|
-
] }),
|
|
964
|
-
/* @__PURE__ */ jsxs2("div", { className: "mt-3 flex flex-wrap gap-2", children: [
|
|
965
|
-
/* @__PURE__ */ jsx3(
|
|
966
|
-
"button",
|
|
967
|
-
{
|
|
968
|
-
type: "button",
|
|
969
|
-
onClick: () => mismatch.resolve("keep_replay"),
|
|
970
|
-
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",
|
|
971
|
-
children: "\u6309\u5F55\u5236\u5185\u5BB9\u7EE7\u7EED"
|
|
972
|
-
}
|
|
973
|
-
),
|
|
974
|
-
/* @__PURE__ */ jsx3(
|
|
975
|
-
"button",
|
|
976
|
-
{
|
|
977
|
-
type: "button",
|
|
978
|
-
onClick: () => mismatch.resolve("continue_replay"),
|
|
979
|
-
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))]",
|
|
980
|
-
children: "\u4ECE\u8FD9\u91CC\u5F00\u59CB\u771F\u7684\u8FD0\u884C"
|
|
981
|
-
}
|
|
982
|
-
)
|
|
983
|
-
] })
|
|
984
|
-
]
|
|
985
|
-
}
|
|
986
|
-
);
|
|
987
|
-
}
|
|
988
|
-
|
|
989
419
|
// src/components/ChatInput.tsx
|
|
990
|
-
import { jsx as
|
|
420
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
991
421
|
function ChatInput({
|
|
992
422
|
value,
|
|
993
423
|
onValueChange,
|
|
@@ -1012,8 +442,8 @@ function ChatInput({
|
|
|
1012
442
|
void handleSend();
|
|
1013
443
|
}
|
|
1014
444
|
};
|
|
1015
|
-
return /* @__PURE__ */
|
|
1016
|
-
/* @__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(
|
|
1017
447
|
"textarea",
|
|
1018
448
|
{
|
|
1019
449
|
value,
|
|
@@ -1030,7 +460,7 @@ function ChatInput({
|
|
|
1030
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)]"
|
|
1031
461
|
}
|
|
1032
462
|
),
|
|
1033
|
-
isStreaming ? /* @__PURE__ */
|
|
463
|
+
isStreaming ? /* @__PURE__ */ jsx2(
|
|
1034
464
|
"button",
|
|
1035
465
|
{
|
|
1036
466
|
type: "button",
|
|
@@ -1039,9 +469,9 @@ function ChatInput({
|
|
|
1039
469
|
"aria-label": isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D",
|
|
1040
470
|
title: isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D",
|
|
1041
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",
|
|
1042
|
-
children: isStopping ? /* @__PURE__ */
|
|
472
|
+
children: isStopping ? /* @__PURE__ */ jsx2(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Square, { size: 12, fill: "currentColor" })
|
|
1043
473
|
}
|
|
1044
|
-
) : /* @__PURE__ */
|
|
474
|
+
) : /* @__PURE__ */ jsx2(
|
|
1045
475
|
"button",
|
|
1046
476
|
{
|
|
1047
477
|
type: "button",
|
|
@@ -1050,20 +480,20 @@ function ChatInput({
|
|
|
1050
480
|
"aria-label": "\u53D1\u9001\u6D88\u606F",
|
|
1051
481
|
title: "\u53D1\u9001\u6D88\u606F",
|
|
1052
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",
|
|
1053
|
-
children: /* @__PURE__ */
|
|
483
|
+
children: /* @__PURE__ */ jsx2(ArrowUp, { size: 15 })
|
|
1054
484
|
}
|
|
1055
485
|
)
|
|
1056
486
|
] }) });
|
|
1057
487
|
}
|
|
1058
488
|
|
|
1059
489
|
// src/components/ConnectionBanner.tsx
|
|
1060
|
-
import { jsx as
|
|
490
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1061
491
|
function ConnectionBanner({ connection, className }) {
|
|
1062
492
|
if (connection === "connected" || connection === "connecting") {
|
|
1063
493
|
return null;
|
|
1064
494
|
}
|
|
1065
495
|
const reconnecting = connection === "reconnecting";
|
|
1066
|
-
return /* @__PURE__ */
|
|
496
|
+
return /* @__PURE__ */ jsx3("div", { className: cn("blade-chat-banner bg-[hsl(var(--background))] px-5 pt-3", className), children: /* @__PURE__ */ jsxs2(
|
|
1067
497
|
"div",
|
|
1068
498
|
{
|
|
1069
499
|
className: cn(
|
|
@@ -1071,10 +501,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1071
501
|
reconnecting ? "border-amber-500/25 bg-amber-500/10 text-amber-100" : "border-rose-500/25 bg-rose-500/10 text-rose-100"
|
|
1072
502
|
),
|
|
1073
503
|
children: [
|
|
1074
|
-
/* @__PURE__ */
|
|
1075
|
-
/* @__PURE__ */
|
|
1076
|
-
/* @__PURE__ */
|
|
1077
|
-
/* @__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" })
|
|
1078
508
|
] })
|
|
1079
509
|
]
|
|
1080
510
|
}
|
|
@@ -1083,10 +513,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1083
513
|
|
|
1084
514
|
// src/components/MessageList.tsx
|
|
1085
515
|
import { isHiddenInternalMessage } from "@blade-hq/agent-client";
|
|
1086
|
-
import { useCallback as
|
|
516
|
+
import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo6, useRef as useRef5, useState as useState9 } from "react";
|
|
1087
517
|
|
|
1088
518
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js
|
|
1089
|
-
import { useCallback
|
|
519
|
+
import { useCallback, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
1090
520
|
var DEFAULT_SPRING_ANIMATION = {
|
|
1091
521
|
/**
|
|
1092
522
|
* A value from 0 to 1, on how much to damp the animation.
|
|
@@ -1123,12 +553,12 @@ globalThis.document?.addEventListener("click", () => {
|
|
|
1123
553
|
mouseDown = false;
|
|
1124
554
|
});
|
|
1125
555
|
var useStickToBottom = (options = {}) => {
|
|
1126
|
-
const [escapedFromLock, updateEscapedFromLock] =
|
|
1127
|
-
const [isAtBottom, updateIsAtBottom] =
|
|
1128
|
-
const [isNearBottom, setIsNearBottom] =
|
|
1129
|
-
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);
|
|
1130
560
|
optionsRef.current = options;
|
|
1131
|
-
const isSelecting =
|
|
561
|
+
const isSelecting = useCallback(() => {
|
|
1132
562
|
if (!mouseDown) {
|
|
1133
563
|
return false;
|
|
1134
564
|
}
|
|
@@ -1139,15 +569,15 @@ var useStickToBottom = (options = {}) => {
|
|
|
1139
569
|
const range = selection.getRangeAt(0);
|
|
1140
570
|
return range.commonAncestorContainer.contains(scrollRef.current) || scrollRef.current?.contains(range.commonAncestorContainer);
|
|
1141
571
|
}, []);
|
|
1142
|
-
const setIsAtBottom =
|
|
572
|
+
const setIsAtBottom = useCallback((isAtBottom2) => {
|
|
1143
573
|
state.isAtBottom = isAtBottom2;
|
|
1144
574
|
updateIsAtBottom(isAtBottom2);
|
|
1145
575
|
}, []);
|
|
1146
|
-
const setEscapedFromLock =
|
|
576
|
+
const setEscapedFromLock = useCallback((escapedFromLock2) => {
|
|
1147
577
|
state.escapedFromLock = escapedFromLock2;
|
|
1148
578
|
updateEscapedFromLock(escapedFromLock2);
|
|
1149
579
|
}, []);
|
|
1150
|
-
const state =
|
|
580
|
+
const state = useMemo2(() => {
|
|
1151
581
|
let lastCalculation;
|
|
1152
582
|
return {
|
|
1153
583
|
escapedFromLock,
|
|
@@ -1200,7 +630,7 @@ var useStickToBottom = (options = {}) => {
|
|
|
1200
630
|
}
|
|
1201
631
|
};
|
|
1202
632
|
}, []);
|
|
1203
|
-
const scrollToBottom =
|
|
633
|
+
const scrollToBottom = useCallback((scrollOptions = {}) => {
|
|
1204
634
|
if (typeof scrollOptions === "string") {
|
|
1205
635
|
scrollOptions = { animation: scrollOptions };
|
|
1206
636
|
}
|
|
@@ -1285,11 +715,11 @@ var useStickToBottom = (options = {}) => {
|
|
|
1285
715
|
}
|
|
1286
716
|
return next();
|
|
1287
717
|
}, [setIsAtBottom, isSelecting, state]);
|
|
1288
|
-
const stopScroll =
|
|
718
|
+
const stopScroll = useCallback(() => {
|
|
1289
719
|
setEscapedFromLock(true);
|
|
1290
720
|
setIsAtBottom(false);
|
|
1291
721
|
}, [setEscapedFromLock, setIsAtBottom]);
|
|
1292
|
-
const handleScroll =
|
|
722
|
+
const handleScroll = useCallback(({ target }) => {
|
|
1293
723
|
if (target !== scrollRef.current) {
|
|
1294
724
|
return;
|
|
1295
725
|
}
|
|
@@ -1328,7 +758,7 @@ var useStickToBottom = (options = {}) => {
|
|
|
1328
758
|
}
|
|
1329
759
|
}, 1);
|
|
1330
760
|
}, [setEscapedFromLock, setIsAtBottom, isSelecting, state]);
|
|
1331
|
-
const handleWheel =
|
|
761
|
+
const handleWheel = useCallback(({ target, deltaY }) => {
|
|
1332
762
|
let element = target;
|
|
1333
763
|
while (!["scroll", "auto"].includes(getComputedStyle(element).overflow)) {
|
|
1334
764
|
if (!element.parentElement) {
|
|
@@ -1398,7 +828,7 @@ var useStickToBottom = (options = {}) => {
|
|
|
1398
828
|
};
|
|
1399
829
|
};
|
|
1400
830
|
function useRefCallback(callback, deps) {
|
|
1401
|
-
const result =
|
|
831
|
+
const result = useCallback((ref) => {
|
|
1402
832
|
result.current = ref;
|
|
1403
833
|
return callback(ref);
|
|
1404
834
|
}, deps);
|
|
@@ -1430,11 +860,11 @@ function mergeAnimations(...animations) {
|
|
|
1430
860
|
|
|
1431
861
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/StickToBottom.js
|
|
1432
862
|
import * as React from "react";
|
|
1433
|
-
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";
|
|
1434
864
|
var StickToBottomContext = createContext2(null);
|
|
1435
|
-
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect :
|
|
865
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect2;
|
|
1436
866
|
function StickToBottom({ instance, children, resize, initial, mass, damping, stiffness, targetScrollTop: currentTargetScrollTop, contextRef, ...props }) {
|
|
1437
|
-
const customTargetScrollTop =
|
|
867
|
+
const customTargetScrollTop = useRef3(null);
|
|
1438
868
|
const targetScrollTop = React.useCallback((target, elements) => {
|
|
1439
869
|
const get = context?.targetScrollTop ?? currentTargetScrollTop;
|
|
1440
870
|
return get?.(target, elements) ?? target;
|
|
@@ -1448,7 +878,7 @@ function StickToBottom({ instance, children, resize, initial, mass, damping, sti
|
|
|
1448
878
|
targetScrollTop
|
|
1449
879
|
});
|
|
1450
880
|
const { scrollRef, contentRef, scrollToBottom, stopScroll, isAtBottom, escapedFromLock, state } = instance ?? defaultInstance;
|
|
1451
|
-
const context =
|
|
881
|
+
const context = useMemo3(() => ({
|
|
1452
882
|
scrollToBottom,
|
|
1453
883
|
stopScroll,
|
|
1454
884
|
scrollRef,
|
|
@@ -1511,10 +941,10 @@ function useStickToBottomContext() {
|
|
|
1511
941
|
|
|
1512
942
|
// src/components/AssistantTurnBlock.tsx
|
|
1513
943
|
import { getTextContent, normalizeMessageContent } from "@blade-hq/agent-client";
|
|
1514
|
-
import { useState as
|
|
944
|
+
import { useState as useState8 } from "react";
|
|
1515
945
|
|
|
1516
946
|
// src/components/AgentLoopBlock.tsx
|
|
1517
|
-
import { useState as
|
|
947
|
+
import { useState as useState3 } from "react";
|
|
1518
948
|
|
|
1519
949
|
// src/components/display-utils.ts
|
|
1520
950
|
var TOOL_NAME_ALIASES = {
|
|
@@ -1636,7 +1066,7 @@ function formatToolResult(result) {
|
|
|
1636
1066
|
}
|
|
1637
1067
|
|
|
1638
1068
|
// src/components/AgentLoopBlock.tsx
|
|
1639
|
-
import { jsx as
|
|
1069
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1640
1070
|
function parseAgentDescription(argumentsJson) {
|
|
1641
1071
|
try {
|
|
1642
1072
|
const parsed = JSON.parse(argumentsJson);
|
|
@@ -1646,12 +1076,12 @@ function parseAgentDescription(argumentsJson) {
|
|
|
1646
1076
|
}
|
|
1647
1077
|
}
|
|
1648
1078
|
function AgentLoopBlock({ toolCall }) {
|
|
1649
|
-
const [expanded, setExpanded] =
|
|
1079
|
+
const [expanded, setExpanded] = useState3(false);
|
|
1650
1080
|
const description = parseAgentDescription(toolCall.arguments);
|
|
1651
1081
|
const running = toolCall.status === "pending" || toolCall.status === "awaiting_answer";
|
|
1652
1082
|
const failed = toolCall.status === "error" || toolCall.status === "cancelled";
|
|
1653
|
-
return /* @__PURE__ */
|
|
1654
|
-
/* @__PURE__ */
|
|
1083
|
+
return /* @__PURE__ */ jsxs3("div", { className: "blade-chat-agent-loop ml-4 text-xs", children: [
|
|
1084
|
+
/* @__PURE__ */ jsxs3(
|
|
1655
1085
|
"div",
|
|
1656
1086
|
{
|
|
1657
1087
|
className: cn(
|
|
@@ -1659,7 +1089,7 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1659
1089
|
failed ? "border-l-[hsl(var(--muted-foreground)/0.5)]" : running ? "border-l-blue-500" : "border-l-[hsl(var(--primary))]"
|
|
1660
1090
|
),
|
|
1661
1091
|
children: [
|
|
1662
|
-
/* @__PURE__ */
|
|
1092
|
+
/* @__PURE__ */ jsxs3(
|
|
1663
1093
|
"button",
|
|
1664
1094
|
{
|
|
1665
1095
|
type: "button",
|
|
@@ -1667,7 +1097,7 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1667
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",
|
|
1668
1098
|
"aria-expanded": expanded,
|
|
1669
1099
|
children: [
|
|
1670
|
-
/* @__PURE__ */
|
|
1100
|
+
/* @__PURE__ */ jsx4(
|
|
1671
1101
|
ChevronRight,
|
|
1672
1102
|
{
|
|
1673
1103
|
size: 11,
|
|
@@ -1677,8 +1107,8 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1677
1107
|
)
|
|
1678
1108
|
}
|
|
1679
1109
|
),
|
|
1680
|
-
/* @__PURE__ */
|
|
1681
|
-
/* @__PURE__ */
|
|
1110
|
+
/* @__PURE__ */ jsx4(Bot, { size: 12, className: "shrink-0 text-[hsl(var(--muted-foreground))]" }),
|
|
1111
|
+
/* @__PURE__ */ jsxs3(
|
|
1682
1112
|
"span",
|
|
1683
1113
|
{
|
|
1684
1114
|
className: cn(
|
|
@@ -1686,35 +1116,35 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1686
1116
|
failed ? "text-[hsl(var(--muted-foreground))]" : running ? "text-blue-300" : "text-[hsl(var(--primary))]"
|
|
1687
1117
|
),
|
|
1688
1118
|
children: [
|
|
1689
|
-
running ? /* @__PURE__ */
|
|
1690
|
-
/* @__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" })
|
|
1691
1121
|
]
|
|
1692
1122
|
}
|
|
1693
1123
|
),
|
|
1694
|
-
/* @__PURE__ */
|
|
1124
|
+
/* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: [
|
|
1695
1125
|
"\u5B50\u667A\u80FD\u4F53\uFF1A",
|
|
1696
1126
|
description
|
|
1697
1127
|
] })
|
|
1698
1128
|
]
|
|
1699
1129
|
}
|
|
1700
1130
|
),
|
|
1701
|
-
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) })
|
|
1702
1132
|
]
|
|
1703
1133
|
}
|
|
1704
1134
|
),
|
|
1705
|
-
expanded && toolCall.result != null && /* @__PURE__ */
|
|
1706
|
-
/* @__PURE__ */
|
|
1707
|
-
/* @__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) })
|
|
1708
1138
|
] })
|
|
1709
1139
|
] });
|
|
1710
1140
|
}
|
|
1711
1141
|
|
|
1712
1142
|
// src/components/MarkdownContent.tsx
|
|
1713
1143
|
import {
|
|
1714
|
-
useEffect as
|
|
1715
|
-
useMemo as
|
|
1716
|
-
useRef as
|
|
1717
|
-
useState as
|
|
1144
|
+
useEffect as useEffect3,
|
|
1145
|
+
useMemo as useMemo4,
|
|
1146
|
+
useRef as useRef4,
|
|
1147
|
+
useState as useState5
|
|
1718
1148
|
} from "react";
|
|
1719
1149
|
|
|
1720
1150
|
// src/lib/media-tags.ts
|
|
@@ -1761,8 +1191,8 @@ function collapseMediaTags(text, options) {
|
|
|
1761
1191
|
}
|
|
1762
1192
|
|
|
1763
1193
|
// src/components/FileCard.tsx
|
|
1764
|
-
import { useState as
|
|
1765
|
-
import { jsx as
|
|
1194
|
+
import { useState as useState4 } from "react";
|
|
1195
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1766
1196
|
var IMAGE_EXTS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "svg", "webp", "ico", "bmp"]);
|
|
1767
1197
|
var SHEET_EXTS = /* @__PURE__ */ new Set(["xlsx", "xls", "xlsm", "xlsb", "csv"]);
|
|
1768
1198
|
var TEXT_EXTS = /* @__PURE__ */ new Set(["txt", "md", "markdown", "pdf", "doc", "docx", "rtf"]);
|
|
@@ -1804,8 +1234,8 @@ function FileCard({
|
|
|
1804
1234
|
...props
|
|
1805
1235
|
}) {
|
|
1806
1236
|
const client = useBladeClient();
|
|
1807
|
-
const [downloading, setDownloading] =
|
|
1808
|
-
const [failed, setFailed] =
|
|
1237
|
+
const [downloading, setDownloading] = useState4(false);
|
|
1238
|
+
const [failed, setFailed] = useState4(false);
|
|
1809
1239
|
const nodeProperties = node && typeof node === "object" && "properties" in node ? node.properties : void 0;
|
|
1810
1240
|
const path = pathAttribute ?? dataPath ?? stringValue(nodeProperties?.["data-path"]) ?? stringValue(nodeProperties?.dataPath) ?? "";
|
|
1811
1241
|
const name = nameAttribute ?? dataName ?? stringValue(nodeProperties?.["data-name"]) ?? stringValue(nodeProperties?.dataName) ?? extractChildrenText(children) ?? "";
|
|
@@ -1823,8 +1253,8 @@ function FileCard({
|
|
|
1823
1253
|
setDownloading(false);
|
|
1824
1254
|
}
|
|
1825
1255
|
};
|
|
1826
|
-
return /* @__PURE__ */
|
|
1827
|
-
/* @__PURE__ */
|
|
1256
|
+
return /* @__PURE__ */ jsxs4("span", { ...props, className: cn("blade-chat-file-card", className), children: [
|
|
1257
|
+
/* @__PURE__ */ jsxs4(
|
|
1828
1258
|
"button",
|
|
1829
1259
|
{
|
|
1830
1260
|
type: "button",
|
|
@@ -1833,24 +1263,24 @@ function FileCard({
|
|
|
1833
1263
|
"aria-label": `\u4E0B\u8F7D\u6587\u4EF6\uFF1A${name}`,
|
|
1834
1264
|
title: failed ? "\u4E0B\u8F7D\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5" : `\u4E0B\u8F7D ${name}`,
|
|
1835
1265
|
children: [
|
|
1836
|
-
/* @__PURE__ */
|
|
1837
|
-
/* @__PURE__ */
|
|
1838
|
-
/* @__PURE__ */
|
|
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" })
|
|
1839
1269
|
]
|
|
1840
1270
|
}
|
|
1841
1271
|
),
|
|
1842
|
-
failed && /* @__PURE__ */
|
|
1272
|
+
failed && /* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-error", children: "\u4E0B\u8F7D\u5931\u8D25" })
|
|
1843
1273
|
] });
|
|
1844
1274
|
}
|
|
1845
1275
|
|
|
1846
1276
|
// src/components/MarkdownContent.tsx
|
|
1847
|
-
import { jsx as
|
|
1277
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1848
1278
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
1849
1279
|
function CodeBlockPre({ children, node: _node, ...props }) {
|
|
1850
|
-
const preRef =
|
|
1851
|
-
const [copied, setCopied] =
|
|
1852
|
-
const [language, setLanguage] =
|
|
1853
|
-
|
|
1280
|
+
const preRef = useRef4(null);
|
|
1281
|
+
const [copied, setCopied] = useState5(false);
|
|
1282
|
+
const [language, setLanguage] = useState5("");
|
|
1283
|
+
useEffect3(() => {
|
|
1854
1284
|
const codeEl = preRef.current?.querySelector("code");
|
|
1855
1285
|
setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
|
|
1856
1286
|
}, []);
|
|
@@ -1861,10 +1291,10 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
1861
1291
|
setTimeout(() => setCopied(false), 2e3);
|
|
1862
1292
|
}
|
|
1863
1293
|
};
|
|
1864
|
-
return /* @__PURE__ */
|
|
1865
|
-
/* @__PURE__ */
|
|
1866
|
-
/* @__PURE__ */
|
|
1867
|
-
/* @__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(
|
|
1868
1298
|
"button",
|
|
1869
1299
|
{
|
|
1870
1300
|
type: "button",
|
|
@@ -1874,13 +1304,13 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
1874
1304
|
copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"
|
|
1875
1305
|
),
|
|
1876
1306
|
children: [
|
|
1877
|
-
copied ? /* @__PURE__ */
|
|
1878
|
-
/* @__PURE__ */
|
|
1307
|
+
copied ? /* @__PURE__ */ jsx6(Check, { size: 12 }) : /* @__PURE__ */ jsx6(Copy, { size: 12 }),
|
|
1308
|
+
/* @__PURE__ */ jsx6("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
|
|
1879
1309
|
]
|
|
1880
1310
|
}
|
|
1881
1311
|
)
|
|
1882
1312
|
] }),
|
|
1883
|
-
/* @__PURE__ */
|
|
1313
|
+
/* @__PURE__ */ jsx6(
|
|
1884
1314
|
"pre",
|
|
1885
1315
|
{
|
|
1886
1316
|
ref: preRef,
|
|
@@ -1892,7 +1322,7 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
1892
1322
|
] });
|
|
1893
1323
|
}
|
|
1894
1324
|
function ExternalAnchor({ node: _node, children, ...props }) {
|
|
1895
|
-
return /* @__PURE__ */
|
|
1325
|
+
return /* @__PURE__ */ jsx6("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
|
|
1896
1326
|
}
|
|
1897
1327
|
var MARKDOWN_COMPONENTS = {
|
|
1898
1328
|
pre: CodeBlockPre,
|
|
@@ -1903,19 +1333,19 @@ var CUSTOM_ALLOWED_TAGS = {
|
|
|
1903
1333
|
};
|
|
1904
1334
|
function MarkdownContent({ children, className, mode, sessionId }) {
|
|
1905
1335
|
const streaming = mode === "streaming";
|
|
1906
|
-
const resolvedChildren =
|
|
1336
|
+
const resolvedChildren = useMemo4(() => {
|
|
1907
1337
|
const withoutReminders = children.replace(SYSTEM_REMINDER_RE, "");
|
|
1908
1338
|
if (!sessionId) return withoutReminders;
|
|
1909
1339
|
return collapseMediaTags(withoutReminders, { streaming });
|
|
1910
1340
|
}, [children, sessionId, streaming]);
|
|
1911
|
-
const components =
|
|
1341
|
+
const components = useMemo4(
|
|
1912
1342
|
() => ({
|
|
1913
1343
|
...MARKDOWN_COMPONENTS,
|
|
1914
|
-
[FILE_CARD_TAG]: (fileCardProps) => /* @__PURE__ */
|
|
1344
|
+
[FILE_CARD_TAG]: (fileCardProps) => /* @__PURE__ */ jsx6(FileCard, { ...fileCardProps, sessionId })
|
|
1915
1345
|
}),
|
|
1916
1346
|
[sessionId]
|
|
1917
1347
|
);
|
|
1918
|
-
return /* @__PURE__ */
|
|
1348
|
+
return /* @__PURE__ */ jsx6(
|
|
1919
1349
|
_r,
|
|
1920
1350
|
{
|
|
1921
1351
|
className: cn("blade-chat-markdown break-words", className),
|
|
@@ -1929,17 +1359,17 @@ function MarkdownContent({ children, className, mode, sessionId }) {
|
|
|
1929
1359
|
}
|
|
1930
1360
|
|
|
1931
1361
|
// src/components/Shimmer.tsx
|
|
1932
|
-
import { jsx as
|
|
1362
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1933
1363
|
function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
|
|
1934
|
-
return /* @__PURE__ */
|
|
1364
|
+
return /* @__PURE__ */ jsx7("span", { className: cn("blade-shimmer-text text-sm font-medium", className), children });
|
|
1935
1365
|
}
|
|
1936
1366
|
|
|
1937
1367
|
// src/components/ToolCallBlock.tsx
|
|
1938
|
-
import { useState as
|
|
1368
|
+
import { useState as useState7 } from "react";
|
|
1939
1369
|
|
|
1940
1370
|
// src/components/AskUserQuestionBlock.tsx
|
|
1941
|
-
import { useEffect as
|
|
1942
|
-
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";
|
|
1943
1373
|
function AskUserQuestionBlock({
|
|
1944
1374
|
data,
|
|
1945
1375
|
answered,
|
|
@@ -1948,16 +1378,16 @@ function AskUserQuestionBlock({
|
|
|
1948
1378
|
answerData,
|
|
1949
1379
|
onAnswer
|
|
1950
1380
|
}) {
|
|
1951
|
-
const [selections, setSelections] =
|
|
1952
|
-
const [customTexts, setCustomTexts] =
|
|
1953
|
-
const [usingCustom, setUsingCustom] =
|
|
1954
|
-
const [submitted, setSubmitted] =
|
|
1955
|
-
|
|
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(() => {
|
|
1956
1386
|
if (sessionStatus === "failed" || sessionStatus === "interrupted") {
|
|
1957
1387
|
setSubmitted(false);
|
|
1958
1388
|
}
|
|
1959
1389
|
}, [sessionStatus]);
|
|
1960
|
-
const displayAnswerState =
|
|
1390
|
+
const displayAnswerState = useMemo5(() => {
|
|
1961
1391
|
if (!(answered && answerData)) {
|
|
1962
1392
|
return { selections, customTexts, usingCustom };
|
|
1963
1393
|
}
|
|
@@ -2042,7 +1472,7 @@ ${parts.join("\n")}`;
|
|
|
2042
1472
|
setSubmitted(true);
|
|
2043
1473
|
onAnswer(text, toolCallId, nextAnswerData);
|
|
2044
1474
|
};
|
|
2045
|
-
return /* @__PURE__ */
|
|
1475
|
+
return /* @__PURE__ */ jsxs6(
|
|
2046
1476
|
"div",
|
|
2047
1477
|
{
|
|
2048
1478
|
className: cn(
|
|
@@ -2050,12 +1480,12 @@ ${parts.join("\n")}`;
|
|
|
2050
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"
|
|
2051
1481
|
),
|
|
2052
1482
|
children: [
|
|
2053
|
-
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: [
|
|
2054
1484
|
"\u5B50\u667A\u80FD\u4F53\u300C",
|
|
2055
1485
|
data.source_loop.description,
|
|
2056
1486
|
"\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
|
|
2057
1487
|
] }),
|
|
2058
|
-
data.questions.map((q, qIdx) => /* @__PURE__ */
|
|
1488
|
+
data.questions.map((q, qIdx) => /* @__PURE__ */ jsx8(
|
|
2059
1489
|
QuestionCard,
|
|
2060
1490
|
{
|
|
2061
1491
|
question: q,
|
|
@@ -2070,7 +1500,7 @@ ${parts.join("\n")}`;
|
|
|
2070
1500
|
},
|
|
2071
1501
|
q.question
|
|
2072
1502
|
)),
|
|
2073
|
-
!answered && !submitted && onAnswer && /* @__PURE__ */
|
|
1503
|
+
!answered && !submitted && onAnswer && /* @__PURE__ */ jsx8(
|
|
2074
1504
|
"button",
|
|
2075
1505
|
{
|
|
2076
1506
|
type: "button",
|
|
@@ -2080,14 +1510,14 @@ ${parts.join("\n")}`;
|
|
|
2080
1510
|
children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
|
|
2081
1511
|
}
|
|
2082
1512
|
),
|
|
2083
|
-
submitted && !answered && /* @__PURE__ */
|
|
1513
|
+
submitted && !answered && /* @__PURE__ */ jsxs6(
|
|
2084
1514
|
"button",
|
|
2085
1515
|
{
|
|
2086
1516
|
type: "button",
|
|
2087
1517
|
disabled: true,
|
|
2088
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",
|
|
2089
1519
|
children: [
|
|
2090
|
-
/* @__PURE__ */
|
|
1520
|
+
/* @__PURE__ */ jsx8(LoaderCircle, { size: 14, className: "animate-spin" }),
|
|
2091
1521
|
"\u786E\u8BA4\u4E2D"
|
|
2092
1522
|
]
|
|
2093
1523
|
}
|
|
@@ -2108,30 +1538,30 @@ function QuestionCard({
|
|
|
2108
1538
|
onCustomChange
|
|
2109
1539
|
}) {
|
|
2110
1540
|
const multi = question.multiSelect ?? false;
|
|
2111
|
-
return /* @__PURE__ */
|
|
2112
|
-
/* @__PURE__ */
|
|
2113
|
-
/* @__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(
|
|
2114
1544
|
MessageSquareMore,
|
|
2115
1545
|
{
|
|
2116
1546
|
size: answered ? 12 : 13,
|
|
2117
1547
|
className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
|
|
2118
1548
|
}
|
|
2119
1549
|
),
|
|
2120
|
-
/* @__PURE__ */
|
|
1550
|
+
/* @__PURE__ */ jsx8(
|
|
2121
1551
|
"div",
|
|
2122
1552
|
{
|
|
2123
1553
|
className: cn(
|
|
2124
1554
|
"min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
|
|
2125
1555
|
answered ? "text-xs" : "text-sm"
|
|
2126
1556
|
),
|
|
2127
|
-
children: /* @__PURE__ */
|
|
1557
|
+
children: /* @__PURE__ */ jsx8(MarkdownContent, { className: "blade-chat-prose", children: question.question })
|
|
2128
1558
|
}
|
|
2129
1559
|
)
|
|
2130
1560
|
] }),
|
|
2131
|
-
/* @__PURE__ */
|
|
1561
|
+
/* @__PURE__ */ jsxs6("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
|
|
2132
1562
|
question.options.map((opt, optIdx) => {
|
|
2133
1563
|
const isSel = selected.has(optIdx);
|
|
2134
|
-
return /* @__PURE__ */
|
|
1564
|
+
return /* @__PURE__ */ jsxs6(
|
|
2135
1565
|
"button",
|
|
2136
1566
|
{
|
|
2137
1567
|
type: "button",
|
|
@@ -2145,14 +1575,14 @@ function QuestionCard({
|
|
|
2145
1575
|
answered && "cursor-default opacity-70"
|
|
2146
1576
|
),
|
|
2147
1577
|
children: [
|
|
2148
|
-
multi && /* @__PURE__ */
|
|
1578
|
+
multi && /* @__PURE__ */ jsx8(
|
|
2149
1579
|
"div",
|
|
2150
1580
|
{
|
|
2151
1581
|
className: cn(
|
|
2152
1582
|
"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
|
|
2153
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))]"
|
|
2154
1584
|
),
|
|
2155
|
-
children: isSel && /* @__PURE__ */
|
|
1585
|
+
children: isSel && /* @__PURE__ */ jsx8(
|
|
2156
1586
|
Check,
|
|
2157
1587
|
{
|
|
2158
1588
|
size: 9,
|
|
@@ -2161,9 +1591,9 @@ function QuestionCard({
|
|
|
2161
1591
|
)
|
|
2162
1592
|
}
|
|
2163
1593
|
),
|
|
2164
|
-
/* @__PURE__ */
|
|
2165
|
-
/* @__PURE__ */
|
|
2166
|
-
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(
|
|
2167
1597
|
"div",
|
|
2168
1598
|
{
|
|
2169
1599
|
className: cn(
|
|
@@ -2180,7 +1610,7 @@ function QuestionCard({
|
|
|
2180
1610
|
opt.label
|
|
2181
1611
|
);
|
|
2182
1612
|
}),
|
|
2183
|
-
answered && !isCustom ? null : /* @__PURE__ */
|
|
1613
|
+
answered && !isCustom ? null : /* @__PURE__ */ jsxs6(
|
|
2184
1614
|
"div",
|
|
2185
1615
|
{
|
|
2186
1616
|
className: cn(
|
|
@@ -2190,8 +1620,8 @@ function QuestionCard({
|
|
|
2190
1620
|
answered && "cursor-default opacity-70"
|
|
2191
1621
|
),
|
|
2192
1622
|
children: [
|
|
2193
|
-
/* @__PURE__ */
|
|
2194
|
-
/* @__PURE__ */
|
|
1623
|
+
/* @__PURE__ */ jsx8("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
|
|
1624
|
+
/* @__PURE__ */ jsx8(
|
|
2195
1625
|
"input",
|
|
2196
1626
|
{
|
|
2197
1627
|
type: "text",
|
|
@@ -2259,7 +1689,7 @@ function normalizeOptionItem(value) {
|
|
|
2259
1689
|
}
|
|
2260
1690
|
|
|
2261
1691
|
// src/components/ToolCallBlock.tsx
|
|
2262
|
-
import { Fragment, jsx as
|
|
1692
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2263
1693
|
function resolveAskQuestionState({
|
|
2264
1694
|
toolStatus,
|
|
2265
1695
|
hasAnswerData,
|
|
@@ -2279,12 +1709,12 @@ function ToolCallBlock({
|
|
|
2279
1709
|
sessionStatus,
|
|
2280
1710
|
renderer
|
|
2281
1711
|
}) {
|
|
2282
|
-
const [expanded, setExpanded] =
|
|
1712
|
+
const [expanded, setExpanded] = useState7(false);
|
|
2283
1713
|
const normalizedName = formatToolName(toolCall.name);
|
|
2284
1714
|
if (renderer) {
|
|
2285
1715
|
const custom = renderer(toolCall);
|
|
2286
1716
|
if (custom !== null && custom !== void 0) {
|
|
2287
|
-
return /* @__PURE__ */
|
|
1717
|
+
return /* @__PURE__ */ jsx9(Fragment, { children: custom });
|
|
2288
1718
|
}
|
|
2289
1719
|
}
|
|
2290
1720
|
if (normalizedName === "AskUserQuestion") {
|
|
@@ -2296,7 +1726,7 @@ function ToolCallBlock({
|
|
|
2296
1726
|
});
|
|
2297
1727
|
const canAnswer = questionState.awaitingAnswer && Boolean(onAnswer);
|
|
2298
1728
|
if (askData) {
|
|
2299
|
-
return /* @__PURE__ */
|
|
1729
|
+
return /* @__PURE__ */ jsx9(
|
|
2300
1730
|
AskUserQuestionBlock,
|
|
2301
1731
|
{
|
|
2302
1732
|
data: askData,
|
|
@@ -2309,24 +1739,24 @@ function ToolCallBlock({
|
|
|
2309
1739
|
);
|
|
2310
1740
|
}
|
|
2311
1741
|
if (toolCall.status === "pending") {
|
|
2312
|
-
return /* @__PURE__ */
|
|
2313
|
-
/* @__PURE__ */
|
|
2314
|
-
/* @__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" })
|
|
2315
1745
|
] });
|
|
2316
1746
|
}
|
|
2317
|
-
return /* @__PURE__ */
|
|
2318
|
-
/* @__PURE__ */
|
|
2319
|
-
/* @__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" })
|
|
2320
1750
|
] });
|
|
2321
1751
|
}
|
|
2322
1752
|
const tone = getToolTone(toolCall.status);
|
|
2323
1753
|
const displayName = getToolDisplayLabel(toolCall);
|
|
2324
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))]";
|
|
2325
|
-
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 });
|
|
2326
1756
|
const statusTextClass = tone === "red" ? "text-[hsl(var(--muted-foreground))]" : tone === "amber" ? "text-amber-300" : tone === "blue" ? "text-blue-300" : "text-[hsl(var(--primary))]";
|
|
2327
|
-
return /* @__PURE__ */
|
|
2328
|
-
/* @__PURE__ */
|
|
2329
|
-
/* @__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(
|
|
2330
1760
|
"button",
|
|
2331
1761
|
{
|
|
2332
1762
|
type: "button",
|
|
@@ -2334,7 +1764,7 @@ function ToolCallBlock({
|
|
|
2334
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",
|
|
2335
1765
|
"aria-expanded": expanded,
|
|
2336
1766
|
children: [
|
|
2337
|
-
/* @__PURE__ */
|
|
1767
|
+
/* @__PURE__ */ jsx9(
|
|
2338
1768
|
ChevronRight,
|
|
2339
1769
|
{
|
|
2340
1770
|
size: 11,
|
|
@@ -2344,24 +1774,24 @@ function ToolCallBlock({
|
|
|
2344
1774
|
)
|
|
2345
1775
|
}
|
|
2346
1776
|
),
|
|
2347
|
-
/* @__PURE__ */
|
|
1777
|
+
/* @__PURE__ */ jsxs7("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
|
|
2348
1778
|
statusIcon,
|
|
2349
|
-
/* @__PURE__ */
|
|
1779
|
+
/* @__PURE__ */ jsx9("span", { children: getToolStatusLabel(toolCall.status) })
|
|
2350
1780
|
] }),
|
|
2351
|
-
/* @__PURE__ */
|
|
1781
|
+
/* @__PURE__ */ jsx9("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: displayName })
|
|
2352
1782
|
]
|
|
2353
1783
|
}
|
|
2354
1784
|
),
|
|
2355
|
-
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) })
|
|
2356
1786
|
] }),
|
|
2357
|
-
expanded && /* @__PURE__ */
|
|
2358
|
-
/* @__PURE__ */
|
|
2359
|
-
/* @__PURE__ */
|
|
2360
|
-
/* @__PURE__ */
|
|
2361
|
-
/* @__PURE__ */
|
|
2362
|
-
toolCall.result != null && /* @__PURE__ */
|
|
2363
|
-
/* @__PURE__ */
|
|
2364
|
-
/* @__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) })
|
|
2365
1795
|
] })
|
|
2366
1796
|
] })
|
|
2367
1797
|
] });
|
|
@@ -2379,11 +1809,11 @@ function buildAskUserPayload(argumentsJson) {
|
|
|
2379
1809
|
}
|
|
2380
1810
|
|
|
2381
1811
|
// src/components/AssistantTurnBlock.tsx
|
|
2382
|
-
import { jsx as
|
|
1812
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2383
1813
|
function ThinkingBlock({ reasoning, isStreaming }) {
|
|
2384
|
-
const [open, setOpen] =
|
|
2385
|
-
return /* @__PURE__ */
|
|
2386
|
-
/* @__PURE__ */
|
|
1814
|
+
const [open, setOpen] = useState8(false);
|
|
1815
|
+
return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
|
|
1816
|
+
/* @__PURE__ */ jsxs8(
|
|
2387
1817
|
"button",
|
|
2388
1818
|
{
|
|
2389
1819
|
type: "button",
|
|
@@ -2391,14 +1821,14 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
2391
1821
|
"aria-expanded": open,
|
|
2392
1822
|
className: "inline-flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
|
|
2393
1823
|
children: [
|
|
2394
|
-
/* @__PURE__ */
|
|
2395
|
-
isStreaming ? /* @__PURE__ */
|
|
2396
|
-
/* @__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: [
|
|
2397
1827
|
"\xB7 ",
|
|
2398
1828
|
new Intl.NumberFormat("zh-CN").format(reasoning.length),
|
|
2399
1829
|
" \u5B57"
|
|
2400
1830
|
] }),
|
|
2401
|
-
/* @__PURE__ */
|
|
1831
|
+
/* @__PURE__ */ jsx10(
|
|
2402
1832
|
ChevronDown,
|
|
2403
1833
|
{
|
|
2404
1834
|
size: 12,
|
|
@@ -2408,7 +1838,7 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
2408
1838
|
]
|
|
2409
1839
|
}
|
|
2410
1840
|
),
|
|
2411
|
-
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 })
|
|
2412
1842
|
] });
|
|
2413
1843
|
}
|
|
2414
1844
|
function getMessageText(message) {
|
|
@@ -2434,21 +1864,21 @@ function AssistantTurnBlock({
|
|
|
2434
1864
|
(message) => getMessageText(message) || message.reasoning || (message.tool_calls?.length ?? 0) > 0
|
|
2435
1865
|
);
|
|
2436
1866
|
const latestReasoningIndex = isStreaming ? findLatestReasoningMessageIndex(messages) : -1;
|
|
2437
|
-
return /* @__PURE__ */
|
|
2438
|
-
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" }),
|
|
2439
1869
|
messages.map((message, index) => {
|
|
2440
1870
|
const isLast = index === messages.length - 1;
|
|
2441
1871
|
const streamingThis = isStreaming && isLast;
|
|
2442
1872
|
const text = getMessageText(message);
|
|
2443
1873
|
const toolCalls = message.tool_calls ?? [];
|
|
2444
1874
|
const showReasoning = !!message.reasoning && (!isStreaming || index === latestReasoningIndex);
|
|
2445
|
-
return /* @__PURE__ */
|
|
1875
|
+
return /* @__PURE__ */ jsxs8(
|
|
2446
1876
|
"div",
|
|
2447
1877
|
{
|
|
2448
1878
|
className: "flex flex-col gap-3",
|
|
2449
1879
|
children: [
|
|
2450
|
-
showReasoning && message.reasoning && /* @__PURE__ */
|
|
2451
|
-
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(
|
|
2452
1882
|
MarkdownContent,
|
|
2453
1883
|
{
|
|
2454
1884
|
mode: streamingThis ? "streaming" : "static",
|
|
@@ -2457,8 +1887,8 @@ function AssistantTurnBlock({
|
|
|
2457
1887
|
children: text
|
|
2458
1888
|
}
|
|
2459
1889
|
) }),
|
|
2460
|
-
toolCalls.length > 0 && /* @__PURE__ */
|
|
2461
|
-
(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(
|
|
2462
1892
|
ToolCallBlock,
|
|
2463
1893
|
{
|
|
2464
1894
|
toolCall,
|
|
@@ -2476,13 +1906,13 @@ function AssistantTurnBlock({
|
|
|
2476
1906
|
message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
|
|
2477
1907
|
);
|
|
2478
1908
|
}),
|
|
2479
|
-
isStreaming && !hasAnyContent && /* @__PURE__ */
|
|
1909
|
+
isStreaming && !hasAnyContent && /* @__PURE__ */ jsx10(Shimmer, { className: "ml-4", children: "\u6B63\u5728\u751F\u6210..." })
|
|
2480
1910
|
] });
|
|
2481
1911
|
}
|
|
2482
1912
|
|
|
2483
1913
|
// src/components/RenderErrorBoundary.tsx
|
|
2484
1914
|
import { Component } from "react";
|
|
2485
|
-
import { jsx as
|
|
1915
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2486
1916
|
function getFirstComponentName(componentStack) {
|
|
2487
1917
|
const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
|
|
2488
1918
|
return match?.[1] ?? null;
|
|
@@ -2515,18 +1945,18 @@ var RenderErrorBoundary = class extends Component {
|
|
|
2515
1945
|
return children;
|
|
2516
1946
|
}
|
|
2517
1947
|
const componentName = getFirstComponentName(componentStack);
|
|
2518
|
-
return /* @__PURE__ */
|
|
2519
|
-
/* @__PURE__ */
|
|
2520
|
-
/* @__PURE__ */
|
|
2521
|
-
/* @__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: [
|
|
2522
1952
|
label,
|
|
2523
1953
|
"\u6E32\u67D3\u5931\u8D25"
|
|
2524
1954
|
] }),
|
|
2525
|
-
/* @__PURE__ */
|
|
1955
|
+
/* @__PURE__ */ jsxs9("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
|
|
2526
1956
|
componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
|
|
2527
1957
|
error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
|
|
2528
1958
|
] }),
|
|
2529
|
-
details ? /* @__PURE__ */
|
|
1959
|
+
details ? /* @__PURE__ */ jsx11("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
|
|
2530
1960
|
] })
|
|
2531
1961
|
] }) });
|
|
2532
1962
|
}
|
|
@@ -2534,7 +1964,7 @@ var RenderErrorBoundary = class extends Component {
|
|
|
2534
1964
|
|
|
2535
1965
|
// src/components/UserMessageBubble.tsx
|
|
2536
1966
|
import { getFileParts, getImageParts, getTextContent as getTextContent2 } from "@blade-hq/agent-client";
|
|
2537
|
-
import { jsx as
|
|
1967
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2538
1968
|
function isUserMessage(message) {
|
|
2539
1969
|
return message.role === "user";
|
|
2540
1970
|
}
|
|
@@ -2546,8 +1976,8 @@ function UserMessageBubble({ message, className }) {
|
|
|
2546
1976
|
const text = getTextContent2(message.content).trim();
|
|
2547
1977
|
const fileParts = getFileParts(message.content);
|
|
2548
1978
|
const imageParts = getImageParts(message.content);
|
|
2549
|
-
return /* @__PURE__ */
|
|
2550
|
-
imageParts.length > 0 && /* @__PURE__ */
|
|
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(
|
|
2551
1981
|
"img",
|
|
2552
1982
|
{
|
|
2553
1983
|
src: part.image_url.url,
|
|
@@ -2556,21 +1986,21 @@ function UserMessageBubble({ message, className }) {
|
|
|
2556
1986
|
},
|
|
2557
1987
|
part.image_url.url
|
|
2558
1988
|
)) }),
|
|
2559
|
-
fileParts.length > 0 && /* @__PURE__ */
|
|
1989
|
+
fileParts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs10(
|
|
2560
1990
|
"div",
|
|
2561
1991
|
{
|
|
2562
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))]",
|
|
2563
1993
|
children: [
|
|
2564
|
-
/* @__PURE__ */
|
|
2565
|
-
/* @__PURE__ */
|
|
1994
|
+
/* @__PURE__ */ jsx12(FileText, { size: 12, className: "shrink-0" }),
|
|
1995
|
+
/* @__PURE__ */ jsx12("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
|
|
2566
1996
|
]
|
|
2567
1997
|
},
|
|
2568
1998
|
`${part.name}-${part.data.length}`
|
|
2569
1999
|
)) }),
|
|
2570
|
-
text && /* @__PURE__ */
|
|
2571
|
-
text && isSending(message) && /* @__PURE__ */
|
|
2572
|
-
/* @__PURE__ */
|
|
2573
|
-
/* @__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" })
|
|
2574
2004
|
] })
|
|
2575
2005
|
] }) });
|
|
2576
2006
|
}
|
|
@@ -2579,11 +2009,11 @@ function ErrorMessageBlock({
|
|
|
2579
2009
|
className
|
|
2580
2010
|
}) {
|
|
2581
2011
|
const text = getTextContent2(message.content);
|
|
2582
|
-
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 }) });
|
|
2583
2013
|
}
|
|
2584
2014
|
|
|
2585
2015
|
// src/components/MessageList.tsx
|
|
2586
|
-
import { jsx as
|
|
2016
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2587
2017
|
function parseModeChange(message) {
|
|
2588
2018
|
if (message.kind !== "mode_change" || typeof message.content !== "string") {
|
|
2589
2019
|
return null;
|
|
@@ -2626,7 +2056,7 @@ function MessageList({
|
|
|
2626
2056
|
className,
|
|
2627
2057
|
sessionId
|
|
2628
2058
|
}) {
|
|
2629
|
-
const renderBlocks =
|
|
2059
|
+
const renderBlocks = useMemo6(() => {
|
|
2630
2060
|
const visible = messages.filter((message) => {
|
|
2631
2061
|
if ((message.loop_name ?? "root") !== "root") return false;
|
|
2632
2062
|
if (isHiddenInternalMessage(message)) return false;
|
|
@@ -2699,24 +2129,24 @@ function MessageList({
|
|
|
2699
2129
|
}
|
|
2700
2130
|
return blocks;
|
|
2701
2131
|
}, [messages, isStreaming]);
|
|
2702
|
-
return /* @__PURE__ */
|
|
2703
|
-
/* @__PURE__ */
|
|
2704
|
-
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */
|
|
2705
|
-
/* @__PURE__ */
|
|
2706
|
-
/* @__PURE__ */
|
|
2707
|
-
/* @__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" })
|
|
2708
2138
|
] }) : renderBlocks.map((block) => {
|
|
2709
2139
|
if (block.type === "message") {
|
|
2710
|
-
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);
|
|
2711
2141
|
}
|
|
2712
2142
|
if (block.type === "assistant_turn") {
|
|
2713
|
-
return /* @__PURE__ */
|
|
2143
|
+
return /* @__PURE__ */ jsx13("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsx13(
|
|
2714
2144
|
RenderErrorBoundary,
|
|
2715
2145
|
{
|
|
2716
2146
|
label: "\u52A9\u624B\u6D88\u606F",
|
|
2717
2147
|
details: block.key,
|
|
2718
2148
|
resetKey: getMessageResetSignature(block.messages),
|
|
2719
|
-
children: /* @__PURE__ */
|
|
2149
|
+
children: /* @__PURE__ */ jsx13(
|
|
2720
2150
|
AssistantTurnBlock,
|
|
2721
2151
|
{
|
|
2722
2152
|
messages: block.messages,
|
|
@@ -2732,30 +2162,30 @@ function MessageList({
|
|
|
2732
2162
|
) }, block.key);
|
|
2733
2163
|
}
|
|
2734
2164
|
if (block.type === "compaction") {
|
|
2735
|
-
return /* @__PURE__ */
|
|
2165
|
+
return /* @__PURE__ */ jsxs11(
|
|
2736
2166
|
"div",
|
|
2737
2167
|
{
|
|
2738
2168
|
className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
2739
2169
|
children: [
|
|
2740
|
-
/* @__PURE__ */
|
|
2741
|
-
/* @__PURE__ */
|
|
2170
|
+
/* @__PURE__ */ jsx13(Layers, { size: 12 }),
|
|
2171
|
+
/* @__PURE__ */ jsx13("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
|
|
2742
2172
|
]
|
|
2743
2173
|
},
|
|
2744
2174
|
block.key
|
|
2745
2175
|
);
|
|
2746
2176
|
}
|
|
2747
|
-
return /* @__PURE__ */
|
|
2177
|
+
return /* @__PURE__ */ jsx13(PlanningDivider, { kind: block.kind }, block.key);
|
|
2748
2178
|
}),
|
|
2749
|
-
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
|
|
2750
2180
|
] }) }) }),
|
|
2751
|
-
/* @__PURE__ */
|
|
2752
|
-
/* @__PURE__ */
|
|
2181
|
+
/* @__PURE__ */ jsx13(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
|
|
2182
|
+
/* @__PURE__ */ jsx13(ScrollToBottomButton, {})
|
|
2753
2183
|
] }) });
|
|
2754
2184
|
}
|
|
2755
2185
|
function AutoScrollOnUserSend({ userMessageCount }) {
|
|
2756
2186
|
const { scrollToBottom } = useStickToBottomContext();
|
|
2757
|
-
const previousCountRef =
|
|
2758
|
-
|
|
2187
|
+
const previousCountRef = useRef5(userMessageCount);
|
|
2188
|
+
useEffect5(() => {
|
|
2759
2189
|
if (userMessageCount > previousCountRef.current) {
|
|
2760
2190
|
scrollToBottom("instant");
|
|
2761
2191
|
}
|
|
@@ -2765,9 +2195,9 @@ function AutoScrollOnUserSend({ userMessageCount }) {
|
|
|
2765
2195
|
}
|
|
2766
2196
|
function ScrollToBottomButton() {
|
|
2767
2197
|
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
|
2768
|
-
const [visible, setVisible] =
|
|
2769
|
-
const hideTimerRef =
|
|
2770
|
-
|
|
2198
|
+
const [visible, setVisible] = useState9(false);
|
|
2199
|
+
const hideTimerRef = useRef5(null);
|
|
2200
|
+
useEffect5(() => {
|
|
2771
2201
|
if (isAtBottom) {
|
|
2772
2202
|
if (!hideTimerRef.current) {
|
|
2773
2203
|
hideTimerRef.current = setTimeout(() => {
|
|
@@ -2789,7 +2219,7 @@ function ScrollToBottomButton() {
|
|
|
2789
2219
|
}
|
|
2790
2220
|
};
|
|
2791
2221
|
}, [isAtBottom]);
|
|
2792
|
-
const handleClick =
|
|
2222
|
+
const handleClick = useCallback3(() => {
|
|
2793
2223
|
if (hideTimerRef.current) {
|
|
2794
2224
|
clearTimeout(hideTimerRef.current);
|
|
2795
2225
|
hideTimerRef.current = null;
|
|
@@ -2798,7 +2228,7 @@ function ScrollToBottomButton() {
|
|
|
2798
2228
|
scrollToBottom();
|
|
2799
2229
|
}, [scrollToBottom]);
|
|
2800
2230
|
if (!visible) return null;
|
|
2801
|
-
return /* @__PURE__ */
|
|
2231
|
+
return /* @__PURE__ */ jsxs11(
|
|
2802
2232
|
"button",
|
|
2803
2233
|
{
|
|
2804
2234
|
type: "button",
|
|
@@ -2806,108 +2236,34 @@ function ScrollToBottomButton() {
|
|
|
2806
2236
|
"aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
|
|
2807
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))]",
|
|
2808
2238
|
children: [
|
|
2809
|
-
/* @__PURE__ */
|
|
2810
|
-
/* @__PURE__ */
|
|
2239
|
+
/* @__PURE__ */ jsx13(ChevronDown, { size: 14 }),
|
|
2240
|
+
/* @__PURE__ */ jsx13("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
|
|
2811
2241
|
]
|
|
2812
2242
|
}
|
|
2813
2243
|
);
|
|
2814
2244
|
}
|
|
2815
2245
|
function PlanningDivider({ kind }) {
|
|
2816
|
-
return /* @__PURE__ */
|
|
2817
|
-
/* @__PURE__ */
|
|
2818
|
-
/* @__PURE__ */
|
|
2819
|
-
/* @__PURE__ */
|
|
2820
|
-
/* @__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" })
|
|
2821
2251
|
] }),
|
|
2822
|
-
/* @__PURE__ */
|
|
2252
|
+
/* @__PURE__ */ jsx13("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
|
|
2823
2253
|
] });
|
|
2824
2254
|
}
|
|
2825
2255
|
|
|
2826
|
-
// src/components/
|
|
2827
|
-
import { jsx as
|
|
2256
|
+
// src/components/ChatView.tsx
|
|
2257
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2828
2258
|
function themeAttr(theme) {
|
|
2829
2259
|
return theme === "dark" ? "dark" : void 0;
|
|
2830
2260
|
}
|
|
2831
|
-
function ChatSurface({
|
|
2832
|
-
theme,
|
|
2833
|
-
classNames,
|
|
2834
|
-
renderers,
|
|
2835
|
-
slots,
|
|
2836
|
-
placeholder,
|
|
2837
|
-
connection,
|
|
2838
|
-
errorMessage,
|
|
2839
|
-
messages,
|
|
2840
|
-
isStreaming,
|
|
2841
|
-
isStopping,
|
|
2842
|
-
inputText,
|
|
2843
|
-
onInputChange,
|
|
2844
|
-
onSend,
|
|
2845
|
-
onStop,
|
|
2846
|
-
sessionStatus,
|
|
2847
|
-
askAnswers,
|
|
2848
|
-
onAnswer,
|
|
2849
|
-
sessionId,
|
|
2850
|
-
beforeInput,
|
|
2851
|
-
banner
|
|
2852
|
-
}) {
|
|
2853
|
-
return /* @__PURE__ */ jsxs14(
|
|
2854
|
-
"div",
|
|
2855
|
-
{
|
|
2856
|
-
"data-theme": themeAttr(theme),
|
|
2857
|
-
className: cn(
|
|
2858
|
-
"blade-chat flex min-h-0 flex-1 flex-col overflow-hidden",
|
|
2859
|
-
classNames?.root
|
|
2860
|
-
),
|
|
2861
|
-
children: [
|
|
2862
|
-
/* @__PURE__ */ jsx16(ConnectionBanner, { connection, className: classNames?.banner }),
|
|
2863
|
-
banner,
|
|
2864
|
-
errorMessage && /* @__PURE__ */ jsxs14("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
|
|
2865
|
-
/* @__PURE__ */ jsx16(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
|
|
2866
|
-
/* @__PURE__ */ jsx16("span", { children: errorMessage })
|
|
2867
|
-
] }),
|
|
2868
|
-
slots?.header,
|
|
2869
|
-
/* @__PURE__ */ jsx16(
|
|
2870
|
-
MessageList,
|
|
2871
|
-
{
|
|
2872
|
-
messages,
|
|
2873
|
-
isStreaming,
|
|
2874
|
-
sessionStatus,
|
|
2875
|
-
askAnswers,
|
|
2876
|
-
onAnswer,
|
|
2877
|
-
toolCallRenderer: renderers?.toolCall,
|
|
2878
|
-
emptyState: slots?.emptyState,
|
|
2879
|
-
className: classNames?.messageList,
|
|
2880
|
-
sessionId
|
|
2881
|
-
}
|
|
2882
|
-
),
|
|
2883
|
-
beforeInput,
|
|
2884
|
-
/* @__PURE__ */ jsx16(
|
|
2885
|
-
ChatInput,
|
|
2886
|
-
{
|
|
2887
|
-
value: inputText,
|
|
2888
|
-
onValueChange: onInputChange,
|
|
2889
|
-
onSend,
|
|
2890
|
-
onStop,
|
|
2891
|
-
isStreaming,
|
|
2892
|
-
isStopping,
|
|
2893
|
-
placeholder,
|
|
2894
|
-
className: classNames?.chatInput
|
|
2895
|
-
}
|
|
2896
|
-
),
|
|
2897
|
-
slots?.footer
|
|
2898
|
-
]
|
|
2899
|
-
}
|
|
2900
|
-
);
|
|
2901
|
-
}
|
|
2902
|
-
|
|
2903
|
-
// src/components/AgentChat.tsx
|
|
2904
|
-
import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2905
2261
|
function isUnauthorizedError(error) {
|
|
2906
2262
|
return error instanceof BladeApiError && error.status === 401;
|
|
2907
2263
|
}
|
|
2908
2264
|
function LoginCard({ client, onLoggedIn }) {
|
|
2909
|
-
const [loggingIn, setLoggingIn] =
|
|
2910
|
-
const [loginError, setLoginError] =
|
|
2265
|
+
const [loggingIn, setLoggingIn] = useState10(false);
|
|
2266
|
+
const [loginError, setLoginError] = useState10(null);
|
|
2911
2267
|
const handleLogin = async () => {
|
|
2912
2268
|
setLoggingIn(true);
|
|
2913
2269
|
setLoginError(null);
|
|
@@ -2920,11 +2276,11 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
2920
2276
|
setLoggingIn(false);
|
|
2921
2277
|
}
|
|
2922
2278
|
};
|
|
2923
|
-
return /* @__PURE__ */
|
|
2924
|
-
/* @__PURE__ */
|
|
2925
|
-
/* @__PURE__ */
|
|
2926
|
-
/* @__PURE__ */
|
|
2927
|
-
/* @__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(
|
|
2928
2284
|
"button",
|
|
2929
2285
|
{
|
|
2930
2286
|
type: "button",
|
|
@@ -2934,20 +2290,20 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
2934
2290
|
children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
|
|
2935
2291
|
}
|
|
2936
2292
|
),
|
|
2937
|
-
loginError && /* @__PURE__ */
|
|
2293
|
+
loginError && /* @__PURE__ */ jsx14("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
|
|
2938
2294
|
] }) });
|
|
2939
2295
|
}
|
|
2940
|
-
function
|
|
2296
|
+
function ChatView(props) {
|
|
2941
2297
|
const client = useBladeClient();
|
|
2942
|
-
const [attempt, setAttempt] =
|
|
2943
|
-
const [needLogin, setNeedLogin] =
|
|
2298
|
+
const [attempt, setAttempt] = useState10(0);
|
|
2299
|
+
const [needLogin, setNeedLogin] = useState10(() => !client.hasToken());
|
|
2944
2300
|
if (needLogin) {
|
|
2945
|
-
return /* @__PURE__ */
|
|
2301
|
+
return /* @__PURE__ */ jsx14(
|
|
2946
2302
|
"div",
|
|
2947
2303
|
{
|
|
2948
2304
|
"data-theme": themeAttr(props.theme),
|
|
2949
2305
|
className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
|
|
2950
|
-
children: /* @__PURE__ */
|
|
2306
|
+
children: /* @__PURE__ */ jsx14(
|
|
2951
2307
|
LoginCard,
|
|
2952
2308
|
{
|
|
2953
2309
|
client,
|
|
@@ -2960,7 +2316,7 @@ function AgentChat(props) {
|
|
|
2960
2316
|
}
|
|
2961
2317
|
);
|
|
2962
2318
|
}
|
|
2963
|
-
return /* @__PURE__ */
|
|
2319
|
+
return /* @__PURE__ */ jsx14(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
|
|
2964
2320
|
}
|
|
2965
2321
|
function ChatSessionView({
|
|
2966
2322
|
sessionId,
|
|
@@ -2979,15 +2335,14 @@ function ChatSessionView({
|
|
|
2979
2335
|
createOptions,
|
|
2980
2336
|
onSessionCreated
|
|
2981
2337
|
});
|
|
2982
|
-
const
|
|
2983
|
-
const [
|
|
2984
|
-
|
|
2985
|
-
useEffect7(() => {
|
|
2338
|
+
const [stopRequested, setStopRequested] = useState10(false);
|
|
2339
|
+
const [inputText, setInputText] = useState10("");
|
|
2340
|
+
useEffect6(() => {
|
|
2986
2341
|
if (session) {
|
|
2987
2342
|
onSessionReady?.(session);
|
|
2988
2343
|
}
|
|
2989
2344
|
}, [session, onSessionReady]);
|
|
2990
|
-
|
|
2345
|
+
useEffect6(() => {
|
|
2991
2346
|
if (!session) return;
|
|
2992
2347
|
const offAttach = session.on("attachRequested", ({ label, content }) => {
|
|
2993
2348
|
setInputText((prev) => `${prev ? `${prev}
|
|
@@ -3003,12 +2358,12 @@ ${content}`);
|
|
|
3003
2358
|
offInsert();
|
|
3004
2359
|
};
|
|
3005
2360
|
}, [session]);
|
|
3006
|
-
|
|
2361
|
+
useEffect6(() => {
|
|
3007
2362
|
if (isUnauthorizedError(error)) {
|
|
3008
2363
|
onUnauthorized();
|
|
3009
2364
|
}
|
|
3010
2365
|
}, [error, onUnauthorized]);
|
|
3011
|
-
|
|
2366
|
+
useEffect6(() => {
|
|
3012
2367
|
if (!session || !commands) return;
|
|
3013
2368
|
const unsubscribes = Object.entries(commands).map(
|
|
3014
2369
|
([action, handler]) => session.onCommand(action, (payload) => handler(payload))
|
|
@@ -3020,7 +2375,7 @@ ${content}`);
|
|
|
3020
2375
|
const isStreaming = state?.isStreaming ?? false;
|
|
3021
2376
|
const isStopping = stopRequested && isStreaming;
|
|
3022
2377
|
const connectError = error && !isUnauthorizedError(error) ? error.message || "\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5" : null;
|
|
3023
|
-
const errorMessage = connectError ?? state?.errorMessage ??
|
|
2378
|
+
const errorMessage = connectError ?? state?.errorMessage ?? null;
|
|
3024
2379
|
const handleSend = (text) => {
|
|
3025
2380
|
setStopRequested(false);
|
|
3026
2381
|
return session?.send(text, { mode: state?.mode ?? void 0 }) ?? Promise.resolve(false);
|
|
@@ -3029,281 +2384,73 @@ ${content}`);
|
|
|
3029
2384
|
setStopRequested(true);
|
|
3030
2385
|
void session?.stop();
|
|
3031
2386
|
};
|
|
3032
|
-
return /* @__PURE__ */
|
|
3033
|
-
|
|
2387
|
+
return /* @__PURE__ */ jsxs12(
|
|
2388
|
+
"div",
|
|
3034
2389
|
{
|
|
3035
|
-
theme,
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
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,
|
|
3044
2398
|
{
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
canControl: replay.canControl,
|
|
3048
|
-
onSpeedChange: (next) => void replay.setSpeed(next),
|
|
3049
|
-
onExit: () => void replay.exitToAutonomous()
|
|
2399
|
+
connection: state?.connection ?? "connecting",
|
|
2400
|
+
className: classNames?.banner
|
|
3050
2401
|
}
|
|
3051
2402
|
),
|
|
3052
|
-
/* @__PURE__ */
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
onInputChange: setInputText,
|
|
3060
|
-
onSend: handleSend,
|
|
3061
|
-
onStop: handleStop,
|
|
3062
|
-
sessionStatus: state?.status ?? void 0,
|
|
3063
|
-
askAnswers: state?.askAnswers,
|
|
3064
|
-
onAnswer: (answer, toolCallId, answerData) => {
|
|
3065
|
-
void session?.send(answer, {
|
|
3066
|
-
mode: state?.mode ?? void 0,
|
|
3067
|
-
askUserAnswer: { tool_call_id: toolCallId, ...answerData }
|
|
3068
|
-
});
|
|
3069
|
-
},
|
|
3070
|
-
sessionId: session?.sessionId
|
|
3071
|
-
}
|
|
3072
|
-
);
|
|
3073
|
-
}
|
|
3074
|
-
|
|
3075
|
-
// src/components/LlmChat.tsx
|
|
3076
|
-
import { useEffect as useEffect8, useMemo as useMemo8, useState as useState14 } from "react";
|
|
3077
|
-
|
|
3078
|
-
// src/components/LlmAdvancedSettings.tsx
|
|
3079
|
-
import { useState as useState13 } from "react";
|
|
3080
|
-
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3081
|
-
var FIELDS = [
|
|
3082
|
-
{ id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
|
|
3083
|
-
{ id: "model", label: "\u6A21\u578B", placeholder: "\u6A21\u578B\u540D\u79F0" },
|
|
3084
|
-
{ id: "apiKey", label: "\u5BC6\u94A5", placeholder: "\u7559\u7A7A\u8868\u793A\u4E0D\u6539", secret: true }
|
|
3085
|
-
];
|
|
3086
|
-
function normalizeAdvanced(value) {
|
|
3087
|
-
if (!value) return null;
|
|
3088
|
-
const config = value === true ? {} : value;
|
|
3089
|
-
return {
|
|
3090
|
-
baseURL: config.baseURL ?? true,
|
|
3091
|
-
model: config.model ?? true,
|
|
3092
|
-
apiKey: config.apiKey ?? false,
|
|
3093
|
-
storage: config.storage ?? "local"
|
|
3094
|
-
};
|
|
3095
|
-
}
|
|
3096
|
-
function storageKeyFor(settings, baseURL) {
|
|
3097
|
-
const explicit = typeof settings === "object" ? settings.storageKey : void 0;
|
|
3098
|
-
return `blade-llm-override:${explicit ?? baseURL}`;
|
|
3099
|
-
}
|
|
3100
|
-
function readOverride(settings, baseURL) {
|
|
3101
|
-
const normalized = normalizeAdvanced(settings);
|
|
3102
|
-
if (!normalized || normalized.storage !== "local" || typeof localStorage === "undefined") return {};
|
|
3103
|
-
try {
|
|
3104
|
-
const raw = localStorage.getItem(storageKeyFor(settings, baseURL));
|
|
3105
|
-
if (!raw) return {};
|
|
3106
|
-
const stored = JSON.parse(raw);
|
|
3107
|
-
return Object.fromEntries(
|
|
3108
|
-
Object.entries(stored).filter(([key]) => normalized[key])
|
|
3109
|
-
);
|
|
3110
|
-
} catch {
|
|
3111
|
-
return {};
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
function writeOverride(settings, baseURL, override) {
|
|
3115
|
-
const normalized = normalizeAdvanced(settings);
|
|
3116
|
-
if (!normalized || normalized.storage !== "local" || typeof localStorage === "undefined") return;
|
|
3117
|
-
try {
|
|
3118
|
-
const key = storageKeyFor(settings, baseURL);
|
|
3119
|
-
if (Object.keys(override).length === 0) localStorage.removeItem(key);
|
|
3120
|
-
else localStorage.setItem(key, JSON.stringify(override));
|
|
3121
|
-
} catch {
|
|
3122
|
-
}
|
|
3123
|
-
}
|
|
3124
|
-
function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
3125
|
-
const normalized = normalizeAdvanced(settings);
|
|
3126
|
-
const [open, setOpen] = useState13(false);
|
|
3127
|
-
const [draft, setDraft] = useState13(override);
|
|
3128
|
-
if (!normalized) return null;
|
|
3129
|
-
const fields = FIELDS.filter((field) => normalized[field.id]);
|
|
3130
|
-
const dirty = Object.keys(override).length > 0;
|
|
3131
|
-
return /* @__PURE__ */ jsxs16("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
|
|
3132
|
-
/* @__PURE__ */ jsxs16(
|
|
3133
|
-
"button",
|
|
3134
|
-
{
|
|
3135
|
-
type: "button",
|
|
3136
|
-
onClick: () => {
|
|
3137
|
-
setDraft(override);
|
|
3138
|
-
setOpen((value) => !value);
|
|
3139
|
-
},
|
|
3140
|
-
className: "flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
|
|
3141
|
-
children: [
|
|
3142
|
-
/* @__PURE__ */ jsx18(Settings2, { size: 13 }),
|
|
3143
|
-
"\u9AD8\u7EA7\u8BBE\u7F6E",
|
|
3144
|
-
dirty && /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
|
|
3145
|
-
]
|
|
3146
|
-
}
|
|
3147
|
-
),
|
|
3148
|
-
open && /* @__PURE__ */ jsxs16("div", { className: "mt-2 flex flex-col gap-2", children: [
|
|
3149
|
-
fields.map((field) => /* @__PURE__ */ jsxs16("label", { className: "flex flex-col gap-1", children: [
|
|
3150
|
-
/* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
|
|
3151
|
-
/* @__PURE__ */ jsx18(
|
|
3152
|
-
"input",
|
|
3153
|
-
{
|
|
3154
|
-
type: field.secret ? "password" : "text",
|
|
3155
|
-
value: draft[field.id] ?? "",
|
|
3156
|
-
placeholder: field.id === "apiKey" ? field.placeholder : defaults[field.id] || field.placeholder,
|
|
3157
|
-
onChange: (event) => setDraft({ ...draft, [field.id]: event.target.value }),
|
|
3158
|
-
className: "rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))] px-2 py-1 text-xs text-[hsl(var(--foreground))] outline-none"
|
|
3159
|
-
}
|
|
3160
|
-
)
|
|
3161
|
-
] }, field.id)),
|
|
3162
|
-
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" }),
|
|
3163
|
-
/* @__PURE__ */ jsxs16("div", { className: "flex gap-2", children: [
|
|
3164
|
-
/* @__PURE__ */ jsx18(
|
|
3165
|
-
"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,
|
|
3166
2410
|
{
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
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
|
+
});
|
|
3174
2420
|
},
|
|
3175
|
-
|
|
3176
|
-
|
|
2421
|
+
toolCallRenderer: renderers?.toolCall,
|
|
2422
|
+
emptyState: slots?.emptyState,
|
|
2423
|
+
className: classNames?.messageList,
|
|
2424
|
+
sessionId: session?.sessionId
|
|
3177
2425
|
}
|
|
3178
2426
|
),
|
|
3179
|
-
/* @__PURE__ */
|
|
3180
|
-
|
|
2427
|
+
/* @__PURE__ */ jsx14(
|
|
2428
|
+
ChatInput,
|
|
3181
2429
|
{
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
}
|
|
3191
|
-
)
|
|
3192
|
-
] })
|
|
3193
|
-
] })
|
|
3194
|
-
] });
|
|
3195
|
-
}
|
|
3196
|
-
|
|
3197
|
-
// src/components/LlmChat.tsx
|
|
3198
|
-
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
3199
|
-
function LlmChat({
|
|
3200
|
-
classNames,
|
|
3201
|
-
renderers,
|
|
3202
|
-
slots,
|
|
3203
|
-
placeholder,
|
|
3204
|
-
theme,
|
|
3205
|
-
onReady,
|
|
3206
|
-
advanced,
|
|
3207
|
-
onOverrideChange,
|
|
3208
|
-
...options
|
|
3209
|
-
}) {
|
|
3210
|
-
const [override, setOverride] = useState14(() => readOverride(advanced, options.baseURL));
|
|
3211
|
-
const effective = { ...options, ...override };
|
|
3212
|
-
const { messages, isStreaming, error, send, stop, reset } = useLlmChat(effective);
|
|
3213
|
-
const [inputText, setInputText] = useState14("");
|
|
3214
|
-
const [stopRequested, setStopRequested] = useState14(false);
|
|
3215
|
-
const handle = useMemo8(
|
|
3216
|
-
() => ({
|
|
3217
|
-
insertText: (text) => setInputText((prev) => prev ? `${prev}
|
|
3218
|
-
${text}` : text),
|
|
3219
|
-
send,
|
|
3220
|
-
reset
|
|
3221
|
-
}),
|
|
3222
|
-
[send, reset]
|
|
3223
|
-
);
|
|
3224
|
-
useEffect8(() => {
|
|
3225
|
-
onReady?.(handle);
|
|
3226
|
-
}, [handle, onReady]);
|
|
3227
|
-
return /* @__PURE__ */ jsx19(
|
|
3228
|
-
ChatSurface,
|
|
3229
|
-
{
|
|
3230
|
-
theme,
|
|
3231
|
-
classNames,
|
|
3232
|
-
renderers,
|
|
3233
|
-
slots,
|
|
3234
|
-
placeholder,
|
|
3235
|
-
connection: "connected",
|
|
3236
|
-
errorMessage: error,
|
|
3237
|
-
messages,
|
|
3238
|
-
isStreaming,
|
|
3239
|
-
isStopping: stopRequested && isStreaming,
|
|
3240
|
-
inputText,
|
|
3241
|
-
onInputChange: setInputText,
|
|
3242
|
-
onSend: async (text) => {
|
|
3243
|
-
setStopRequested(false);
|
|
3244
|
-
if (!text.trim() || isStreaming) return false;
|
|
3245
|
-
void send(text);
|
|
3246
|
-
return true;
|
|
3247
|
-
},
|
|
3248
|
-
onStop: () => {
|
|
3249
|
-
setStopRequested(true);
|
|
3250
|
-
stop();
|
|
3251
|
-
},
|
|
3252
|
-
beforeInput: advanced ? /* @__PURE__ */ jsx19(
|
|
3253
|
-
LlmAdvancedSettingsBar,
|
|
3254
|
-
{
|
|
3255
|
-
settings: advanced,
|
|
3256
|
-
defaults: { baseURL: options.baseURL, model: options.model },
|
|
3257
|
-
override,
|
|
3258
|
-
onChange: (next) => {
|
|
3259
|
-
setOverride(next);
|
|
3260
|
-
writeOverride(advanced, options.baseURL, next);
|
|
3261
|
-
onOverrideChange?.(next);
|
|
2430
|
+
value: inputText,
|
|
2431
|
+
onValueChange: setInputText,
|
|
2432
|
+
onSend: handleSend,
|
|
2433
|
+
onStop: handleStop,
|
|
2434
|
+
isStreaming,
|
|
2435
|
+
isStopping,
|
|
2436
|
+
placeholder,
|
|
2437
|
+
className: classNames?.chatInput
|
|
3262
2438
|
}
|
|
3263
|
-
|
|
3264
|
-
|
|
2439
|
+
),
|
|
2440
|
+
slots?.footer
|
|
2441
|
+
]
|
|
3265
2442
|
}
|
|
3266
2443
|
);
|
|
3267
2444
|
}
|
|
3268
2445
|
|
|
3269
|
-
// src/components/ChatView.tsx
|
|
3270
|
-
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
3271
|
-
function ChatView(props) {
|
|
3272
|
-
const { mode, llm, onLlmReady, ...rest } = props;
|
|
3273
|
-
if (mode === "llm") {
|
|
3274
|
-
if (!llm) {
|
|
3275
|
-
throw new Error('ChatView: mode="llm" \u9700\u8981\u540C\u65F6\u4F20 llm={{ baseURL, model }}');
|
|
3276
|
-
}
|
|
3277
|
-
return /* @__PURE__ */ jsx20(
|
|
3278
|
-
LlmChat,
|
|
3279
|
-
{
|
|
3280
|
-
...llm,
|
|
3281
|
-
classNames: rest.classNames,
|
|
3282
|
-
renderers: rest.renderers,
|
|
3283
|
-
slots: rest.slots,
|
|
3284
|
-
placeholder: rest.placeholder,
|
|
3285
|
-
theme: rest.theme,
|
|
3286
|
-
onReady: onLlmReady
|
|
3287
|
-
}
|
|
3288
|
-
);
|
|
3289
|
-
}
|
|
3290
|
-
return /* @__PURE__ */ jsx20(AgentChat, { ...rest });
|
|
3291
|
-
}
|
|
3292
|
-
|
|
3293
2446
|
// src/index.ts
|
|
3294
2447
|
export * from "@blade-hq/agent-client";
|
|
3295
2448
|
export {
|
|
3296
|
-
AgentChat,
|
|
3297
2449
|
BladeProvider,
|
|
3298
2450
|
ChatView,
|
|
3299
|
-
LlmChat,
|
|
3300
2451
|
MarkdownContent,
|
|
3301
|
-
ReplayBar,
|
|
3302
|
-
ReplayMismatchPrompt,
|
|
3303
2452
|
useAgentSession,
|
|
3304
|
-
useBladeClient
|
|
3305
|
-
useLlmChat,
|
|
3306
|
-
useReplay
|
|
2453
|
+
useBladeClient
|
|
3307
2454
|
};
|
|
3308
2455
|
/*! Bundled license information:
|
|
3309
2456
|
|
|
@@ -3334,8 +2481,6 @@ lucide-react/dist/esm/icons/lock-keyhole.js:
|
|
|
3334
2481
|
lucide-react/dist/esm/icons/message-square-more.js:
|
|
3335
2482
|
lucide-react/dist/esm/icons/message-square.js:
|
|
3336
2483
|
lucide-react/dist/esm/icons/music.js:
|
|
3337
|
-
lucide-react/dist/esm/icons/play.js:
|
|
3338
|
-
lucide-react/dist/esm/icons/settings-2.js:
|
|
3339
2484
|
lucide-react/dist/esm/icons/square.js:
|
|
3340
2485
|
lucide-react/dist/esm/icons/triangle-alert.js:
|
|
3341
2486
|
lucide-react/dist/esm/icons/x.js:
|