@timbal-ai/timbal-react 0.2.2 → 0.3.0
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 +326 -44
- package/dist/index.cjs +2619 -417
- package/dist/index.d.cts +820 -17
- package/dist/index.d.ts +820 -17
- package/dist/index.esm.js +2646 -471
- package/dist/styles.css +210 -0
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -30,15 +30,24 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
|
|
33
|
+
ARTIFACT_AGENT_INSTRUCTIONS: () => ARTIFACT_AGENT_INSTRUCTIONS,
|
|
34
|
+
ARTIFACT_FENCE_LANGUAGES: () => ARTIFACT_FENCE_LANGUAGES,
|
|
35
|
+
ActionBarPrimitive: () => import_react26.ActionBarPrimitive,
|
|
36
|
+
ArtifactCard: () => ArtifactCard,
|
|
37
|
+
ArtifactRegistryProvider: () => ArtifactRegistryProvider,
|
|
38
|
+
ArtifactView: () => ArtifactView,
|
|
39
|
+
AssistantRuntimeProvider: () => import_react26.AssistantRuntimeProvider,
|
|
34
40
|
AuthGuard: () => AuthGuard,
|
|
35
41
|
Avatar: () => Avatar,
|
|
36
42
|
AvatarFallback: () => AvatarFallback,
|
|
37
43
|
AvatarImage: () => AvatarImage,
|
|
38
44
|
Button: () => Button,
|
|
45
|
+
ChartArtifactView: () => ChartArtifactView,
|
|
46
|
+
Composer: () => Composer,
|
|
39
47
|
ComposerAddAttachment: () => ComposerAddAttachment,
|
|
40
48
|
ComposerAttachments: () => ComposerAttachments,
|
|
41
|
-
ComposerPrimitive: () =>
|
|
49
|
+
ComposerPrimitive: () => import_react26.ComposerPrimitive,
|
|
50
|
+
DEFAULT_UPLOAD_ACCEPT: () => DEFAULT_UPLOAD_ACCEPT,
|
|
42
51
|
Dialog: () => Dialog,
|
|
43
52
|
DialogClose: () => DialogClose,
|
|
44
53
|
DialogContent: () => DialogContent,
|
|
@@ -46,37 +55,72 @@ __export(index_exports, {
|
|
|
46
55
|
DialogPortal: () => DialogPortal,
|
|
47
56
|
DialogTitle: () => DialogTitle,
|
|
48
57
|
DialogTrigger: () => DialogTrigger,
|
|
58
|
+
HtmlArtifactView: () => HtmlArtifactView,
|
|
59
|
+
JsonArtifactView: () => JsonArtifactView,
|
|
49
60
|
MarkdownText: () => MarkdownText,
|
|
50
|
-
MessagePrimitive: () =>
|
|
61
|
+
MessagePrimitive: () => import_react26.MessagePrimitive,
|
|
62
|
+
QuestionArtifactView: () => QuestionArtifactView,
|
|
51
63
|
SessionProvider: () => SessionProvider,
|
|
52
64
|
Shimmer: () => Shimmer,
|
|
65
|
+
Suggestions: () => Suggestions,
|
|
53
66
|
SyntaxHighlighter: () => syntax_highlighter_default,
|
|
67
|
+
TableArtifactView: () => TableArtifactView,
|
|
54
68
|
Thread: () => Thread,
|
|
55
|
-
ThreadPrimitive: () =>
|
|
69
|
+
ThreadPrimitive: () => import_react26.ThreadPrimitive,
|
|
56
70
|
TimbalChat: () => TimbalChat,
|
|
71
|
+
TimbalChatShell: () => TimbalChatShell,
|
|
57
72
|
TimbalRuntimeProvider: () => TimbalRuntimeProvider,
|
|
73
|
+
ToolArtifactFallback: () => ToolArtifactFallback,
|
|
58
74
|
ToolFallback: () => ToolFallback,
|
|
59
75
|
Tooltip: () => Tooltip,
|
|
60
76
|
TooltipContent: () => TooltipContent,
|
|
61
77
|
TooltipIconButton: () => TooltipIconButton,
|
|
62
78
|
TooltipProvider: () => TooltipProvider,
|
|
63
79
|
TooltipTrigger: () => TooltipTrigger,
|
|
80
|
+
UiArtifactView: () => UiArtifactView,
|
|
81
|
+
UiCustomNodeRegistryProvider: () => UiCustomNodeRegistryProvider,
|
|
82
|
+
UiEventProvider: () => UiEventProvider,
|
|
83
|
+
UiNodeView: () => UiNodeView,
|
|
64
84
|
UserMessageAttachments: () => UserMessageAttachments,
|
|
85
|
+
WorkforceSelector: () => WorkforceSelector,
|
|
65
86
|
authFetch: () => authFetch,
|
|
66
87
|
buttonVariants: () => buttonVariants,
|
|
67
88
|
clearTokens: () => clearTokens,
|
|
68
89
|
cn: () => cn,
|
|
90
|
+
createDefaultAttachmentAdapter: () => createDefaultAttachmentAdapter,
|
|
91
|
+
createUploadAttachmentAdapter: () => createUploadAttachmentAdapter,
|
|
92
|
+
defaultArtifactRenderers: () => defaultArtifactRenderers,
|
|
69
93
|
fetchCurrentUser: () => fetchCurrentUser,
|
|
94
|
+
findMarkdownArtifacts: () => findMarkdownArtifacts,
|
|
70
95
|
getAccessToken: () => getAccessToken,
|
|
96
|
+
getPath: () => getPath,
|
|
71
97
|
getRefreshToken: () => getRefreshToken,
|
|
98
|
+
isArtifact: () => isArtifact,
|
|
99
|
+
isArtifactFenceLanguage: () => isArtifactFenceLanguage,
|
|
100
|
+
isUiBinding: () => isUiBinding,
|
|
101
|
+
parseArtifactFromToolResult: () => parseArtifactFromToolResult,
|
|
102
|
+
parseSSELine: () => import_timbal_sdk2.parseSSELine,
|
|
72
103
|
refreshAccessToken: () => refreshAccessToken,
|
|
104
|
+
resolveAttachmentAdapter: () => resolveAttachmentAdapter,
|
|
105
|
+
resolveBindable: () => resolveBindable,
|
|
73
106
|
setAccessToken: () => setAccessToken,
|
|
107
|
+
setPath: () => setPath,
|
|
74
108
|
setRefreshToken: () => setRefreshToken,
|
|
75
|
-
|
|
76
|
-
|
|
109
|
+
splitMarkdownByArtifacts: () => splitMarkdownByArtifacts,
|
|
110
|
+
useArtifactRegistry: () => useArtifactRegistry,
|
|
111
|
+
useComposerRuntime: () => import_react26.useComposerRuntime,
|
|
112
|
+
useMessageRuntime: () => import_react26.useMessageRuntime,
|
|
113
|
+
useResolvedSuggestions: () => useResolvedSuggestions,
|
|
77
114
|
useSession: () => useSession,
|
|
78
|
-
useThread: () =>
|
|
79
|
-
useThreadRuntime: () =>
|
|
115
|
+
useThread: () => import_react26.useThread,
|
|
116
|
+
useThreadRuntime: () => import_react26.useThreadRuntime,
|
|
117
|
+
useTimbalRuntime: () => useTimbalRuntime,
|
|
118
|
+
useTimbalStream: () => useTimbalStream,
|
|
119
|
+
useUiCustomNodeRegistry: () => useUiCustomNodeRegistry,
|
|
120
|
+
useUiDispatch: () => useUiDispatch,
|
|
121
|
+
useUiEventEmitter: () => useUiEventEmitter,
|
|
122
|
+
useUiState: () => useUiState,
|
|
123
|
+
useWorkforces: () => useWorkforces
|
|
80
124
|
});
|
|
81
125
|
module.exports = __toCommonJS(index_exports);
|
|
82
126
|
|
|
@@ -166,13 +210,506 @@ var fetchCurrentUser = async () => {
|
|
|
166
210
|
}
|
|
167
211
|
};
|
|
168
212
|
|
|
213
|
+
// src/artifacts/types.ts
|
|
214
|
+
function isArtifact(value) {
|
|
215
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.type === "string";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// src/runtime/reducer.ts
|
|
219
|
+
function createReducerState() {
|
|
220
|
+
return { parts: [], toolIndexById: /* @__PURE__ */ new Map() };
|
|
221
|
+
}
|
|
222
|
+
function reduceSseEvent(state, event) {
|
|
223
|
+
switch (event.type) {
|
|
224
|
+
case "DELTA":
|
|
225
|
+
return reduceDelta(state, event.item);
|
|
226
|
+
case "OUTPUT": {
|
|
227
|
+
const path = event.path;
|
|
228
|
+
const isNested = typeof path === "string" && path.includes(".");
|
|
229
|
+
if (!isNested) {
|
|
230
|
+
const errorMessage = readErrorMessage(event);
|
|
231
|
+
if (errorMessage) {
|
|
232
|
+
state.parts.push({ type: "text", text: `**Error:** ${errorMessage}` });
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (isNested) {
|
|
237
|
+
return reduceNestedOutput(
|
|
238
|
+
state,
|
|
239
|
+
path,
|
|
240
|
+
event.output
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
return reduceOutput(
|
|
244
|
+
state,
|
|
245
|
+
event.output
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
default:
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function reduceDelta(state, item) {
|
|
253
|
+
if (!item) return false;
|
|
254
|
+
if (item.type === "text_delta" && typeof item.text_delta === "string") {
|
|
255
|
+
lastTextPart(state).text += item.text_delta;
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
if (item.type === "thinking_delta" && typeof item.thinking_delta === "string") {
|
|
259
|
+
lastThinkingPart(state).text += item.thinking_delta;
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
if (item.type === "tool_use") {
|
|
263
|
+
const toolCallId = item.id || `tool-${crypto.randomUUID()}`;
|
|
264
|
+
const inputStr = stringifyInput(item.input);
|
|
265
|
+
const part = {
|
|
266
|
+
type: "tool-call",
|
|
267
|
+
toolCallId,
|
|
268
|
+
toolName: item.name || "unknown",
|
|
269
|
+
argsText: inputStr,
|
|
270
|
+
status: "running"
|
|
271
|
+
};
|
|
272
|
+
state.parts.push(part);
|
|
273
|
+
state.toolIndexById.set(toolCallId, state.parts.length - 1);
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
if (item.type === "tool_use_delta") {
|
|
277
|
+
const idx = state.toolIndexById.get(item.id);
|
|
278
|
+
if (idx !== void 0 && typeof item.input_delta === "string") {
|
|
279
|
+
state.parts[idx].argsText += item.input_delta;
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
function reduceNestedOutput(state, path, output) {
|
|
286
|
+
if (!output || typeof output !== "object") return false;
|
|
287
|
+
if (!Array.isArray(output.content) && isArtifact(output)) {
|
|
288
|
+
const toolName = toolNameFromPath(path);
|
|
289
|
+
if (toolName && attachToolResult(state, { toolName, result: output })) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return reduceOutput(state, output, { toolResultsOnly: true, allowOrphan: false });
|
|
294
|
+
}
|
|
295
|
+
function reduceOutput(state, output, options) {
|
|
296
|
+
if (!output) return false;
|
|
297
|
+
if (typeof output === "string") {
|
|
298
|
+
if (state.parts.length === 0) {
|
|
299
|
+
state.parts.push({ type: "text", text: output });
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
if (Array.isArray(output.content)) {
|
|
305
|
+
let changed = false;
|
|
306
|
+
const blocks = output.content;
|
|
307
|
+
for (const block of blocks) {
|
|
308
|
+
if (block.type === "tool_use") {
|
|
309
|
+
if (!options?.toolResultsOnly && recordToolUse(state, block)) {
|
|
310
|
+
changed = true;
|
|
311
|
+
}
|
|
312
|
+
} else if (block.type === "tool_result") {
|
|
313
|
+
if (recordToolResult(state, block, options)) changed = true;
|
|
314
|
+
} else if (!options?.toolResultsOnly) {
|
|
315
|
+
if (block.type === "text" && typeof block.text === "string" && !lastTextPart(state).text) {
|
|
316
|
+
lastTextPart(state).text = block.text;
|
|
317
|
+
changed = true;
|
|
318
|
+
} else if (block.type === "thinking" && typeof block.thinking === "string" && !lastThinkingPart(state).text) {
|
|
319
|
+
lastThinkingPart(state).text = block.thinking;
|
|
320
|
+
changed = true;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return changed;
|
|
325
|
+
}
|
|
326
|
+
if (state.parts.length === 0) {
|
|
327
|
+
state.parts.push({ type: "text", text: JSON.stringify(output) });
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
function recordToolUse(state, block) {
|
|
333
|
+
const id = block.id || `tool-${crypto.randomUUID()}`;
|
|
334
|
+
if (state.toolIndexById.has(id)) return false;
|
|
335
|
+
const inputStr = stringifyInput(block.input);
|
|
336
|
+
const part = {
|
|
337
|
+
type: "tool-call",
|
|
338
|
+
toolCallId: id,
|
|
339
|
+
toolName: block.name || "unknown",
|
|
340
|
+
argsText: inputStr,
|
|
341
|
+
status: "running"
|
|
342
|
+
};
|
|
343
|
+
state.parts.push(part);
|
|
344
|
+
state.toolIndexById.set(id, state.parts.length - 1);
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
function recordToolResult(state, block, options) {
|
|
348
|
+
const allowOrphan = options?.allowOrphan !== false;
|
|
349
|
+
const id = block.id || block.tool_use_id || "";
|
|
350
|
+
const { result, resultText } = parseToolResultContent(block.content);
|
|
351
|
+
const toolName = block.name || void 0;
|
|
352
|
+
if (id) {
|
|
353
|
+
const idx = state.toolIndexById.get(id);
|
|
354
|
+
if (idx !== void 0) {
|
|
355
|
+
const part2 = state.parts[idx];
|
|
356
|
+
part2.result = result;
|
|
357
|
+
if (resultText) part2.resultText = resultText;
|
|
358
|
+
part2.status = "complete";
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
if (!allowOrphan) return false;
|
|
362
|
+
}
|
|
363
|
+
if (!id && toolName && attachToolResult(state, {
|
|
364
|
+
toolName,
|
|
365
|
+
result,
|
|
366
|
+
resultText
|
|
367
|
+
})) {
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
if (!id || !allowOrphan) return false;
|
|
371
|
+
const part = {
|
|
372
|
+
type: "tool-call",
|
|
373
|
+
toolCallId: id,
|
|
374
|
+
toolName: toolName || "unknown",
|
|
375
|
+
argsText: "",
|
|
376
|
+
result,
|
|
377
|
+
resultText,
|
|
378
|
+
status: "complete"
|
|
379
|
+
};
|
|
380
|
+
state.parts.push(part);
|
|
381
|
+
state.toolIndexById.set(id, state.parts.length - 1);
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
function toolNameFromPath(path) {
|
|
385
|
+
const segment = path.split(".").pop();
|
|
386
|
+
return segment && segment !== "agent" && segment !== "llm" ? segment : null;
|
|
387
|
+
}
|
|
388
|
+
function attachToolResult(state, {
|
|
389
|
+
toolCallId,
|
|
390
|
+
toolName,
|
|
391
|
+
result,
|
|
392
|
+
resultText
|
|
393
|
+
}) {
|
|
394
|
+
if (toolCallId) {
|
|
395
|
+
const idx = state.toolIndexById.get(toolCallId);
|
|
396
|
+
if (idx !== void 0) {
|
|
397
|
+
const part = state.parts[idx];
|
|
398
|
+
part.result = result;
|
|
399
|
+
if (resultText) part.resultText = resultText;
|
|
400
|
+
part.status = "complete";
|
|
401
|
+
return true;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (toolName) {
|
|
405
|
+
for (let i = state.parts.length - 1; i >= 0; i--) {
|
|
406
|
+
const part = state.parts[i];
|
|
407
|
+
if (part.type === "tool-call" && part.toolName === toolName && part.result === void 0) {
|
|
408
|
+
part.result = result;
|
|
409
|
+
if (resultText) part.resultText = resultText;
|
|
410
|
+
part.status = "complete";
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
function parseToolResultContent(content) {
|
|
418
|
+
if (typeof content === "string") {
|
|
419
|
+
return { result: content, resultText: content };
|
|
420
|
+
}
|
|
421
|
+
if (!Array.isArray(content)) {
|
|
422
|
+
return { result: content };
|
|
423
|
+
}
|
|
424
|
+
const textChunks = [];
|
|
425
|
+
for (const item of content) {
|
|
426
|
+
if (typeof item === "string") {
|
|
427
|
+
textChunks.push(item);
|
|
428
|
+
} else if (item && typeof item === "object") {
|
|
429
|
+
const obj = item;
|
|
430
|
+
if (obj.type === "text" && typeof obj.text === "string") {
|
|
431
|
+
textChunks.push(obj.text);
|
|
432
|
+
} else if (obj.type === "thinking" && typeof obj.thinking === "string") {
|
|
433
|
+
textChunks.push(obj.thinking);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
result: content,
|
|
439
|
+
resultText: textChunks.length > 0 ? textChunks.join("\n") : void 0
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
function readErrorMessage(event) {
|
|
443
|
+
const status = event.status;
|
|
444
|
+
const isErrorStatus = status?.code === "error";
|
|
445
|
+
const error = event.error;
|
|
446
|
+
let type = null;
|
|
447
|
+
let message = null;
|
|
448
|
+
if (isErrorStatus && typeof status?.message === "string" && status.message.length > 0) {
|
|
449
|
+
message = status.message;
|
|
450
|
+
}
|
|
451
|
+
if (!message && typeof error === "string" && error.length > 0) {
|
|
452
|
+
message = error;
|
|
453
|
+
} else if (error && typeof error === "object") {
|
|
454
|
+
const obj = error;
|
|
455
|
+
if (typeof obj.type === "string" && obj.type.length > 0) {
|
|
456
|
+
type = obj.type;
|
|
457
|
+
}
|
|
458
|
+
if (!message && typeof obj.message === "string" && obj.message.length > 0) {
|
|
459
|
+
message = obj.message;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
if (!message && !isErrorStatus) return null;
|
|
463
|
+
if (!message) return "The agent failed to generate a response.";
|
|
464
|
+
const compact = compactError(message);
|
|
465
|
+
return type ? `${type}: ${compact}` : compact;
|
|
466
|
+
}
|
|
467
|
+
var ERROR_MAX_CHARS = 480;
|
|
468
|
+
function compactError(message) {
|
|
469
|
+
const trimmed = message.split(/\n\s*Traceback \(most recent call last\):/u)[0].trim();
|
|
470
|
+
if (trimmed.length <= ERROR_MAX_CHARS) return trimmed;
|
|
471
|
+
return `${trimmed.slice(0, ERROR_MAX_CHARS).trimEnd()}\u2026`;
|
|
472
|
+
}
|
|
473
|
+
function stringifyInput(input) {
|
|
474
|
+
if (input === void 0 || input === null) return "{}";
|
|
475
|
+
return typeof input === "string" ? input : JSON.stringify(input);
|
|
476
|
+
}
|
|
477
|
+
function lastTextPart(state) {
|
|
478
|
+
const last = state.parts[state.parts.length - 1];
|
|
479
|
+
if (last?.type === "text") return last;
|
|
480
|
+
const next = { type: "text", text: "" };
|
|
481
|
+
state.parts.push(next);
|
|
482
|
+
return next;
|
|
483
|
+
}
|
|
484
|
+
function lastThinkingPart(state) {
|
|
485
|
+
const last = state.parts[state.parts.length - 1];
|
|
486
|
+
if (last?.type === "thinking") return last;
|
|
487
|
+
const next = { type: "thinking", text: "" };
|
|
488
|
+
state.parts.push(next);
|
|
489
|
+
return next;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/runtime/attachments.ts
|
|
493
|
+
async function extractAttachment(attachment) {
|
|
494
|
+
const file = attachment.file;
|
|
495
|
+
let src = null;
|
|
496
|
+
let contentType;
|
|
497
|
+
let name = attachment.name ?? file?.name;
|
|
498
|
+
const content = attachment.content;
|
|
499
|
+
if (content) {
|
|
500
|
+
for (const block of content) {
|
|
501
|
+
if (block.type === "image" && typeof block.image === "string") {
|
|
502
|
+
src = block.image;
|
|
503
|
+
if (typeof block.mimeType === "string") {
|
|
504
|
+
contentType = block.mimeType;
|
|
505
|
+
}
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
if (block.type === "file" && typeof block.data === "string") {
|
|
509
|
+
src = block.data;
|
|
510
|
+
if (typeof block.mimeType === "string") contentType = block.mimeType;
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (src === null && file) {
|
|
516
|
+
src = await fileToDataUrl(file);
|
|
517
|
+
if (!contentType) contentType = file.type || void 0;
|
|
518
|
+
if (!name) name = file.name;
|
|
519
|
+
}
|
|
520
|
+
if (!src) return null;
|
|
521
|
+
if (!contentType) contentType = mimeFromDataUrl(src);
|
|
522
|
+
const rawType = String(attachment.type ?? "file");
|
|
523
|
+
const type = rawType === "image" || rawType === "document" ? rawType : "file";
|
|
524
|
+
return {
|
|
525
|
+
id: attachment.id ?? crypto.randomUUID(),
|
|
526
|
+
type,
|
|
527
|
+
...name !== void 0 ? { name } : {},
|
|
528
|
+
...contentType !== void 0 ? { contentType } : {},
|
|
529
|
+
dataUrl: src
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
function fileToDataUrl(file) {
|
|
533
|
+
return new Promise((resolve, reject) => {
|
|
534
|
+
const reader = new FileReader();
|
|
535
|
+
reader.onload = () => resolve(reader.result);
|
|
536
|
+
reader.onerror = () => reject(reader.error);
|
|
537
|
+
reader.readAsDataURL(file);
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
function mimeFromDataUrl(dataUrl) {
|
|
541
|
+
const match = /^data:([^;,]+)[;,]/.exec(dataUrl);
|
|
542
|
+
return match?.[1];
|
|
543
|
+
}
|
|
544
|
+
function buildPromptBody({
|
|
545
|
+
input,
|
|
546
|
+
attachments,
|
|
547
|
+
parentId
|
|
548
|
+
}) {
|
|
549
|
+
const context = { parent_id: parentId };
|
|
550
|
+
const files = attachments ?? [];
|
|
551
|
+
if (files.length === 0) {
|
|
552
|
+
return { prompt: input, context };
|
|
553
|
+
}
|
|
554
|
+
const parts = [];
|
|
555
|
+
if (input) parts.push({ type: "text", text: input });
|
|
556
|
+
for (const attachment of files) {
|
|
557
|
+
parts.push({ type: "file", file: attachment.dataUrl });
|
|
558
|
+
}
|
|
559
|
+
return { prompt: parts, context };
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/runtime/upload-adapter.ts
|
|
563
|
+
var DEFAULT_UPLOAD_ACCEPT = "image/*,application/pdf,text/*,.md,.json,.csv,.tsv,.xlsx,.docx";
|
|
564
|
+
function createDefaultAttachmentAdapter({
|
|
565
|
+
baseUrl = "",
|
|
566
|
+
uploadUrl,
|
|
567
|
+
fetch: fetchFn = authFetch,
|
|
568
|
+
accept = DEFAULT_UPLOAD_ACCEPT
|
|
569
|
+
} = {}) {
|
|
570
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
571
|
+
const resolvedUploadUrl = uploadUrl ?? `${base}/files/upload`;
|
|
572
|
+
return {
|
|
573
|
+
accept,
|
|
574
|
+
async add({ file }) {
|
|
575
|
+
const isImage = file.type.startsWith("image/");
|
|
576
|
+
const pending = {
|
|
577
|
+
id: crypto.randomUUID(),
|
|
578
|
+
type: isImage ? "image" : "file",
|
|
579
|
+
name: file.name,
|
|
580
|
+
contentType: file.type || "application/octet-stream",
|
|
581
|
+
file,
|
|
582
|
+
status: { type: "requires-action", reason: "composer-send" }
|
|
583
|
+
};
|
|
584
|
+
return pending;
|
|
585
|
+
},
|
|
586
|
+
async send(attachment) {
|
|
587
|
+
const fd = new FormData();
|
|
588
|
+
fd.append("file", attachment.file);
|
|
589
|
+
const res = await fetchFn(resolvedUploadUrl, { method: "POST", body: fd });
|
|
590
|
+
if (!res.ok) {
|
|
591
|
+
const detail = await res.text().catch(() => "");
|
|
592
|
+
throw new Error(
|
|
593
|
+
`Attachment upload failed (${res.status}): ${detail || res.statusText}`
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
const remoteUrl = await readUploadedUrl(res);
|
|
597
|
+
const mime = attachment.contentType ?? "application/octet-stream";
|
|
598
|
+
const filename = attachment.name;
|
|
599
|
+
const complete = {
|
|
600
|
+
...attachment,
|
|
601
|
+
status: { type: "complete" },
|
|
602
|
+
content: mime.startsWith("image/") ? [{ type: "image", image: remoteUrl, filename }] : [{ type: "file", data: remoteUrl, mimeType: mime, filename }]
|
|
603
|
+
};
|
|
604
|
+
return complete;
|
|
605
|
+
},
|
|
606
|
+
async remove() {
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
var createUploadAttachmentAdapter = createDefaultAttachmentAdapter;
|
|
611
|
+
async function readUploadedUrl(res) {
|
|
612
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
613
|
+
if (contentType.includes("application/json")) {
|
|
614
|
+
const data = await res.json();
|
|
615
|
+
const candidate = data.url ?? data.signed_url ?? data.id;
|
|
616
|
+
if (typeof candidate === "string" && candidate.length > 0) {
|
|
617
|
+
return candidate;
|
|
618
|
+
}
|
|
619
|
+
throw new Error(
|
|
620
|
+
"Attachment upload response did not include a `url`, `signed_url`, or `id` field."
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
const text = (await res.text()).trim();
|
|
624
|
+
if (!text) {
|
|
625
|
+
throw new Error("Attachment upload response was empty.");
|
|
626
|
+
}
|
|
627
|
+
return text;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/runtime/resolve-attachments.ts
|
|
631
|
+
function isAttachmentAdapter(value) {
|
|
632
|
+
return typeof value === "object" && value !== null && "accept" in value && typeof value.add === "function" && typeof value.send === "function" && typeof value.remove === "function";
|
|
633
|
+
}
|
|
634
|
+
function resolveAttachmentAdapter(attachments, options = {}) {
|
|
635
|
+
const baseUrl = options.baseUrl ?? "/api";
|
|
636
|
+
const legacyUploadUrl = options.uploadUrl;
|
|
637
|
+
const legacyAccept = options.accept;
|
|
638
|
+
if (attachments === null) return void 0;
|
|
639
|
+
const legacyEnables = legacyUploadUrl !== void 0 || legacyAccept !== void 0;
|
|
640
|
+
if (attachments === void 0) {
|
|
641
|
+
if (!legacyEnables) return void 0;
|
|
642
|
+
return createDefaultAttachmentAdapter({
|
|
643
|
+
baseUrl,
|
|
644
|
+
fetch: options.fetch,
|
|
645
|
+
uploadUrl: legacyUploadUrl,
|
|
646
|
+
accept: legacyAccept
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
if (attachments === true) {
|
|
650
|
+
return createDefaultAttachmentAdapter({
|
|
651
|
+
baseUrl,
|
|
652
|
+
fetch: options.fetch,
|
|
653
|
+
uploadUrl: legacyUploadUrl,
|
|
654
|
+
accept: legacyAccept
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
if (isAttachmentAdapter(attachments)) return attachments;
|
|
658
|
+
const config = attachments;
|
|
659
|
+
return createDefaultAttachmentAdapter({
|
|
660
|
+
baseUrl,
|
|
661
|
+
fetch: options.fetch,
|
|
662
|
+
uploadUrl: config.uploadUrl ?? legacyUploadUrl,
|
|
663
|
+
accept: config.accept ?? legacyAccept
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
|
|
169
667
|
// src/runtime/provider.tsx
|
|
170
668
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
669
|
+
function projectAttachment(attachment) {
|
|
670
|
+
const filename = attachment.name ?? "attachment";
|
|
671
|
+
const mimeType = attachment.contentType ?? "application/octet-stream";
|
|
672
|
+
if (attachment.type === "image") {
|
|
673
|
+
return {
|
|
674
|
+
id: attachment.id,
|
|
675
|
+
type: "image",
|
|
676
|
+
name: filename,
|
|
677
|
+
contentType: mimeType,
|
|
678
|
+
status: { type: "complete" },
|
|
679
|
+
content: [{ type: "image", image: attachment.dataUrl, filename }]
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
return {
|
|
683
|
+
id: attachment.id,
|
|
684
|
+
type: attachment.type,
|
|
685
|
+
name: filename,
|
|
686
|
+
contentType: mimeType,
|
|
687
|
+
status: { type: "complete" },
|
|
688
|
+
content: [
|
|
689
|
+
{ type: "file", data: attachment.dataUrl, mimeType, filename }
|
|
690
|
+
]
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
var convertMessage = (message) => {
|
|
694
|
+
const content = message.content.map((part) => {
|
|
695
|
+
if (part.type === "text") return { type: "text", text: part.text };
|
|
696
|
+
if (part.type === "thinking") return { type: "reasoning", text: part.text };
|
|
697
|
+
return {
|
|
698
|
+
type: "tool-call",
|
|
699
|
+
toolCallId: part.toolCallId,
|
|
700
|
+
toolName: part.toolName,
|
|
701
|
+
argsText: part.argsText,
|
|
702
|
+
...part.result !== void 0 ? { result: part.result } : {}
|
|
703
|
+
};
|
|
704
|
+
});
|
|
705
|
+
const attachments = message.attachments && message.attachments.length > 0 ? message.attachments.map(projectAttachment) : void 0;
|
|
706
|
+
return {
|
|
707
|
+
role: message.role,
|
|
708
|
+
content,
|
|
709
|
+
id: message.id,
|
|
710
|
+
...attachments ? { attachments } : {}
|
|
711
|
+
};
|
|
712
|
+
};
|
|
176
713
|
function findParentId(messages, beforeIndex) {
|
|
177
714
|
const slice = beforeIndex !== void 0 ? messages.slice(0, beforeIndex) : messages;
|
|
178
715
|
for (let i = slice.length - 1; i >= 0; i--) {
|
|
@@ -180,18 +717,18 @@ function findParentId(messages, beforeIndex) {
|
|
|
180
717
|
}
|
|
181
718
|
return null;
|
|
182
719
|
}
|
|
183
|
-
function isTopLevelStart(event) {
|
|
184
|
-
return event.type === "START" && typeof event.run_id === "string" && typeof event.path === "string" && !event.path.includes(".");
|
|
185
|
-
}
|
|
186
720
|
function getTextFromMessage(message) {
|
|
187
721
|
const part = message.content.find((c) => c.type === "text");
|
|
188
|
-
return part?.type === "text" ? part.text :
|
|
722
|
+
return part?.type === "text" ? part.text : "";
|
|
189
723
|
}
|
|
190
|
-
function
|
|
724
|
+
function getAttachmentsFromMessage(message) {
|
|
725
|
+
return message.attachments?.length ? message.attachments : void 0;
|
|
726
|
+
}
|
|
727
|
+
function useTimbalStream({
|
|
191
728
|
workforceId,
|
|
192
|
-
children,
|
|
193
729
|
baseUrl = "/api",
|
|
194
|
-
fetch: fetchFn
|
|
730
|
+
fetch: fetchFn,
|
|
731
|
+
debug = false
|
|
195
732
|
}) {
|
|
196
733
|
const [messages, setMessages] = (0, import_react.useState)([]);
|
|
197
734
|
const [isRunning, setIsRunning] = (0, import_react.useState)(false);
|
|
@@ -201,40 +738,41 @@ function TimbalRuntimeProvider({
|
|
|
201
738
|
(0, import_react.useEffect)(() => {
|
|
202
739
|
fetchFnRef.current = fetchFn ?? authFetch;
|
|
203
740
|
}, [fetchFn]);
|
|
741
|
+
const debugRef = (0, import_react.useRef)(debug);
|
|
742
|
+
(0, import_react.useEffect)(() => {
|
|
743
|
+
debugRef.current = debug;
|
|
744
|
+
}, [debug]);
|
|
204
745
|
(0, import_react.useEffect)(() => {
|
|
205
746
|
messagesRef.current = messages;
|
|
206
747
|
}, [messages]);
|
|
207
748
|
const streamAssistantResponse = (0, import_react.useCallback)(
|
|
208
|
-
async (input, userId, assistantId, parentId, signal) => {
|
|
209
|
-
const
|
|
210
|
-
const toolIndexById = /* @__PURE__ */ new Map();
|
|
211
|
-
const lastTextPart = () => {
|
|
212
|
-
const last = parts[parts.length - 1];
|
|
213
|
-
if (last?.type === "text") return last;
|
|
214
|
-
const next = { type: "text", text: "" };
|
|
215
|
-
parts.push(next);
|
|
216
|
-
return next;
|
|
217
|
-
};
|
|
749
|
+
async (input, attachments, userId, assistantId, parentId, signal) => {
|
|
750
|
+
const state = createReducerState();
|
|
218
751
|
const flush = () => {
|
|
219
752
|
setMessages(
|
|
220
|
-
(prev) => prev.map(
|
|
753
|
+
(prev) => prev.map(
|
|
754
|
+
(m) => m.id === assistantId ? { ...m, content: [...state.parts] } : m
|
|
755
|
+
)
|
|
221
756
|
);
|
|
222
757
|
};
|
|
223
758
|
const stampRunId = (runId) => {
|
|
224
759
|
setMessages(
|
|
225
|
-
(prev) => prev.map(
|
|
760
|
+
(prev) => prev.map(
|
|
761
|
+
(m) => m.id === userId || m.id === assistantId ? { ...m, runId } : m
|
|
762
|
+
)
|
|
226
763
|
);
|
|
227
764
|
};
|
|
228
765
|
try {
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
766
|
+
const body = buildPromptBody({ input, attachments, parentId });
|
|
767
|
+
const res = await fetchFnRef.current(
|
|
768
|
+
`${baseUrl}/workforce/${workforceId}/stream`,
|
|
769
|
+
{
|
|
770
|
+
method: "POST",
|
|
771
|
+
headers: { "Content-Type": "application/json" },
|
|
772
|
+
body: JSON.stringify(body),
|
|
773
|
+
signal
|
|
774
|
+
}
|
|
775
|
+
);
|
|
238
776
|
if (!res.ok || !res.body) throw new Error(`Request failed: ${res.status}`);
|
|
239
777
|
const reader = res.body.getReader();
|
|
240
778
|
const decoder = new TextDecoder();
|
|
@@ -249,84 +787,34 @@ function TimbalRuntimeProvider({
|
|
|
249
787
|
for (const line of lines) {
|
|
250
788
|
const event = (0, import_timbal_sdk.parseSSELine)(line);
|
|
251
789
|
if (!event) continue;
|
|
252
|
-
if (
|
|
253
|
-
|
|
254
|
-
stampRunId(capturedRunId);
|
|
790
|
+
if (debugRef.current) {
|
|
791
|
+
console.debug("[timbal]", event.type, event);
|
|
255
792
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
lastTextPart().text += item.text_delta;
|
|
262
|
-
flush();
|
|
263
|
-
} else if (item.type === "tool_use") {
|
|
264
|
-
const toolCallId = item.id || `tool-${crypto.randomUUID()}`;
|
|
265
|
-
const inputStr = typeof item.input === "string" ? item.input : JSON.stringify(item.input ?? {});
|
|
266
|
-
parts.push({
|
|
267
|
-
type: "tool-call",
|
|
268
|
-
toolCallId,
|
|
269
|
-
toolName: item.name || "unknown",
|
|
270
|
-
argsText: inputStr
|
|
271
|
-
});
|
|
272
|
-
toolIndexById.set(toolCallId, parts.length - 1);
|
|
273
|
-
flush();
|
|
274
|
-
} else if (item.type === "tool_use_delta") {
|
|
275
|
-
const idx = toolIndexById.get(item.id);
|
|
276
|
-
if (idx !== void 0 && typeof item.input_delta === "string") {
|
|
277
|
-
parts[idx].argsText += item.input_delta;
|
|
278
|
-
flush();
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
break;
|
|
282
|
-
}
|
|
283
|
-
case "OUTPUT": {
|
|
284
|
-
const output = event.output;
|
|
285
|
-
if (!output) break;
|
|
286
|
-
if (typeof output === "object" && Array.isArray(output.content)) {
|
|
287
|
-
for (const block of output.content) {
|
|
288
|
-
if (block.type === "tool_use") {
|
|
289
|
-
const id = block.id || `tool-${crypto.randomUUID()}`;
|
|
290
|
-
const idx = toolIndexById.get(id);
|
|
291
|
-
if (idx !== void 0) {
|
|
292
|
-
parts[idx].result = "Tool executed";
|
|
293
|
-
} else {
|
|
294
|
-
const inputStr = typeof block.input === "string" ? block.input : JSON.stringify(block.input ?? {});
|
|
295
|
-
parts.push({
|
|
296
|
-
type: "tool-call",
|
|
297
|
-
toolCallId: id,
|
|
298
|
-
toolName: block.name || "unknown",
|
|
299
|
-
argsText: inputStr,
|
|
300
|
-
result: "Tool executed"
|
|
301
|
-
});
|
|
302
|
-
toolIndexById.set(id, parts.length - 1);
|
|
303
|
-
}
|
|
304
|
-
} else if (block.type === "text" && typeof block.text === "string" && !lastTextPart().text) {
|
|
305
|
-
lastTextPart().text = block.text;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
flush();
|
|
309
|
-
} else if (parts.length === 0) {
|
|
310
|
-
const text = typeof output === "string" ? output : JSON.stringify(output);
|
|
311
|
-
parts.push({ type: "text", text });
|
|
312
|
-
flush();
|
|
313
|
-
}
|
|
314
|
-
break;
|
|
793
|
+
if (!capturedRunId) {
|
|
794
|
+
const runId = readTopLevelStartRunId(event);
|
|
795
|
+
if (runId) {
|
|
796
|
+
capturedRunId = runId;
|
|
797
|
+
stampRunId(runId);
|
|
315
798
|
}
|
|
316
799
|
}
|
|
800
|
+
const changed = reduceSseEvent(state, event);
|
|
801
|
+
if (changed) flush();
|
|
317
802
|
}
|
|
318
803
|
}
|
|
319
804
|
if (buffer.trim()) {
|
|
320
805
|
const event = (0, import_timbal_sdk.parseSSELine)(buffer);
|
|
321
|
-
if (event
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
806
|
+
if (event) {
|
|
807
|
+
if (debugRef.current) {
|
|
808
|
+
console.debug("[timbal]", event.type, event);
|
|
809
|
+
}
|
|
810
|
+
if (reduceSseEvent(state, event)) flush();
|
|
325
811
|
}
|
|
326
812
|
}
|
|
327
813
|
} catch (err) {
|
|
328
814
|
if (err.name !== "AbortError") {
|
|
329
|
-
if (parts.length === 0)
|
|
815
|
+
if (state.parts.length === 0) {
|
|
816
|
+
state.parts.push({ type: "text", text: "Something went wrong." });
|
|
817
|
+
}
|
|
330
818
|
flush();
|
|
331
819
|
}
|
|
332
820
|
} finally {
|
|
@@ -336,44 +824,46 @@ function TimbalRuntimeProvider({
|
|
|
336
824
|
},
|
|
337
825
|
[workforceId, baseUrl]
|
|
338
826
|
);
|
|
339
|
-
const
|
|
340
|
-
async (
|
|
341
|
-
const textPart = message.content.find((c) => c.type === "text");
|
|
342
|
-
if (!textPart || textPart.type !== "text") return;
|
|
343
|
-
const input = textPart.text;
|
|
827
|
+
const send = (0, import_react.useCallback)(
|
|
828
|
+
async (input, options) => {
|
|
344
829
|
const userId = crypto.randomUUID();
|
|
345
830
|
const assistantId = crypto.randomUUID();
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
|
|
831
|
+
const base = messagesRef.current;
|
|
832
|
+
const parentId = options?.parentId !== void 0 ? options.parentId : findParentId(base);
|
|
833
|
+
const userMessage = {
|
|
834
|
+
id: userId,
|
|
835
|
+
role: "user",
|
|
836
|
+
content: input ? [{ type: "text", text: input }] : [],
|
|
837
|
+
...options?.attachments && options.attachments.length > 0 ? { attachments: options.attachments } : {}
|
|
838
|
+
};
|
|
354
839
|
setMessages([
|
|
355
840
|
...base,
|
|
356
|
-
|
|
357
|
-
]);
|
|
358
|
-
setIsRunning(true);
|
|
359
|
-
setMessages((prev) => [
|
|
360
|
-
...prev,
|
|
841
|
+
userMessage,
|
|
361
842
|
{ id: assistantId, role: "assistant", content: [] }
|
|
362
843
|
]);
|
|
844
|
+
setIsRunning(true);
|
|
363
845
|
const controller = new AbortController();
|
|
364
846
|
abortRef.current = controller;
|
|
365
|
-
await streamAssistantResponse(
|
|
847
|
+
await streamAssistantResponse(
|
|
848
|
+
input,
|
|
849
|
+
options?.attachments,
|
|
850
|
+
userId,
|
|
851
|
+
assistantId,
|
|
852
|
+
parentId,
|
|
853
|
+
controller.signal
|
|
854
|
+
);
|
|
366
855
|
},
|
|
367
856
|
[streamAssistantResponse]
|
|
368
857
|
);
|
|
369
|
-
const
|
|
858
|
+
const reload = (0, import_react.useCallback)(
|
|
370
859
|
async (messageId) => {
|
|
371
860
|
const current = messagesRef.current;
|
|
372
861
|
const idx = messageId ? current.findIndex((m) => m.id === messageId) : current.length - 2;
|
|
373
862
|
const userMessage = idx >= 0 ? current[idx] : null;
|
|
374
863
|
if (!userMessage || userMessage.role !== "user") return;
|
|
375
864
|
const input = getTextFromMessage(userMessage);
|
|
376
|
-
|
|
865
|
+
const messageAttachments = getAttachmentsFromMessage(userMessage);
|
|
866
|
+
if (!input && !messageAttachments?.length) return;
|
|
377
867
|
const assistantId = crypto.randomUUID();
|
|
378
868
|
const parentId = findParentId(current, idx);
|
|
379
869
|
setMessages((prev) => [
|
|
@@ -383,25 +873,115 @@ function TimbalRuntimeProvider({
|
|
|
383
873
|
setIsRunning(true);
|
|
384
874
|
const controller = new AbortController();
|
|
385
875
|
abortRef.current = controller;
|
|
386
|
-
await streamAssistantResponse(
|
|
876
|
+
await streamAssistantResponse(
|
|
877
|
+
input,
|
|
878
|
+
messageAttachments,
|
|
879
|
+
userMessage.id,
|
|
880
|
+
assistantId,
|
|
881
|
+
parentId,
|
|
882
|
+
controller.signal
|
|
883
|
+
);
|
|
387
884
|
},
|
|
388
885
|
[streamAssistantResponse]
|
|
389
886
|
);
|
|
390
|
-
const
|
|
887
|
+
const cancel = (0, import_react.useCallback)(() => {
|
|
888
|
+
abortRef.current?.abort();
|
|
889
|
+
}, []);
|
|
890
|
+
const clear = (0, import_react.useCallback)(() => {
|
|
391
891
|
abortRef.current?.abort();
|
|
892
|
+
setMessages([]);
|
|
392
893
|
}, []);
|
|
894
|
+
return (0, import_react.useMemo)(
|
|
895
|
+
() => ({ messages, isRunning, send, reload, cancel, clear }),
|
|
896
|
+
[messages, isRunning, send, reload, cancel, clear]
|
|
897
|
+
);
|
|
898
|
+
}
|
|
899
|
+
function readTopLevelStartRunId(event) {
|
|
900
|
+
if (event.type === "START" && typeof event.run_id === "string" && typeof event.path === "string" && !event.path.includes(".")) {
|
|
901
|
+
return event.run_id;
|
|
902
|
+
}
|
|
903
|
+
return null;
|
|
904
|
+
}
|
|
905
|
+
var TimbalStreamContext = (0, import_react.createContext)(null);
|
|
906
|
+
function useTimbalRuntime() {
|
|
907
|
+
const ctx = (0, import_react.useContext)(TimbalStreamContext);
|
|
908
|
+
if (!ctx) {
|
|
909
|
+
throw new Error(
|
|
910
|
+
"useTimbalRuntime must be used inside a <TimbalRuntimeProvider>."
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
return ctx;
|
|
914
|
+
}
|
|
915
|
+
function TimbalRuntimeProvider({
|
|
916
|
+
workforceId,
|
|
917
|
+
children,
|
|
918
|
+
baseUrl = "/api",
|
|
919
|
+
fetch: fetchFn,
|
|
920
|
+
attachments,
|
|
921
|
+
attachmentsUploadUrl,
|
|
922
|
+
attachmentsAccept,
|
|
923
|
+
debug
|
|
924
|
+
}) {
|
|
925
|
+
const stream = useTimbalStream({
|
|
926
|
+
workforceId,
|
|
927
|
+
baseUrl,
|
|
928
|
+
fetch: fetchFn,
|
|
929
|
+
debug
|
|
930
|
+
});
|
|
931
|
+
const attachmentAdapter = (0, import_react.useMemo)(
|
|
932
|
+
() => resolveAttachmentAdapter(attachments, {
|
|
933
|
+
baseUrl,
|
|
934
|
+
fetch: fetchFn,
|
|
935
|
+
uploadUrl: attachmentsUploadUrl,
|
|
936
|
+
accept: attachmentsAccept
|
|
937
|
+
}),
|
|
938
|
+
[attachments, attachmentsUploadUrl, attachmentsAccept, baseUrl, fetchFn]
|
|
939
|
+
);
|
|
940
|
+
const onNew = (0, import_react.useCallback)(
|
|
941
|
+
async (message) => {
|
|
942
|
+
const textPart = message.content.find((c) => c.type === "text");
|
|
943
|
+
const input = textPart && textPart.type === "text" ? textPart.text : "";
|
|
944
|
+
const auiAttachments = message.attachments;
|
|
945
|
+
const attachments2 = auiAttachments ? (await Promise.all(auiAttachments.map(extractAttachment))).filter((a) => a !== null) : [];
|
|
946
|
+
if (!input && attachments2.length === 0) return;
|
|
947
|
+
const parentId = message.parentId !== null && message.parentId !== void 0 ? findParentIdFromAuiParent(stream.messages, message.parentId) : void 0;
|
|
948
|
+
await stream.send(input, {
|
|
949
|
+
attachments: attachments2.length > 0 ? attachments2 : void 0,
|
|
950
|
+
...parentId !== void 0 ? { parentId } : {}
|
|
951
|
+
});
|
|
952
|
+
},
|
|
953
|
+
[stream]
|
|
954
|
+
);
|
|
955
|
+
const onReload = (0, import_react.useCallback)(
|
|
956
|
+
async (messageId) => {
|
|
957
|
+
await stream.reload(messageId);
|
|
958
|
+
},
|
|
959
|
+
[stream]
|
|
960
|
+
);
|
|
961
|
+
const onCancel = (0, import_react.useCallback)(async () => {
|
|
962
|
+
stream.cancel();
|
|
963
|
+
}, [stream]);
|
|
393
964
|
const runtime = (0, import_react2.useExternalStoreRuntime)({
|
|
394
|
-
isRunning,
|
|
395
|
-
messages,
|
|
965
|
+
isRunning: stream.isRunning,
|
|
966
|
+
messages: stream.messages,
|
|
396
967
|
convertMessage,
|
|
397
968
|
onNew,
|
|
398
969
|
onEdit: onNew,
|
|
399
970
|
onReload,
|
|
400
|
-
onCancel
|
|
971
|
+
onCancel,
|
|
972
|
+
...attachmentAdapter ? { adapters: { attachments: attachmentAdapter } } : {}
|
|
401
973
|
});
|
|
402
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.AssistantRuntimeProvider, { runtime, children });
|
|
974
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimbalStreamContext.Provider, { value: stream, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.AssistantRuntimeProvider, { runtime, children }) });
|
|
975
|
+
}
|
|
976
|
+
function findParentIdFromAuiParent(messages, auiParentId) {
|
|
977
|
+
const idx = messages.findIndex((m) => m.id === auiParentId);
|
|
978
|
+
if (idx < 0) return null;
|
|
979
|
+
return findParentId(messages.slice(0, idx + 1));
|
|
403
980
|
}
|
|
404
981
|
|
|
982
|
+
// src/index.ts
|
|
983
|
+
var import_timbal_sdk2 = require("@timbal-ai/timbal-sdk");
|
|
984
|
+
|
|
405
985
|
// src/components/attachment.tsx
|
|
406
986
|
var import_react4 = require("react");
|
|
407
987
|
var import_lucide_react2 = require("lucide-react");
|
|
@@ -854,78 +1434,1117 @@ var import_react_markdown = require("@assistant-ui/react-markdown");
|
|
|
854
1434
|
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
855
1435
|
var import_remark_math = __toESM(require("remark-math"), 1);
|
|
856
1436
|
var import_rehype_katex = __toESM(require("rehype-katex"), 1);
|
|
857
|
-
var
|
|
858
|
-
var
|
|
1437
|
+
var import_react16 = require("react");
|
|
1438
|
+
var import_lucide_react4 = require("lucide-react");
|
|
859
1439
|
|
|
860
1440
|
// src/components/syntax-highlighter.tsx
|
|
861
|
-
var
|
|
1441
|
+
var import_react15 = require("react");
|
|
862
1442
|
var import_core = require("shiki/core");
|
|
863
1443
|
var import_javascript = require("shiki/engine/javascript");
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
var
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
var
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
var import_jsx = __toESM(require("shiki/langs/jsx.mjs"), 1);
|
|
873
|
-
var import_tsx = __toESM(require("shiki/langs/tsx.mjs"), 1);
|
|
874
|
-
var import_sql = __toESM(require("shiki/langs/sql.mjs"), 1);
|
|
875
|
-
var import_yaml = __toESM(require("shiki/langs/yaml.mjs"), 1);
|
|
876
|
-
var import_rust = __toESM(require("shiki/langs/rust.mjs"), 1);
|
|
877
|
-
var import_go = __toESM(require("shiki/langs/go.mjs"), 1);
|
|
878
|
-
var import_java = __toESM(require("shiki/langs/java.mjs"), 1);
|
|
879
|
-
var import_c = __toESM(require("shiki/langs/c.mjs"), 1);
|
|
880
|
-
var import_cpp = __toESM(require("shiki/langs/cpp.mjs"), 1);
|
|
881
|
-
var import_vitesse_dark = __toESM(require("shiki/themes/vitesse-dark.mjs"), 1);
|
|
882
|
-
var import_vitesse_light = __toESM(require("shiki/themes/vitesse-light.mjs"), 1);
|
|
1444
|
+
|
|
1445
|
+
// src/artifacts/registry.tsx
|
|
1446
|
+
var import_react14 = require("react");
|
|
1447
|
+
|
|
1448
|
+
// src/artifacts/chart-artifact.tsx
|
|
1449
|
+
var import_react6 = require("react");
|
|
1450
|
+
|
|
1451
|
+
// src/artifacts/artifact-card.tsx
|
|
883
1452
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
884
|
-
var
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1453
|
+
var ArtifactCard = ({ title, kind, className, bodyClassName, toolbar, children }) => {
|
|
1454
|
+
const hasHeader = Boolean(title || toolbar);
|
|
1455
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1456
|
+
"div",
|
|
1457
|
+
{
|
|
1458
|
+
className: cn(
|
|
1459
|
+
"aui-artifact-root my-3 overflow-hidden rounded-xl border border-border/60 bg-background shadow-sm",
|
|
1460
|
+
className
|
|
1461
|
+
),
|
|
1462
|
+
"data-artifact-kind": kind,
|
|
1463
|
+
children: [
|
|
1464
|
+
hasHeader && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "aui-artifact-header flex items-center gap-2 border-b border-border/40 bg-muted/30 px-3 py-1.5", children: [
|
|
1465
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "aui-artifact-title flex-1 truncate text-xs font-semibold text-foreground/80", children: title }),
|
|
1466
|
+
!title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "flex-1" }),
|
|
1467
|
+
toolbar
|
|
1468
|
+
] }),
|
|
1469
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("aui-artifact-body", bodyClassName), children })
|
|
1470
|
+
]
|
|
1471
|
+
}
|
|
1472
|
+
);
|
|
1473
|
+
};
|
|
1474
|
+
|
|
1475
|
+
// src/artifacts/chart-artifact.tsx
|
|
1476
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1477
|
+
var ChartArtifactView = ({
|
|
1478
|
+
artifact
|
|
1479
|
+
}) => {
|
|
1480
|
+
const { type: _t, chartType = "bar", data = [] } = artifact;
|
|
1481
|
+
const xKey = artifact.xKey ?? inferXKey(data);
|
|
1482
|
+
const dataKeys = (0, import_react6.useMemo)(() => {
|
|
1483
|
+
if (Array.isArray(artifact.dataKey)) return artifact.dataKey;
|
|
1484
|
+
if (typeof artifact.dataKey === "string") return [artifact.dataKey];
|
|
1485
|
+
return inferDataKeys(data, xKey);
|
|
1486
|
+
}, [artifact.dataKey, data, xKey]);
|
|
1487
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ArtifactCard, { title: artifact.title, kind: "chart", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "aui-artifact-chart p-3", children: [
|
|
1488
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1489
|
+
ChartSvg,
|
|
1490
|
+
{
|
|
1491
|
+
chartType,
|
|
1492
|
+
data,
|
|
1493
|
+
xKey,
|
|
1494
|
+
dataKeys,
|
|
1495
|
+
unit: artifact.unit
|
|
1496
|
+
}
|
|
1497
|
+
),
|
|
1498
|
+
dataKeys.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Legend, { dataKeys })
|
|
1499
|
+
] }) });
|
|
1500
|
+
};
|
|
1501
|
+
var COLORS = [
|
|
1502
|
+
"var(--primary, #6366f1)",
|
|
1503
|
+
"#22c55e",
|
|
1504
|
+
"#f59e0b",
|
|
1505
|
+
"#ef4444",
|
|
1506
|
+
"#06b6d4",
|
|
1507
|
+
"#a855f7"
|
|
1508
|
+
];
|
|
1509
|
+
var W = 600;
|
|
1510
|
+
var H = 240;
|
|
1511
|
+
var PAD = { top: 12, right: 16, bottom: 28, left: 36 };
|
|
1512
|
+
var ChartSvg = ({ chartType, data, xKey, dataKeys, unit }) => {
|
|
1513
|
+
if (data.length === 0 || dataKeys.length === 0) {
|
|
1514
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EmptyState, {});
|
|
1515
|
+
}
|
|
1516
|
+
if (chartType === "pie") {
|
|
1517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PieChart, { data, xKey, dataKey: dataKeys[0] });
|
|
1518
|
+
}
|
|
1519
|
+
const innerW = W - PAD.left - PAD.right;
|
|
1520
|
+
const innerH = H - PAD.top - PAD.bottom;
|
|
1521
|
+
const all = dataKeys.flatMap((k) => data.map((d) => toNum(d[k])));
|
|
1522
|
+
const maxV = Math.max(0, ...all);
|
|
1523
|
+
const minV = Math.min(0, ...all);
|
|
1524
|
+
const range = maxV - minV || 1;
|
|
1525
|
+
const yScale = (v) => PAD.top + innerH - (v - minV) / range * innerH;
|
|
1526
|
+
const xCount = data.length;
|
|
1527
|
+
const xStep = xCount > 1 ? innerW / (xCount - 1) : innerW;
|
|
1528
|
+
const xPos = (i) => chartType === "bar" ? PAD.left + innerW * (i + 0.5) / xCount : PAD.left + i * xStep;
|
|
1529
|
+
const ticks = niceTicks(minV, maxV);
|
|
1530
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1531
|
+
"svg",
|
|
1532
|
+
{
|
|
1533
|
+
viewBox: `0 0 ${W} ${H}`,
|
|
1534
|
+
className: "aui-artifact-chart-svg w-full",
|
|
1535
|
+
role: "img",
|
|
1536
|
+
"aria-label": "Chart",
|
|
1537
|
+
children: [
|
|
1538
|
+
ticks.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("g", { children: [
|
|
1539
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1540
|
+
"line",
|
|
1541
|
+
{
|
|
1542
|
+
x1: PAD.left,
|
|
1543
|
+
x2: W - PAD.right,
|
|
1544
|
+
y1: yScale(t),
|
|
1545
|
+
y2: yScale(t),
|
|
1546
|
+
stroke: "currentColor",
|
|
1547
|
+
strokeOpacity: 0.08
|
|
1548
|
+
}
|
|
1549
|
+
),
|
|
1550
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1551
|
+
"text",
|
|
1552
|
+
{
|
|
1553
|
+
x: PAD.left - 6,
|
|
1554
|
+
y: yScale(t),
|
|
1555
|
+
textAnchor: "end",
|
|
1556
|
+
dominantBaseline: "middle",
|
|
1557
|
+
className: "fill-muted-foreground text-[10px]",
|
|
1558
|
+
children: formatTick(t, unit)
|
|
1559
|
+
}
|
|
1560
|
+
)
|
|
1561
|
+
] }, i)),
|
|
1562
|
+
data.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1563
|
+
"text",
|
|
1564
|
+
{
|
|
1565
|
+
x: xPos(i),
|
|
1566
|
+
y: H - PAD.bottom + 14,
|
|
1567
|
+
textAnchor: "middle",
|
|
1568
|
+
className: "fill-muted-foreground text-[10px]",
|
|
1569
|
+
children: String(d[xKey] ?? i)
|
|
1570
|
+
},
|
|
1571
|
+
i
|
|
1572
|
+
)),
|
|
1573
|
+
chartType === "bar" && renderBars({ data, dataKeys, xCount, xPos, yScale, minV, innerW }),
|
|
1574
|
+
chartType === "line" && dataKeys.map((k, ki) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1575
|
+
Polyline,
|
|
1576
|
+
{
|
|
1577
|
+
data,
|
|
1578
|
+
dataKey: k,
|
|
1579
|
+
xPos,
|
|
1580
|
+
yScale,
|
|
1581
|
+
color: COLORS[ki % COLORS.length]
|
|
1582
|
+
},
|
|
1583
|
+
k
|
|
1584
|
+
)),
|
|
1585
|
+
chartType === "area" && dataKeys.map((k, ki) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1586
|
+
Area,
|
|
1587
|
+
{
|
|
1588
|
+
data,
|
|
1589
|
+
dataKey: k,
|
|
1590
|
+
xPos,
|
|
1591
|
+
yScale,
|
|
1592
|
+
baseY: yScale(Math.max(0, minV)),
|
|
1593
|
+
color: COLORS[ki % COLORS.length]
|
|
1594
|
+
},
|
|
1595
|
+
k
|
|
1596
|
+
))
|
|
1597
|
+
]
|
|
1598
|
+
}
|
|
1599
|
+
);
|
|
1600
|
+
};
|
|
1601
|
+
function renderBars(args) {
|
|
1602
|
+
const { data, dataKeys, xCount, xPos, yScale, minV, innerW } = args;
|
|
1603
|
+
const groupWidth = innerW / xCount * 0.7;
|
|
1604
|
+
const barWidth = groupWidth / dataKeys.length;
|
|
1605
|
+
const baseY = yScale(Math.max(0, minV));
|
|
1606
|
+
return dataKeys.flatMap(
|
|
1607
|
+
(k, ki) => data.map((d, i) => {
|
|
1608
|
+
const v = toNum(d[k]);
|
|
1609
|
+
const y = yScale(v);
|
|
1610
|
+
const x = xPos(i) - groupWidth / 2 + ki * barWidth;
|
|
1611
|
+
const top = Math.min(y, baseY);
|
|
1612
|
+
const height = Math.abs(y - baseY);
|
|
1613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1614
|
+
"rect",
|
|
1615
|
+
{
|
|
1616
|
+
x,
|
|
1617
|
+
y: top,
|
|
1618
|
+
width: Math.max(1, barWidth - 2),
|
|
1619
|
+
height: Math.max(1, height),
|
|
1620
|
+
rx: 2,
|
|
1621
|
+
fill: COLORS[ki % COLORS.length]
|
|
1622
|
+
},
|
|
1623
|
+
`${k}-${i}`
|
|
1624
|
+
);
|
|
1625
|
+
})
|
|
1626
|
+
);
|
|
1627
|
+
}
|
|
1628
|
+
var Polyline = ({ data, dataKey, xPos, yScale, color }) => {
|
|
1629
|
+
const points = data.map((d, i) => `${xPos(i)},${yScale(toNum(d[dataKey]))}`).join(" ");
|
|
1630
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1631
|
+
"polyline",
|
|
1632
|
+
{
|
|
1633
|
+
points,
|
|
1634
|
+
fill: "none",
|
|
1635
|
+
stroke: color,
|
|
1636
|
+
strokeWidth: 2,
|
|
1637
|
+
strokeLinejoin: "round",
|
|
1638
|
+
strokeLinecap: "round"
|
|
1639
|
+
}
|
|
1640
|
+
);
|
|
1641
|
+
};
|
|
1642
|
+
var Area = ({ data, dataKey, xPos, yScale, baseY, color }) => {
|
|
1643
|
+
if (data.length === 0) return null;
|
|
1644
|
+
const top = data.map((d, i) => `${xPos(i)},${yScale(toNum(d[dataKey]))}`).join(" ");
|
|
1645
|
+
const path = `M ${xPos(0)},${baseY} L ${top} L ${xPos(data.length - 1)},${baseY} Z`;
|
|
1646
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
1647
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: path, fill: color, fillOpacity: 0.18 }),
|
|
1648
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Polyline, { data, dataKey, xPos, yScale, color })
|
|
1649
|
+
] });
|
|
1650
|
+
};
|
|
1651
|
+
var PieChart = ({ data, xKey, dataKey }) => {
|
|
1652
|
+
const cx = W / 2;
|
|
1653
|
+
const cy = H / 2;
|
|
1654
|
+
const r = Math.min(W, H) / 2 - 16;
|
|
1655
|
+
const total = data.reduce((sum, d) => sum + toNum(d[dataKey]), 0) || 1;
|
|
1656
|
+
let acc = 0;
|
|
1657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1658
|
+
"svg",
|
|
1659
|
+
{
|
|
1660
|
+
viewBox: `0 0 ${W} ${H}`,
|
|
1661
|
+
className: "aui-artifact-chart-svg w-full",
|
|
1662
|
+
role: "img",
|
|
1663
|
+
"aria-label": "Pie chart",
|
|
1664
|
+
children: data.map((d, i) => {
|
|
1665
|
+
const value = toNum(d[dataKey]);
|
|
1666
|
+
const start = acc / total * Math.PI * 2;
|
|
1667
|
+
acc += value;
|
|
1668
|
+
const end = acc / total * Math.PI * 2;
|
|
1669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1670
|
+
PieSlice,
|
|
1671
|
+
{
|
|
1672
|
+
cx,
|
|
1673
|
+
cy,
|
|
1674
|
+
r,
|
|
1675
|
+
start,
|
|
1676
|
+
end,
|
|
1677
|
+
color: COLORS[i % COLORS.length],
|
|
1678
|
+
label: String(d[xKey] ?? i)
|
|
1679
|
+
},
|
|
1680
|
+
i
|
|
1681
|
+
);
|
|
1682
|
+
})
|
|
1683
|
+
}
|
|
1684
|
+
);
|
|
1685
|
+
};
|
|
1686
|
+
var PieSlice = ({ cx, cy, r, start, end, color, label }) => {
|
|
1687
|
+
const x1 = cx + Math.sin(start) * r;
|
|
1688
|
+
const y1 = cy - Math.cos(start) * r;
|
|
1689
|
+
const x2 = cx + Math.sin(end) * r;
|
|
1690
|
+
const y2 = cy - Math.cos(end) * r;
|
|
1691
|
+
const large = end - start > Math.PI ? 1 : 0;
|
|
1692
|
+
const path = `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2} Z`;
|
|
1693
|
+
const mid = (start + end) / 2;
|
|
1694
|
+
const lx = cx + Math.sin(mid) * (r * 0.65);
|
|
1695
|
+
const ly = cy - Math.cos(mid) * (r * 0.65);
|
|
1696
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("g", { children: [
|
|
1697
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: path, fill: color, stroke: "var(--background, #fff)", strokeWidth: 1 }),
|
|
1698
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1699
|
+
"text",
|
|
1700
|
+
{
|
|
1701
|
+
x: lx,
|
|
1702
|
+
y: ly,
|
|
1703
|
+
textAnchor: "middle",
|
|
1704
|
+
dominantBaseline: "middle",
|
|
1705
|
+
className: "fill-white text-[10px] font-semibold",
|
|
1706
|
+
children: label
|
|
1707
|
+
}
|
|
1708
|
+
)
|
|
1709
|
+
] });
|
|
1710
|
+
};
|
|
1711
|
+
var Legend = ({ dataKeys }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "aui-artifact-chart-legend mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: dataKeys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1713
|
+
"span",
|
|
1714
|
+
{
|
|
1715
|
+
className: "inline-block size-2 rounded-sm",
|
|
1716
|
+
style: { background: COLORS[i % COLORS.length] },
|
|
1717
|
+
"aria-hidden": true
|
|
1718
|
+
}
|
|
1719
|
+
),
|
|
1720
|
+
k
|
|
1721
|
+
] }, k)) });
|
|
1722
|
+
var EmptyState = () => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "aui-artifact-chart-empty flex h-32 items-center justify-center text-xs text-muted-foreground", children: "No data" });
|
|
1723
|
+
function inferXKey(data) {
|
|
1724
|
+
if (data.length === 0) return "x";
|
|
1725
|
+
for (const k of Object.keys(data[0])) {
|
|
1726
|
+
if (typeof data[0][k] !== "number") return k;
|
|
1727
|
+
}
|
|
1728
|
+
return Object.keys(data[0])[0] ?? "x";
|
|
1729
|
+
}
|
|
1730
|
+
function inferDataKeys(data, xKey) {
|
|
1731
|
+
if (data.length === 0) return [];
|
|
1732
|
+
return Object.keys(data[0]).filter(
|
|
1733
|
+
(k) => k !== xKey && typeof data[0][k] === "number"
|
|
1734
|
+
);
|
|
1735
|
+
}
|
|
1736
|
+
function toNum(value) {
|
|
1737
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
1738
|
+
return Number.isFinite(n) ? n : 0;
|
|
1739
|
+
}
|
|
1740
|
+
function niceTicks(min, max, count = 4) {
|
|
1741
|
+
if (max === min) return [min];
|
|
1742
|
+
const range = max - min;
|
|
1743
|
+
const step = niceStep(range / count);
|
|
1744
|
+
const start = Math.floor(min / step) * step;
|
|
1745
|
+
const out = [];
|
|
1746
|
+
for (let v = start; v <= max + step / 2; v += step) {
|
|
1747
|
+
out.push(round(v));
|
|
1748
|
+
}
|
|
1749
|
+
return out;
|
|
1750
|
+
}
|
|
1751
|
+
function niceStep(raw) {
|
|
1752
|
+
const exp = Math.floor(Math.log10(Math.abs(raw))) || 0;
|
|
1753
|
+
const base = Math.pow(10, exp);
|
|
1754
|
+
const norm = raw / base;
|
|
1755
|
+
let nice = 1;
|
|
1756
|
+
if (norm >= 5) nice = 5;
|
|
1757
|
+
else if (norm >= 2) nice = 2;
|
|
1758
|
+
return nice * base;
|
|
1759
|
+
}
|
|
1760
|
+
function round(v) {
|
|
1761
|
+
return Math.round(v * 1e6) / 1e6;
|
|
1762
|
+
}
|
|
1763
|
+
function formatTick(v, unit) {
|
|
1764
|
+
const s = Math.abs(v) >= 1e3 ? `${(v / 1e3).toFixed(1)}k` : String(round(v));
|
|
1765
|
+
return unit ? `${s}${unit}` : s;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
// src/artifacts/question-artifact.tsx
|
|
1769
|
+
var import_react7 = require("react");
|
|
1770
|
+
var import_react8 = require("@assistant-ui/react");
|
|
1771
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1772
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1773
|
+
var QuestionArtifactView = ({
|
|
1774
|
+
artifact
|
|
1775
|
+
}) => {
|
|
1776
|
+
const runtime = (0, import_react8.useThreadRuntime)();
|
|
1777
|
+
const [selected, setSelected] = (0, import_react7.useState)([]);
|
|
1778
|
+
const [submitted, setSubmitted] = (0, import_react7.useState)(null);
|
|
1779
|
+
const isMulti = artifact.multi === true;
|
|
1780
|
+
const send = (labels) => {
|
|
1781
|
+
if (labels.length === 0) return;
|
|
1782
|
+
const text = labels.join(", ");
|
|
1783
|
+
setSubmitted(text);
|
|
1784
|
+
runtime.append({ role: "user", content: [{ type: "text", text }] });
|
|
1785
|
+
};
|
|
1786
|
+
const onPick = (option) => {
|
|
1787
|
+
if (submitted) return;
|
|
1788
|
+
if (!isMulti) {
|
|
1789
|
+
send([option.label]);
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
setSelected(
|
|
1793
|
+
(prev) => prev.includes(option.id) ? prev.filter((id) => id !== option.id) : [...prev, option.id]
|
|
1794
|
+
);
|
|
1795
|
+
};
|
|
1796
|
+
const onConfirm = () => {
|
|
1797
|
+
const labels = artifact.options.filter((o) => selected.includes(o.id)).map((o) => o.label);
|
|
1798
|
+
send(labels);
|
|
1799
|
+
};
|
|
1800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ArtifactCard, { kind: "question", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "aui-artifact-question p-3", children: [
|
|
1801
|
+
artifact.prompt && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "aui-artifact-question-prompt mb-2 text-sm text-foreground/85", children: artifact.prompt }),
|
|
1802
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "aui-artifact-question-options flex flex-col gap-1.5", children: artifact.options.map((option) => {
|
|
1803
|
+
const isSelected = isMulti && selected.includes(option.id);
|
|
1804
|
+
const isDisabled = Boolean(submitted);
|
|
1805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1806
|
+
"button",
|
|
1807
|
+
{
|
|
1808
|
+
type: "button",
|
|
1809
|
+
disabled: isDisabled,
|
|
1810
|
+
onClick: () => onPick(option),
|
|
1811
|
+
className: cn(
|
|
1812
|
+
"aui-artifact-question-option flex items-center gap-2 rounded-lg border px-3 py-2 text-left text-sm transition-colors",
|
|
1813
|
+
"border-border/60 hover:border-primary/40 hover:bg-muted/40",
|
|
1814
|
+
isSelected && "border-primary/60 bg-primary/5",
|
|
1815
|
+
isDisabled && "cursor-not-allowed opacity-60 hover:border-border/60 hover:bg-transparent"
|
|
1816
|
+
),
|
|
1817
|
+
children: [
|
|
1818
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1819
|
+
"span",
|
|
1820
|
+
{
|
|
1821
|
+
className: cn(
|
|
1822
|
+
"flex size-4 shrink-0 items-center justify-center rounded-full border",
|
|
1823
|
+
isSelected ? "border-primary bg-primary text-primary-foreground" : "border-border"
|
|
1824
|
+
),
|
|
1825
|
+
"aria-hidden": true,
|
|
1826
|
+
children: isSelected && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.CheckIcon, { className: "size-3" })
|
|
1827
|
+
}
|
|
1828
|
+
),
|
|
1829
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "aui-artifact-question-option-text flex-1", children: [
|
|
1830
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "font-medium text-foreground/90", children: option.label }),
|
|
1831
|
+
option.description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-xs text-muted-foreground", children: option.description })
|
|
1832
|
+
] })
|
|
1833
|
+
]
|
|
1834
|
+
},
|
|
1835
|
+
option.id
|
|
1836
|
+
);
|
|
1837
|
+
}) }),
|
|
1838
|
+
isMulti && !submitted && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-2 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1839
|
+
Button,
|
|
1840
|
+
{
|
|
1841
|
+
type: "button",
|
|
1842
|
+
size: "sm",
|
|
1843
|
+
disabled: selected.length === 0,
|
|
1844
|
+
onClick: onConfirm,
|
|
1845
|
+
children: "Confirm"
|
|
1846
|
+
}
|
|
1847
|
+
) }),
|
|
1848
|
+
submitted && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "aui-artifact-question-submitted mt-2 text-xs text-muted-foreground", children: [
|
|
1849
|
+
"Sent: ",
|
|
1850
|
+
submitted
|
|
1851
|
+
] })
|
|
1852
|
+
] }) });
|
|
1853
|
+
};
|
|
1854
|
+
|
|
1855
|
+
// src/artifacts/html-artifact.tsx
|
|
1856
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1857
|
+
var HtmlArtifactView = ({ artifact }) => {
|
|
1858
|
+
const sandboxed = artifact.sandboxed !== false;
|
|
1859
|
+
const sandbox = sandboxed ? "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-pointer-lock" : void 0;
|
|
1860
|
+
const height = artifact.height ?? "320px";
|
|
1861
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ArtifactCard, { title: artifact.title, kind: "html", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1862
|
+
"iframe",
|
|
1863
|
+
{
|
|
1864
|
+
title: artifact.title ?? "HTML artifact",
|
|
1865
|
+
srcDoc: artifact.content,
|
|
1866
|
+
sandbox,
|
|
1867
|
+
className: "aui-artifact-html w-full border-0 bg-background",
|
|
1868
|
+
style: { height }
|
|
1869
|
+
}
|
|
1870
|
+
) });
|
|
1871
|
+
};
|
|
1872
|
+
|
|
1873
|
+
// src/artifacts/json-artifact.tsx
|
|
1874
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1875
|
+
var JsonArtifactView = ({
|
|
1876
|
+
artifact
|
|
1877
|
+
}) => {
|
|
1878
|
+
const data = "data" in artifact ? artifact.data : artifact;
|
|
1879
|
+
const title = artifact.title;
|
|
1880
|
+
let body;
|
|
1881
|
+
try {
|
|
1882
|
+
body = JSON.stringify(data, null, 2);
|
|
1883
|
+
} catch {
|
|
1884
|
+
body = String(data);
|
|
1885
|
+
}
|
|
1886
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ArtifactCard, { title, kind: "json", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("pre", { className: "aui-artifact-json m-0 max-h-[420px] overflow-auto p-3 font-mono text-[12px] leading-relaxed text-foreground/85", children: body }) });
|
|
1887
|
+
};
|
|
1888
|
+
|
|
1889
|
+
// src/artifacts/table-artifact.tsx
|
|
1890
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1891
|
+
var TableArtifactView = ({ artifact }) => {
|
|
1892
|
+
const rows = artifact.rows ?? [];
|
|
1893
|
+
const columns = artifact.columns ?? deriveColumns(rows);
|
|
1894
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ArtifactCard, { title: artifact.title, kind: "table", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "aui-artifact-table-wrap overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("table", { className: "aui-artifact-table w-full border-collapse text-sm", children: [
|
|
1895
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tr", { className: "border-b border-border/40 bg-muted/20", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1896
|
+
"th",
|
|
1897
|
+
{
|
|
1898
|
+
className: "px-3 py-2 text-left text-xs font-semibold uppercase tracking-wider text-muted-foreground",
|
|
1899
|
+
children: col.label ?? col.key
|
|
1900
|
+
},
|
|
1901
|
+
col.key
|
|
1902
|
+
)) }) }),
|
|
1903
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1904
|
+
"tr",
|
|
1905
|
+
{
|
|
1906
|
+
className: "border-b border-border/30 transition-colors last:border-b-0 hover:bg-muted/20",
|
|
1907
|
+
children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1908
|
+
"td",
|
|
1909
|
+
{
|
|
1910
|
+
className: "px-3 py-2 align-top text-foreground/85",
|
|
1911
|
+
children: formatCell(row[col.key])
|
|
1912
|
+
},
|
|
1913
|
+
col.key
|
|
1914
|
+
))
|
|
1915
|
+
},
|
|
1916
|
+
i
|
|
1917
|
+
)) })
|
|
1918
|
+
] }) }) });
|
|
1919
|
+
};
|
|
1920
|
+
function deriveColumns(rows) {
|
|
1921
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1922
|
+
const cols = [];
|
|
1923
|
+
for (const row of rows) {
|
|
1924
|
+
for (const key of Object.keys(row)) {
|
|
1925
|
+
if (!seen.has(key)) {
|
|
1926
|
+
seen.add(key);
|
|
1927
|
+
cols.push({ key });
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
return cols;
|
|
1932
|
+
}
|
|
1933
|
+
function formatCell(value) {
|
|
1934
|
+
if (value === null || value === void 0) return "";
|
|
1935
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
1936
|
+
return String(value);
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
// src/artifacts/ui/ui-artifact.tsx
|
|
1940
|
+
var import_react13 = require("react");
|
|
1941
|
+
|
|
1942
|
+
// src/artifacts/ui/types.ts
|
|
1943
|
+
function isUiBinding(value) {
|
|
1944
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.$bind === "string";
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
// src/artifacts/ui/state.ts
|
|
1948
|
+
function uiStateReducer(state, action) {
|
|
1949
|
+
switch (action.type) {
|
|
1950
|
+
case "set":
|
|
1951
|
+
return setPath(state, action.path, action.value);
|
|
1952
|
+
case "toggle": {
|
|
1953
|
+
const current = getPath(state, action.path);
|
|
1954
|
+
return setPath(state, action.path, !current);
|
|
1955
|
+
}
|
|
1956
|
+
case "replace":
|
|
1957
|
+
return action.state;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
function getPath(state, path) {
|
|
1961
|
+
if (!path) return void 0;
|
|
1962
|
+
const parts = path.split(".");
|
|
1963
|
+
let cursor = state;
|
|
1964
|
+
for (const part of parts) {
|
|
1965
|
+
if (typeof cursor !== "object" || cursor === null) return void 0;
|
|
1966
|
+
cursor = cursor[part];
|
|
1967
|
+
}
|
|
1968
|
+
return cursor;
|
|
1969
|
+
}
|
|
1970
|
+
function setPath(state, path, value) {
|
|
1971
|
+
if (!path) return state;
|
|
1972
|
+
const parts = path.split(".");
|
|
1973
|
+
const next = { ...state };
|
|
1974
|
+
let cursor = next;
|
|
1975
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1976
|
+
const key = parts[i];
|
|
1977
|
+
const child = cursor[key];
|
|
1978
|
+
const cloned = typeof child === "object" && child !== null && !Array.isArray(child) ? { ...child } : {};
|
|
1979
|
+
cursor[key] = cloned;
|
|
1980
|
+
cursor = cloned;
|
|
1981
|
+
}
|
|
1982
|
+
cursor[parts[parts.length - 1]] = value;
|
|
1983
|
+
return next;
|
|
1984
|
+
}
|
|
1985
|
+
function resolveBindable(value, state) {
|
|
1986
|
+
if (isUiBinding(value)) {
|
|
1987
|
+
return getPath(state, value.$bind);
|
|
1988
|
+
}
|
|
1989
|
+
return value;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
// src/artifacts/ui/registry.tsx
|
|
1993
|
+
var import_react9 = require("react");
|
|
1994
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1995
|
+
var UiStateContext = (0, import_react9.createContext)({});
|
|
1996
|
+
var UiDispatchContext = (0, import_react9.createContext)(() => {
|
|
1997
|
+
});
|
|
1998
|
+
var UiStateProvider = ({ state, dispatch, children }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiStateContext.Provider, { value: state, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiDispatchContext.Provider, { value: dispatch, children }) });
|
|
1999
|
+
function useUiState() {
|
|
2000
|
+
return (0, import_react9.useContext)(UiStateContext);
|
|
2001
|
+
}
|
|
2002
|
+
function useUiDispatch() {
|
|
2003
|
+
return (0, import_react9.useContext)(UiDispatchContext);
|
|
2004
|
+
}
|
|
2005
|
+
var UiEventContext = (0, import_react9.createContext)(
|
|
2006
|
+
null
|
|
2007
|
+
);
|
|
2008
|
+
var UiEventProvider = ({ onEvent, children }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiEventContext.Provider, { value: onEvent, children });
|
|
2009
|
+
function useUiEventEmitter() {
|
|
2010
|
+
return (0, import_react9.useContext)(UiEventContext);
|
|
2011
|
+
}
|
|
2012
|
+
var UiCustomNodeRegistryContext = (0, import_react9.createContext)({});
|
|
2013
|
+
var UiCustomNodeRegistryProvider = ({ renderers, children }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiCustomNodeRegistryContext.Provider, { value: renderers, children });
|
|
2014
|
+
function useUiCustomNodeRegistry() {
|
|
2015
|
+
return (0, import_react9.useContext)(UiCustomNodeRegistryContext);
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
// src/artifacts/ui/nodes.tsx
|
|
2019
|
+
var import_react10 = require("react");
|
|
2020
|
+
var import_react11 = require("motion/react");
|
|
2021
|
+
var import_react12 = require("@assistant-ui/react");
|
|
2022
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2023
|
+
var UiNodeView = ({ node }) => {
|
|
2024
|
+
switch (node.kind) {
|
|
2025
|
+
case "box":
|
|
2026
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(BoxNode, { node });
|
|
2027
|
+
case "text":
|
|
2028
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TextNode, { node });
|
|
2029
|
+
case "heading":
|
|
2030
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(HeadingNode, { node });
|
|
2031
|
+
case "badge":
|
|
2032
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(BadgeNode, { node });
|
|
2033
|
+
case "button":
|
|
2034
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ButtonNode, { node });
|
|
2035
|
+
case "toggle":
|
|
2036
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ToggleNode, { node });
|
|
2037
|
+
case "slider":
|
|
2038
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SliderNode, { node });
|
|
2039
|
+
case "tooltip":
|
|
2040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipNode, { node });
|
|
2041
|
+
case "draggable":
|
|
2042
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DraggableNode, { node });
|
|
2043
|
+
case "custom":
|
|
2044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CustomNode, { node });
|
|
2045
|
+
default:
|
|
2046
|
+
return null;
|
|
2047
|
+
}
|
|
2048
|
+
};
|
|
2049
|
+
function useActionRunner() {
|
|
2050
|
+
const state = useUiState();
|
|
2051
|
+
const dispatch = useUiDispatch();
|
|
2052
|
+
const runtime = (0, import_react12.useThreadRuntime)();
|
|
2053
|
+
const emit = useUiEventEmitter();
|
|
2054
|
+
return (0, import_react10.useCallback)(
|
|
2055
|
+
(actions) => {
|
|
2056
|
+
if (!actions) return;
|
|
2057
|
+
const list = Array.isArray(actions) ? actions : [actions];
|
|
2058
|
+
for (const action of list) {
|
|
2059
|
+
switch (action.kind) {
|
|
2060
|
+
case "message": {
|
|
2061
|
+
const text = resolveBindable(action.text, state);
|
|
2062
|
+
if (typeof text === "string" && text.length > 0) {
|
|
2063
|
+
runtime?.append({
|
|
2064
|
+
role: "user",
|
|
2065
|
+
content: [{ type: "text", text }]
|
|
2066
|
+
});
|
|
2067
|
+
}
|
|
2068
|
+
break;
|
|
2069
|
+
}
|
|
2070
|
+
case "set": {
|
|
2071
|
+
const value = resolveBindable(action.value, state);
|
|
2072
|
+
dispatch({ type: "set", path: action.path, value });
|
|
2073
|
+
break;
|
|
2074
|
+
}
|
|
2075
|
+
case "toggle": {
|
|
2076
|
+
dispatch({ type: "toggle", path: action.path });
|
|
2077
|
+
break;
|
|
2078
|
+
}
|
|
2079
|
+
case "emit": {
|
|
2080
|
+
emit?.({ name: action.name, payload: action.payload });
|
|
2081
|
+
break;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
},
|
|
2086
|
+
[state, dispatch, runtime, emit]
|
|
2087
|
+
);
|
|
2088
|
+
}
|
|
2089
|
+
var ALIGN_CLS = {
|
|
2090
|
+
start: "items-start",
|
|
2091
|
+
center: "items-center",
|
|
2092
|
+
end: "items-end",
|
|
2093
|
+
stretch: "items-stretch"
|
|
2094
|
+
};
|
|
2095
|
+
var JUSTIFY_CLS = {
|
|
2096
|
+
start: "justify-start",
|
|
2097
|
+
center: "justify-center",
|
|
2098
|
+
end: "justify-end",
|
|
2099
|
+
between: "justify-between",
|
|
2100
|
+
around: "justify-around"
|
|
2101
|
+
};
|
|
2102
|
+
var BoxNode = ({ node }) => {
|
|
2103
|
+
const dir = node.direction ?? "col";
|
|
2104
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2105
|
+
"div",
|
|
2106
|
+
{
|
|
2107
|
+
className: cn(
|
|
2108
|
+
"aui-ui-box flex",
|
|
2109
|
+
dir === "col" ? "flex-col" : "flex-row",
|
|
2110
|
+
node.wrap && "flex-wrap",
|
|
2111
|
+
node.align && ALIGN_CLS[node.align],
|
|
2112
|
+
node.justify && JUSTIFY_CLS[node.justify],
|
|
2113
|
+
node.className
|
|
2114
|
+
),
|
|
2115
|
+
style: {
|
|
2116
|
+
gap: node.gap !== void 0 ? `${node.gap * 0.25}rem` : void 0,
|
|
2117
|
+
padding: node.padding !== void 0 ? `${node.padding * 0.25}rem` : void 0
|
|
2118
|
+
},
|
|
2119
|
+
children: node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: child }, child.id ?? i))
|
|
2120
|
+
}
|
|
2121
|
+
);
|
|
2122
|
+
};
|
|
2123
|
+
var TEXT_SIZE = {
|
|
2124
|
+
xs: "text-xs",
|
|
2125
|
+
sm: "text-sm",
|
|
2126
|
+
base: "text-base",
|
|
2127
|
+
lg: "text-lg"
|
|
2128
|
+
};
|
|
2129
|
+
var TEXT_WEIGHT = {
|
|
2130
|
+
normal: "font-normal",
|
|
2131
|
+
medium: "font-medium",
|
|
2132
|
+
semibold: "font-semibold",
|
|
2133
|
+
bold: "font-bold"
|
|
2134
|
+
};
|
|
2135
|
+
var TextNode = ({ node }) => {
|
|
2136
|
+
const state = useUiState();
|
|
2137
|
+
const value = resolveBindable(node.value, state);
|
|
2138
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2139
|
+
"span",
|
|
2140
|
+
{
|
|
2141
|
+
className: cn(
|
|
2142
|
+
"aui-ui-text",
|
|
2143
|
+
node.muted && "text-muted-foreground",
|
|
2144
|
+
node.size && TEXT_SIZE[node.size],
|
|
2145
|
+
node.weight && TEXT_WEIGHT[node.weight],
|
|
2146
|
+
node.className
|
|
2147
|
+
),
|
|
2148
|
+
children: value === void 0 || value === null ? "" : String(value)
|
|
2149
|
+
}
|
|
2150
|
+
);
|
|
2151
|
+
};
|
|
2152
|
+
var HEADING_CLS = {
|
|
2153
|
+
1: "text-2xl",
|
|
2154
|
+
2: "text-xl",
|
|
2155
|
+
3: "text-lg",
|
|
2156
|
+
4: "text-base"
|
|
2157
|
+
};
|
|
2158
|
+
var HeadingNode = ({ node }) => {
|
|
2159
|
+
const state = useUiState();
|
|
2160
|
+
const value = String(resolveBindable(node.value, state) ?? "");
|
|
2161
|
+
const level = node.level ?? 2;
|
|
2162
|
+
const cls = cn(
|
|
2163
|
+
"aui-ui-heading font-semibold text-foreground",
|
|
2164
|
+
HEADING_CLS[level],
|
|
2165
|
+
node.className
|
|
2166
|
+
);
|
|
2167
|
+
switch (level) {
|
|
2168
|
+
case 1:
|
|
2169
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h1", { className: cls, children: value });
|
|
2170
|
+
case 2:
|
|
2171
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { className: cls, children: value });
|
|
2172
|
+
case 3:
|
|
2173
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { className: cls, children: value });
|
|
2174
|
+
case 4:
|
|
2175
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h4", { className: cls, children: value });
|
|
2176
|
+
}
|
|
2177
|
+
};
|
|
2178
|
+
var BADGE_TONE = {
|
|
2179
|
+
default: "bg-muted text-foreground",
|
|
2180
|
+
primary: "bg-primary/10 text-primary",
|
|
2181
|
+
success: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
|
|
2182
|
+
warn: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
|
|
2183
|
+
danger: "bg-destructive/10 text-destructive"
|
|
2184
|
+
};
|
|
2185
|
+
var BadgeNode = ({ node }) => {
|
|
2186
|
+
const state = useUiState();
|
|
2187
|
+
const value = String(resolveBindable(node.value, state) ?? "");
|
|
2188
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2189
|
+
"span",
|
|
2190
|
+
{
|
|
2191
|
+
className: cn(
|
|
2192
|
+
"aui-ui-badge inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
|
|
2193
|
+
BADGE_TONE[node.tone ?? "default"],
|
|
2194
|
+
node.className
|
|
2195
|
+
),
|
|
2196
|
+
children: value
|
|
2197
|
+
}
|
|
2198
|
+
);
|
|
2199
|
+
};
|
|
2200
|
+
var ButtonNode = ({ node }) => {
|
|
2201
|
+
const state = useUiState();
|
|
2202
|
+
const run = useActionRunner();
|
|
2203
|
+
const label = String(resolveBindable(node.label, state) ?? "");
|
|
2204
|
+
const disabled = node.disabled !== void 0 ? Boolean(resolveBindable(node.disabled, state)) : false;
|
|
2205
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2206
|
+
Button,
|
|
2207
|
+
{
|
|
2208
|
+
variant: node.variant ?? "default",
|
|
2209
|
+
size: node.size ?? "default",
|
|
2210
|
+
disabled,
|
|
2211
|
+
className: node.className,
|
|
2212
|
+
onClick: () => run(node.onClick),
|
|
2213
|
+
children: label
|
|
2214
|
+
}
|
|
2215
|
+
);
|
|
2216
|
+
};
|
|
2217
|
+
var ToggleNode = ({ node }) => {
|
|
2218
|
+
const state = useUiState();
|
|
2219
|
+
const dispatch = useUiDispatch();
|
|
2220
|
+
const run = useActionRunner();
|
|
2221
|
+
const value = Boolean(getPath(state, node.binding));
|
|
2222
|
+
const label = node.label ? String(resolveBindable(node.label, state) ?? "") : null;
|
|
2223
|
+
const onToggle = () => {
|
|
2224
|
+
dispatch({ type: "toggle", path: node.binding });
|
|
2225
|
+
run(node.onChange);
|
|
2226
|
+
};
|
|
2227
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2228
|
+
"label",
|
|
2229
|
+
{
|
|
2230
|
+
className: cn(
|
|
2231
|
+
"aui-ui-toggle inline-flex cursor-pointer items-center gap-2 text-sm select-none",
|
|
2232
|
+
node.className
|
|
2233
|
+
),
|
|
2234
|
+
children: [
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2236
|
+
"button",
|
|
2237
|
+
{
|
|
2238
|
+
type: "button",
|
|
2239
|
+
role: "switch",
|
|
2240
|
+
"aria-checked": value,
|
|
2241
|
+
onClick: onToggle,
|
|
2242
|
+
className: cn(
|
|
2243
|
+
"relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border transition-colors",
|
|
2244
|
+
value ? "border-primary bg-primary" : "border-border bg-muted hover:bg-muted/80"
|
|
2245
|
+
),
|
|
2246
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2247
|
+
"span",
|
|
2248
|
+
{
|
|
2249
|
+
className: cn(
|
|
2250
|
+
"inline-block size-4 transform rounded-full bg-background shadow transition-transform",
|
|
2251
|
+
value ? "translate-x-4" : "translate-x-0.5"
|
|
2252
|
+
),
|
|
2253
|
+
"aria-hidden": true
|
|
2254
|
+
}
|
|
2255
|
+
)
|
|
2256
|
+
}
|
|
2257
|
+
),
|
|
2258
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-foreground/85", children: label })
|
|
2259
|
+
]
|
|
2260
|
+
}
|
|
2261
|
+
);
|
|
2262
|
+
};
|
|
2263
|
+
var SliderNode = ({ node }) => {
|
|
2264
|
+
const state = useUiState();
|
|
2265
|
+
const dispatch = useUiDispatch();
|
|
2266
|
+
const run = useActionRunner();
|
|
2267
|
+
const min = node.min ?? 0;
|
|
2268
|
+
const max = node.max ?? 100;
|
|
2269
|
+
const step = node.step ?? 1;
|
|
2270
|
+
const raw = getPath(state, node.binding);
|
|
2271
|
+
const value = typeof raw === "number" ? raw : min;
|
|
2272
|
+
const showValue = node.showValue ?? true;
|
|
2273
|
+
const label = node.label ? String(resolveBindable(node.label, state) ?? "") : null;
|
|
2274
|
+
const onChange = (e) => {
|
|
2275
|
+
const next = Number(e.target.value);
|
|
2276
|
+
dispatch({ type: "set", path: node.binding, value: next });
|
|
2277
|
+
};
|
|
2278
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cn("aui-ui-slider flex flex-col gap-1", node.className), children: [
|
|
2279
|
+
(label || showValue) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
|
|
2280
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: label }),
|
|
2281
|
+
showValue && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-mono", children: value })
|
|
2282
|
+
] }),
|
|
2283
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2284
|
+
"input",
|
|
2285
|
+
{
|
|
2286
|
+
type: "range",
|
|
2287
|
+
min,
|
|
2288
|
+
max,
|
|
2289
|
+
step,
|
|
2290
|
+
value,
|
|
2291
|
+
onChange,
|
|
2292
|
+
onMouseUp: () => run(node.onChange),
|
|
2293
|
+
onKeyUp: (e) => {
|
|
2294
|
+
if (e.key === "Enter" || e.key === " ") run(node.onChange);
|
|
2295
|
+
},
|
|
2296
|
+
onTouchEnd: () => run(node.onChange),
|
|
2297
|
+
className: "aui-ui-slider-input h-1.5 w-full cursor-pointer appearance-none rounded-full bg-muted accent-primary"
|
|
2298
|
+
}
|
|
2299
|
+
)
|
|
2300
|
+
] });
|
|
2301
|
+
};
|
|
2302
|
+
var TooltipNode = ({ node }) => {
|
|
2303
|
+
const state = useUiState();
|
|
2304
|
+
const content = String(resolveBindable(node.content, state) ?? "");
|
|
2305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Tooltip, { children: [
|
|
2306
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: cn("aui-ui-tooltip-trigger inline-flex", node.className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: node.child }) }) }),
|
|
2307
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipContent, { side: node.side ?? "top", children: content })
|
|
2308
|
+
] }) });
|
|
2309
|
+
};
|
|
2310
|
+
var DraggableNode = ({ node }) => {
|
|
2311
|
+
const run = useActionRunner();
|
|
2312
|
+
const snapBack = node.snapBack ?? true;
|
|
2313
|
+
const axis = node.axis ?? "both";
|
|
2314
|
+
const dragProp = axis === "both" ? true : axis;
|
|
2315
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2316
|
+
import_react11.motion.div,
|
|
2317
|
+
{
|
|
2318
|
+
drag: dragProp,
|
|
2319
|
+
dragMomentum: false,
|
|
2320
|
+
dragSnapToOrigin: snapBack,
|
|
2321
|
+
whileDrag: { scale: 1.02, cursor: "grabbing" },
|
|
2322
|
+
onDragEnd: () => run(node.onDragEnd),
|
|
2323
|
+
className: cn(
|
|
2324
|
+
"aui-ui-draggable inline-block cursor-grab touch-none",
|
|
2325
|
+
node.className
|
|
2326
|
+
),
|
|
2327
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: node.child })
|
|
2328
|
+
}
|
|
2329
|
+
);
|
|
2330
|
+
};
|
|
2331
|
+
var CustomNode = ({ node }) => {
|
|
2332
|
+
const state = useUiState();
|
|
2333
|
+
const registry = useUiCustomNodeRegistry();
|
|
2334
|
+
const Renderer = registry[node.name];
|
|
2335
|
+
if (!Renderer) return null;
|
|
2336
|
+
const resolvedProps = resolveProps(node.props ?? {}, state);
|
|
2337
|
+
const children = node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: child }, child.id ?? i));
|
|
2338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Renderer, { props: resolvedProps, children });
|
|
2339
|
+
};
|
|
2340
|
+
function resolveProps(props, state) {
|
|
2341
|
+
const out = {};
|
|
2342
|
+
for (const [k, v] of Object.entries(props)) {
|
|
2343
|
+
out[k] = resolveBindable(v, state);
|
|
2344
|
+
}
|
|
2345
|
+
return out;
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
// src/artifacts/ui/ui-artifact.tsx
|
|
2349
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2350
|
+
var UiArtifactView = ({ artifact }) => {
|
|
2351
|
+
const [state, dispatch] = (0, import_react13.useReducer)(
|
|
2352
|
+
uiStateReducer,
|
|
2353
|
+
artifact.initialState ?? {}
|
|
2354
|
+
);
|
|
2355
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ArtifactCard, { title: artifact.title, kind: "ui", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiStateProvider, { state, dispatch, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "aui-ui-root p-3", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: artifact.root }) }) }) });
|
|
2356
|
+
};
|
|
2357
|
+
|
|
2358
|
+
// src/artifacts/registry.tsx
|
|
2359
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2360
|
+
var defaultArtifactRenderers = {
|
|
2361
|
+
chart: ChartArtifactView,
|
|
2362
|
+
question: QuestionArtifactView,
|
|
2363
|
+
html: HtmlArtifactView,
|
|
2364
|
+
json: JsonArtifactView,
|
|
2365
|
+
table: TableArtifactView,
|
|
2366
|
+
ui: UiArtifactView
|
|
2367
|
+
};
|
|
2368
|
+
var ArtifactRegistryContext = (0, import_react14.createContext)(
|
|
2369
|
+
defaultArtifactRenderers
|
|
2370
|
+
);
|
|
2371
|
+
var ArtifactRegistryProvider = ({ renderers, override, children }) => {
|
|
2372
|
+
const merged = (0, import_react14.useMemo)(() => {
|
|
2373
|
+
if (!renderers) return defaultArtifactRenderers;
|
|
2374
|
+
if (override) return renderers;
|
|
2375
|
+
return { ...defaultArtifactRenderers, ...renderers };
|
|
2376
|
+
}, [renderers, override]);
|
|
2377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ArtifactRegistryContext.Provider, { value: merged, children });
|
|
2378
|
+
};
|
|
2379
|
+
function useArtifactRegistry() {
|
|
2380
|
+
return (0, import_react14.useContext)(ArtifactRegistryContext);
|
|
2381
|
+
}
|
|
2382
|
+
var ArtifactView = ({ artifact }) => {
|
|
2383
|
+
const registry = useArtifactRegistry();
|
|
2384
|
+
const Renderer = registry[artifact.type] ?? registry.json;
|
|
2385
|
+
if (!Renderer) return null;
|
|
2386
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Renderer, { artifact });
|
|
2387
|
+
};
|
|
2388
|
+
|
|
2389
|
+
// src/artifacts/parse.ts
|
|
2390
|
+
var ARTIFACT_FENCE_LANGUAGES = /* @__PURE__ */ new Set([
|
|
2391
|
+
"timbal-artifact",
|
|
2392
|
+
"timbal"
|
|
2393
|
+
]);
|
|
2394
|
+
function isArtifactFenceLanguage(language) {
|
|
2395
|
+
return typeof language === "string" && ARTIFACT_FENCE_LANGUAGES.has(language);
|
|
2396
|
+
}
|
|
2397
|
+
function tryParseStructuredText(text) {
|
|
2398
|
+
const trimmed = text.trim();
|
|
2399
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
|
|
2400
|
+
try {
|
|
2401
|
+
return JSON.parse(trimmed);
|
|
2402
|
+
} catch {
|
|
2403
|
+
}
|
|
2404
|
+
try {
|
|
2405
|
+
const asJson = trimmed.replace(/\bTrue\b/g, "true").replace(/\bFalse\b/g, "false").replace(/\bNone\b/g, "null").replace(/'/g, '"');
|
|
2406
|
+
return JSON.parse(asJson);
|
|
2407
|
+
} catch {
|
|
2408
|
+
return null;
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
function parseArtifactFromToolResult(result) {
|
|
2412
|
+
if (result === void 0 || result === null) return null;
|
|
2413
|
+
if (typeof result === "string") {
|
|
2414
|
+
const parsed = tryParseStructuredText(result);
|
|
2415
|
+
if (parsed === null) return null;
|
|
2416
|
+
return parseArtifactFromToolResult(parsed);
|
|
2417
|
+
}
|
|
2418
|
+
if (Array.isArray(result)) {
|
|
2419
|
+
for (const item of result) {
|
|
2420
|
+
if (typeof item === "object" && item !== null && "text" in item) {
|
|
2421
|
+
const text = item.text;
|
|
2422
|
+
if (typeof text === "string") {
|
|
2423
|
+
const fromText = parseArtifactFromToolResult(text);
|
|
2424
|
+
if (fromText) return fromText;
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
return null;
|
|
2429
|
+
}
|
|
2430
|
+
if (typeof result === "object") {
|
|
2431
|
+
const obj = result;
|
|
2432
|
+
if (obj.type === "text" && typeof obj.text === "string") {
|
|
2433
|
+
return parseArtifactFromToolResult(obj.text);
|
|
2434
|
+
}
|
|
2435
|
+
if (obj.type === "thinking" && typeof obj.thinking === "string") {
|
|
2436
|
+
return parseArtifactFromToolResult(obj.thinking);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
return isArtifact(result) ? result : null;
|
|
2440
|
+
}
|
|
2441
|
+
var FENCE_RE = /```(?:timbal-artifact|timbal)\s*\n([\s\S]*?)\n```/g;
|
|
2442
|
+
function findMarkdownArtifacts(markdown) {
|
|
2443
|
+
const matches = [];
|
|
2444
|
+
FENCE_RE.lastIndex = 0;
|
|
2445
|
+
let m;
|
|
2446
|
+
while ((m = FENCE_RE.exec(markdown)) !== null) {
|
|
2447
|
+
const raw = m[0];
|
|
2448
|
+
const body = m[1];
|
|
2449
|
+
try {
|
|
2450
|
+
const parsed = JSON.parse(body);
|
|
2451
|
+
if (isArtifact(parsed)) {
|
|
2452
|
+
matches.push({
|
|
2453
|
+
artifact: parsed,
|
|
2454
|
+
raw,
|
|
2455
|
+
start: m.index,
|
|
2456
|
+
end: m.index + raw.length
|
|
2457
|
+
});
|
|
2458
|
+
}
|
|
2459
|
+
} catch {
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
return matches;
|
|
2463
|
+
}
|
|
2464
|
+
function splitMarkdownByArtifacts(markdown) {
|
|
2465
|
+
const matches = findMarkdownArtifacts(markdown);
|
|
2466
|
+
if (matches.length === 0) return [{ kind: "text", text: markdown }];
|
|
2467
|
+
const segments = [];
|
|
2468
|
+
let cursor = 0;
|
|
2469
|
+
for (const match of matches) {
|
|
2470
|
+
if (match.start > cursor) {
|
|
2471
|
+
segments.push({ kind: "text", text: markdown.slice(cursor, match.start) });
|
|
2472
|
+
}
|
|
2473
|
+
segments.push({ kind: "artifact", artifact: match.artifact });
|
|
2474
|
+
cursor = match.end;
|
|
2475
|
+
}
|
|
2476
|
+
if (cursor < markdown.length) {
|
|
2477
|
+
segments.push({ kind: "text", text: markdown.slice(cursor) });
|
|
2478
|
+
}
|
|
2479
|
+
return segments;
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
// src/components/syntax-highlighter.tsx
|
|
2483
|
+
var import_javascript2 = __toESM(require("shiki/langs/javascript.mjs"), 1);
|
|
2484
|
+
var import_typescript = __toESM(require("shiki/langs/typescript.mjs"), 1);
|
|
2485
|
+
var import_python = __toESM(require("shiki/langs/python.mjs"), 1);
|
|
2486
|
+
var import_html = __toESM(require("shiki/langs/html.mjs"), 1);
|
|
2487
|
+
var import_css = __toESM(require("shiki/langs/css.mjs"), 1);
|
|
2488
|
+
var import_json = __toESM(require("shiki/langs/json.mjs"), 1);
|
|
2489
|
+
var import_bash = __toESM(require("shiki/langs/bash.mjs"), 1);
|
|
2490
|
+
var import_markdown = __toESM(require("shiki/langs/markdown.mjs"), 1);
|
|
2491
|
+
var import_jsx = __toESM(require("shiki/langs/jsx.mjs"), 1);
|
|
2492
|
+
var import_tsx = __toESM(require("shiki/langs/tsx.mjs"), 1);
|
|
2493
|
+
var import_sql = __toESM(require("shiki/langs/sql.mjs"), 1);
|
|
2494
|
+
var import_yaml = __toESM(require("shiki/langs/yaml.mjs"), 1);
|
|
2495
|
+
var import_rust = __toESM(require("shiki/langs/rust.mjs"), 1);
|
|
2496
|
+
var import_go = __toESM(require("shiki/langs/go.mjs"), 1);
|
|
2497
|
+
var import_java = __toESM(require("shiki/langs/java.mjs"), 1);
|
|
2498
|
+
var import_c = __toESM(require("shiki/langs/c.mjs"), 1);
|
|
2499
|
+
var import_cpp = __toESM(require("shiki/langs/cpp.mjs"), 1);
|
|
2500
|
+
var import_vitesse_dark = __toESM(require("shiki/themes/vitesse-dark.mjs"), 1);
|
|
2501
|
+
var import_vitesse_light = __toESM(require("shiki/themes/vitesse-light.mjs"), 1);
|
|
2502
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2503
|
+
var SHIKI_THEME_DARK = "vitesse-dark";
|
|
2504
|
+
var SHIKI_THEME_LIGHT = "vitesse-light";
|
|
2505
|
+
var highlighterPromise = null;
|
|
2506
|
+
function getHighlighter() {
|
|
2507
|
+
if (!highlighterPromise) {
|
|
2508
|
+
highlighterPromise = (0, import_core.createHighlighterCore)({
|
|
2509
|
+
themes: [import_vitesse_dark.default, import_vitesse_light.default],
|
|
2510
|
+
langs: [
|
|
2511
|
+
import_javascript2.default,
|
|
2512
|
+
import_typescript.default,
|
|
2513
|
+
import_python.default,
|
|
2514
|
+
import_html.default,
|
|
2515
|
+
import_css.default,
|
|
2516
|
+
import_json.default,
|
|
2517
|
+
import_bash.default,
|
|
2518
|
+
import_markdown.default,
|
|
2519
|
+
import_jsx.default,
|
|
2520
|
+
import_tsx.default,
|
|
2521
|
+
import_sql.default,
|
|
2522
|
+
import_yaml.default,
|
|
2523
|
+
import_rust.default,
|
|
2524
|
+
import_go.default,
|
|
2525
|
+
import_java.default,
|
|
2526
|
+
import_c.default,
|
|
2527
|
+
import_cpp.default
|
|
2528
|
+
],
|
|
2529
|
+
engine: (0, import_javascript.createJavaScriptRegexEngine)()
|
|
2530
|
+
});
|
|
2531
|
+
}
|
|
2532
|
+
return highlighterPromise;
|
|
2533
|
+
}
|
|
2534
|
+
getHighlighter();
|
|
2535
|
+
var ShikiSyntaxHighlighter = ({
|
|
2536
|
+
components: { Pre, Code: Code2 },
|
|
2537
|
+
language,
|
|
2538
|
+
code
|
|
2539
|
+
}) => {
|
|
2540
|
+
const [html, setHtml] = (0, import_react15.useState)(null);
|
|
2541
|
+
(0, import_react15.useEffect)(() => {
|
|
2542
|
+
let cancelled = false;
|
|
2543
|
+
(async () => {
|
|
2544
|
+
try {
|
|
2545
|
+
const highlighter = await getHighlighter();
|
|
2546
|
+
const loadedLangs = highlighter.getLoadedLanguages();
|
|
2547
|
+
if (!loadedLangs.includes(language)) {
|
|
929
2548
|
if (!cancelled) setHtml(null);
|
|
930
2549
|
return;
|
|
931
2550
|
}
|
|
@@ -945,8 +2564,17 @@ var ShikiSyntaxHighlighter = ({
|
|
|
945
2564
|
cancelled = true;
|
|
946
2565
|
};
|
|
947
2566
|
}, [code, language]);
|
|
2567
|
+
if (isArtifactFenceLanguage(language)) {
|
|
2568
|
+
try {
|
|
2569
|
+
const parsed = JSON.parse(code);
|
|
2570
|
+
if (isArtifact(parsed)) {
|
|
2571
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ArtifactView, { artifact: parsed });
|
|
2572
|
+
}
|
|
2573
|
+
} catch {
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
948
2576
|
if (html) {
|
|
949
|
-
return /* @__PURE__ */ (0,
|
|
2577
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
950
2578
|
"div",
|
|
951
2579
|
{
|
|
952
2580
|
className: "shiki-wrapper [&>pre]:!m-0 [&>pre]:!rounded-t-none [&>pre]:!rounded-b-lg [&>pre]:!border [&>pre]:!border-t-0 [&>pre]:!border-border/50 [&>pre]:!p-3 [&>pre]:!text-xs [&>pre]:!leading-relaxed [&>pre]:overflow-x-auto",
|
|
@@ -954,14 +2582,14 @@ var ShikiSyntaxHighlighter = ({
|
|
|
954
2582
|
}
|
|
955
2583
|
);
|
|
956
2584
|
}
|
|
957
|
-
return /* @__PURE__ */ (0,
|
|
2585
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pre, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Code2, { children: code }) });
|
|
958
2586
|
};
|
|
959
2587
|
var syntax_highlighter_default = ShikiSyntaxHighlighter;
|
|
960
2588
|
|
|
961
2589
|
// src/components/markdown-text.tsx
|
|
962
|
-
var
|
|
2590
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
963
2591
|
var MarkdownTextImpl = () => {
|
|
964
|
-
return /* @__PURE__ */ (0,
|
|
2592
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
965
2593
|
import_react_markdown.MarkdownTextPrimitive,
|
|
966
2594
|
{
|
|
967
2595
|
remarkPlugins: [import_remark_gfm.default, import_remark_math.default],
|
|
@@ -974,27 +2602,28 @@ var MarkdownTextImpl = () => {
|
|
|
974
2602
|
}
|
|
975
2603
|
);
|
|
976
2604
|
};
|
|
977
|
-
var MarkdownText = (0,
|
|
2605
|
+
var MarkdownText = (0, import_react16.memo)(MarkdownTextImpl);
|
|
978
2606
|
var CodeHeader = ({ language, code }) => {
|
|
979
2607
|
const { isCopied, copyToClipboard } = useCopyToClipboard();
|
|
2608
|
+
if (isArtifactFenceLanguage(language)) return null;
|
|
980
2609
|
const onCopy = () => {
|
|
981
2610
|
if (!code || isCopied) return;
|
|
982
2611
|
copyToClipboard(code);
|
|
983
2612
|
};
|
|
984
|
-
return /* @__PURE__ */ (0,
|
|
985
|
-
/* @__PURE__ */ (0,
|
|
986
|
-
/* @__PURE__ */ (0,
|
|
2613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "aui-code-header flex items-center justify-between rounded-t-lg border border-b-0 border-border/50 bg-zinc-100 px-4 py-2 dark:bg-zinc-800/80", children: [
|
|
2614
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-wide text-muted-foreground/80 uppercase", children: [
|
|
2615
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40" }),
|
|
987
2616
|
language
|
|
988
2617
|
] }),
|
|
989
|
-
/* @__PURE__ */ (0,
|
|
2618
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
990
2619
|
TooltipIconButton,
|
|
991
2620
|
{
|
|
992
2621
|
tooltip: isCopied ? "Copied!" : "Copy",
|
|
993
2622
|
onClick: onCopy,
|
|
994
2623
|
className: "transition-colors hover:text-foreground",
|
|
995
2624
|
children: [
|
|
996
|
-
!isCopied && /* @__PURE__ */ (0,
|
|
997
|
-
isCopied && /* @__PURE__ */ (0,
|
|
2625
|
+
!isCopied && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.CopyIcon, { className: "h-3.5 w-3.5" }),
|
|
2626
|
+
isCopied && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.CheckIcon, { className: "h-3.5 w-3.5 text-emerald-500" })
|
|
998
2627
|
]
|
|
999
2628
|
}
|
|
1000
2629
|
)
|
|
@@ -1003,7 +2632,7 @@ var CodeHeader = ({ language, code }) => {
|
|
|
1003
2632
|
var useCopyToClipboard = ({
|
|
1004
2633
|
copiedDuration = 3e3
|
|
1005
2634
|
} = {}) => {
|
|
1006
|
-
const [isCopied, setIsCopied] = (0,
|
|
2635
|
+
const [isCopied, setIsCopied] = (0, import_react16.useState)(false);
|
|
1007
2636
|
const copyToClipboard = (value) => {
|
|
1008
2637
|
if (!value) return;
|
|
1009
2638
|
navigator.clipboard.writeText(value).then(() => {
|
|
@@ -1014,7 +2643,7 @@ var useCopyToClipboard = ({
|
|
|
1014
2643
|
return { isCopied, copyToClipboard };
|
|
1015
2644
|
};
|
|
1016
2645
|
var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownComponents)({
|
|
1017
|
-
h1: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2646
|
+
h1: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1018
2647
|
"h1",
|
|
1019
2648
|
{
|
|
1020
2649
|
className: cn(
|
|
@@ -1024,7 +2653,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1024
2653
|
...props
|
|
1025
2654
|
}
|
|
1026
2655
|
),
|
|
1027
|
-
h2: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2656
|
+
h2: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1028
2657
|
"h2",
|
|
1029
2658
|
{
|
|
1030
2659
|
className: cn(
|
|
@@ -1034,7 +2663,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1034
2663
|
...props
|
|
1035
2664
|
}
|
|
1036
2665
|
),
|
|
1037
|
-
h3: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2666
|
+
h3: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1038
2667
|
"h3",
|
|
1039
2668
|
{
|
|
1040
2669
|
className: cn(
|
|
@@ -1044,7 +2673,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1044
2673
|
...props
|
|
1045
2674
|
}
|
|
1046
2675
|
),
|
|
1047
|
-
h4: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2676
|
+
h4: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1048
2677
|
"h4",
|
|
1049
2678
|
{
|
|
1050
2679
|
className: cn(
|
|
@@ -1054,7 +2683,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1054
2683
|
...props
|
|
1055
2684
|
}
|
|
1056
2685
|
),
|
|
1057
|
-
h5: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2686
|
+
h5: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1058
2687
|
"h5",
|
|
1059
2688
|
{
|
|
1060
2689
|
className: cn(
|
|
@@ -1064,7 +2693,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1064
2693
|
...props
|
|
1065
2694
|
}
|
|
1066
2695
|
),
|
|
1067
|
-
h6: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2696
|
+
h6: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1068
2697
|
"h6",
|
|
1069
2698
|
{
|
|
1070
2699
|
className: cn(
|
|
@@ -1074,7 +2703,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1074
2703
|
...props
|
|
1075
2704
|
}
|
|
1076
2705
|
),
|
|
1077
|
-
p: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2706
|
+
p: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1078
2707
|
"p",
|
|
1079
2708
|
{
|
|
1080
2709
|
className: cn(
|
|
@@ -1084,7 +2713,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1084
2713
|
...props
|
|
1085
2714
|
}
|
|
1086
2715
|
),
|
|
1087
|
-
a: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2716
|
+
a: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1088
2717
|
"a",
|
|
1089
2718
|
{
|
|
1090
2719
|
className: cn(
|
|
@@ -1096,7 +2725,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1096
2725
|
...props
|
|
1097
2726
|
}
|
|
1098
2727
|
),
|
|
1099
|
-
blockquote: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2728
|
+
blockquote: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1100
2729
|
"blockquote",
|
|
1101
2730
|
{
|
|
1102
2731
|
className: cn(
|
|
@@ -1106,7 +2735,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1106
2735
|
...props
|
|
1107
2736
|
}
|
|
1108
2737
|
),
|
|
1109
|
-
ul: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2738
|
+
ul: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1110
2739
|
"ul",
|
|
1111
2740
|
{
|
|
1112
2741
|
className: cn(
|
|
@@ -1116,7 +2745,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1116
2745
|
...props
|
|
1117
2746
|
}
|
|
1118
2747
|
),
|
|
1119
|
-
ol: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2748
|
+
ol: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1120
2749
|
"ol",
|
|
1121
2750
|
{
|
|
1122
2751
|
className: cn(
|
|
@@ -1126,7 +2755,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1126
2755
|
...props
|
|
1127
2756
|
}
|
|
1128
2757
|
),
|
|
1129
|
-
hr: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2758
|
+
hr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1130
2759
|
"hr",
|
|
1131
2760
|
{
|
|
1132
2761
|
className: cn(
|
|
@@ -1136,14 +2765,14 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1136
2765
|
...props
|
|
1137
2766
|
}
|
|
1138
2767
|
),
|
|
1139
|
-
table: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2768
|
+
table: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "my-4 w-full overflow-x-auto rounded-lg border border-border/50", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1140
2769
|
"table",
|
|
1141
2770
|
{
|
|
1142
2771
|
className: cn("aui-md-table w-full border-collapse text-sm", className),
|
|
1143
2772
|
...props
|
|
1144
2773
|
}
|
|
1145
2774
|
) }),
|
|
1146
|
-
th: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2775
|
+
th: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1147
2776
|
"th",
|
|
1148
2777
|
{
|
|
1149
2778
|
className: cn(
|
|
@@ -1153,7 +2782,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1153
2782
|
...props
|
|
1154
2783
|
}
|
|
1155
2784
|
),
|
|
1156
|
-
td: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2785
|
+
td: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1157
2786
|
"td",
|
|
1158
2787
|
{
|
|
1159
2788
|
className: cn(
|
|
@@ -1163,7 +2792,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1163
2792
|
...props
|
|
1164
2793
|
}
|
|
1165
2794
|
),
|
|
1166
|
-
tr: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2795
|
+
tr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1167
2796
|
"tr",
|
|
1168
2797
|
{
|
|
1169
2798
|
className: cn(
|
|
@@ -1173,8 +2802,8 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1173
2802
|
...props
|
|
1174
2803
|
}
|
|
1175
2804
|
),
|
|
1176
|
-
li: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
1177
|
-
sup: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2805
|
+
li: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("li", { className: cn("aui-md-li leading-[1.7]", className), ...props }),
|
|
2806
|
+
sup: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1178
2807
|
"sup",
|
|
1179
2808
|
{
|
|
1180
2809
|
className: cn(
|
|
@@ -1184,7 +2813,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1184
2813
|
...props
|
|
1185
2814
|
}
|
|
1186
2815
|
),
|
|
1187
|
-
pre: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2816
|
+
pre: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1188
2817
|
"pre",
|
|
1189
2818
|
{
|
|
1190
2819
|
className: cn(
|
|
@@ -1196,7 +2825,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1196
2825
|
),
|
|
1197
2826
|
code: function Code({ className, ...props }) {
|
|
1198
2827
|
const isCodeBlock = (0, import_react_markdown.useIsMarkdownCodeBlock)();
|
|
1199
|
-
return /* @__PURE__ */ (0,
|
|
2828
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1200
2829
|
"code",
|
|
1201
2830
|
{
|
|
1202
2831
|
className: cn(
|
|
@@ -1207,19 +2836,19 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1207
2836
|
}
|
|
1208
2837
|
);
|
|
1209
2838
|
},
|
|
1210
|
-
strong: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
1211
|
-
em: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2839
|
+
strong: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { className: cn("font-semibold text-foreground", className), ...props }),
|
|
2840
|
+
em: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("em", { className: cn("italic", className), ...props }),
|
|
1212
2841
|
CodeHeader
|
|
1213
2842
|
});
|
|
1214
2843
|
|
|
1215
2844
|
// src/components/tool-fallback.tsx
|
|
1216
|
-
var
|
|
1217
|
-
var
|
|
2845
|
+
var import_react19 = require("react");
|
|
2846
|
+
var import_lucide_react5 = require("lucide-react");
|
|
1218
2847
|
|
|
1219
2848
|
// src/ui/shimmer.tsx
|
|
1220
|
-
var
|
|
1221
|
-
var
|
|
1222
|
-
var
|
|
2849
|
+
var import_react17 = require("motion/react");
|
|
2850
|
+
var import_react18 = require("react");
|
|
2851
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1223
2852
|
var ShimmerComponent = ({
|
|
1224
2853
|
children,
|
|
1225
2854
|
as: Component = "p",
|
|
@@ -1227,14 +2856,14 @@ var ShimmerComponent = ({
|
|
|
1227
2856
|
duration = 2,
|
|
1228
2857
|
spread = 2
|
|
1229
2858
|
}) => {
|
|
1230
|
-
const MotionComponent =
|
|
2859
|
+
const MotionComponent = import_react17.motion.create(
|
|
1231
2860
|
Component
|
|
1232
2861
|
);
|
|
1233
|
-
const dynamicSpread = (0,
|
|
2862
|
+
const dynamicSpread = (0, import_react18.useMemo)(
|
|
1234
2863
|
() => (children?.length ?? 0) * spread,
|
|
1235
2864
|
[children, spread]
|
|
1236
2865
|
);
|
|
1237
|
-
return /* @__PURE__ */ (0,
|
|
2866
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1238
2867
|
MotionComponent,
|
|
1239
2868
|
{
|
|
1240
2869
|
animate: { backgroundPosition: "0% center" },
|
|
@@ -1257,36 +2886,303 @@ var ShimmerComponent = ({
|
|
|
1257
2886
|
}
|
|
1258
2887
|
);
|
|
1259
2888
|
};
|
|
1260
|
-
var Shimmer = (0,
|
|
2889
|
+
var Shimmer = (0, import_react18.memo)(ShimmerComponent);
|
|
1261
2890
|
|
|
1262
2891
|
// src/components/tool-fallback.tsx
|
|
1263
|
-
var
|
|
2892
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1264
2893
|
var ToolFallbackImpl = ({
|
|
1265
2894
|
toolName,
|
|
2895
|
+
argsText,
|
|
2896
|
+
result,
|
|
1266
2897
|
status
|
|
1267
2898
|
}) => {
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
/* @__PURE__ */ (0,
|
|
1272
|
-
|
|
2899
|
+
const isRunning = status?.type === "running";
|
|
2900
|
+
const isError = status?.type === "incomplete" && status.reason !== "cancelled";
|
|
2901
|
+
if (isRunning) {
|
|
2902
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "aui-tool-fallback-running flex items-center gap-2 py-1 text-sm text-muted-foreground", children: [
|
|
2903
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react5.WrenchIcon, { className: "size-4" }),
|
|
2904
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Shimmer, { as: "span", duration: 1.8, spread: 2.5, children: `Using tool: ${toolName}` })
|
|
2905
|
+
] });
|
|
2906
|
+
}
|
|
2907
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2908
|
+
ToolPanel,
|
|
2909
|
+
{
|
|
2910
|
+
toolName,
|
|
2911
|
+
argsText,
|
|
2912
|
+
result,
|
|
2913
|
+
isError
|
|
2914
|
+
}
|
|
2915
|
+
);
|
|
2916
|
+
};
|
|
2917
|
+
var ToolPanel = ({ toolName, argsText, result, isError }) => {
|
|
2918
|
+
const [open, setOpen] = (0, import_react19.useState)(false);
|
|
2919
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2920
|
+
"div",
|
|
2921
|
+
{
|
|
2922
|
+
className: cn(
|
|
2923
|
+
"aui-tool-fallback-root my-2 overflow-hidden rounded-lg border border-border/60 bg-muted/30 text-sm",
|
|
2924
|
+
isError && "border-destructive/50 bg-destructive/5"
|
|
2925
|
+
),
|
|
2926
|
+
children: [
|
|
2927
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2928
|
+
"button",
|
|
2929
|
+
{
|
|
2930
|
+
type: "button",
|
|
2931
|
+
onClick: () => setOpen((v) => !v),
|
|
2932
|
+
className: "aui-tool-fallback-header flex w-full items-center gap-2 px-3 py-2 text-left text-muted-foreground transition-colors hover:bg-muted/50",
|
|
2933
|
+
"aria-expanded": open,
|
|
2934
|
+
children: [
|
|
2935
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react5.WrenchIcon, { className: "size-3.5" }),
|
|
2936
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "aui-tool-fallback-name flex-1 truncate font-mono text-xs font-medium text-foreground/80", children: toolName }),
|
|
2937
|
+
isError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "aui-tool-fallback-status text-xs font-medium text-destructive", children: "error" }),
|
|
2938
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2939
|
+
import_lucide_react5.ChevronDownIcon,
|
|
2940
|
+
{
|
|
2941
|
+
className: cn(
|
|
2942
|
+
"size-3.5 shrink-0 transition-transform",
|
|
2943
|
+
open && "rotate-180"
|
|
2944
|
+
)
|
|
2945
|
+
}
|
|
2946
|
+
)
|
|
2947
|
+
]
|
|
2948
|
+
}
|
|
2949
|
+
),
|
|
2950
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "aui-tool-fallback-body grid gap-2 border-t border-border/40 bg-background/50 px-3 py-2.5 text-xs", children: [
|
|
2951
|
+
argsText && argsText !== "{}" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Section, { label: "Input", value: argsText }),
|
|
2952
|
+
result !== void 0 && result !== null && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Section, { label: "Output", value: formatResult(result) })
|
|
2953
|
+
] })
|
|
2954
|
+
]
|
|
2955
|
+
}
|
|
2956
|
+
);
|
|
1273
2957
|
};
|
|
1274
|
-
var
|
|
2958
|
+
var Section = ({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "aui-tool-fallback-section", children: [
|
|
2959
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "aui-tool-fallback-section-label mb-0.5 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
|
|
2960
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("pre", { className: "aui-tool-fallback-section-value overflow-x-auto whitespace-pre-wrap break-words font-mono text-[11px] leading-relaxed text-foreground/85", children: value })
|
|
2961
|
+
] });
|
|
2962
|
+
function formatResult(result) {
|
|
2963
|
+
if (typeof result === "string") return result;
|
|
2964
|
+
try {
|
|
2965
|
+
return JSON.stringify(result, null, 2);
|
|
2966
|
+
} catch {
|
|
2967
|
+
return String(result);
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
var ToolFallback = (0, import_react19.memo)(
|
|
1275
2971
|
ToolFallbackImpl
|
|
1276
2972
|
);
|
|
1277
2973
|
ToolFallback.displayName = "ToolFallback";
|
|
1278
2974
|
|
|
2975
|
+
// src/artifacts/tool-artifact.tsx
|
|
2976
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2977
|
+
var ToolArtifactFallback = (props) => {
|
|
2978
|
+
const registry = useArtifactRegistry();
|
|
2979
|
+
const isRunning = props.status?.type === "running";
|
|
2980
|
+
if (!isRunning) {
|
|
2981
|
+
const artifact = parseArtifactFromToolResult(props.result);
|
|
2982
|
+
if (artifact) {
|
|
2983
|
+
const Renderer = registry[artifact.type];
|
|
2984
|
+
if (Renderer) {
|
|
2985
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Renderer, { artifact });
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolFallback, { ...props });
|
|
2990
|
+
};
|
|
2991
|
+
|
|
2992
|
+
// src/components/composer.tsx
|
|
2993
|
+
var import_react20 = require("@assistant-ui/react");
|
|
2994
|
+
var import_lucide_react6 = require("lucide-react");
|
|
2995
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2996
|
+
var Composer = ({
|
|
2997
|
+
placeholder = "Send a message...",
|
|
2998
|
+
showAttachments = true,
|
|
2999
|
+
toolbar,
|
|
3000
|
+
sendTooltip = "Send message",
|
|
3001
|
+
noAutoFocus,
|
|
3002
|
+
className
|
|
3003
|
+
}) => {
|
|
3004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3005
|
+
import_react20.ComposerPrimitive.Root,
|
|
3006
|
+
{
|
|
3007
|
+
className: cn(
|
|
3008
|
+
"aui-composer-root relative mt-3 flex w-full flex-col",
|
|
3009
|
+
className
|
|
3010
|
+
),
|
|
3011
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
3012
|
+
import_react20.ComposerPrimitive.AttachmentDropzone,
|
|
3013
|
+
{
|
|
3014
|
+
className: "aui-composer-attachment-dropzone flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50",
|
|
3015
|
+
children: [
|
|
3016
|
+
showAttachments && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerAttachments, {}),
|
|
3017
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerInput, { placeholder, autoFocus: !noAutoFocus }),
|
|
3018
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3019
|
+
ComposerToolbar,
|
|
3020
|
+
{
|
|
3021
|
+
showAttachments,
|
|
3022
|
+
toolbar,
|
|
3023
|
+
sendTooltip
|
|
3024
|
+
}
|
|
3025
|
+
)
|
|
3026
|
+
]
|
|
3027
|
+
}
|
|
3028
|
+
)
|
|
3029
|
+
}
|
|
3030
|
+
);
|
|
3031
|
+
};
|
|
3032
|
+
var ComposerInput = ({
|
|
3033
|
+
placeholder,
|
|
3034
|
+
autoFocus
|
|
3035
|
+
}) => {
|
|
3036
|
+
const composer = (0, import_react20.useComposerRuntime)();
|
|
3037
|
+
const onKeyDown = (e) => {
|
|
3038
|
+
if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
|
|
3039
|
+
e.preventDefault();
|
|
3040
|
+
composer.send();
|
|
3041
|
+
}
|
|
3042
|
+
};
|
|
3043
|
+
const onInput = (e) => {
|
|
3044
|
+
const el = e.currentTarget;
|
|
3045
|
+
el.style.height = "auto";
|
|
3046
|
+
el.style.height = `${Math.min(el.scrollHeight, 240)}px`;
|
|
3047
|
+
};
|
|
3048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3049
|
+
import_react20.ComposerPrimitive.Input,
|
|
3050
|
+
{
|
|
3051
|
+
placeholder,
|
|
3052
|
+
className: "aui-composer-input mb-1 max-h-60 min-h-12 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-0",
|
|
3053
|
+
rows: 1,
|
|
3054
|
+
autoFocus,
|
|
3055
|
+
"aria-label": "Message input",
|
|
3056
|
+
onKeyDown,
|
|
3057
|
+
onInput
|
|
3058
|
+
}
|
|
3059
|
+
);
|
|
3060
|
+
};
|
|
3061
|
+
var ComposerToolbar = ({ showAttachments, toolbar, sendTooltip }) => {
|
|
3062
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "aui-composer-action-wrapper relative mx-2 mb-2 flex items-center gap-1", children: [
|
|
3063
|
+
showAttachments && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerAddAttachment, {}),
|
|
3064
|
+
toolbar,
|
|
3065
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1" }),
|
|
3066
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerSendOrCancel, { sendTooltip })
|
|
3067
|
+
] });
|
|
3068
|
+
};
|
|
3069
|
+
var ComposerSendOrCancel = ({ sendTooltip }) => {
|
|
3070
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
3071
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.AuiIf, { condition: (s) => !s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3072
|
+
TooltipIconButton,
|
|
3073
|
+
{
|
|
3074
|
+
tooltip: sendTooltip,
|
|
3075
|
+
side: "bottom",
|
|
3076
|
+
type: "submit",
|
|
3077
|
+
variant: "default",
|
|
3078
|
+
size: "icon",
|
|
3079
|
+
className: "aui-composer-send size-8 rounded-full",
|
|
3080
|
+
"aria-label": "Send message",
|
|
3081
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
|
|
3082
|
+
}
|
|
3083
|
+
) }) }),
|
|
3084
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.AuiIf, { condition: (s) => s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3085
|
+
Button,
|
|
3086
|
+
{
|
|
3087
|
+
type: "button",
|
|
3088
|
+
variant: "default",
|
|
3089
|
+
size: "icon",
|
|
3090
|
+
className: "aui-composer-cancel size-8 rounded-full",
|
|
3091
|
+
"aria-label": "Stop generating",
|
|
3092
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
|
|
3093
|
+
}
|
|
3094
|
+
) }) })
|
|
3095
|
+
] });
|
|
3096
|
+
};
|
|
3097
|
+
|
|
3098
|
+
// src/components/suggestions.tsx
|
|
3099
|
+
var import_react21 = require("react");
|
|
3100
|
+
var import_react22 = require("@assistant-ui/react");
|
|
3101
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
3102
|
+
var Suggestions = ({
|
|
3103
|
+
suggestions,
|
|
3104
|
+
layout = "grid",
|
|
3105
|
+
className
|
|
3106
|
+
}) => {
|
|
3107
|
+
const items = useResolvedSuggestions(suggestions);
|
|
3108
|
+
if (!items || items.length === 0) return null;
|
|
3109
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3110
|
+
"div",
|
|
3111
|
+
{
|
|
3112
|
+
className: cn(
|
|
3113
|
+
"aui-thread-suggestions w-full pb-4",
|
|
3114
|
+
layout === "grid" ? "grid gap-2 @md:grid-cols-2" : "flex gap-2 overflow-x-auto pb-1 [&::-webkit-scrollbar]:hidden",
|
|
3115
|
+
className
|
|
3116
|
+
),
|
|
3117
|
+
children: items.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SuggestionChip, { suggestion: s, compact: layout === "row" }, s.title + i))
|
|
3118
|
+
}
|
|
3119
|
+
);
|
|
3120
|
+
};
|
|
3121
|
+
var SuggestionChip = ({
|
|
3122
|
+
suggestion,
|
|
3123
|
+
compact
|
|
3124
|
+
}) => {
|
|
3125
|
+
const runtime = (0, import_react22.useThreadRuntime)();
|
|
3126
|
+
const onClick = () => {
|
|
3127
|
+
const text = suggestion.prompt ?? suggestion.title;
|
|
3128
|
+
runtime.append({ role: "user", content: [{ type: "text", text }] });
|
|
3129
|
+
};
|
|
3130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "aui-thread-suggestion-display fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
3131
|
+
Button,
|
|
3132
|
+
{
|
|
3133
|
+
variant: "ghost",
|
|
3134
|
+
onClick,
|
|
3135
|
+
className: cn(
|
|
3136
|
+
"aui-thread-suggestion h-auto rounded-2xl border text-left text-sm transition-colors hover:bg-muted",
|
|
3137
|
+
compact ? "shrink-0 flex-row items-center gap-2 whitespace-nowrap px-3 py-2" : "w-full flex-wrap items-start justify-start gap-1 px-4 py-3 @md:flex-col"
|
|
3138
|
+
),
|
|
3139
|
+
children: [
|
|
3140
|
+
suggestion.icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "aui-thread-suggestion-icon shrink-0 text-muted-foreground", children: suggestion.icon }),
|
|
3141
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "aui-thread-suggestion-text-1 font-medium", children: suggestion.title }),
|
|
3142
|
+
suggestion.description && !compact && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "aui-thread-suggestion-text-2 text-muted-foreground", children: suggestion.description })
|
|
3143
|
+
]
|
|
3144
|
+
}
|
|
3145
|
+
) });
|
|
3146
|
+
};
|
|
3147
|
+
function useResolvedSuggestions(source) {
|
|
3148
|
+
const [resolved, setResolved] = (0, import_react21.useState)(
|
|
3149
|
+
() => Array.isArray(source) ? source : void 0
|
|
3150
|
+
);
|
|
3151
|
+
(0, import_react21.useEffect)(() => {
|
|
3152
|
+
if (!source) {
|
|
3153
|
+
setResolved(void 0);
|
|
3154
|
+
return;
|
|
3155
|
+
}
|
|
3156
|
+
if (Array.isArray(source)) {
|
|
3157
|
+
setResolved(source);
|
|
3158
|
+
return;
|
|
3159
|
+
}
|
|
3160
|
+
let cancelled = false;
|
|
3161
|
+
Promise.resolve().then(() => source()).then((value) => {
|
|
3162
|
+
if (!cancelled) setResolved(value);
|
|
3163
|
+
}).catch(() => {
|
|
3164
|
+
if (!cancelled) setResolved([]);
|
|
3165
|
+
});
|
|
3166
|
+
return () => {
|
|
3167
|
+
cancelled = true;
|
|
3168
|
+
};
|
|
3169
|
+
}, [source]);
|
|
3170
|
+
return (0, import_react21.useMemo)(() => resolved, [resolved]);
|
|
3171
|
+
}
|
|
3172
|
+
|
|
1279
3173
|
// src/components/thread.tsx
|
|
1280
|
-
var
|
|
1281
|
-
var
|
|
1282
|
-
var
|
|
3174
|
+
var import_react23 = require("@assistant-ui/react");
|
|
3175
|
+
var import_lucide_react7 = require("lucide-react");
|
|
3176
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1283
3177
|
var Thread = ({
|
|
1284
3178
|
className,
|
|
1285
3179
|
maxWidth = "44rem",
|
|
1286
3180
|
welcome,
|
|
1287
3181
|
suggestions,
|
|
1288
3182
|
composerPlaceholder = "Send a message...",
|
|
1289
|
-
components
|
|
3183
|
+
components,
|
|
3184
|
+
artifacts,
|
|
3185
|
+
onArtifactEvent
|
|
1290
3186
|
}) => {
|
|
1291
3187
|
const WelcomeSlot = components?.Welcome ?? ThreadWelcome;
|
|
1292
3188
|
const ComposerSlot = components?.Composer ?? Composer;
|
|
@@ -1294,59 +3190,79 @@ var Thread = ({
|
|
|
1294
3190
|
const AssistantMessageSlot = components?.AssistantMessage ?? AssistantMessage;
|
|
1295
3191
|
const EditComposerSlot = components?.EditComposer ?? EditComposer;
|
|
1296
3192
|
const ScrollToBottomSlot = components?.ScrollToBottom ?? ThreadScrollToBottom;
|
|
1297
|
-
|
|
1298
|
-
|
|
3193
|
+
const SuggestionsSlot = components?.Suggestions ?? Suggestions;
|
|
3194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3195
|
+
ArtifactRegistryProvider,
|
|
1299
3196
|
{
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
),
|
|
1304
|
-
|
|
1305
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1306
|
-
import_react11.ThreadPrimitive.Viewport,
|
|
3197
|
+
renderers: artifacts?.renderers,
|
|
3198
|
+
override: artifacts?.override,
|
|
3199
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(UiEventProvider, { onEvent: onArtifactEvent ?? (() => {
|
|
3200
|
+
}), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3201
|
+
import_react23.ThreadPrimitive.Root,
|
|
1307
3202
|
{
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
3203
|
+
className: cn(
|
|
3204
|
+
"aui-root aui-thread-root @container flex h-full flex-col bg-background",
|
|
3205
|
+
className
|
|
3206
|
+
),
|
|
3207
|
+
style: { ["--thread-max-width"]: maxWidth },
|
|
3208
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3209
|
+
import_react23.ThreadPrimitive.Viewport,
|
|
3210
|
+
{
|
|
3211
|
+
turnAnchor: "bottom",
|
|
3212
|
+
className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4 pt-4",
|
|
3213
|
+
children: [
|
|
3214
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3215
|
+
WelcomeSlot,
|
|
3216
|
+
{
|
|
3217
|
+
config: welcome,
|
|
3218
|
+
suggestions,
|
|
3219
|
+
Suggestions: SuggestionsSlot
|
|
3220
|
+
}
|
|
3221
|
+
),
|
|
3222
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3223
|
+
import_react23.ThreadPrimitive.Messages,
|
|
3224
|
+
{
|
|
3225
|
+
components: {
|
|
3226
|
+
UserMessage: UserMessageSlot,
|
|
3227
|
+
EditComposer: EditComposerSlot,
|
|
3228
|
+
AssistantMessage: AssistantMessageSlot
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
),
|
|
3232
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4 md:pb-6", children: [
|
|
3233
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScrollToBottomSlot, {}),
|
|
3234
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerSlot, { placeholder: composerPlaceholder })
|
|
3235
|
+
] })
|
|
3236
|
+
]
|
|
3237
|
+
}
|
|
3238
|
+
)
|
|
1327
3239
|
}
|
|
1328
|
-
)
|
|
3240
|
+
) })
|
|
1329
3241
|
}
|
|
1330
3242
|
);
|
|
1331
3243
|
};
|
|
1332
3244
|
var ThreadScrollToBottom = () => {
|
|
1333
|
-
return /* @__PURE__ */ (0,
|
|
3245
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1334
3246
|
TooltipIconButton,
|
|
1335
3247
|
{
|
|
1336
3248
|
tooltip: "Scroll to bottom",
|
|
1337
3249
|
variant: "outline",
|
|
1338
3250
|
className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:hover:bg-accent",
|
|
1339
|
-
children: /* @__PURE__ */ (0,
|
|
3251
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.ArrowDownIcon, {})
|
|
1340
3252
|
}
|
|
1341
3253
|
) });
|
|
1342
3254
|
};
|
|
1343
|
-
var ThreadWelcome = ({
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
3255
|
+
var ThreadWelcome = ({
|
|
3256
|
+
config,
|
|
3257
|
+
suggestions,
|
|
3258
|
+
Suggestions: SuggestionsSlot = Suggestions
|
|
3259
|
+
}) => {
|
|
3260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.AuiIf, { condition: (s) => s.thread.isEmpty, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
|
|
3261
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-thread-welcome-message flex size-full flex-col items-center justify-center px-4 text-center", children: [
|
|
3262
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "fade-in animate-in fill-mode-both relative mb-6 flex size-14 items-center justify-center duration-300", children: [
|
|
3263
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "animate-ai-ring-glow absolute inset-0 rounded-2xl bg-gradient-to-br from-primary/15 to-primary/5 ring-1 ring-primary/15" }),
|
|
3264
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "animate-ai-pulse-ring absolute inset-0" }),
|
|
3265
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1350
3266
|
"svg",
|
|
1351
3267
|
{
|
|
1352
3268
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -1357,139 +3273,74 @@ var ThreadWelcome = ({ config, suggestions }) => {
|
|
|
1357
3273
|
strokeLinecap: "round",
|
|
1358
3274
|
strokeLinejoin: "round",
|
|
1359
3275
|
className: "animate-ai-breathe relative size-7 text-primary/75",
|
|
1360
|
-
children: /* @__PURE__ */ (0,
|
|
3276
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" })
|
|
1361
3277
|
}
|
|
1362
3278
|
)
|
|
1363
3279
|
] }),
|
|
1364
|
-
/* @__PURE__ */ (0,
|
|
1365
|
-
/* @__PURE__ */ (0,
|
|
3280
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both font-semibold text-2xl duration-200", children: config?.heading ?? "How can I help you today?" }),
|
|
3281
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground mt-2 delay-75 duration-200", children: config?.subheading ?? "Send a message to start a conversation." })
|
|
1366
3282
|
] }) }),
|
|
1367
|
-
suggestions &&
|
|
1368
|
-
] }) });
|
|
1369
|
-
};
|
|
1370
|
-
var ThreadSuggestions = ({ suggestions }) => {
|
|
1371
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4", children: suggestions.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ThreadSuggestionItem, { title: s.title, description: s.description }, i)) });
|
|
1372
|
-
};
|
|
1373
|
-
var ThreadSuggestionItem = ({ title, description }) => {
|
|
1374
|
-
const runtime = (0, import_react11.useThreadRuntime)();
|
|
1375
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-thread-welcome-suggestion-display fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1376
|
-
Button,
|
|
1377
|
-
{
|
|
1378
|
-
variant: "ghost",
|
|
1379
|
-
className: "aui-thread-welcome-suggestion h-auto w-full @md:flex-col flex-wrap items-start justify-start gap-1 rounded-2xl border px-4 py-3 text-left text-sm transition-colors hover:bg-muted",
|
|
1380
|
-
onClick: () => runtime.append({
|
|
1381
|
-
role: "user",
|
|
1382
|
-
content: [{ type: "text", text: title }]
|
|
1383
|
-
}),
|
|
1384
|
-
children: [
|
|
1385
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "aui-thread-welcome-suggestion-text-1 font-medium", children: title }),
|
|
1386
|
-
description && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "aui-thread-welcome-suggestion-text-2 text-muted-foreground", children: description })
|
|
1387
|
-
]
|
|
1388
|
-
}
|
|
1389
|
-
) });
|
|
1390
|
-
};
|
|
1391
|
-
var Composer = ({ placeholder }) => {
|
|
1392
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ComposerPrimitive.Root, { className: "aui-composer-root relative mt-3 flex w-full flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react11.ComposerPrimitive.AttachmentDropzone, { className: "aui-composer-attachment-dropzone flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50", children: [
|
|
1393
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ComposerAttachments, {}),
|
|
1394
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1395
|
-
import_react11.ComposerPrimitive.Input,
|
|
1396
|
-
{
|
|
1397
|
-
placeholder: placeholder ?? "Send a message...",
|
|
1398
|
-
className: "aui-composer-input mb-1 max-h-32 min-h-14 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-0",
|
|
1399
|
-
rows: 1,
|
|
1400
|
-
autoFocus: true,
|
|
1401
|
-
"aria-label": "Message input"
|
|
1402
|
-
}
|
|
1403
|
-
),
|
|
1404
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ComposerAction, {})
|
|
3283
|
+
suggestions && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SuggestionsSlot, { suggestions })
|
|
1405
3284
|
] }) });
|
|
1406
3285
|
};
|
|
1407
|
-
var ComposerAction = () => {
|
|
1408
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-composer-action-wrapper relative mx-2 mb-2 flex items-center justify-end", children: [
|
|
1409
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.AuiIf, { condition: (s) => !s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1410
|
-
TooltipIconButton,
|
|
1411
|
-
{
|
|
1412
|
-
tooltip: "Send message",
|
|
1413
|
-
side: "bottom",
|
|
1414
|
-
type: "submit",
|
|
1415
|
-
variant: "default",
|
|
1416
|
-
size: "icon",
|
|
1417
|
-
className: "aui-composer-send size-8 rounded-full",
|
|
1418
|
-
"aria-label": "Send message",
|
|
1419
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
|
|
1420
|
-
}
|
|
1421
|
-
) }) }),
|
|
1422
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.AuiIf, { condition: (s) => s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1423
|
-
Button,
|
|
1424
|
-
{
|
|
1425
|
-
type: "button",
|
|
1426
|
-
variant: "default",
|
|
1427
|
-
size: "icon",
|
|
1428
|
-
className: "aui-composer-cancel size-8 rounded-full",
|
|
1429
|
-
"aria-label": "Stop generating",
|
|
1430
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
|
|
1431
|
-
}
|
|
1432
|
-
) }) })
|
|
1433
|
-
] });
|
|
1434
|
-
};
|
|
1435
3286
|
var MessageError = () => {
|
|
1436
|
-
return /* @__PURE__ */ (0,
|
|
3287
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.MessagePrimitive.Error, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ErrorPrimitive.Root, { className: "aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm dark:bg-destructive/5 dark:text-red-200", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) });
|
|
1437
3288
|
};
|
|
1438
3289
|
var AssistantMessage = () => {
|
|
1439
|
-
return /* @__PURE__ */ (0,
|
|
1440
|
-
|
|
3290
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3291
|
+
import_react23.MessagePrimitive.Root,
|
|
1441
3292
|
{
|
|
1442
3293
|
className: "aui-assistant-message-root fade-in slide-in-from-bottom-1 relative mx-auto w-full max-w-(--thread-max-width) animate-in py-3 duration-150",
|
|
1443
3294
|
"data-role": "assistant",
|
|
1444
3295
|
children: [
|
|
1445
|
-
/* @__PURE__ */ (0,
|
|
1446
|
-
/* @__PURE__ */ (0,
|
|
1447
|
-
|
|
3296
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed", children: [
|
|
3297
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3298
|
+
import_react23.MessagePrimitive.Parts,
|
|
1448
3299
|
{
|
|
1449
3300
|
components: {
|
|
1450
3301
|
Text: MarkdownText,
|
|
1451
|
-
tools: { Fallback:
|
|
3302
|
+
tools: { Fallback: ToolArtifactFallback }
|
|
1452
3303
|
}
|
|
1453
3304
|
}
|
|
1454
3305
|
),
|
|
1455
|
-
/* @__PURE__ */ (0,
|
|
3306
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(MessageError, {})
|
|
1456
3307
|
] }),
|
|
1457
|
-
/* @__PURE__ */ (0,
|
|
3308
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-assistant-message-footer mt-1 ml-2 flex", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AssistantActionBar, {}) })
|
|
1458
3309
|
]
|
|
1459
3310
|
}
|
|
1460
3311
|
);
|
|
1461
3312
|
};
|
|
1462
3313
|
var AssistantActionBar = () => {
|
|
1463
|
-
return /* @__PURE__ */ (0,
|
|
1464
|
-
|
|
3314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3315
|
+
import_react23.ActionBarPrimitive.Root,
|
|
1465
3316
|
{
|
|
1466
3317
|
hideWhenRunning: true,
|
|
1467
3318
|
autohide: "not-last",
|
|
1468
3319
|
autohideFloat: "single-branch",
|
|
1469
3320
|
className: "aui-assistant-action-bar-root col-start-3 row-start-2 -ml-1 flex gap-1 text-muted-foreground data-floating:absolute data-floating:rounded-md data-floating:border data-floating:bg-background data-floating:p-1 data-floating:shadow-sm",
|
|
1470
3321
|
children: [
|
|
1471
|
-
/* @__PURE__ */ (0,
|
|
1472
|
-
/* @__PURE__ */ (0,
|
|
1473
|
-
/* @__PURE__ */ (0,
|
|
3322
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.Copy, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(TooltipIconButton, { tooltip: "Copy", children: [
|
|
3323
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.AuiIf, { condition: (s) => s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.CheckIcon, {}) }),
|
|
3324
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.AuiIf, { condition: (s) => !s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.CopyIcon, {}) })
|
|
1474
3325
|
] }) }),
|
|
1475
|
-
/* @__PURE__ */ (0,
|
|
1476
|
-
/* @__PURE__ */ (0,
|
|
1477
|
-
/* @__PURE__ */ (0,
|
|
3326
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.Reload, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TooltipIconButton, { tooltip: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.RefreshCwIcon, {}) }) }),
|
|
3327
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ActionBarMorePrimitive.Root, { children: [
|
|
3328
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarMorePrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1478
3329
|
TooltipIconButton,
|
|
1479
3330
|
{
|
|
1480
3331
|
tooltip: "More",
|
|
1481
3332
|
className: "data-[state=open]:bg-accent",
|
|
1482
|
-
children: /* @__PURE__ */ (0,
|
|
3333
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.MoreHorizontalIcon, {})
|
|
1483
3334
|
}
|
|
1484
3335
|
) }),
|
|
1485
|
-
/* @__PURE__ */ (0,
|
|
1486
|
-
|
|
3336
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3337
|
+
import_react23.ActionBarMorePrimitive.Content,
|
|
1487
3338
|
{
|
|
1488
3339
|
side: "bottom",
|
|
1489
3340
|
align: "start",
|
|
1490
3341
|
className: "aui-action-bar-more-content z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
|
|
1491
|
-
children: /* @__PURE__ */ (0,
|
|
1492
|
-
/* @__PURE__ */ (0,
|
|
3342
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground", children: [
|
|
3343
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.DownloadIcon, { className: "size-4" }),
|
|
1493
3344
|
"Export as Markdown"
|
|
1494
3345
|
] }) })
|
|
1495
3346
|
}
|
|
@@ -1500,65 +3351,372 @@ var AssistantActionBar = () => {
|
|
|
1500
3351
|
);
|
|
1501
3352
|
};
|
|
1502
3353
|
var UserMessage = () => {
|
|
1503
|
-
return /* @__PURE__ */ (0,
|
|
1504
|
-
|
|
3354
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3355
|
+
import_react23.MessagePrimitive.Root,
|
|
1505
3356
|
{
|
|
1506
3357
|
className: "aui-user-message-root fade-in slide-in-from-bottom-1 mx-auto grid w-full max-w-(--thread-max-width) animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 py-3 duration-150 [&:where(>*)]:col-start-2",
|
|
1507
3358
|
"data-role": "user",
|
|
1508
3359
|
children: [
|
|
1509
|
-
/* @__PURE__ */ (0,
|
|
1510
|
-
/* @__PURE__ */ (0,
|
|
1511
|
-
/* @__PURE__ */ (0,
|
|
1512
|
-
/* @__PURE__ */ (0,
|
|
3360
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(UserMessageAttachments, {}),
|
|
3361
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [
|
|
3362
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-user-message-content wrap-break-word rounded-2xl bg-muted px-4 py-2.5 text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.MessagePrimitive.Parts, {}) }),
|
|
3363
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(UserActionBar, {}) })
|
|
1513
3364
|
] })
|
|
1514
3365
|
]
|
|
1515
3366
|
}
|
|
1516
3367
|
);
|
|
1517
3368
|
};
|
|
1518
3369
|
var UserActionBar = () => {
|
|
1519
|
-
return /* @__PURE__ */ (0,
|
|
1520
|
-
|
|
3370
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3371
|
+
import_react23.ActionBarPrimitive.Root,
|
|
1521
3372
|
{
|
|
1522
3373
|
hideWhenRunning: true,
|
|
1523
3374
|
autohide: "not-last",
|
|
1524
3375
|
className: "aui-user-action-bar-root flex flex-col items-end",
|
|
1525
|
-
children: /* @__PURE__ */ (0,
|
|
3376
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.Edit, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TooltipIconButton, { tooltip: "Edit", className: "aui-user-action-edit p-4", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.PencilIcon, {}) }) })
|
|
1526
3377
|
}
|
|
1527
3378
|
);
|
|
1528
3379
|
};
|
|
1529
3380
|
var EditComposer = () => {
|
|
1530
|
-
return /* @__PURE__ */ (0,
|
|
1531
|
-
/* @__PURE__ */ (0,
|
|
1532
|
-
|
|
3381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.MessagePrimitive.Root, { className: "aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ComposerPrimitive.Root, { className: "aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted", children: [
|
|
3382
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3383
|
+
import_react23.ComposerPrimitive.Input,
|
|
1533
3384
|
{
|
|
1534
3385
|
className: "aui-edit-composer-input min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none",
|
|
1535
3386
|
autoFocus: true
|
|
1536
3387
|
}
|
|
1537
3388
|
),
|
|
1538
|
-
/* @__PURE__ */ (0,
|
|
1539
|
-
/* @__PURE__ */ (0,
|
|
1540
|
-
/* @__PURE__ */ (0,
|
|
3389
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end", children: [
|
|
3390
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { variant: "ghost", size: "sm", children: "Cancel" }) }),
|
|
3391
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { size: "sm", children: "Update" }) })
|
|
1541
3392
|
] })
|
|
1542
3393
|
] }) });
|
|
1543
3394
|
};
|
|
1544
3395
|
|
|
1545
3396
|
// src/components/chat.tsx
|
|
1546
|
-
var
|
|
3397
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1547
3398
|
function TimbalChat({
|
|
1548
3399
|
workforceId,
|
|
1549
3400
|
baseUrl,
|
|
1550
3401
|
fetch: fetch2,
|
|
3402
|
+
attachments,
|
|
3403
|
+
attachmentsUploadUrl,
|
|
3404
|
+
attachmentsAccept,
|
|
3405
|
+
debug,
|
|
1551
3406
|
...threadProps
|
|
1552
3407
|
}) {
|
|
1553
|
-
return /* @__PURE__ */ (0,
|
|
3408
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3409
|
+
TimbalRuntimeProvider,
|
|
3410
|
+
{
|
|
3411
|
+
workforceId,
|
|
3412
|
+
baseUrl,
|
|
3413
|
+
fetch: fetch2,
|
|
3414
|
+
attachments,
|
|
3415
|
+
attachmentsUploadUrl,
|
|
3416
|
+
attachmentsAccept,
|
|
3417
|
+
debug,
|
|
3418
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Thread, { ...threadProps })
|
|
3419
|
+
}
|
|
3420
|
+
);
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
// src/artifacts/agent-instructions.ts
|
|
3424
|
+
var ARTIFACT_AGENT_INSTRUCTIONS = `
|
|
3425
|
+
## Rich artifacts (Timbal chat UI)
|
|
3426
|
+
|
|
3427
|
+
When you need charts, tables, choice widgets, or interactive controls, return a **JSON artifact object** instead of plain prose. The chat UI renders these automatically.
|
|
3428
|
+
|
|
3429
|
+
### Delivery channels (either works)
|
|
3430
|
+
|
|
3431
|
+
1. **Tool result (preferred)** \u2014 return a single JSON object (or a JSON string) from a tool. The object must include a string \`type\` field.
|
|
3432
|
+
2. **Inline markdown fence** \u2014 embed the same JSON inside a fenced block:
|
|
3433
|
+
|
|
3434
|
+
\`\`\`timbal-artifact
|
|
3435
|
+
{"type":"chart","data":[{"month":"Jan","sales":120}]}
|
|
3436
|
+
\`\`\`
|
|
3437
|
+
|
|
3438
|
+
The alias \`\`\`timbal\`\`\` is also accepted.
|
|
3439
|
+
|
|
3440
|
+
### Built-in artifact types
|
|
3441
|
+
|
|
3442
|
+
| \`type\` | Use for |
|
|
3443
|
+
|---|---|
|
|
3444
|
+
| \`chart\` | Bar, line, area, or pie charts. Fields: \`data\`, optional \`chartType\`, \`xKey\`, \`dataKey\`, \`title\`, \`unit\`. |
|
|
3445
|
+
| \`table\` | Tabular data. Fields: \`rows\`, optional \`columns\`, \`title\`. |
|
|
3446
|
+
| \`question\` | In-thread multiple choice. Fields: \`options: [{ id, label, description? }]\`, optional \`prompt\`, \`multi\`. User replies are sent back as a normal user message. |
|
|
3447
|
+
| \`html\` | Custom HTML/CSS/JS in an iframe. Fields: \`content\` (HTML document or fragment), optional \`title\`, \`height\`, \`sandboxed\` (default \`true\`; set \`false\` for unrestricted scripts/CDN). |
|
|
3448
|
+
| \`json\` | Fallback structured view. Fields: \`data\`, optional \`title\`. |
|
|
3449
|
+
| \`ui\` | **Interactive UI** composed from a fixed node palette (hover, click, drag). See below. |
|
|
3450
|
+
|
|
3451
|
+
### When to use \`type: "html"\`
|
|
3452
|
+
|
|
3453
|
+
Use \`html\` when the user wants a **rich visual or interactive page** that does not fit the \`ui\` palette \u2014 e.g. styled layouts, SVG graphics, CSS animations, canvas, small games, calculators, or multi-section mockups. Pass a full HTML document or a body fragment in \`content\`.
|
|
3454
|
+
|
|
3455
|
+
- Inline \`<style>\`, \`<script>\`, SVG, and canvas are supported.
|
|
3456
|
+
- Default \`sandboxed: true\` runs in an isolated iframe with scripts enabled.
|
|
3457
|
+
- Set \`sandboxed: false\` only for trusted content that needs external CDN scripts/styles or full DOM freedom.
|
|
3458
|
+
- Prefer \`ui\` when controls should send chat messages or host events; prefer \`html\` for self-contained mini-apps and visual demos.
|
|
3459
|
+
|
|
3460
|
+
### When to use \`type: "ui"\`
|
|
3461
|
+
|
|
3462
|
+
Use a \`ui\` artifact when the user should **hover, click, drag, or adjust controls** in-thread and those actions should integrate with the chat runtime (messages, \`onArtifactEvent\`). For standalone visual/interactive HTML, use \`html\` instead.
|
|
3463
|
+
|
|
3464
|
+
Each \`ui\` artifact has:
|
|
3465
|
+
|
|
3466
|
+
- \`initialState\` \u2014 optional object seeding local state (per widget instance).
|
|
3467
|
+
- \`root\` \u2014 a single node tree (see node kinds below).
|
|
3468
|
+
- optional \`title\` \u2014 card heading.
|
|
3469
|
+
|
|
3470
|
+
**Bindings:** anywhere a primitive is accepted, you may use \`{ "$bind": "dotted.path" }\` to read from \`initialState\` / local state (e.g. \`{ "$bind": "qty" }\`).
|
|
3471
|
+
|
|
3472
|
+
**Actions:** nodes may attach \`onClick\`, \`onChange\`, or \`onDragEnd\` with one action or an array:
|
|
3473
|
+
|
|
3474
|
+
| Action | Shape | Effect |
|
|
3475
|
+
|---|---|---|
|
|
3476
|
+
| User message | \`{ "kind": "message", "text": "..." }\` or \`{ "kind": "message", "text": { "$bind": "path" } }\` | Sends text as the next user message. |
|
|
3477
|
+
| Set state | \`{ "kind": "set", "path": "foo", "value": 1 }\` | Writes local widget state. |
|
|
3478
|
+
| Toggle boolean | \`{ "kind": "toggle", "path": "enabled" }\` | Flips a boolean at \`path\`. |
|
|
3479
|
+
| Host event | \`{ "kind": "emit", "name": "event-name", "payload": { ... } }\` | Bubbles to the host app (\`onArtifactEvent\` on \`<Thread>\`). |
|
|
3480
|
+
|
|
3481
|
+
### \`ui\` node palette (\`root.kind\`)
|
|
3482
|
+
|
|
3483
|
+
| \`kind\` | Purpose | Key fields |
|
|
3484
|
+
|---|---|---|
|
|
3485
|
+
| \`box\` | Layout container | \`children\`, \`direction\` (\`row\`/\`col\`), \`gap\`, \`padding\`, \`align\`, \`justify\`, \`wrap\` |
|
|
3486
|
+
| \`text\` | Body text | \`value\`, optional \`muted\`, \`size\`, \`weight\` |
|
|
3487
|
+
| \`heading\` | Heading | \`value\`, optional \`level\` (1\u20134) |
|
|
3488
|
+
| \`badge\` | Pill label | \`value\`, optional \`tone\` (\`default\`, \`primary\`, \`success\`, \`warn\`, \`danger\`) |
|
|
3489
|
+
| \`button\` | Clickable button | \`label\`, optional \`variant\`, \`size\`, \`disabled\`, \`onClick\` |
|
|
3490
|
+
| \`toggle\` | Boolean switch | \`binding\` (state path), optional \`label\`, \`onChange\` |
|
|
3491
|
+
| \`slider\` | Numeric range | \`binding\`, optional \`min\`, \`max\`, \`step\`, \`label\`, \`showValue\`, \`onChange\` |
|
|
3492
|
+
| \`tooltip\` | Hover tooltip | \`content\`, \`child\` (single node), optional \`side\` |
|
|
3493
|
+
| \`draggable\` | Drag gesture | \`child\`, optional \`axis\` (\`x\`/\`y\`/\`both\`), \`snapBack\`, \`onDragEnd\` |
|
|
3494
|
+
| \`custom\` | Host-registered widget | \`name\`, optional \`props\`, \`children\` \u2014 only if the app registered that name |
|
|
3495
|
+
|
|
3496
|
+
### Example \`ui\` artifact
|
|
3497
|
+
|
|
3498
|
+
\`\`\`json
|
|
3499
|
+
{
|
|
3500
|
+
"type": "ui",
|
|
3501
|
+
"title": "Configure plan",
|
|
3502
|
+
"initialState": { "qty": 1, "premium": false },
|
|
3503
|
+
"root": {
|
|
3504
|
+
"kind": "box",
|
|
3505
|
+
"direction": "col",
|
|
3506
|
+
"gap": 3,
|
|
3507
|
+
"children": [
|
|
3508
|
+
{ "kind": "heading", "value": "Choose quantity", "level": 3 },
|
|
3509
|
+
{
|
|
3510
|
+
"kind": "tooltip",
|
|
3511
|
+
"content": "Drag to adjust quantity",
|
|
3512
|
+
"child": {
|
|
3513
|
+
"kind": "slider",
|
|
3514
|
+
"binding": "qty",
|
|
3515
|
+
"min": 1,
|
|
3516
|
+
"max": 50,
|
|
3517
|
+
"label": "Quantity",
|
|
3518
|
+
"onChange": { "kind": "emit", "name": "qty-changed" }
|
|
3519
|
+
}
|
|
3520
|
+
},
|
|
3521
|
+
{ "kind": "toggle", "binding": "premium", "label": "Premium support" },
|
|
3522
|
+
{
|
|
3523
|
+
"kind": "button",
|
|
3524
|
+
"label": "Confirm",
|
|
3525
|
+
"onClick": { "kind": "message", "text": { "$bind": "qty" } }
|
|
3526
|
+
}
|
|
3527
|
+
]
|
|
3528
|
+
}
|
|
1554
3529
|
}
|
|
3530
|
+
\`\`\`
|
|
3531
|
+
|
|
3532
|
+
### Rules
|
|
3533
|
+
|
|
3534
|
+
- Always set \`type\` to a built-in value above unless the app documented a custom type.
|
|
3535
|
+
- Prefer \`ui\` over \`html\` when actions must bubble to the host chat (\`message\`, \`emit\`).
|
|
3536
|
+
- Prefer \`question\` for simple A/B/C choices; use \`ui\` when you need sliders, toggles, drag, or multi-control layouts.
|
|
3537
|
+
- Keep \`data\` arrays reasonably small (charts/tables).
|
|
3538
|
+
|
|
3539
|
+
### After calling an artifact tool (critical)
|
|
3540
|
+
|
|
3541
|
+
When you call a tool that returns an artifact (\`make_chart\`, \`ask_question\`, \`show_table\`, \`show_html\`, \`make_ui_demo\`, etc.):
|
|
3542
|
+
|
|
3543
|
+
1. **Do not** paste, quote, paraphrase as JSON, or fence the tool return value in your assistant message. The chat UI already renders it from the tool result.
|
|
3544
|
+
2. **Do not** emit a matching \`\`\`timbal-artifact\`\`\` block for the same payload \u2014 pick **one** channel (tool result only).
|
|
3545
|
+
3. Your follow-up text should be **empty**, or at most **one short sentence** (e.g. "Pick an option above." / "Try the controls."). Never include \`type\`, \`options\`, \`data\`, or dict/JSON syntax.
|
|
3546
|
+
4. Treat the widget as visible to the user; refer to it as "above" / "the chart" / "the choices" \u2014 never reproduce its contents.
|
|
3547
|
+
`.trim();
|
|
1555
3548
|
|
|
1556
3549
|
// src/index.ts
|
|
1557
|
-
var
|
|
3550
|
+
var import_react26 = require("@assistant-ui/react");
|
|
3551
|
+
|
|
3552
|
+
// src/hooks/use-workforces.ts
|
|
3553
|
+
var import_react24 = require("react");
|
|
3554
|
+
function useWorkforces(options = {}) {
|
|
3555
|
+
const { baseUrl = "/api", fetch: fetchFn, pickInitial } = options;
|
|
3556
|
+
const [workforces, setWorkforces] = (0, import_react24.useState)([]);
|
|
3557
|
+
const [selectedId, setSelectedId] = (0, import_react24.useState)("");
|
|
3558
|
+
const [isLoading, setIsLoading] = (0, import_react24.useState)(true);
|
|
3559
|
+
const [error, setError] = (0, import_react24.useState)(null);
|
|
3560
|
+
const fetchFnRef = (0, import_react24.useRef)(fetchFn ?? authFetch);
|
|
3561
|
+
(0, import_react24.useEffect)(() => {
|
|
3562
|
+
fetchFnRef.current = fetchFn ?? authFetch;
|
|
3563
|
+
}, [fetchFn]);
|
|
3564
|
+
const pickInitialRef = (0, import_react24.useRef)(pickInitial);
|
|
3565
|
+
(0, import_react24.useEffect)(() => {
|
|
3566
|
+
pickInitialRef.current = pickInitial;
|
|
3567
|
+
}, [pickInitial]);
|
|
3568
|
+
const load = (0, import_react24.useMemo)(() => {
|
|
3569
|
+
return async () => {
|
|
3570
|
+
setIsLoading(true);
|
|
3571
|
+
setError(null);
|
|
3572
|
+
try {
|
|
3573
|
+
const res = await fetchFnRef.current(`${baseUrl}/workforce`);
|
|
3574
|
+
if (!res.ok) throw new Error(`Failed to load workforces (${res.status})`);
|
|
3575
|
+
const data = await res.json();
|
|
3576
|
+
setWorkforces(data);
|
|
3577
|
+
setSelectedId((current) => {
|
|
3578
|
+
if (current && data.some((w) => idOf(w) === current)) return current;
|
|
3579
|
+
const initial = pickInitialRef.current?.(data) ?? data.find((w) => w.type === "agent") ?? data[0];
|
|
3580
|
+
return initial ? idOf(initial) : "";
|
|
3581
|
+
});
|
|
3582
|
+
} catch (err) {
|
|
3583
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
3584
|
+
} finally {
|
|
3585
|
+
setIsLoading(false);
|
|
3586
|
+
}
|
|
3587
|
+
};
|
|
3588
|
+
}, [baseUrl]);
|
|
3589
|
+
(0, import_react24.useEffect)(() => {
|
|
3590
|
+
load();
|
|
3591
|
+
}, [load]);
|
|
3592
|
+
const selected = (0, import_react24.useMemo)(
|
|
3593
|
+
() => workforces.find((w) => idOf(w) === selectedId),
|
|
3594
|
+
[workforces, selectedId]
|
|
3595
|
+
);
|
|
3596
|
+
return {
|
|
3597
|
+
workforces,
|
|
3598
|
+
selectedId,
|
|
3599
|
+
setSelectedId,
|
|
3600
|
+
selected,
|
|
3601
|
+
isLoading,
|
|
3602
|
+
error,
|
|
3603
|
+
refresh: load
|
|
3604
|
+
};
|
|
3605
|
+
}
|
|
3606
|
+
function idOf(item) {
|
|
3607
|
+
return item.id ?? item.uid ?? item.name ?? "";
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3610
|
+
// src/components/workforce-selector.tsx
|
|
3611
|
+
var import_lucide_react8 = require("lucide-react");
|
|
3612
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
3613
|
+
var WorkforceSelector = ({
|
|
3614
|
+
workforces,
|
|
3615
|
+
value,
|
|
3616
|
+
onChange,
|
|
3617
|
+
hideWhenSingle = true,
|
|
3618
|
+
className,
|
|
3619
|
+
placeholder = "Select agent"
|
|
3620
|
+
}) => {
|
|
3621
|
+
if (workforces.length === 0) return null;
|
|
3622
|
+
if (hideWhenSingle && workforces.length === 1) return null;
|
|
3623
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("aui-workforce-selector relative inline-flex items-center", className), children: [
|
|
3624
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3625
|
+
"select",
|
|
3626
|
+
{
|
|
3627
|
+
className: "aui-workforce-selector-input h-7 cursor-pointer appearance-none rounded-md border-none bg-transparent pr-5 pl-1.5 text-xs font-medium text-muted-foreground shadow-none outline-none ring-0 transition-colors hover:text-foreground focus:ring-0",
|
|
3628
|
+
value,
|
|
3629
|
+
onChange: (e) => onChange(e.target.value),
|
|
3630
|
+
"aria-label": placeholder,
|
|
3631
|
+
children: [
|
|
3632
|
+
!value && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: "", children: placeholder }),
|
|
3633
|
+
workforces.map((w) => {
|
|
3634
|
+
const id = idOf2(w);
|
|
3635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: id, children: w.name ?? id }, id);
|
|
3636
|
+
})
|
|
3637
|
+
]
|
|
3638
|
+
}
|
|
3639
|
+
),
|
|
3640
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.ChevronDownIcon, { className: "aui-workforce-selector-icon pointer-events-none absolute right-1 size-3 text-muted-foreground" })
|
|
3641
|
+
] });
|
|
3642
|
+
};
|
|
3643
|
+
function idOf2(item) {
|
|
3644
|
+
return item.id ?? item.uid ?? item.name ?? "";
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
// src/components/chat-shell.tsx
|
|
3648
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
3649
|
+
var TimbalChatShell = ({
|
|
3650
|
+
workforceId,
|
|
3651
|
+
brand,
|
|
3652
|
+
headerActions,
|
|
3653
|
+
hideWorkforceSelector,
|
|
3654
|
+
className,
|
|
3655
|
+
headerClassName,
|
|
3656
|
+
baseUrl,
|
|
3657
|
+
fetch: fetch2,
|
|
3658
|
+
...chatProps
|
|
3659
|
+
}) => {
|
|
3660
|
+
const {
|
|
3661
|
+
workforces,
|
|
3662
|
+
selectedId,
|
|
3663
|
+
setSelectedId
|
|
3664
|
+
} = useWorkforces({ baseUrl, fetch: fetch2 });
|
|
3665
|
+
const effectiveId = workforceId ?? selectedId;
|
|
3666
|
+
const showSelector = !hideWorkforceSelector && !workforceId && workforces.length > 0;
|
|
3667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
3668
|
+
"div",
|
|
3669
|
+
{
|
|
3670
|
+
className: cn(
|
|
3671
|
+
"aui-chat-shell flex h-screen flex-col overflow-hidden",
|
|
3672
|
+
className
|
|
3673
|
+
),
|
|
3674
|
+
children: [
|
|
3675
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
3676
|
+
"header",
|
|
3677
|
+
{
|
|
3678
|
+
className: cn(
|
|
3679
|
+
"aui-chat-shell-header flex shrink-0 items-center justify-between border-b border-border/50 bg-background/90 px-5 py-2 backdrop-blur-md",
|
|
3680
|
+
headerClassName
|
|
3681
|
+
),
|
|
3682
|
+
children: [
|
|
3683
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center", children: [
|
|
3684
|
+
brand,
|
|
3685
|
+
showSelector && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
3686
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "mx-3.5 h-3.5 w-px bg-border" }),
|
|
3687
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3688
|
+
WorkforceSelector,
|
|
3689
|
+
{
|
|
3690
|
+
workforces,
|
|
3691
|
+
value: selectedId,
|
|
3692
|
+
onChange: setSelectedId
|
|
3693
|
+
}
|
|
3694
|
+
)
|
|
3695
|
+
] })
|
|
3696
|
+
] }),
|
|
3697
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex items-center gap-0.5", children: headerActions })
|
|
3698
|
+
]
|
|
3699
|
+
}
|
|
3700
|
+
),
|
|
3701
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3702
|
+
TimbalChat,
|
|
3703
|
+
{
|
|
3704
|
+
workforceId: effectiveId,
|
|
3705
|
+
baseUrl,
|
|
3706
|
+
fetch: fetch2,
|
|
3707
|
+
className: "min-h-0 flex-1",
|
|
3708
|
+
...chatProps
|
|
3709
|
+
},
|
|
3710
|
+
effectiveId
|
|
3711
|
+
)
|
|
3712
|
+
]
|
|
3713
|
+
}
|
|
3714
|
+
);
|
|
3715
|
+
};
|
|
1558
3716
|
|
|
1559
3717
|
// src/auth/provider.tsx
|
|
1560
|
-
var
|
|
1561
|
-
var
|
|
3718
|
+
var import_react25 = require("react");
|
|
3719
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1562
3720
|
function isInsideIframe() {
|
|
1563
3721
|
try {
|
|
1564
3722
|
return typeof window !== "undefined" && window.self !== window.top;
|
|
@@ -1566,9 +3724,9 @@ function isInsideIframe() {
|
|
|
1566
3724
|
return true;
|
|
1567
3725
|
}
|
|
1568
3726
|
}
|
|
1569
|
-
var SessionContext = (0,
|
|
3727
|
+
var SessionContext = (0, import_react25.createContext)(void 0);
|
|
1570
3728
|
var useSession = () => {
|
|
1571
|
-
const context = (0,
|
|
3729
|
+
const context = (0, import_react25.useContext)(SessionContext);
|
|
1572
3730
|
if (context === void 0) {
|
|
1573
3731
|
throw new Error("useSession must be used within a SessionProvider");
|
|
1574
3732
|
}
|
|
@@ -1578,10 +3736,10 @@ var SessionProvider = ({
|
|
|
1578
3736
|
children,
|
|
1579
3737
|
enabled = true
|
|
1580
3738
|
}) => {
|
|
1581
|
-
const [user, setUser] = (0,
|
|
1582
|
-
const [loading, setLoading] = (0,
|
|
1583
|
-
const [embedded] = (0,
|
|
1584
|
-
(0,
|
|
3739
|
+
const [user, setUser] = (0, import_react25.useState)(null);
|
|
3740
|
+
const [loading, setLoading] = (0, import_react25.useState)(enabled);
|
|
3741
|
+
const [embedded] = (0, import_react25.useState)(isInsideIframe);
|
|
3742
|
+
(0, import_react25.useEffect)(() => {
|
|
1585
3743
|
if (!enabled) {
|
|
1586
3744
|
setLoading(false);
|
|
1587
3745
|
return;
|
|
@@ -1642,7 +3800,7 @@ var SessionProvider = ({
|
|
|
1642
3800
|
messageCleanup?.();
|
|
1643
3801
|
};
|
|
1644
3802
|
}, [enabled, embedded]);
|
|
1645
|
-
const logout = (0,
|
|
3803
|
+
const logout = (0, import_react25.useCallback)(() => {
|
|
1646
3804
|
clearTokens();
|
|
1647
3805
|
setUser(null);
|
|
1648
3806
|
const returnTo = encodeURIComponent(
|
|
@@ -1652,7 +3810,7 @@ var SessionProvider = ({
|
|
|
1652
3810
|
() => window.location.href = `/api/auth/login?return_to=${returnTo}`
|
|
1653
3811
|
);
|
|
1654
3812
|
}, []);
|
|
1655
|
-
return /* @__PURE__ */ (0,
|
|
3813
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1656
3814
|
SessionContext.Provider,
|
|
1657
3815
|
{
|
|
1658
3816
|
value: {
|
|
@@ -1668,8 +3826,8 @@ var SessionProvider = ({
|
|
|
1668
3826
|
};
|
|
1669
3827
|
|
|
1670
3828
|
// src/auth/guard.tsx
|
|
1671
|
-
var
|
|
1672
|
-
var
|
|
3829
|
+
var import_lucide_react9 = require("lucide-react");
|
|
3830
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1673
3831
|
var AuthGuard = ({
|
|
1674
3832
|
children,
|
|
1675
3833
|
requireAuth = false,
|
|
@@ -1680,7 +3838,7 @@ var AuthGuard = ({
|
|
|
1680
3838
|
return children;
|
|
1681
3839
|
}
|
|
1682
3840
|
if (loading) {
|
|
1683
|
-
return /* @__PURE__ */ (0,
|
|
3841
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react9.Loader2, { className: "w-8 h-8 animate-spin" }) });
|
|
1684
3842
|
}
|
|
1685
3843
|
if (requireAuth && !isAuthenticated && !isEmbedded) {
|
|
1686
3844
|
const returnTo = encodeURIComponent(
|
|
@@ -1693,15 +3851,24 @@ var AuthGuard = ({
|
|
|
1693
3851
|
};
|
|
1694
3852
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1695
3853
|
0 && (module.exports = {
|
|
3854
|
+
ARTIFACT_AGENT_INSTRUCTIONS,
|
|
3855
|
+
ARTIFACT_FENCE_LANGUAGES,
|
|
1696
3856
|
ActionBarPrimitive,
|
|
3857
|
+
ArtifactCard,
|
|
3858
|
+
ArtifactRegistryProvider,
|
|
3859
|
+
ArtifactView,
|
|
3860
|
+
AssistantRuntimeProvider,
|
|
1697
3861
|
AuthGuard,
|
|
1698
3862
|
Avatar,
|
|
1699
3863
|
AvatarFallback,
|
|
1700
3864
|
AvatarImage,
|
|
1701
3865
|
Button,
|
|
3866
|
+
ChartArtifactView,
|
|
3867
|
+
Composer,
|
|
1702
3868
|
ComposerAddAttachment,
|
|
1703
3869
|
ComposerAttachments,
|
|
1704
3870
|
ComposerPrimitive,
|
|
3871
|
+
DEFAULT_UPLOAD_ACCEPT,
|
|
1705
3872
|
Dialog,
|
|
1706
3873
|
DialogClose,
|
|
1707
3874
|
DialogContent,
|
|
@@ -1709,35 +3876,70 @@ var AuthGuard = ({
|
|
|
1709
3876
|
DialogPortal,
|
|
1710
3877
|
DialogTitle,
|
|
1711
3878
|
DialogTrigger,
|
|
3879
|
+
HtmlArtifactView,
|
|
3880
|
+
JsonArtifactView,
|
|
1712
3881
|
MarkdownText,
|
|
1713
3882
|
MessagePrimitive,
|
|
3883
|
+
QuestionArtifactView,
|
|
1714
3884
|
SessionProvider,
|
|
1715
3885
|
Shimmer,
|
|
3886
|
+
Suggestions,
|
|
1716
3887
|
SyntaxHighlighter,
|
|
3888
|
+
TableArtifactView,
|
|
1717
3889
|
Thread,
|
|
1718
3890
|
ThreadPrimitive,
|
|
1719
3891
|
TimbalChat,
|
|
3892
|
+
TimbalChatShell,
|
|
1720
3893
|
TimbalRuntimeProvider,
|
|
3894
|
+
ToolArtifactFallback,
|
|
1721
3895
|
ToolFallback,
|
|
1722
3896
|
Tooltip,
|
|
1723
3897
|
TooltipContent,
|
|
1724
3898
|
TooltipIconButton,
|
|
1725
3899
|
TooltipProvider,
|
|
1726
3900
|
TooltipTrigger,
|
|
3901
|
+
UiArtifactView,
|
|
3902
|
+
UiCustomNodeRegistryProvider,
|
|
3903
|
+
UiEventProvider,
|
|
3904
|
+
UiNodeView,
|
|
1727
3905
|
UserMessageAttachments,
|
|
3906
|
+
WorkforceSelector,
|
|
1728
3907
|
authFetch,
|
|
1729
3908
|
buttonVariants,
|
|
1730
3909
|
clearTokens,
|
|
1731
3910
|
cn,
|
|
3911
|
+
createDefaultAttachmentAdapter,
|
|
3912
|
+
createUploadAttachmentAdapter,
|
|
3913
|
+
defaultArtifactRenderers,
|
|
1732
3914
|
fetchCurrentUser,
|
|
3915
|
+
findMarkdownArtifacts,
|
|
1733
3916
|
getAccessToken,
|
|
3917
|
+
getPath,
|
|
1734
3918
|
getRefreshToken,
|
|
3919
|
+
isArtifact,
|
|
3920
|
+
isArtifactFenceLanguage,
|
|
3921
|
+
isUiBinding,
|
|
3922
|
+
parseArtifactFromToolResult,
|
|
3923
|
+
parseSSELine,
|
|
1735
3924
|
refreshAccessToken,
|
|
3925
|
+
resolveAttachmentAdapter,
|
|
3926
|
+
resolveBindable,
|
|
1736
3927
|
setAccessToken,
|
|
3928
|
+
setPath,
|
|
1737
3929
|
setRefreshToken,
|
|
3930
|
+
splitMarkdownByArtifacts,
|
|
3931
|
+
useArtifactRegistry,
|
|
1738
3932
|
useComposerRuntime,
|
|
1739
3933
|
useMessageRuntime,
|
|
3934
|
+
useResolvedSuggestions,
|
|
1740
3935
|
useSession,
|
|
1741
3936
|
useThread,
|
|
1742
|
-
useThreadRuntime
|
|
3937
|
+
useThreadRuntime,
|
|
3938
|
+
useTimbalRuntime,
|
|
3939
|
+
useTimbalStream,
|
|
3940
|
+
useUiCustomNodeRegistry,
|
|
3941
|
+
useUiDispatch,
|
|
3942
|
+
useUiEventEmitter,
|
|
3943
|
+
useUiState,
|
|
3944
|
+
useWorkforces
|
|
1743
3945
|
});
|