@timbal-ai/timbal-react 0.2.2 → 0.4.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 +3323 -511
- package/dist/index.d.cts +1000 -31
- package/dist/index.d.ts +1000 -31
- package/dist/index.esm.js +3252 -509
- package/dist/styles.css +180 -0
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -30,15 +30,26 @@ 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
|
+
ActionBarMorePrimitive: () => import_react29.ActionBarMorePrimitive,
|
|
36
|
+
ActionBarPrimitive: () => import_react29.ActionBarPrimitive,
|
|
37
|
+
ArtifactCard: () => ArtifactCard,
|
|
38
|
+
ArtifactRegistryProvider: () => ArtifactRegistryProvider,
|
|
39
|
+
ArtifactView: () => ArtifactView,
|
|
40
|
+
AssistantRuntimeProvider: () => import_react29.AssistantRuntimeProvider,
|
|
41
|
+
AuiIf: () => import_react29.AuiIf,
|
|
34
42
|
AuthGuard: () => AuthGuard,
|
|
35
43
|
Avatar: () => Avatar,
|
|
36
44
|
AvatarFallback: () => AvatarFallback,
|
|
37
45
|
AvatarImage: () => AvatarImage,
|
|
38
46
|
Button: () => Button,
|
|
47
|
+
ChartArtifactView: () => ChartArtifactView,
|
|
48
|
+
Composer: () => Composer,
|
|
39
49
|
ComposerAddAttachment: () => ComposerAddAttachment,
|
|
40
50
|
ComposerAttachments: () => ComposerAttachments,
|
|
41
|
-
ComposerPrimitive: () =>
|
|
51
|
+
ComposerPrimitive: () => import_react29.ComposerPrimitive,
|
|
52
|
+
DEFAULT_UPLOAD_ACCEPT: () => DEFAULT_UPLOAD_ACCEPT,
|
|
42
53
|
Dialog: () => Dialog,
|
|
43
54
|
DialogClose: () => DialogClose,
|
|
44
55
|
DialogContent: () => DialogContent,
|
|
@@ -46,37 +57,121 @@ __export(index_exports, {
|
|
|
46
57
|
DialogPortal: () => DialogPortal,
|
|
47
58
|
DialogTitle: () => DialogTitle,
|
|
48
59
|
DialogTrigger: () => DialogTrigger,
|
|
60
|
+
ErrorPrimitive: () => import_react29.ErrorPrimitive,
|
|
61
|
+
HtmlArtifactView: () => HtmlArtifactView,
|
|
62
|
+
JsonArtifactView: () => JsonArtifactView,
|
|
49
63
|
MarkdownText: () => MarkdownText,
|
|
50
|
-
|
|
64
|
+
MessagePartPrimitive: () => import_react29.MessagePartPrimitive,
|
|
65
|
+
MessagePrimitive: () => import_react29.MessagePrimitive,
|
|
66
|
+
QuestionArtifactView: () => QuestionArtifactView,
|
|
67
|
+
STUDIO_INSET_LEFT: () => STUDIO_INSET_LEFT,
|
|
68
|
+
STUDIO_PILL_HEIGHT: () => STUDIO_PILL_HEIGHT,
|
|
69
|
+
STUDIO_SIDEBAR_GAP: () => STUDIO_SIDEBAR_GAP,
|
|
70
|
+
STUDIO_SIDEBAR_WIDTH: () => STUDIO_SIDEBAR_WIDTH,
|
|
71
|
+
STUDIO_TOPBAR_GAP: () => STUDIO_TOPBAR_GAP,
|
|
72
|
+
STUDIO_TOPBAR_HEIGHT: () => STUDIO_TOPBAR_HEIGHT,
|
|
51
73
|
SessionProvider: () => SessionProvider,
|
|
52
74
|
Shimmer: () => Shimmer,
|
|
75
|
+
Suggestions: () => Suggestions,
|
|
53
76
|
SyntaxHighlighter: () => syntax_highlighter_default,
|
|
77
|
+
TIMBAL_V2_BORDER: () => TIMBAL_V2_BORDER,
|
|
78
|
+
TIMBAL_V2_FILL: () => TIMBAL_V2_FILL,
|
|
79
|
+
TIMBAL_V2_LABEL: () => TIMBAL_V2_LABEL,
|
|
80
|
+
TIMBAL_V2_PILL_SURFACE: () => TIMBAL_V2_PILL_SURFACE,
|
|
81
|
+
TIMBAL_V2_SECONDARY_CHROME: () => TIMBAL_V2_SECONDARY_CHROME,
|
|
82
|
+
TIMBAL_V2_SHADOW: () => TIMBAL_V2_SHADOW,
|
|
83
|
+
TIMBAL_V2_SIZE_HEIGHT: () => TIMBAL_V2_SIZE_HEIGHT,
|
|
84
|
+
TIMBAL_V2_SIZE_ICON: () => TIMBAL_V2_SIZE_ICON,
|
|
85
|
+
TIMBAL_V2_SIZE_LABEL_PX: () => TIMBAL_V2_SIZE_LABEL_PX,
|
|
86
|
+
TableArtifactView: () => TableArtifactView,
|
|
54
87
|
Thread: () => Thread,
|
|
55
|
-
ThreadPrimitive: () =>
|
|
88
|
+
ThreadPrimitive: () => import_react29.ThreadPrimitive,
|
|
56
89
|
TimbalChat: () => TimbalChat,
|
|
90
|
+
TimbalChatShell: () => TimbalChatShell,
|
|
57
91
|
TimbalRuntimeProvider: () => TimbalRuntimeProvider,
|
|
92
|
+
TimbalV2Button: () => TimbalV2Button,
|
|
93
|
+
ToolArtifactFallback: () => ToolArtifactFallback,
|
|
94
|
+
ToolBodyPresence: () => ToolBodyPresence,
|
|
58
95
|
ToolFallback: () => ToolFallback,
|
|
96
|
+
ToolMotion: () => ToolMotion,
|
|
97
|
+
ToolPresence: () => ToolPresence,
|
|
59
98
|
Tooltip: () => Tooltip,
|
|
60
99
|
TooltipContent: () => TooltipContent,
|
|
61
100
|
TooltipIconButton: () => TooltipIconButton,
|
|
62
101
|
TooltipProvider: () => TooltipProvider,
|
|
63
102
|
TooltipTrigger: () => TooltipTrigger,
|
|
103
|
+
UiArtifactView: () => UiArtifactView,
|
|
104
|
+
UiCustomNodeRegistryProvider: () => UiCustomNodeRegistryProvider,
|
|
105
|
+
UiEventProvider: () => UiEventProvider,
|
|
106
|
+
UiNodeView: () => UiNodeView,
|
|
64
107
|
UserMessageAttachments: () => UserMessageAttachments,
|
|
108
|
+
WorkforceSelector: () => WorkforceSelector,
|
|
65
109
|
authFetch: () => authFetch,
|
|
66
110
|
buttonVariants: () => buttonVariants,
|
|
67
111
|
clearTokens: () => clearTokens,
|
|
68
112
|
cn: () => cn,
|
|
113
|
+
createDefaultAttachmentAdapter: () => createDefaultAttachmentAdapter,
|
|
114
|
+
createUploadAttachmentAdapter: () => createUploadAttachmentAdapter,
|
|
115
|
+
defaultArtifactRenderers: () => defaultArtifactRenderers,
|
|
69
116
|
fetchCurrentUser: () => fetchCurrentUser,
|
|
117
|
+
findMarkdownArtifacts: () => findMarkdownArtifacts,
|
|
70
118
|
getAccessToken: () => getAccessToken,
|
|
119
|
+
getPath: () => getPath,
|
|
71
120
|
getRefreshToken: () => getRefreshToken,
|
|
121
|
+
isArtifact: () => isArtifact,
|
|
122
|
+
isArtifactFenceLanguage: () => isArtifactFenceLanguage,
|
|
123
|
+
isUiBinding: () => isUiBinding,
|
|
124
|
+
luxuryEase: () => luxuryEase,
|
|
125
|
+
parseArtifactFromToolResult: () => parseArtifactFromToolResult,
|
|
126
|
+
parseSSELine: () => import_timbal_sdk2.parseSSELine,
|
|
72
127
|
refreshAccessToken: () => refreshAccessToken,
|
|
128
|
+
resolveAttachmentAdapter: () => resolveAttachmentAdapter,
|
|
129
|
+
resolveBindable: () => resolveBindable,
|
|
73
130
|
setAccessToken: () => setAccessToken,
|
|
131
|
+
setPath: () => setPath,
|
|
74
132
|
setRefreshToken: () => setRefreshToken,
|
|
75
|
-
|
|
76
|
-
|
|
133
|
+
splitMarkdownByArtifacts: () => splitMarkdownByArtifacts,
|
|
134
|
+
studioArtifactShellClass: () => studioArtifactShellClass,
|
|
135
|
+
studioChromeShellStyle: () => studioChromeShellStyle,
|
|
136
|
+
studioComposeInputShellClass: () => studioComposeInputShellClass,
|
|
137
|
+
studioComposerIoWellClass: () => studioComposerIoWellClass,
|
|
138
|
+
studioIntegrationBorder: () => studioIntegrationBorder,
|
|
139
|
+
studioIntegrationCardClass: () => studioIntegrationCardClass,
|
|
140
|
+
studioIntegrationIconTileClass: () => studioIntegrationIconTileClass,
|
|
141
|
+
studioIntegrationSurfaceSolid: () => studioIntegrationSurfaceSolid,
|
|
142
|
+
studioListRowButtonClass: () => studioListRowButtonClass,
|
|
143
|
+
studioPillSurfaceClass: () => studioPillSurfaceClass,
|
|
144
|
+
studioPlaygroundGradientClass: () => studioPlaygroundGradientClass,
|
|
145
|
+
studioQuestionOptionClass: () => studioQuestionOptionClass,
|
|
146
|
+
studioQuestionOptionSelectedClass: () => studioQuestionOptionSelectedClass,
|
|
147
|
+
studioSecondaryChromeClass: () => studioSecondaryChromeClass,
|
|
148
|
+
studioTimelineActionClass: () => studioTimelineActionClass,
|
|
149
|
+
studioTimelineBodyPadClass: () => studioTimelineBodyPadClass,
|
|
150
|
+
studioTimelineChevronClass: () => studioTimelineChevronClass,
|
|
151
|
+
studioTimelineDetailClass: () => studioTimelineDetailClass,
|
|
152
|
+
studioTimelineRowButtonClass: () => studioTimelineRowButtonClass,
|
|
153
|
+
studioTimelineShimmerActionClass: () => studioTimelineShimmerActionClass,
|
|
154
|
+
studioTimelineTextClass: () => studioTimelineTextClass,
|
|
155
|
+
studioToolCardShellClass: () => studioToolCardShellClass,
|
|
156
|
+
studioTopbarIconPillClass: () => studioTopbarIconPillClass,
|
|
157
|
+
studioTopbarPillHeightClass: () => studioTopbarPillHeightClass,
|
|
158
|
+
toolPresenceTransition: () => toolPresenceTransition,
|
|
159
|
+
useArtifactRegistry: () => useArtifactRegistry,
|
|
160
|
+
useAuiState: () => import_react29.useAuiState,
|
|
161
|
+
useComposerRuntime: () => import_react29.useComposerRuntime,
|
|
162
|
+
useMessageRuntime: () => import_react29.useMessageRuntime,
|
|
163
|
+
useResolvedSuggestions: () => useResolvedSuggestions,
|
|
77
164
|
useSession: () => useSession,
|
|
78
|
-
useThread: () =>
|
|
79
|
-
useThreadRuntime: () =>
|
|
165
|
+
useThread: () => import_react29.useThread,
|
|
166
|
+
useThreadRuntime: () => import_react29.useThreadRuntime,
|
|
167
|
+
useTimbalRuntime: () => useTimbalRuntime,
|
|
168
|
+
useTimbalStream: () => useTimbalStream,
|
|
169
|
+
useToolRunning: () => useToolRunning,
|
|
170
|
+
useUiCustomNodeRegistry: () => useUiCustomNodeRegistry,
|
|
171
|
+
useUiDispatch: () => useUiDispatch,
|
|
172
|
+
useUiEventEmitter: () => useUiEventEmitter,
|
|
173
|
+
useUiState: () => useUiState,
|
|
174
|
+
useWorkforces: () => useWorkforces
|
|
80
175
|
});
|
|
81
176
|
module.exports = __toCommonJS(index_exports);
|
|
82
177
|
|
|
@@ -166,13 +261,506 @@ var fetchCurrentUser = async () => {
|
|
|
166
261
|
}
|
|
167
262
|
};
|
|
168
263
|
|
|
264
|
+
// src/artifacts/types.ts
|
|
265
|
+
function isArtifact(value) {
|
|
266
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.type === "string";
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// src/runtime/reducer.ts
|
|
270
|
+
function createReducerState() {
|
|
271
|
+
return { parts: [], toolIndexById: /* @__PURE__ */ new Map() };
|
|
272
|
+
}
|
|
273
|
+
function reduceSseEvent(state, event) {
|
|
274
|
+
switch (event.type) {
|
|
275
|
+
case "DELTA":
|
|
276
|
+
return reduceDelta(state, event.item);
|
|
277
|
+
case "OUTPUT": {
|
|
278
|
+
const path = event.path;
|
|
279
|
+
const isNested = typeof path === "string" && path.includes(".");
|
|
280
|
+
if (!isNested) {
|
|
281
|
+
const errorMessage = readErrorMessage(event);
|
|
282
|
+
if (errorMessage) {
|
|
283
|
+
state.parts.push({ type: "text", text: `**Error:** ${errorMessage}` });
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (isNested) {
|
|
288
|
+
return reduceNestedOutput(
|
|
289
|
+
state,
|
|
290
|
+
path,
|
|
291
|
+
event.output
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
return reduceOutput(
|
|
295
|
+
state,
|
|
296
|
+
event.output
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
default:
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function reduceDelta(state, item) {
|
|
304
|
+
if (!item) return false;
|
|
305
|
+
if (item.type === "text_delta" && typeof item.text_delta === "string") {
|
|
306
|
+
lastTextPart(state).text += item.text_delta;
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
if (item.type === "thinking_delta" && typeof item.thinking_delta === "string") {
|
|
310
|
+
lastThinkingPart(state).text += item.thinking_delta;
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
if (item.type === "tool_use") {
|
|
314
|
+
const toolCallId = item.id || `tool-${crypto.randomUUID()}`;
|
|
315
|
+
const inputStr = stringifyInput(item.input);
|
|
316
|
+
const part = {
|
|
317
|
+
type: "tool-call",
|
|
318
|
+
toolCallId,
|
|
319
|
+
toolName: item.name || "unknown",
|
|
320
|
+
argsText: inputStr,
|
|
321
|
+
status: "running"
|
|
322
|
+
};
|
|
323
|
+
state.parts.push(part);
|
|
324
|
+
state.toolIndexById.set(toolCallId, state.parts.length - 1);
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
if (item.type === "tool_use_delta") {
|
|
328
|
+
const idx = state.toolIndexById.get(item.id);
|
|
329
|
+
if (idx !== void 0 && typeof item.input_delta === "string") {
|
|
330
|
+
state.parts[idx].argsText += item.input_delta;
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
function reduceNestedOutput(state, path, output) {
|
|
337
|
+
if (!output || typeof output !== "object") return false;
|
|
338
|
+
if (!Array.isArray(output.content) && isArtifact(output)) {
|
|
339
|
+
const toolName = toolNameFromPath(path);
|
|
340
|
+
if (toolName && attachToolResult(state, { toolName, result: output })) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return reduceOutput(state, output, { toolResultsOnly: true, allowOrphan: false });
|
|
345
|
+
}
|
|
346
|
+
function reduceOutput(state, output, options) {
|
|
347
|
+
if (!output) return false;
|
|
348
|
+
if (typeof output === "string") {
|
|
349
|
+
if (state.parts.length === 0) {
|
|
350
|
+
state.parts.push({ type: "text", text: output });
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
if (Array.isArray(output.content)) {
|
|
356
|
+
let changed = false;
|
|
357
|
+
const blocks = output.content;
|
|
358
|
+
for (const block of blocks) {
|
|
359
|
+
if (block.type === "tool_use") {
|
|
360
|
+
if (!options?.toolResultsOnly && recordToolUse(state, block)) {
|
|
361
|
+
changed = true;
|
|
362
|
+
}
|
|
363
|
+
} else if (block.type === "tool_result") {
|
|
364
|
+
if (recordToolResult(state, block, options)) changed = true;
|
|
365
|
+
} else if (!options?.toolResultsOnly) {
|
|
366
|
+
if (block.type === "text" && typeof block.text === "string" && !lastTextPart(state).text) {
|
|
367
|
+
lastTextPart(state).text = block.text;
|
|
368
|
+
changed = true;
|
|
369
|
+
} else if (block.type === "thinking" && typeof block.thinking === "string" && !lastThinkingPart(state).text) {
|
|
370
|
+
lastThinkingPart(state).text = block.thinking;
|
|
371
|
+
changed = true;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return changed;
|
|
376
|
+
}
|
|
377
|
+
if (state.parts.length === 0) {
|
|
378
|
+
state.parts.push({ type: "text", text: JSON.stringify(output) });
|
|
379
|
+
return true;
|
|
380
|
+
}
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
function recordToolUse(state, block) {
|
|
384
|
+
const id = block.id || `tool-${crypto.randomUUID()}`;
|
|
385
|
+
if (state.toolIndexById.has(id)) return false;
|
|
386
|
+
const inputStr = stringifyInput(block.input);
|
|
387
|
+
const part = {
|
|
388
|
+
type: "tool-call",
|
|
389
|
+
toolCallId: id,
|
|
390
|
+
toolName: block.name || "unknown",
|
|
391
|
+
argsText: inputStr,
|
|
392
|
+
status: "running"
|
|
393
|
+
};
|
|
394
|
+
state.parts.push(part);
|
|
395
|
+
state.toolIndexById.set(id, state.parts.length - 1);
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
function recordToolResult(state, block, options) {
|
|
399
|
+
const allowOrphan = options?.allowOrphan !== false;
|
|
400
|
+
const id = block.id || block.tool_use_id || "";
|
|
401
|
+
const { result, resultText } = parseToolResultContent(block.content);
|
|
402
|
+
const toolName = block.name || void 0;
|
|
403
|
+
if (id) {
|
|
404
|
+
const idx = state.toolIndexById.get(id);
|
|
405
|
+
if (idx !== void 0) {
|
|
406
|
+
const part2 = state.parts[idx];
|
|
407
|
+
part2.result = result;
|
|
408
|
+
if (resultText) part2.resultText = resultText;
|
|
409
|
+
part2.status = "complete";
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
if (!allowOrphan) return false;
|
|
413
|
+
}
|
|
414
|
+
if (!id && toolName && attachToolResult(state, {
|
|
415
|
+
toolName,
|
|
416
|
+
result,
|
|
417
|
+
resultText
|
|
418
|
+
})) {
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
if (!id || !allowOrphan) return false;
|
|
422
|
+
const part = {
|
|
423
|
+
type: "tool-call",
|
|
424
|
+
toolCallId: id,
|
|
425
|
+
toolName: toolName || "unknown",
|
|
426
|
+
argsText: "",
|
|
427
|
+
result,
|
|
428
|
+
resultText,
|
|
429
|
+
status: "complete"
|
|
430
|
+
};
|
|
431
|
+
state.parts.push(part);
|
|
432
|
+
state.toolIndexById.set(id, state.parts.length - 1);
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
function toolNameFromPath(path) {
|
|
436
|
+
const segment = path.split(".").pop();
|
|
437
|
+
return segment && segment !== "agent" && segment !== "llm" ? segment : null;
|
|
438
|
+
}
|
|
439
|
+
function attachToolResult(state, {
|
|
440
|
+
toolCallId,
|
|
441
|
+
toolName,
|
|
442
|
+
result,
|
|
443
|
+
resultText
|
|
444
|
+
}) {
|
|
445
|
+
if (toolCallId) {
|
|
446
|
+
const idx = state.toolIndexById.get(toolCallId);
|
|
447
|
+
if (idx !== void 0) {
|
|
448
|
+
const part = state.parts[idx];
|
|
449
|
+
part.result = result;
|
|
450
|
+
if (resultText) part.resultText = resultText;
|
|
451
|
+
part.status = "complete";
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (toolName) {
|
|
456
|
+
for (let i = state.parts.length - 1; i >= 0; i--) {
|
|
457
|
+
const part = state.parts[i];
|
|
458
|
+
if (part.type === "tool-call" && part.toolName === toolName && part.result === void 0) {
|
|
459
|
+
part.result = result;
|
|
460
|
+
if (resultText) part.resultText = resultText;
|
|
461
|
+
part.status = "complete";
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
function parseToolResultContent(content) {
|
|
469
|
+
if (typeof content === "string") {
|
|
470
|
+
return { result: content, resultText: content };
|
|
471
|
+
}
|
|
472
|
+
if (!Array.isArray(content)) {
|
|
473
|
+
return { result: content };
|
|
474
|
+
}
|
|
475
|
+
const textChunks = [];
|
|
476
|
+
for (const item of content) {
|
|
477
|
+
if (typeof item === "string") {
|
|
478
|
+
textChunks.push(item);
|
|
479
|
+
} else if (item && typeof item === "object") {
|
|
480
|
+
const obj = item;
|
|
481
|
+
if (obj.type === "text" && typeof obj.text === "string") {
|
|
482
|
+
textChunks.push(obj.text);
|
|
483
|
+
} else if (obj.type === "thinking" && typeof obj.thinking === "string") {
|
|
484
|
+
textChunks.push(obj.thinking);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
result: content,
|
|
490
|
+
resultText: textChunks.length > 0 ? textChunks.join("\n") : void 0
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
function readErrorMessage(event) {
|
|
494
|
+
const status = event.status;
|
|
495
|
+
const isErrorStatus = status?.code === "error";
|
|
496
|
+
const error = event.error;
|
|
497
|
+
let type = null;
|
|
498
|
+
let message = null;
|
|
499
|
+
if (isErrorStatus && typeof status?.message === "string" && status.message.length > 0) {
|
|
500
|
+
message = status.message;
|
|
501
|
+
}
|
|
502
|
+
if (!message && typeof error === "string" && error.length > 0) {
|
|
503
|
+
message = error;
|
|
504
|
+
} else if (error && typeof error === "object") {
|
|
505
|
+
const obj = error;
|
|
506
|
+
if (typeof obj.type === "string" && obj.type.length > 0) {
|
|
507
|
+
type = obj.type;
|
|
508
|
+
}
|
|
509
|
+
if (!message && typeof obj.message === "string" && obj.message.length > 0) {
|
|
510
|
+
message = obj.message;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (!message && !isErrorStatus) return null;
|
|
514
|
+
if (!message) return "The agent failed to generate a response.";
|
|
515
|
+
const compact = compactError(message);
|
|
516
|
+
return type ? `${type}: ${compact}` : compact;
|
|
517
|
+
}
|
|
518
|
+
var ERROR_MAX_CHARS = 480;
|
|
519
|
+
function compactError(message) {
|
|
520
|
+
const trimmed = message.split(/\n\s*Traceback \(most recent call last\):/u)[0].trim();
|
|
521
|
+
if (trimmed.length <= ERROR_MAX_CHARS) return trimmed;
|
|
522
|
+
return `${trimmed.slice(0, ERROR_MAX_CHARS).trimEnd()}\u2026`;
|
|
523
|
+
}
|
|
524
|
+
function stringifyInput(input) {
|
|
525
|
+
if (input === void 0 || input === null) return "{}";
|
|
526
|
+
return typeof input === "string" ? input : JSON.stringify(input);
|
|
527
|
+
}
|
|
528
|
+
function lastTextPart(state) {
|
|
529
|
+
const last = state.parts[state.parts.length - 1];
|
|
530
|
+
if (last?.type === "text") return last;
|
|
531
|
+
const next = { type: "text", text: "" };
|
|
532
|
+
state.parts.push(next);
|
|
533
|
+
return next;
|
|
534
|
+
}
|
|
535
|
+
function lastThinkingPart(state) {
|
|
536
|
+
const last = state.parts[state.parts.length - 1];
|
|
537
|
+
if (last?.type === "thinking") return last;
|
|
538
|
+
const next = { type: "thinking", text: "" };
|
|
539
|
+
state.parts.push(next);
|
|
540
|
+
return next;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// src/runtime/attachments.ts
|
|
544
|
+
async function extractAttachment(attachment) {
|
|
545
|
+
const file = attachment.file;
|
|
546
|
+
let src = null;
|
|
547
|
+
let contentType;
|
|
548
|
+
let name = attachment.name ?? file?.name;
|
|
549
|
+
const content = attachment.content;
|
|
550
|
+
if (content) {
|
|
551
|
+
for (const block of content) {
|
|
552
|
+
if (block.type === "image" && typeof block.image === "string") {
|
|
553
|
+
src = block.image;
|
|
554
|
+
if (typeof block.mimeType === "string") {
|
|
555
|
+
contentType = block.mimeType;
|
|
556
|
+
}
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
if (block.type === "file" && typeof block.data === "string") {
|
|
560
|
+
src = block.data;
|
|
561
|
+
if (typeof block.mimeType === "string") contentType = block.mimeType;
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
if (src === null && file) {
|
|
567
|
+
src = await fileToDataUrl(file);
|
|
568
|
+
if (!contentType) contentType = file.type || void 0;
|
|
569
|
+
if (!name) name = file.name;
|
|
570
|
+
}
|
|
571
|
+
if (!src) return null;
|
|
572
|
+
if (!contentType) contentType = mimeFromDataUrl(src);
|
|
573
|
+
const rawType = String(attachment.type ?? "file");
|
|
574
|
+
const type = rawType === "image" || rawType === "document" ? rawType : "file";
|
|
575
|
+
return {
|
|
576
|
+
id: attachment.id ?? crypto.randomUUID(),
|
|
577
|
+
type,
|
|
578
|
+
...name !== void 0 ? { name } : {},
|
|
579
|
+
...contentType !== void 0 ? { contentType } : {},
|
|
580
|
+
dataUrl: src
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
function fileToDataUrl(file) {
|
|
584
|
+
return new Promise((resolve, reject) => {
|
|
585
|
+
const reader = new FileReader();
|
|
586
|
+
reader.onload = () => resolve(reader.result);
|
|
587
|
+
reader.onerror = () => reject(reader.error);
|
|
588
|
+
reader.readAsDataURL(file);
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
function mimeFromDataUrl(dataUrl) {
|
|
592
|
+
const match = /^data:([^;,]+)[;,]/.exec(dataUrl);
|
|
593
|
+
return match?.[1];
|
|
594
|
+
}
|
|
595
|
+
function buildPromptBody({
|
|
596
|
+
input,
|
|
597
|
+
attachments,
|
|
598
|
+
parentId
|
|
599
|
+
}) {
|
|
600
|
+
const context = { parent_id: parentId };
|
|
601
|
+
const files = attachments ?? [];
|
|
602
|
+
if (files.length === 0) {
|
|
603
|
+
return { prompt: input, context };
|
|
604
|
+
}
|
|
605
|
+
const parts = [];
|
|
606
|
+
if (input) parts.push({ type: "text", text: input });
|
|
607
|
+
for (const attachment of files) {
|
|
608
|
+
parts.push({ type: "file", file: attachment.dataUrl });
|
|
609
|
+
}
|
|
610
|
+
return { prompt: parts, context };
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/runtime/upload-adapter.ts
|
|
614
|
+
var DEFAULT_UPLOAD_ACCEPT = "image/*,application/pdf,text/*,.md,.json,.csv,.tsv,.xlsx,.docx";
|
|
615
|
+
function createDefaultAttachmentAdapter({
|
|
616
|
+
baseUrl = "",
|
|
617
|
+
uploadUrl,
|
|
618
|
+
fetch: fetchFn = authFetch,
|
|
619
|
+
accept = DEFAULT_UPLOAD_ACCEPT
|
|
620
|
+
} = {}) {
|
|
621
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
622
|
+
const resolvedUploadUrl = uploadUrl ?? `${base}/files/upload`;
|
|
623
|
+
return {
|
|
624
|
+
accept,
|
|
625
|
+
async add({ file }) {
|
|
626
|
+
const isImage = file.type.startsWith("image/");
|
|
627
|
+
const pending = {
|
|
628
|
+
id: crypto.randomUUID(),
|
|
629
|
+
type: isImage ? "image" : "file",
|
|
630
|
+
name: file.name,
|
|
631
|
+
contentType: file.type || "application/octet-stream",
|
|
632
|
+
file,
|
|
633
|
+
status: { type: "requires-action", reason: "composer-send" }
|
|
634
|
+
};
|
|
635
|
+
return pending;
|
|
636
|
+
},
|
|
637
|
+
async send(attachment) {
|
|
638
|
+
const fd = new FormData();
|
|
639
|
+
fd.append("file", attachment.file);
|
|
640
|
+
const res = await fetchFn(resolvedUploadUrl, { method: "POST", body: fd });
|
|
641
|
+
if (!res.ok) {
|
|
642
|
+
const detail = await res.text().catch(() => "");
|
|
643
|
+
throw new Error(
|
|
644
|
+
`Attachment upload failed (${res.status}): ${detail || res.statusText}`
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
const remoteUrl = await readUploadedUrl(res);
|
|
648
|
+
const mime = attachment.contentType ?? "application/octet-stream";
|
|
649
|
+
const filename = attachment.name;
|
|
650
|
+
const complete = {
|
|
651
|
+
...attachment,
|
|
652
|
+
status: { type: "complete" },
|
|
653
|
+
content: mime.startsWith("image/") ? [{ type: "image", image: remoteUrl, filename }] : [{ type: "file", data: remoteUrl, mimeType: mime, filename }]
|
|
654
|
+
};
|
|
655
|
+
return complete;
|
|
656
|
+
},
|
|
657
|
+
async remove() {
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
var createUploadAttachmentAdapter = createDefaultAttachmentAdapter;
|
|
662
|
+
async function readUploadedUrl(res) {
|
|
663
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
664
|
+
if (contentType.includes("application/json")) {
|
|
665
|
+
const data = await res.json();
|
|
666
|
+
const candidate = data.url ?? data.signed_url ?? data.id;
|
|
667
|
+
if (typeof candidate === "string" && candidate.length > 0) {
|
|
668
|
+
return candidate;
|
|
669
|
+
}
|
|
670
|
+
throw new Error(
|
|
671
|
+
"Attachment upload response did not include a `url`, `signed_url`, or `id` field."
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
const text = (await res.text()).trim();
|
|
675
|
+
if (!text) {
|
|
676
|
+
throw new Error("Attachment upload response was empty.");
|
|
677
|
+
}
|
|
678
|
+
return text;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// src/runtime/resolve-attachments.ts
|
|
682
|
+
function isAttachmentAdapter(value) {
|
|
683
|
+
return typeof value === "object" && value !== null && "accept" in value && typeof value.add === "function" && typeof value.send === "function" && typeof value.remove === "function";
|
|
684
|
+
}
|
|
685
|
+
function resolveAttachmentAdapter(attachments, options = {}) {
|
|
686
|
+
const baseUrl = options.baseUrl ?? "/api";
|
|
687
|
+
const legacyUploadUrl = options.uploadUrl;
|
|
688
|
+
const legacyAccept = options.accept;
|
|
689
|
+
if (attachments === null) return void 0;
|
|
690
|
+
const legacyEnables = legacyUploadUrl !== void 0 || legacyAccept !== void 0;
|
|
691
|
+
if (attachments === void 0) {
|
|
692
|
+
if (!legacyEnables) return void 0;
|
|
693
|
+
return createDefaultAttachmentAdapter({
|
|
694
|
+
baseUrl,
|
|
695
|
+
fetch: options.fetch,
|
|
696
|
+
uploadUrl: legacyUploadUrl,
|
|
697
|
+
accept: legacyAccept
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
if (attachments === true) {
|
|
701
|
+
return createDefaultAttachmentAdapter({
|
|
702
|
+
baseUrl,
|
|
703
|
+
fetch: options.fetch,
|
|
704
|
+
uploadUrl: legacyUploadUrl,
|
|
705
|
+
accept: legacyAccept
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
if (isAttachmentAdapter(attachments)) return attachments;
|
|
709
|
+
const config = attachments;
|
|
710
|
+
return createDefaultAttachmentAdapter({
|
|
711
|
+
baseUrl,
|
|
712
|
+
fetch: options.fetch,
|
|
713
|
+
uploadUrl: config.uploadUrl ?? legacyUploadUrl,
|
|
714
|
+
accept: config.accept ?? legacyAccept
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
|
|
169
718
|
// src/runtime/provider.tsx
|
|
170
719
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
720
|
+
function projectAttachment(attachment) {
|
|
721
|
+
const filename = attachment.name ?? "attachment";
|
|
722
|
+
const mimeType = attachment.contentType ?? "application/octet-stream";
|
|
723
|
+
if (attachment.type === "image") {
|
|
724
|
+
return {
|
|
725
|
+
id: attachment.id,
|
|
726
|
+
type: "image",
|
|
727
|
+
name: filename,
|
|
728
|
+
contentType: mimeType,
|
|
729
|
+
status: { type: "complete" },
|
|
730
|
+
content: [{ type: "image", image: attachment.dataUrl, filename }]
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
return {
|
|
734
|
+
id: attachment.id,
|
|
735
|
+
type: attachment.type,
|
|
736
|
+
name: filename,
|
|
737
|
+
contentType: mimeType,
|
|
738
|
+
status: { type: "complete" },
|
|
739
|
+
content: [
|
|
740
|
+
{ type: "file", data: attachment.dataUrl, mimeType, filename }
|
|
741
|
+
]
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
var convertMessage = (message) => {
|
|
745
|
+
const content = message.content.map((part) => {
|
|
746
|
+
if (part.type === "text") return { type: "text", text: part.text };
|
|
747
|
+
if (part.type === "thinking") return { type: "reasoning", text: part.text };
|
|
748
|
+
return {
|
|
749
|
+
type: "tool-call",
|
|
750
|
+
toolCallId: part.toolCallId,
|
|
751
|
+
toolName: part.toolName,
|
|
752
|
+
argsText: part.argsText,
|
|
753
|
+
...part.result !== void 0 ? { result: part.result } : {}
|
|
754
|
+
};
|
|
755
|
+
});
|
|
756
|
+
const attachments = message.attachments && message.attachments.length > 0 ? message.attachments.map(projectAttachment) : void 0;
|
|
757
|
+
return {
|
|
758
|
+
role: message.role,
|
|
759
|
+
content,
|
|
760
|
+
id: message.id,
|
|
761
|
+
...attachments ? { attachments } : {}
|
|
762
|
+
};
|
|
763
|
+
};
|
|
176
764
|
function findParentId(messages, beforeIndex) {
|
|
177
765
|
const slice = beforeIndex !== void 0 ? messages.slice(0, beforeIndex) : messages;
|
|
178
766
|
for (let i = slice.length - 1; i >= 0; i--) {
|
|
@@ -180,18 +768,18 @@ function findParentId(messages, beforeIndex) {
|
|
|
180
768
|
}
|
|
181
769
|
return null;
|
|
182
770
|
}
|
|
183
|
-
function isTopLevelStart(event) {
|
|
184
|
-
return event.type === "START" && typeof event.run_id === "string" && typeof event.path === "string" && !event.path.includes(".");
|
|
185
|
-
}
|
|
186
771
|
function getTextFromMessage(message) {
|
|
187
772
|
const part = message.content.find((c) => c.type === "text");
|
|
188
|
-
return part?.type === "text" ? part.text :
|
|
773
|
+
return part?.type === "text" ? part.text : "";
|
|
189
774
|
}
|
|
190
|
-
function
|
|
775
|
+
function getAttachmentsFromMessage(message) {
|
|
776
|
+
return message.attachments?.length ? message.attachments : void 0;
|
|
777
|
+
}
|
|
778
|
+
function useTimbalStream({
|
|
191
779
|
workforceId,
|
|
192
|
-
children,
|
|
193
780
|
baseUrl = "/api",
|
|
194
|
-
fetch: fetchFn
|
|
781
|
+
fetch: fetchFn,
|
|
782
|
+
debug = false
|
|
195
783
|
}) {
|
|
196
784
|
const [messages, setMessages] = (0, import_react.useState)([]);
|
|
197
785
|
const [isRunning, setIsRunning] = (0, import_react.useState)(false);
|
|
@@ -201,40 +789,41 @@ function TimbalRuntimeProvider({
|
|
|
201
789
|
(0, import_react.useEffect)(() => {
|
|
202
790
|
fetchFnRef.current = fetchFn ?? authFetch;
|
|
203
791
|
}, [fetchFn]);
|
|
792
|
+
const debugRef = (0, import_react.useRef)(debug);
|
|
793
|
+
(0, import_react.useEffect)(() => {
|
|
794
|
+
debugRef.current = debug;
|
|
795
|
+
}, [debug]);
|
|
204
796
|
(0, import_react.useEffect)(() => {
|
|
205
797
|
messagesRef.current = messages;
|
|
206
798
|
}, [messages]);
|
|
207
799
|
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
|
-
};
|
|
800
|
+
async (input, attachments, userId, assistantId, parentId, signal) => {
|
|
801
|
+
const state = createReducerState();
|
|
218
802
|
const flush = () => {
|
|
219
803
|
setMessages(
|
|
220
|
-
(prev) => prev.map(
|
|
804
|
+
(prev) => prev.map(
|
|
805
|
+
(m) => m.id === assistantId ? { ...m, content: [...state.parts] } : m
|
|
806
|
+
)
|
|
221
807
|
);
|
|
222
808
|
};
|
|
223
809
|
const stampRunId = (runId) => {
|
|
224
810
|
setMessages(
|
|
225
|
-
(prev) => prev.map(
|
|
811
|
+
(prev) => prev.map(
|
|
812
|
+
(m) => m.id === userId || m.id === assistantId ? { ...m, runId } : m
|
|
813
|
+
)
|
|
226
814
|
);
|
|
227
815
|
};
|
|
228
816
|
try {
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
817
|
+
const body = buildPromptBody({ input, attachments, parentId });
|
|
818
|
+
const res = await fetchFnRef.current(
|
|
819
|
+
`${baseUrl}/workforce/${workforceId}/stream`,
|
|
820
|
+
{
|
|
821
|
+
method: "POST",
|
|
822
|
+
headers: { "Content-Type": "application/json" },
|
|
823
|
+
body: JSON.stringify(body),
|
|
824
|
+
signal
|
|
825
|
+
}
|
|
826
|
+
);
|
|
238
827
|
if (!res.ok || !res.body) throw new Error(`Request failed: ${res.status}`);
|
|
239
828
|
const reader = res.body.getReader();
|
|
240
829
|
const decoder = new TextDecoder();
|
|
@@ -249,84 +838,34 @@ function TimbalRuntimeProvider({
|
|
|
249
838
|
for (const line of lines) {
|
|
250
839
|
const event = (0, import_timbal_sdk.parseSSELine)(line);
|
|
251
840
|
if (!event) continue;
|
|
252
|
-
if (
|
|
253
|
-
|
|
254
|
-
stampRunId(capturedRunId);
|
|
841
|
+
if (debugRef.current) {
|
|
842
|
+
console.debug("[timbal]", event.type, event);
|
|
255
843
|
}
|
|
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;
|
|
844
|
+
if (!capturedRunId) {
|
|
845
|
+
const runId = readTopLevelStartRunId(event);
|
|
846
|
+
if (runId) {
|
|
847
|
+
capturedRunId = runId;
|
|
848
|
+
stampRunId(runId);
|
|
315
849
|
}
|
|
316
850
|
}
|
|
851
|
+
const changed = reduceSseEvent(state, event);
|
|
852
|
+
if (changed) flush();
|
|
317
853
|
}
|
|
318
854
|
}
|
|
319
855
|
if (buffer.trim()) {
|
|
320
856
|
const event = (0, import_timbal_sdk.parseSSELine)(buffer);
|
|
321
|
-
if (event
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
857
|
+
if (event) {
|
|
858
|
+
if (debugRef.current) {
|
|
859
|
+
console.debug("[timbal]", event.type, event);
|
|
860
|
+
}
|
|
861
|
+
if (reduceSseEvent(state, event)) flush();
|
|
325
862
|
}
|
|
326
863
|
}
|
|
327
864
|
} catch (err) {
|
|
328
865
|
if (err.name !== "AbortError") {
|
|
329
|
-
if (parts.length === 0)
|
|
866
|
+
if (state.parts.length === 0) {
|
|
867
|
+
state.parts.push({ type: "text", text: "Something went wrong." });
|
|
868
|
+
}
|
|
330
869
|
flush();
|
|
331
870
|
}
|
|
332
871
|
} finally {
|
|
@@ -336,44 +875,46 @@ function TimbalRuntimeProvider({
|
|
|
336
875
|
},
|
|
337
876
|
[workforceId, baseUrl]
|
|
338
877
|
);
|
|
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;
|
|
878
|
+
const send = (0, import_react.useCallback)(
|
|
879
|
+
async (input, options) => {
|
|
344
880
|
const userId = crypto.randomUUID();
|
|
345
881
|
const assistantId = crypto.randomUUID();
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
|
|
882
|
+
const base = messagesRef.current;
|
|
883
|
+
const parentId = options?.parentId !== void 0 ? options.parentId : findParentId(base);
|
|
884
|
+
const userMessage = {
|
|
885
|
+
id: userId,
|
|
886
|
+
role: "user",
|
|
887
|
+
content: input ? [{ type: "text", text: input }] : [],
|
|
888
|
+
...options?.attachments && options.attachments.length > 0 ? { attachments: options.attachments } : {}
|
|
889
|
+
};
|
|
354
890
|
setMessages([
|
|
355
891
|
...base,
|
|
356
|
-
|
|
357
|
-
]);
|
|
358
|
-
setIsRunning(true);
|
|
359
|
-
setMessages((prev) => [
|
|
360
|
-
...prev,
|
|
892
|
+
userMessage,
|
|
361
893
|
{ id: assistantId, role: "assistant", content: [] }
|
|
362
894
|
]);
|
|
895
|
+
setIsRunning(true);
|
|
363
896
|
const controller = new AbortController();
|
|
364
897
|
abortRef.current = controller;
|
|
365
|
-
await streamAssistantResponse(
|
|
898
|
+
await streamAssistantResponse(
|
|
899
|
+
input,
|
|
900
|
+
options?.attachments,
|
|
901
|
+
userId,
|
|
902
|
+
assistantId,
|
|
903
|
+
parentId,
|
|
904
|
+
controller.signal
|
|
905
|
+
);
|
|
366
906
|
},
|
|
367
907
|
[streamAssistantResponse]
|
|
368
908
|
);
|
|
369
|
-
const
|
|
909
|
+
const reload = (0, import_react.useCallback)(
|
|
370
910
|
async (messageId) => {
|
|
371
911
|
const current = messagesRef.current;
|
|
372
912
|
const idx = messageId ? current.findIndex((m) => m.id === messageId) : current.length - 2;
|
|
373
913
|
const userMessage = idx >= 0 ? current[idx] : null;
|
|
374
914
|
if (!userMessage || userMessage.role !== "user") return;
|
|
375
915
|
const input = getTextFromMessage(userMessage);
|
|
376
|
-
|
|
916
|
+
const messageAttachments = getAttachmentsFromMessage(userMessage);
|
|
917
|
+
if (!input && !messageAttachments?.length) return;
|
|
377
918
|
const assistantId = crypto.randomUUID();
|
|
378
919
|
const parentId = findParentId(current, idx);
|
|
379
920
|
setMessages((prev) => [
|
|
@@ -383,25 +924,120 @@ function TimbalRuntimeProvider({
|
|
|
383
924
|
setIsRunning(true);
|
|
384
925
|
const controller = new AbortController();
|
|
385
926
|
abortRef.current = controller;
|
|
386
|
-
await streamAssistantResponse(
|
|
927
|
+
await streamAssistantResponse(
|
|
928
|
+
input,
|
|
929
|
+
messageAttachments,
|
|
930
|
+
userMessage.id,
|
|
931
|
+
assistantId,
|
|
932
|
+
parentId,
|
|
933
|
+
controller.signal
|
|
934
|
+
);
|
|
387
935
|
},
|
|
388
936
|
[streamAssistantResponse]
|
|
389
937
|
);
|
|
390
|
-
const
|
|
938
|
+
const cancel = (0, import_react.useCallback)(() => {
|
|
939
|
+
abortRef.current?.abort();
|
|
940
|
+
}, []);
|
|
941
|
+
const clear = (0, import_react.useCallback)(() => {
|
|
391
942
|
abortRef.current?.abort();
|
|
943
|
+
setMessages([]);
|
|
392
944
|
}, []);
|
|
945
|
+
return (0, import_react.useMemo)(
|
|
946
|
+
() => ({ messages, isRunning, send, reload, cancel, clear }),
|
|
947
|
+
[messages, isRunning, send, reload, cancel, clear]
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
function readTopLevelStartRunId(event) {
|
|
951
|
+
if (event.type === "START" && typeof event.run_id === "string" && typeof event.path === "string" && !event.path.includes(".")) {
|
|
952
|
+
return event.run_id;
|
|
953
|
+
}
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
var TimbalStreamContext = (0, import_react.createContext)(null);
|
|
957
|
+
function useTimbalRuntime() {
|
|
958
|
+
const ctx = (0, import_react.useContext)(TimbalStreamContext);
|
|
959
|
+
if (!ctx) {
|
|
960
|
+
throw new Error(
|
|
961
|
+
"useTimbalRuntime must be used inside a <TimbalRuntimeProvider>."
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
return ctx;
|
|
965
|
+
}
|
|
966
|
+
function TimbalRuntimeProvider({
|
|
967
|
+
workforceId,
|
|
968
|
+
children,
|
|
969
|
+
baseUrl = "/api",
|
|
970
|
+
fetch: fetchFn,
|
|
971
|
+
attachments,
|
|
972
|
+
attachmentsUploadUrl,
|
|
973
|
+
attachmentsAccept,
|
|
974
|
+
debug
|
|
975
|
+
}) {
|
|
976
|
+
const stream = useTimbalStream({
|
|
977
|
+
workforceId,
|
|
978
|
+
baseUrl,
|
|
979
|
+
fetch: fetchFn,
|
|
980
|
+
debug
|
|
981
|
+
});
|
|
982
|
+
const attachmentAdapter = (0, import_react.useMemo)(
|
|
983
|
+
() => resolveAttachmentAdapter(attachments, {
|
|
984
|
+
baseUrl,
|
|
985
|
+
fetch: fetchFn,
|
|
986
|
+
uploadUrl: attachmentsUploadUrl,
|
|
987
|
+
accept: attachmentsAccept
|
|
988
|
+
}),
|
|
989
|
+
[attachments, attachmentsUploadUrl, attachmentsAccept, baseUrl, fetchFn]
|
|
990
|
+
);
|
|
991
|
+
const onNew = (0, import_react.useCallback)(
|
|
992
|
+
async (message) => {
|
|
993
|
+
const textPart = message.content.find((c) => c.type === "text");
|
|
994
|
+
const input = textPart && textPart.type === "text" ? textPart.text : "";
|
|
995
|
+
const auiAttachments = message.attachments;
|
|
996
|
+
const attachments2 = auiAttachments ? (await Promise.all(auiAttachments.map(extractAttachment))).filter((a) => a !== null) : [];
|
|
997
|
+
if (!input && attachments2.length === 0) return;
|
|
998
|
+
const parentId = message.parentId !== null && message.parentId !== void 0 ? findParentIdFromAuiParent(stream.messages, message.parentId) : void 0;
|
|
999
|
+
await stream.send(input, {
|
|
1000
|
+
attachments: attachments2.length > 0 ? attachments2 : void 0,
|
|
1001
|
+
...parentId !== void 0 ? { parentId } : {}
|
|
1002
|
+
});
|
|
1003
|
+
},
|
|
1004
|
+
[stream]
|
|
1005
|
+
);
|
|
1006
|
+
const onReload = (0, import_react.useCallback)(
|
|
1007
|
+
async (messageId) => {
|
|
1008
|
+
await stream.reload(messageId);
|
|
1009
|
+
},
|
|
1010
|
+
[stream]
|
|
1011
|
+
);
|
|
1012
|
+
const onCancel = (0, import_react.useCallback)(async () => {
|
|
1013
|
+
stream.cancel();
|
|
1014
|
+
}, [stream]);
|
|
393
1015
|
const runtime = (0, import_react2.useExternalStoreRuntime)({
|
|
394
|
-
isRunning,
|
|
395
|
-
messages,
|
|
1016
|
+
isRunning: stream.isRunning,
|
|
1017
|
+
messages: stream.messages,
|
|
396
1018
|
convertMessage,
|
|
397
1019
|
onNew,
|
|
398
1020
|
onEdit: onNew,
|
|
399
1021
|
onReload,
|
|
400
|
-
onCancel
|
|
1022
|
+
onCancel,
|
|
1023
|
+
...attachmentAdapter ? { adapters: { attachments: attachmentAdapter } } : {}
|
|
401
1024
|
});
|
|
402
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.AssistantRuntimeProvider, { runtime, children });
|
|
1025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimbalStreamContext.Provider, { value: stream, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.AssistantRuntimeProvider, { runtime, children }) });
|
|
1026
|
+
}
|
|
1027
|
+
function findParentIdFromAuiParent(messages, auiParentId) {
|
|
1028
|
+
const idx = messages.findIndex((m) => m.id === auiParentId);
|
|
1029
|
+
if (idx < 0) return null;
|
|
1030
|
+
return findParentId(messages.slice(0, idx + 1));
|
|
403
1031
|
}
|
|
404
1032
|
|
|
1033
|
+
// src/index.ts
|
|
1034
|
+
var import_timbal_sdk2 = require("@timbal-ai/timbal-sdk");
|
|
1035
|
+
|
|
1036
|
+
// src/components/thread.tsx
|
|
1037
|
+
var import_react25 = require("@assistant-ui/react");
|
|
1038
|
+
var import_lucide_react8 = require("lucide-react");
|
|
1039
|
+
var import_react26 = require("motion/react");
|
|
1040
|
+
|
|
405
1041
|
// src/components/attachment.tsx
|
|
406
1042
|
var import_react4 = require("react");
|
|
407
1043
|
var import_lucide_react2 = require("lucide-react");
|
|
@@ -609,83 +1245,143 @@ function AvatarFallback({
|
|
|
609
1245
|
|
|
610
1246
|
// src/components/tooltip-icon-button.tsx
|
|
611
1247
|
var import_react3 = require("react");
|
|
612
|
-
var import_react_slot = require("@radix-ui/react-slot");
|
|
613
1248
|
|
|
614
|
-
// src/ui/button.tsx
|
|
615
|
-
var
|
|
1249
|
+
// src/ui/timbal-v2-button.tsx
|
|
1250
|
+
var React = __toESM(require("react"), 1);
|
|
616
1251
|
var import_radix_ui4 = require("radix-ui");
|
|
1252
|
+
|
|
1253
|
+
// src/ui/timbal-v2-button-tokens.ts
|
|
1254
|
+
var TIMBAL_V2_SIZE_HEIGHT = {
|
|
1255
|
+
xs: "min-h-8 h-8",
|
|
1256
|
+
sm: "min-h-9 h-9",
|
|
1257
|
+
md: "min-h-10 h-10",
|
|
1258
|
+
lg: "min-h-11 h-11"
|
|
1259
|
+
};
|
|
1260
|
+
var TIMBAL_V2_SIZE_ICON = {
|
|
1261
|
+
xs: "min-h-8 min-w-8 size-8",
|
|
1262
|
+
sm: "min-h-8 min-w-8 size-8",
|
|
1263
|
+
md: "min-h-10 min-w-10 size-10",
|
|
1264
|
+
lg: "min-h-11 min-w-11 size-11"
|
|
1265
|
+
};
|
|
1266
|
+
var TIMBAL_V2_SIZE_LABEL_PX = {
|
|
1267
|
+
xs: "px-3",
|
|
1268
|
+
sm: "px-4",
|
|
1269
|
+
md: "px-5",
|
|
1270
|
+
lg: "px-6"
|
|
1271
|
+
};
|
|
1272
|
+
var TIMBAL_V2_FILL = {
|
|
1273
|
+
primary: "bg-gradient-to-b from-neutral-800 to-black group-hover/tbv2:from-neutral-700 group-hover/tbv2:to-neutral-900 group-active/tbv2:from-black group-active/tbv2:to-black dark:from-white dark:to-neutral-200 dark:group-hover/tbv2:from-white dark:group-hover/tbv2:to-neutral-100 dark:group-active/tbv2:from-neutral-200 dark:group-active/tbv2:to-neutral-400",
|
|
1274
|
+
informative: "bg-blue-600 group-active/tbv2:[background-image:linear-gradient(to_top,rgba(0,0,0,0.08),transparent_55%)]",
|
|
1275
|
+
destructive: "bg-gradient-to-b from-white to-neutral-50/75 group-hover/tbv2:from-red-50/90 group-hover/tbv2:to-red-100/70 group-active/tbv2:from-red-100/90 group-active/tbv2:to-red-200/65 dark:from-white/[0.05] dark:to-white/[0.025] dark:group-hover/tbv2:from-red-500/12 dark:group-hover/tbv2:to-red-500/8 dark:group-active/tbv2:from-red-500/20 dark:group-active/tbv2:to-red-500/12",
|
|
1276
|
+
secondary: "bg-gradient-to-b from-white to-neutral-50/70 group-hover/tbv2:from-neutral-50/50 group-hover/tbv2:to-neutral-100/65 group-active/tbv2:from-neutral-100/70 group-active/tbv2:to-neutral-200/65 dark:from-white/[0.05] dark:to-white/[0.025] dark:group-hover/tbv2:from-white/[0.07] dark:group-hover/tbv2:to-white/[0.045] dark:group-active/tbv2:from-white/[0.10] dark:group-active/tbv2:to-white/[0.07]",
|
|
1277
|
+
ghost: "bg-transparent group-hover/tbv2:bg-neutral-100/70 group-active/tbv2:bg-neutral-200/70 dark:group-hover/tbv2:bg-white/10 dark:group-active/tbv2:bg-white/15",
|
|
1278
|
+
link: "bg-transparent"
|
|
1279
|
+
};
|
|
1280
|
+
var TIMBAL_V2_LABEL = {
|
|
1281
|
+
primary: "text-white dark:text-neutral-900",
|
|
1282
|
+
informative: "text-white",
|
|
1283
|
+
destructive: "text-destructive dark:text-red-400",
|
|
1284
|
+
secondary: "text-foreground",
|
|
1285
|
+
ghost: "text-foreground",
|
|
1286
|
+
link: "text-foreground underline decoration-black/25 underline-offset-2 group-hover/tbv2:decoration-black/45 dark:decoration-white/25 dark:group-hover/tbv2:decoration-white/45"
|
|
1287
|
+
};
|
|
1288
|
+
var TIMBAL_V2_BORDER = {
|
|
1289
|
+
primary: "",
|
|
1290
|
+
informative: "border border-white/15 dark:border-white/10",
|
|
1291
|
+
destructive: "border border-destructive/45 dark:border-red-500/55",
|
|
1292
|
+
secondary: "border border-neutral-200/80 dark:border-white/[0.08]",
|
|
1293
|
+
ghost: "",
|
|
1294
|
+
link: ""
|
|
1295
|
+
};
|
|
1296
|
+
var TIMBAL_V2_SHADOW = {
|
|
1297
|
+
primary: "shadow-sm shadow-black/15 dark:shadow-black/40",
|
|
1298
|
+
informative: "shadow-sm shadow-blue-900/20 dark:shadow-black/40",
|
|
1299
|
+
destructive: "shadow-[0_1px_2px_-0.5px_rgba(0,0,0,0.05)] dark:shadow-[0_1px_3px_rgba(0,0,0,0.22)]",
|
|
1300
|
+
secondary: "shadow-[0_1px_2px_-0.5px_rgba(0,0,0,0.05)] dark:shadow-[0_1px_3px_rgba(0,0,0,0.22)]",
|
|
1301
|
+
ghost: "",
|
|
1302
|
+
link: ""
|
|
1303
|
+
};
|
|
1304
|
+
var TIMBAL_V2_PILL_SURFACE = "bg-gradient-to-b from-white to-neutral-50/70 border border-neutral-200/80 shadow-[0_1px_2px_-0.5px_rgba(0,0,0,0.05)] dark:from-white/[0.05] dark:to-white/[0.025] dark:border-white/[0.08] dark:shadow-[0_1px_3px_rgba(0,0,0,0.22)]";
|
|
1305
|
+
var TIMBAL_V2_SECONDARY_CHROME = "bg-gradient-to-b from-white to-neutral-50/70 border border-neutral-200/80 shadow-[0_1px_2px_-0.5px_rgba(0,0,0,0.05)] transition-[background-color,box-shadow,border-color] duration-200 ease-in-out hover:from-neutral-50/40 hover:to-neutral-100/60 active:from-neutral-100/65 active:to-neutral-200/65 dark:from-white/[0.05] dark:to-white/[0.025] dark:border-white/[0.08] dark:shadow-[0_1px_3px_rgba(0,0,0,0.22)] dark:hover:from-white/[0.07] dark:hover:to-white/[0.045] dark:active:from-white/[0.10] dark:active:to-white/[0.07]";
|
|
1306
|
+
|
|
1307
|
+
// src/ui/timbal-v2-button.tsx
|
|
617
1308
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
618
|
-
var
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
625
|
-
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
626
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
627
|
-
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
628
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
629
|
-
},
|
|
630
|
-
size: {
|
|
631
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
632
|
-
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
633
|
-
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
634
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
635
|
-
icon: "size-9",
|
|
636
|
-
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
637
|
-
"icon-sm": "size-8",
|
|
638
|
-
"icon-lg": "size-10"
|
|
639
|
-
}
|
|
640
|
-
},
|
|
641
|
-
defaultVariants: {
|
|
642
|
-
variant: "default",
|
|
643
|
-
size: "default"
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
);
|
|
647
|
-
function Button({
|
|
648
|
-
className,
|
|
649
|
-
variant = "default",
|
|
650
|
-
size = "default",
|
|
1309
|
+
var TimbalV2Button = React.forwardRef(function TimbalV2Button2({
|
|
1310
|
+
variant = "secondary",
|
|
1311
|
+
size = "sm",
|
|
1312
|
+
isIconOnly = false,
|
|
1313
|
+
isLoading = false,
|
|
1314
|
+
fullWidth = false,
|
|
651
1315
|
asChild = false,
|
|
1316
|
+
className,
|
|
1317
|
+
disabled,
|
|
1318
|
+
type = "button",
|
|
1319
|
+
children,
|
|
652
1320
|
...props
|
|
653
|
-
}) {
|
|
1321
|
+
}, ref) {
|
|
1322
|
+
const isDisabled = disabled || isLoading;
|
|
654
1323
|
const Comp = asChild ? import_radix_ui4.Slot.Root : "button";
|
|
655
|
-
|
|
1324
|
+
const sizeClass = isIconOnly ? TIMBAL_V2_SIZE_ICON[size] : TIMBAL_V2_SIZE_HEIGHT[size];
|
|
1325
|
+
const radiusClass = variant === "link" || variant === "ghost" ? "rounded-md" : "rounded-full";
|
|
1326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
656
1327
|
Comp,
|
|
657
1328
|
{
|
|
658
|
-
|
|
1329
|
+
ref,
|
|
1330
|
+
type: asChild ? void 0 : type,
|
|
1331
|
+
disabled: asChild ? void 0 : isDisabled,
|
|
1332
|
+
"aria-disabled": asChild && isDisabled ? true : void 0,
|
|
1333
|
+
"data-slot": "timbal-v2-button",
|
|
659
1334
|
"data-variant": variant,
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
1335
|
+
className: cn(
|
|
1336
|
+
"group/tbv2 relative box-border inline-flex flex-col items-stretch overflow-hidden border-0 bg-transparent p-0 text-sm font-normal shadow-none transition duration-200 ease-in-out",
|
|
1337
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400/60 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
|
|
1338
|
+
sizeClass,
|
|
1339
|
+
radiusClass,
|
|
1340
|
+
TIMBAL_V2_BORDER[variant],
|
|
1341
|
+
TIMBAL_V2_SHADOW[variant],
|
|
1342
|
+
fullWidth && "w-full",
|
|
1343
|
+
isDisabled && "pointer-events-none opacity-50",
|
|
1344
|
+
className
|
|
1345
|
+
),
|
|
1346
|
+
...props,
|
|
1347
|
+
children: [
|
|
1348
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1349
|
+
"span",
|
|
1350
|
+
{
|
|
1351
|
+
"aria-hidden": true,
|
|
1352
|
+
className: cn(
|
|
1353
|
+
"pointer-events-none absolute inset-0 transition duration-200 ease-in-out",
|
|
1354
|
+
TIMBAL_V2_FILL[variant]
|
|
1355
|
+
)
|
|
1356
|
+
}
|
|
1357
|
+
),
|
|
1358
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1359
|
+
"span",
|
|
1360
|
+
{
|
|
1361
|
+
className: cn(
|
|
1362
|
+
"relative z-10 flex min-h-0 flex-1 items-center justify-center gap-1 leading-tight",
|
|
1363
|
+
!isIconOnly && TIMBAL_V2_SIZE_LABEL_PX[size],
|
|
1364
|
+
TIMBAL_V2_LABEL[variant]
|
|
1365
|
+
),
|
|
1366
|
+
children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "size-4 animate-spin rounded-full border-2 border-current border-t-transparent" }) : children
|
|
1367
|
+
}
|
|
1368
|
+
)
|
|
1369
|
+
]
|
|
663
1370
|
}
|
|
664
1371
|
);
|
|
665
|
-
}
|
|
1372
|
+
});
|
|
666
1373
|
|
|
667
1374
|
// src/components/tooltip-icon-button.tsx
|
|
668
1375
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
669
|
-
var TooltipIconButton = (0, import_react3.forwardRef)(({
|
|
1376
|
+
var TooltipIconButton = (0, import_react3.forwardRef)(function TooltipIconButton2({ tooltip, side = "bottom", variant = "secondary", children, ...props }, ref) {
|
|
670
1377
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Tooltip, { children: [
|
|
671
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
672
|
-
|
|
673
|
-
{
|
|
674
|
-
|
|
675
|
-
size: "icon",
|
|
676
|
-
...rest,
|
|
677
|
-
className: cn("aui-button-icon size-6 p-1", className),
|
|
678
|
-
ref,
|
|
679
|
-
children: [
|
|
680
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_slot.Slottable, { children }),
|
|
681
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "aui-sr-only sr-only", children: tooltip })
|
|
682
|
-
]
|
|
683
|
-
}
|
|
684
|
-
) }),
|
|
1378
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(TimbalV2Button, { ref, variant, size: "sm", isIconOnly: true, ...props, children: [
|
|
1379
|
+
children,
|
|
1380
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "sr-only", children: tooltip })
|
|
1381
|
+
] }) }),
|
|
685
1382
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipContent, { side, children: tooltip })
|
|
686
1383
|
] });
|
|
687
1384
|
});
|
|
688
|
-
TooltipIconButton.displayName = "TooltipIconButton";
|
|
689
1385
|
|
|
690
1386
|
// src/components/attachment.tsx
|
|
691
1387
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
@@ -821,46 +1517,1232 @@ var AttachmentRemove = () => {
|
|
|
821
1517
|
}
|
|
822
1518
|
) });
|
|
823
1519
|
};
|
|
824
|
-
var UserMessageAttachments = () => {
|
|
825
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "aui-user-message-attachments-end col-span-full col-start-1 row-start-1 flex w-full flex-row justify-end gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react5.MessagePrimitive.Attachments, { components: { Attachment: AttachmentUI } }) });
|
|
1520
|
+
var UserMessageAttachments = () => {
|
|
1521
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "aui-user-message-attachments-end col-span-full col-start-1 row-start-1 flex w-full flex-row justify-end gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react5.MessagePrimitive.Attachments, { components: { Attachment: AttachmentUI } }) });
|
|
1522
|
+
};
|
|
1523
|
+
var ComposerAttachments = () => {
|
|
1524
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "aui-composer-attachments mb-2 flex w-full flex-row items-center gap-2 overflow-x-auto px-1.5 pt-0.5 pb-1 empty:hidden", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1525
|
+
import_react5.ComposerPrimitive.Attachments,
|
|
1526
|
+
{
|
|
1527
|
+
components: { Attachment: AttachmentUI }
|
|
1528
|
+
}
|
|
1529
|
+
) });
|
|
1530
|
+
};
|
|
1531
|
+
var ComposerAddAttachment = () => {
|
|
1532
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react5.ComposerPrimitive.AddAttachment, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1533
|
+
TooltipIconButton,
|
|
1534
|
+
{
|
|
1535
|
+
tooltip: "Add Attachment",
|
|
1536
|
+
side: "bottom",
|
|
1537
|
+
variant: "secondary",
|
|
1538
|
+
className: "aui-composer-add-attachment shrink-0 text-neutral-500 dark:text-muted-foreground",
|
|
1539
|
+
"aria-label": "Add Attachment",
|
|
1540
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.PlusIcon, { className: "aui-attachment-add-icon size-4 stroke-[1.5]" })
|
|
1541
|
+
}
|
|
1542
|
+
) });
|
|
1543
|
+
};
|
|
1544
|
+
|
|
1545
|
+
// src/components/markdown-text.tsx
|
|
1546
|
+
var import_dot = require("@assistant-ui/react-markdown/styles/dot.css");
|
|
1547
|
+
var import_katex_min = require("katex/dist/katex.min.css");
|
|
1548
|
+
var import_react_markdown = require("@assistant-ui/react-markdown");
|
|
1549
|
+
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
1550
|
+
var import_remark_math = __toESM(require("remark-math"), 1);
|
|
1551
|
+
var import_rehype_katex = __toESM(require("rehype-katex"), 1);
|
|
1552
|
+
var import_react16 = require("react");
|
|
1553
|
+
var import_lucide_react4 = require("lucide-react");
|
|
1554
|
+
|
|
1555
|
+
// src/components/syntax-highlighter.tsx
|
|
1556
|
+
var import_react15 = require("react");
|
|
1557
|
+
var import_core = require("shiki/core");
|
|
1558
|
+
var import_javascript = require("shiki/engine/javascript");
|
|
1559
|
+
|
|
1560
|
+
// src/artifacts/registry.tsx
|
|
1561
|
+
var import_react14 = require("react");
|
|
1562
|
+
|
|
1563
|
+
// src/artifacts/chart-artifact.tsx
|
|
1564
|
+
var import_react6 = require("react");
|
|
1565
|
+
|
|
1566
|
+
// src/artifacts/artifact-card.tsx
|
|
1567
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1568
|
+
var ArtifactCard = ({ title, kind, className, bodyClassName, toolbar, children }) => {
|
|
1569
|
+
const hasHeader = Boolean(title || toolbar);
|
|
1570
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1571
|
+
"div",
|
|
1572
|
+
{
|
|
1573
|
+
className: cn(
|
|
1574
|
+
"aui-artifact-root my-3 overflow-hidden rounded-xl border border-border/60 bg-background shadow-sm",
|
|
1575
|
+
className
|
|
1576
|
+
),
|
|
1577
|
+
"data-artifact-kind": kind,
|
|
1578
|
+
children: [
|
|
1579
|
+
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: [
|
|
1580
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "aui-artifact-title flex-1 truncate text-xs font-semibold text-foreground/80", children: title }),
|
|
1581
|
+
!title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "flex-1" }),
|
|
1582
|
+
toolbar
|
|
1583
|
+
] }),
|
|
1584
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("aui-artifact-body", bodyClassName), children })
|
|
1585
|
+
]
|
|
1586
|
+
}
|
|
1587
|
+
);
|
|
1588
|
+
};
|
|
1589
|
+
|
|
1590
|
+
// src/artifacts/chart-artifact.tsx
|
|
1591
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1592
|
+
var ChartArtifactView = ({
|
|
1593
|
+
artifact
|
|
1594
|
+
}) => {
|
|
1595
|
+
const { type: _t, chartType = "bar", data = [] } = artifact;
|
|
1596
|
+
const xKey = artifact.xKey ?? inferXKey(data);
|
|
1597
|
+
const dataKeys = (0, import_react6.useMemo)(() => {
|
|
1598
|
+
if (Array.isArray(artifact.dataKey)) return artifact.dataKey;
|
|
1599
|
+
if (typeof artifact.dataKey === "string") return [artifact.dataKey];
|
|
1600
|
+
return inferDataKeys(data, xKey);
|
|
1601
|
+
}, [artifact.dataKey, data, xKey]);
|
|
1602
|
+
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: [
|
|
1603
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1604
|
+
ChartSvg,
|
|
1605
|
+
{
|
|
1606
|
+
chartType,
|
|
1607
|
+
data,
|
|
1608
|
+
xKey,
|
|
1609
|
+
dataKeys,
|
|
1610
|
+
unit: artifact.unit
|
|
1611
|
+
}
|
|
1612
|
+
),
|
|
1613
|
+
dataKeys.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Legend, { dataKeys })
|
|
1614
|
+
] }) });
|
|
1615
|
+
};
|
|
1616
|
+
var COLORS = [
|
|
1617
|
+
"var(--primary, #6366f1)",
|
|
1618
|
+
"#22c55e",
|
|
1619
|
+
"#f59e0b",
|
|
1620
|
+
"#ef4444",
|
|
1621
|
+
"#06b6d4",
|
|
1622
|
+
"#a855f7"
|
|
1623
|
+
];
|
|
1624
|
+
var W = 600;
|
|
1625
|
+
var H = 240;
|
|
1626
|
+
var PAD = { top: 12, right: 16, bottom: 28, left: 36 };
|
|
1627
|
+
var ChartSvg = ({ chartType, data, xKey, dataKeys, unit }) => {
|
|
1628
|
+
if (data.length === 0 || dataKeys.length === 0) {
|
|
1629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EmptyState, {});
|
|
1630
|
+
}
|
|
1631
|
+
if (chartType === "pie") {
|
|
1632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PieChart, { data, xKey, dataKey: dataKeys[0] });
|
|
1633
|
+
}
|
|
1634
|
+
const innerW = W - PAD.left - PAD.right;
|
|
1635
|
+
const innerH = H - PAD.top - PAD.bottom;
|
|
1636
|
+
const all = dataKeys.flatMap((k) => data.map((d) => toNum(d[k])));
|
|
1637
|
+
const maxV = Math.max(0, ...all);
|
|
1638
|
+
const minV = Math.min(0, ...all);
|
|
1639
|
+
const range = maxV - minV || 1;
|
|
1640
|
+
const yScale = (v) => PAD.top + innerH - (v - minV) / range * innerH;
|
|
1641
|
+
const xCount = data.length;
|
|
1642
|
+
const xStep = xCount > 1 ? innerW / (xCount - 1) : innerW;
|
|
1643
|
+
const xPos = (i) => chartType === "bar" ? PAD.left + innerW * (i + 0.5) / xCount : PAD.left + i * xStep;
|
|
1644
|
+
const ticks = niceTicks(minV, maxV);
|
|
1645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1646
|
+
"svg",
|
|
1647
|
+
{
|
|
1648
|
+
viewBox: `0 0 ${W} ${H}`,
|
|
1649
|
+
className: "aui-artifact-chart-svg w-full",
|
|
1650
|
+
role: "img",
|
|
1651
|
+
"aria-label": "Chart",
|
|
1652
|
+
children: [
|
|
1653
|
+
ticks.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("g", { children: [
|
|
1654
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1655
|
+
"line",
|
|
1656
|
+
{
|
|
1657
|
+
x1: PAD.left,
|
|
1658
|
+
x2: W - PAD.right,
|
|
1659
|
+
y1: yScale(t),
|
|
1660
|
+
y2: yScale(t),
|
|
1661
|
+
stroke: "currentColor",
|
|
1662
|
+
strokeOpacity: 0.08
|
|
1663
|
+
}
|
|
1664
|
+
),
|
|
1665
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1666
|
+
"text",
|
|
1667
|
+
{
|
|
1668
|
+
x: PAD.left - 6,
|
|
1669
|
+
y: yScale(t),
|
|
1670
|
+
textAnchor: "end",
|
|
1671
|
+
dominantBaseline: "middle",
|
|
1672
|
+
className: "fill-muted-foreground text-[10px]",
|
|
1673
|
+
children: formatTick(t, unit)
|
|
1674
|
+
}
|
|
1675
|
+
)
|
|
1676
|
+
] }, i)),
|
|
1677
|
+
data.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1678
|
+
"text",
|
|
1679
|
+
{
|
|
1680
|
+
x: xPos(i),
|
|
1681
|
+
y: H - PAD.bottom + 14,
|
|
1682
|
+
textAnchor: "middle",
|
|
1683
|
+
className: "fill-muted-foreground text-[10px]",
|
|
1684
|
+
children: String(d[xKey] ?? i)
|
|
1685
|
+
},
|
|
1686
|
+
i
|
|
1687
|
+
)),
|
|
1688
|
+
chartType === "bar" && renderBars({ data, dataKeys, xCount, xPos, yScale, minV, innerW }),
|
|
1689
|
+
chartType === "line" && dataKeys.map((k, ki) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1690
|
+
Polyline,
|
|
1691
|
+
{
|
|
1692
|
+
data,
|
|
1693
|
+
dataKey: k,
|
|
1694
|
+
xPos,
|
|
1695
|
+
yScale,
|
|
1696
|
+
color: COLORS[ki % COLORS.length]
|
|
1697
|
+
},
|
|
1698
|
+
k
|
|
1699
|
+
)),
|
|
1700
|
+
chartType === "area" && dataKeys.map((k, ki) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1701
|
+
Area,
|
|
1702
|
+
{
|
|
1703
|
+
data,
|
|
1704
|
+
dataKey: k,
|
|
1705
|
+
xPos,
|
|
1706
|
+
yScale,
|
|
1707
|
+
baseY: yScale(Math.max(0, minV)),
|
|
1708
|
+
color: COLORS[ki % COLORS.length]
|
|
1709
|
+
},
|
|
1710
|
+
k
|
|
1711
|
+
))
|
|
1712
|
+
]
|
|
1713
|
+
}
|
|
1714
|
+
);
|
|
1715
|
+
};
|
|
1716
|
+
function renderBars(args) {
|
|
1717
|
+
const { data, dataKeys, xCount, xPos, yScale, minV, innerW } = args;
|
|
1718
|
+
const groupWidth = innerW / xCount * 0.7;
|
|
1719
|
+
const barWidth = groupWidth / dataKeys.length;
|
|
1720
|
+
const baseY = yScale(Math.max(0, minV));
|
|
1721
|
+
return dataKeys.flatMap(
|
|
1722
|
+
(k, ki) => data.map((d, i) => {
|
|
1723
|
+
const v = toNum(d[k]);
|
|
1724
|
+
const y = yScale(v);
|
|
1725
|
+
const x = xPos(i) - groupWidth / 2 + ki * barWidth;
|
|
1726
|
+
const top = Math.min(y, baseY);
|
|
1727
|
+
const height = Math.abs(y - baseY);
|
|
1728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1729
|
+
"rect",
|
|
1730
|
+
{
|
|
1731
|
+
x,
|
|
1732
|
+
y: top,
|
|
1733
|
+
width: Math.max(1, barWidth - 2),
|
|
1734
|
+
height: Math.max(1, height),
|
|
1735
|
+
rx: 2,
|
|
1736
|
+
fill: COLORS[ki % COLORS.length]
|
|
1737
|
+
},
|
|
1738
|
+
`${k}-${i}`
|
|
1739
|
+
);
|
|
1740
|
+
})
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
var Polyline = ({ data, dataKey, xPos, yScale, color }) => {
|
|
1744
|
+
const points = data.map((d, i) => `${xPos(i)},${yScale(toNum(d[dataKey]))}`).join(" ");
|
|
1745
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1746
|
+
"polyline",
|
|
1747
|
+
{
|
|
1748
|
+
points,
|
|
1749
|
+
fill: "none",
|
|
1750
|
+
stroke: color,
|
|
1751
|
+
strokeWidth: 2,
|
|
1752
|
+
strokeLinejoin: "round",
|
|
1753
|
+
strokeLinecap: "round"
|
|
1754
|
+
}
|
|
1755
|
+
);
|
|
1756
|
+
};
|
|
1757
|
+
var Area = ({ data, dataKey, xPos, yScale, baseY, color }) => {
|
|
1758
|
+
if (data.length === 0) return null;
|
|
1759
|
+
const top = data.map((d, i) => `${xPos(i)},${yScale(toNum(d[dataKey]))}`).join(" ");
|
|
1760
|
+
const path = `M ${xPos(0)},${baseY} L ${top} L ${xPos(data.length - 1)},${baseY} Z`;
|
|
1761
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
1762
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: path, fill: color, fillOpacity: 0.18 }),
|
|
1763
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Polyline, { data, dataKey, xPos, yScale, color })
|
|
1764
|
+
] });
|
|
1765
|
+
};
|
|
1766
|
+
var PieChart = ({ data, xKey, dataKey }) => {
|
|
1767
|
+
const cx = W / 2;
|
|
1768
|
+
const cy = H / 2;
|
|
1769
|
+
const r = Math.min(W, H) / 2 - 16;
|
|
1770
|
+
const total = data.reduce((sum, d) => sum + toNum(d[dataKey]), 0) || 1;
|
|
1771
|
+
let acc = 0;
|
|
1772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1773
|
+
"svg",
|
|
1774
|
+
{
|
|
1775
|
+
viewBox: `0 0 ${W} ${H}`,
|
|
1776
|
+
className: "aui-artifact-chart-svg w-full",
|
|
1777
|
+
role: "img",
|
|
1778
|
+
"aria-label": "Pie chart",
|
|
1779
|
+
children: data.map((d, i) => {
|
|
1780
|
+
const value = toNum(d[dataKey]);
|
|
1781
|
+
const start = acc / total * Math.PI * 2;
|
|
1782
|
+
acc += value;
|
|
1783
|
+
const end = acc / total * Math.PI * 2;
|
|
1784
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1785
|
+
PieSlice,
|
|
1786
|
+
{
|
|
1787
|
+
cx,
|
|
1788
|
+
cy,
|
|
1789
|
+
r,
|
|
1790
|
+
start,
|
|
1791
|
+
end,
|
|
1792
|
+
color: COLORS[i % COLORS.length],
|
|
1793
|
+
label: String(d[xKey] ?? i)
|
|
1794
|
+
},
|
|
1795
|
+
i
|
|
1796
|
+
);
|
|
1797
|
+
})
|
|
1798
|
+
}
|
|
1799
|
+
);
|
|
1800
|
+
};
|
|
1801
|
+
var PieSlice = ({ cx, cy, r, start, end, color, label }) => {
|
|
1802
|
+
const x1 = cx + Math.sin(start) * r;
|
|
1803
|
+
const y1 = cy - Math.cos(start) * r;
|
|
1804
|
+
const x2 = cx + Math.sin(end) * r;
|
|
1805
|
+
const y2 = cy - Math.cos(end) * r;
|
|
1806
|
+
const large = end - start > Math.PI ? 1 : 0;
|
|
1807
|
+
const path = `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2} Z`;
|
|
1808
|
+
const mid = (start + end) / 2;
|
|
1809
|
+
const lx = cx + Math.sin(mid) * (r * 0.65);
|
|
1810
|
+
const ly = cy - Math.cos(mid) * (r * 0.65);
|
|
1811
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("g", { children: [
|
|
1812
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: path, fill: color, stroke: "var(--background, #fff)", strokeWidth: 1 }),
|
|
1813
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1814
|
+
"text",
|
|
1815
|
+
{
|
|
1816
|
+
x: lx,
|
|
1817
|
+
y: ly,
|
|
1818
|
+
textAnchor: "middle",
|
|
1819
|
+
dominantBaseline: "middle",
|
|
1820
|
+
className: "fill-white text-[10px] font-semibold",
|
|
1821
|
+
children: label
|
|
1822
|
+
}
|
|
1823
|
+
)
|
|
1824
|
+
] });
|
|
1825
|
+
};
|
|
1826
|
+
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: [
|
|
1827
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1828
|
+
"span",
|
|
1829
|
+
{
|
|
1830
|
+
className: "inline-block size-2 rounded-sm",
|
|
1831
|
+
style: { background: COLORS[i % COLORS.length] },
|
|
1832
|
+
"aria-hidden": true
|
|
1833
|
+
}
|
|
1834
|
+
),
|
|
1835
|
+
k
|
|
1836
|
+
] }, k)) });
|
|
1837
|
+
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" });
|
|
1838
|
+
function inferXKey(data) {
|
|
1839
|
+
if (data.length === 0) return "x";
|
|
1840
|
+
for (const k of Object.keys(data[0])) {
|
|
1841
|
+
if (typeof data[0][k] !== "number") return k;
|
|
1842
|
+
}
|
|
1843
|
+
return Object.keys(data[0])[0] ?? "x";
|
|
1844
|
+
}
|
|
1845
|
+
function inferDataKeys(data, xKey) {
|
|
1846
|
+
if (data.length === 0) return [];
|
|
1847
|
+
return Object.keys(data[0]).filter(
|
|
1848
|
+
(k) => k !== xKey && typeof data[0][k] === "number"
|
|
1849
|
+
);
|
|
1850
|
+
}
|
|
1851
|
+
function toNum(value) {
|
|
1852
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
1853
|
+
return Number.isFinite(n) ? n : 0;
|
|
1854
|
+
}
|
|
1855
|
+
function niceTicks(min, max, count = 4) {
|
|
1856
|
+
if (max === min) return [min];
|
|
1857
|
+
const range = max - min;
|
|
1858
|
+
const step = niceStep(range / count);
|
|
1859
|
+
const start = Math.floor(min / step) * step;
|
|
1860
|
+
const out = [];
|
|
1861
|
+
for (let v = start; v <= max + step / 2; v += step) {
|
|
1862
|
+
out.push(round(v));
|
|
1863
|
+
}
|
|
1864
|
+
return out;
|
|
1865
|
+
}
|
|
1866
|
+
function niceStep(raw) {
|
|
1867
|
+
const exp = Math.floor(Math.log10(Math.abs(raw))) || 0;
|
|
1868
|
+
const base = Math.pow(10, exp);
|
|
1869
|
+
const norm = raw / base;
|
|
1870
|
+
let nice = 1;
|
|
1871
|
+
if (norm >= 5) nice = 5;
|
|
1872
|
+
else if (norm >= 2) nice = 2;
|
|
1873
|
+
return nice * base;
|
|
1874
|
+
}
|
|
1875
|
+
function round(v) {
|
|
1876
|
+
return Math.round(v * 1e6) / 1e6;
|
|
1877
|
+
}
|
|
1878
|
+
function formatTick(v, unit) {
|
|
1879
|
+
const s = Math.abs(v) >= 1e3 ? `${(v / 1e3).toFixed(1)}k` : String(round(v));
|
|
1880
|
+
return unit ? `${s}${unit}` : s;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
// src/artifacts/question-artifact.tsx
|
|
1884
|
+
var import_react7 = require("react");
|
|
1885
|
+
var import_react8 = require("@assistant-ui/react");
|
|
1886
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1887
|
+
|
|
1888
|
+
// src/ui/chrome.ts
|
|
1889
|
+
var STUDIO_TOPBAR_GAP = "0.5rem";
|
|
1890
|
+
var STUDIO_TOPBAR_HEIGHT = "3rem";
|
|
1891
|
+
var STUDIO_PILL_HEIGHT = "2.5rem";
|
|
1892
|
+
var STUDIO_SIDEBAR_GAP = "0.5rem";
|
|
1893
|
+
var STUDIO_SIDEBAR_WIDTH = "3rem";
|
|
1894
|
+
var STUDIO_INSET_LEFT = `calc(${STUDIO_SIDEBAR_GAP} + ${STUDIO_SIDEBAR_WIDTH})`;
|
|
1895
|
+
var studioChromeShellStyle = {
|
|
1896
|
+
"--studio-topbar-gap": STUDIO_TOPBAR_GAP,
|
|
1897
|
+
"--studio-topbar-height": STUDIO_TOPBAR_HEIGHT,
|
|
1898
|
+
"--studio-chrome-pill-height": STUDIO_PILL_HEIGHT,
|
|
1899
|
+
"--studio-inset-top": `calc(${STUDIO_TOPBAR_GAP} + ${STUDIO_TOPBAR_HEIGHT})`,
|
|
1900
|
+
"--studio-sidebar-gap": STUDIO_SIDEBAR_GAP,
|
|
1901
|
+
"--studio-sidebar-width": STUDIO_SIDEBAR_WIDTH,
|
|
1902
|
+
"--studio-inset-left": STUDIO_INSET_LEFT
|
|
1903
|
+
};
|
|
1904
|
+
var studioTopbarPillHeightClass = "h-[var(--studio-chrome-pill-height)] min-h-[var(--studio-chrome-pill-height)]";
|
|
1905
|
+
var studioTopbarIconPillClass = "shrink-0 flex-none size-[var(--studio-chrome-pill-height)] min-h-[var(--studio-chrome-pill-height)] min-w-[var(--studio-chrome-pill-height)]";
|
|
1906
|
+
var studioPlaygroundGradientClass = "bg-gradient-to-b from-neutral-200/60 via-neutral-100/30 to-background dark:from-zinc-800 dark:via-zinc-900 dark:to-zinc-950";
|
|
1907
|
+
var studioComposeInputShellClass = "flex w-full flex-col rounded-2xl border border-neutral-200/60 bg-background shadow-lg shadow-black/5 outline-none transition-[box-shadow,border-color] focus-within:border-neutral-400/80 focus-within:ring-2 focus-within:ring-foreground/5 focus-within:shadow-xl focus-within:shadow-black/10 dark:border-white/12 dark:bg-zinc-900 dark:shadow-black/20 dark:focus-within:border-white/22 dark:focus-within:ring-0";
|
|
1908
|
+
var studioPillSurfaceClass = TIMBAL_V2_PILL_SURFACE;
|
|
1909
|
+
var studioSecondaryChromeClass = TIMBAL_V2_SECONDARY_CHROME;
|
|
1910
|
+
var studioIntegrationSurfaceSolid = "bg-white bg-gradient-to-b from-white to-neutral-50/70 shadow-[0_1px_2px_-0.5px_rgba(0,0,0,0.05)] dark:bg-zinc-900 dark:from-white/[0.05] dark:to-white/[0.025] dark:shadow-[0_1px_3px_rgba(0,0,0,0.22)]";
|
|
1911
|
+
var studioIntegrationBorder = "border border-neutral-200/80 dark:border-white/[0.08]";
|
|
1912
|
+
var studioIntegrationCardClass = cn(
|
|
1913
|
+
"rounded-xl",
|
|
1914
|
+
studioIntegrationSurfaceSolid,
|
|
1915
|
+
studioIntegrationBorder
|
|
1916
|
+
);
|
|
1917
|
+
var studioIntegrationIconTileClass = cn(
|
|
1918
|
+
"flex size-9 shrink-0 items-center justify-center rounded-lg",
|
|
1919
|
+
studioIntegrationSurfaceSolid,
|
|
1920
|
+
studioIntegrationBorder
|
|
1921
|
+
);
|
|
1922
|
+
var studioListRowButtonClass = cn(
|
|
1923
|
+
"flex w-full cursor-pointer items-center gap-3 rounded-xl px-3 py-2.5 text-left",
|
|
1924
|
+
studioIntegrationCardClass,
|
|
1925
|
+
"transition-[background-color,box-shadow,border-color] duration-200 ease-in-out",
|
|
1926
|
+
"hover:border-neutral-300 dark:hover:border-white/15",
|
|
1927
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background dark:focus-visible:ring-white/20"
|
|
1928
|
+
);
|
|
1929
|
+
var studioComposerIoWellClass = cn(
|
|
1930
|
+
"rounded-lg",
|
|
1931
|
+
studioIntegrationSurfaceSolid,
|
|
1932
|
+
studioIntegrationBorder
|
|
1933
|
+
);
|
|
1934
|
+
var studioToolCardShellClass = cn(
|
|
1935
|
+
studioIntegrationCardClass,
|
|
1936
|
+
"my-2 min-h-0 overflow-hidden"
|
|
1937
|
+
);
|
|
1938
|
+
var studioTimelineRowButtonClass = "group flex w-full min-w-0 cursor-pointer items-center justify-start rounded-md border-0 bg-transparent py-1 text-left shadow-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2";
|
|
1939
|
+
var studioTimelineTextClass = "text-xs font-normal leading-snug";
|
|
1940
|
+
var studioTimelineActionClass = cn(
|
|
1941
|
+
studioTimelineTextClass,
|
|
1942
|
+
"shrink-0 text-foreground/70 transition-colors duration-150 group-hover:text-foreground/80"
|
|
1943
|
+
);
|
|
1944
|
+
var studioTimelineShimmerActionClass = cn(
|
|
1945
|
+
studioTimelineTextClass,
|
|
1946
|
+
"shrink-0"
|
|
1947
|
+
);
|
|
1948
|
+
var studioTimelineDetailClass = cn(
|
|
1949
|
+
studioTimelineTextClass,
|
|
1950
|
+
"min-w-0 truncate text-muted-foreground transition-colors duration-150"
|
|
1951
|
+
);
|
|
1952
|
+
function studioTimelineChevronClass(expanded) {
|
|
1953
|
+
return cn(
|
|
1954
|
+
"ml-0.5 size-3 min-h-3 min-w-3 shrink-0 transition-all duration-150",
|
|
1955
|
+
expanded ? "rotate-90 text-foreground opacity-60" : "text-muted-foreground opacity-0 group-hover:opacity-70"
|
|
1956
|
+
);
|
|
1957
|
+
}
|
|
1958
|
+
var studioTimelineBodyPadClass = "flex flex-col gap-2 pt-0.5 pb-0.5";
|
|
1959
|
+
var studioArtifactShellClass = cn(
|
|
1960
|
+
studioIntegrationCardClass,
|
|
1961
|
+
"my-2 w-full min-w-0 overflow-hidden"
|
|
1962
|
+
);
|
|
1963
|
+
var studioQuestionOptionClass = "flex w-full items-center gap-2 rounded-lg border border-transparent px-2 py-1.5 text-left text-sm transition-[background-color,border-color,box-shadow] duration-200 hover:bg-neutral-100/80 dark:hover:bg-white/[0.05] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2";
|
|
1964
|
+
var studioQuestionOptionSelectedClass = cn(
|
|
1965
|
+
studioQuestionOptionClass,
|
|
1966
|
+
"border-neutral-200/80 bg-neutral-50/90 ring-1 ring-foreground/10 dark:border-white/[0.12] dark:bg-white/[0.06] dark:ring-white/10"
|
|
1967
|
+
);
|
|
1968
|
+
|
|
1969
|
+
// src/artifacts/question-artifact.tsx
|
|
1970
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1971
|
+
function optionKey(option, index) {
|
|
1972
|
+
const id = option.id?.trim();
|
|
1973
|
+
return id ? id : `__option-${index}`;
|
|
1974
|
+
}
|
|
1975
|
+
var OptionRadio = ({ selected }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1976
|
+
"span",
|
|
1977
|
+
{
|
|
1978
|
+
className: cn(
|
|
1979
|
+
"flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
|
|
1980
|
+
selected ? "border-foreground bg-foreground text-background" : "border-neutral-300 bg-background dark:border-white/20"
|
|
1981
|
+
),
|
|
1982
|
+
"aria-hidden": true,
|
|
1983
|
+
children: selected ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.CheckIcon, { className: "size-2.5 stroke-[3]" }) : null
|
|
1984
|
+
}
|
|
1985
|
+
);
|
|
1986
|
+
var QuestionArtifactView = ({
|
|
1987
|
+
artifact
|
|
1988
|
+
}) => {
|
|
1989
|
+
const runtime = (0, import_react8.useThreadRuntime)();
|
|
1990
|
+
const [selected, setSelected] = (0, import_react7.useState)([]);
|
|
1991
|
+
const [submittedIds, setSubmittedIds] = (0, import_react7.useState)(null);
|
|
1992
|
+
const isMulti = artifact.multi === true;
|
|
1993
|
+
const isDisabled = submittedIds !== null;
|
|
1994
|
+
const send = (0, import_react7.useCallback)(
|
|
1995
|
+
(keys) => {
|
|
1996
|
+
if (keys.length === 0) return;
|
|
1997
|
+
const labels = artifact.options.map((option, index) => ({ option, key: optionKey(option, index) })).filter(({ key }) => keys.includes(key)).map(({ option }) => option.label);
|
|
1998
|
+
setSubmittedIds(keys);
|
|
1999
|
+
runtime.append({
|
|
2000
|
+
role: "user",
|
|
2001
|
+
content: [{ type: "text", text: labels.join(", ") }]
|
|
2002
|
+
});
|
|
2003
|
+
},
|
|
2004
|
+
[artifact.options, runtime]
|
|
2005
|
+
);
|
|
2006
|
+
const onPick = (0, import_react7.useCallback)(
|
|
2007
|
+
(key) => {
|
|
2008
|
+
if (isDisabled) return;
|
|
2009
|
+
if (!isMulti) {
|
|
2010
|
+
send([key]);
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
setSelected(
|
|
2014
|
+
(prev) => prev.includes(key) ? prev.filter((id) => id !== key) : [...prev, key]
|
|
2015
|
+
);
|
|
2016
|
+
},
|
|
2017
|
+
[isDisabled, isMulti, send]
|
|
2018
|
+
);
|
|
2019
|
+
const onConfirm = (0, import_react7.useCallback)(() => {
|
|
2020
|
+
send(selected);
|
|
2021
|
+
}, [selected, send]);
|
|
2022
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: studioArtifactShellClass, "data-artifact-kind": "question", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "px-2.5 py-2", children: [
|
|
2023
|
+
artifact.prompt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "mb-2 text-sm font-normal leading-snug text-foreground", children: artifact.prompt }) : null,
|
|
2024
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-col gap-0.5", role: "list", children: artifact.options.map((option, index) => {
|
|
2025
|
+
const key = optionKey(option, index);
|
|
2026
|
+
const isSelected = submittedIds ? submittedIds.includes(key) : isMulti && selected.includes(key);
|
|
2027
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2028
|
+
"button",
|
|
2029
|
+
{
|
|
2030
|
+
type: "button",
|
|
2031
|
+
role: "listitem",
|
|
2032
|
+
disabled: isDisabled,
|
|
2033
|
+
onClick: () => onPick(key),
|
|
2034
|
+
className: cn(
|
|
2035
|
+
isSelected ? studioQuestionOptionSelectedClass : studioQuestionOptionClass,
|
|
2036
|
+
isDisabled && (isSelected ? "cursor-default" : "cursor-not-allowed opacity-50")
|
|
2037
|
+
),
|
|
2038
|
+
children: [
|
|
2039
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(OptionRadio, { selected: isSelected }),
|
|
2040
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "min-w-0 flex-1 text-left", children: [
|
|
2041
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "block font-normal text-foreground", children: option.label }),
|
|
2042
|
+
option.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mt-0.5 block text-xs text-muted-foreground", children: option.description }) : null
|
|
2043
|
+
] })
|
|
2044
|
+
]
|
|
2045
|
+
},
|
|
2046
|
+
key
|
|
2047
|
+
);
|
|
2048
|
+
}) }),
|
|
2049
|
+
isMulti && !submittedIds ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-2 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2050
|
+
TimbalV2Button,
|
|
2051
|
+
{
|
|
2052
|
+
type: "button",
|
|
2053
|
+
variant: "primary",
|
|
2054
|
+
size: "sm",
|
|
2055
|
+
disabled: selected.length === 0,
|
|
2056
|
+
onClick: onConfirm,
|
|
2057
|
+
children: "Confirm"
|
|
2058
|
+
}
|
|
2059
|
+
) }) : null
|
|
2060
|
+
] }) });
|
|
2061
|
+
};
|
|
2062
|
+
|
|
2063
|
+
// src/artifacts/html-artifact.tsx
|
|
2064
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2065
|
+
var HtmlArtifactView = ({ artifact }) => {
|
|
2066
|
+
const sandboxed = artifact.sandboxed !== false;
|
|
2067
|
+
const sandbox = sandboxed ? "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-pointer-lock" : void 0;
|
|
2068
|
+
const height = artifact.height ?? "320px";
|
|
2069
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ArtifactCard, { title: artifact.title, kind: "html", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2070
|
+
"iframe",
|
|
2071
|
+
{
|
|
2072
|
+
title: artifact.title ?? "HTML artifact",
|
|
2073
|
+
srcDoc: artifact.content,
|
|
2074
|
+
sandbox,
|
|
2075
|
+
className: "aui-artifact-html w-full border-0 bg-background",
|
|
2076
|
+
style: { height }
|
|
2077
|
+
}
|
|
2078
|
+
) });
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
// src/artifacts/json-artifact.tsx
|
|
2082
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2083
|
+
var JsonArtifactView = ({
|
|
2084
|
+
artifact
|
|
2085
|
+
}) => {
|
|
2086
|
+
const data = "data" in artifact ? artifact.data : artifact;
|
|
2087
|
+
const title = artifact.title;
|
|
2088
|
+
let body;
|
|
2089
|
+
try {
|
|
2090
|
+
body = JSON.stringify(data, null, 2);
|
|
2091
|
+
} catch {
|
|
2092
|
+
body = String(data);
|
|
2093
|
+
}
|
|
2094
|
+
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 }) });
|
|
2095
|
+
};
|
|
2096
|
+
|
|
2097
|
+
// src/artifacts/table-artifact.tsx
|
|
2098
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2099
|
+
var TableArtifactView = ({ artifact }) => {
|
|
2100
|
+
const rows = artifact.rows ?? [];
|
|
2101
|
+
const columns = artifact.columns ?? deriveColumns(rows);
|
|
2102
|
+
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: [
|
|
2103
|
+
/* @__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)(
|
|
2104
|
+
"th",
|
|
2105
|
+
{
|
|
2106
|
+
className: "px-3 py-2 text-left text-xs font-semibold uppercase tracking-wider text-muted-foreground",
|
|
2107
|
+
children: col.label ?? col.key
|
|
2108
|
+
},
|
|
2109
|
+
col.key
|
|
2110
|
+
)) }) }),
|
|
2111
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2112
|
+
"tr",
|
|
2113
|
+
{
|
|
2114
|
+
className: "border-b border-border/30 transition-colors last:border-b-0 hover:bg-muted/20",
|
|
2115
|
+
children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2116
|
+
"td",
|
|
2117
|
+
{
|
|
2118
|
+
className: "px-3 py-2 align-top text-foreground/85",
|
|
2119
|
+
children: formatCell(row[col.key])
|
|
2120
|
+
},
|
|
2121
|
+
col.key
|
|
2122
|
+
))
|
|
2123
|
+
},
|
|
2124
|
+
i
|
|
2125
|
+
)) })
|
|
2126
|
+
] }) }) });
|
|
2127
|
+
};
|
|
2128
|
+
function deriveColumns(rows) {
|
|
2129
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2130
|
+
const cols = [];
|
|
2131
|
+
for (const row of rows) {
|
|
2132
|
+
for (const key of Object.keys(row)) {
|
|
2133
|
+
if (!seen.has(key)) {
|
|
2134
|
+
seen.add(key);
|
|
2135
|
+
cols.push({ key });
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
return cols;
|
|
2140
|
+
}
|
|
2141
|
+
function formatCell(value) {
|
|
2142
|
+
if (value === null || value === void 0) return "";
|
|
2143
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
2144
|
+
return String(value);
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
// src/artifacts/ui/ui-artifact.tsx
|
|
2148
|
+
var import_react13 = require("react");
|
|
2149
|
+
|
|
2150
|
+
// src/artifacts/ui/types.ts
|
|
2151
|
+
function isUiBinding(value) {
|
|
2152
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.$bind === "string";
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
// src/artifacts/ui/state.ts
|
|
2156
|
+
function uiStateReducer(state, action) {
|
|
2157
|
+
switch (action.type) {
|
|
2158
|
+
case "set":
|
|
2159
|
+
return setPath(state, action.path, action.value);
|
|
2160
|
+
case "toggle": {
|
|
2161
|
+
const current = getPath(state, action.path);
|
|
2162
|
+
return setPath(state, action.path, !current);
|
|
2163
|
+
}
|
|
2164
|
+
case "replace":
|
|
2165
|
+
return action.state;
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
function getPath(state, path) {
|
|
2169
|
+
if (!path) return void 0;
|
|
2170
|
+
const parts = path.split(".");
|
|
2171
|
+
let cursor = state;
|
|
2172
|
+
for (const part of parts) {
|
|
2173
|
+
if (typeof cursor !== "object" || cursor === null) return void 0;
|
|
2174
|
+
cursor = cursor[part];
|
|
2175
|
+
}
|
|
2176
|
+
return cursor;
|
|
2177
|
+
}
|
|
2178
|
+
function setPath(state, path, value) {
|
|
2179
|
+
if (!path) return state;
|
|
2180
|
+
const parts = path.split(".");
|
|
2181
|
+
const next = { ...state };
|
|
2182
|
+
let cursor = next;
|
|
2183
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
2184
|
+
const key = parts[i];
|
|
2185
|
+
const child = cursor[key];
|
|
2186
|
+
const cloned = typeof child === "object" && child !== null && !Array.isArray(child) ? { ...child } : {};
|
|
2187
|
+
cursor[key] = cloned;
|
|
2188
|
+
cursor = cloned;
|
|
2189
|
+
}
|
|
2190
|
+
cursor[parts[parts.length - 1]] = value;
|
|
2191
|
+
return next;
|
|
2192
|
+
}
|
|
2193
|
+
function resolveBindable(value, state) {
|
|
2194
|
+
if (isUiBinding(value)) {
|
|
2195
|
+
return getPath(state, value.$bind);
|
|
2196
|
+
}
|
|
2197
|
+
return value;
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
// src/artifacts/ui/registry.tsx
|
|
2201
|
+
var import_react9 = require("react");
|
|
2202
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2203
|
+
var UiStateContext = (0, import_react9.createContext)({});
|
|
2204
|
+
var UiDispatchContext = (0, import_react9.createContext)(() => {
|
|
2205
|
+
});
|
|
2206
|
+
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 }) });
|
|
2207
|
+
function useUiState() {
|
|
2208
|
+
return (0, import_react9.useContext)(UiStateContext);
|
|
2209
|
+
}
|
|
2210
|
+
function useUiDispatch() {
|
|
2211
|
+
return (0, import_react9.useContext)(UiDispatchContext);
|
|
2212
|
+
}
|
|
2213
|
+
var UiEventContext = (0, import_react9.createContext)(
|
|
2214
|
+
null
|
|
2215
|
+
);
|
|
2216
|
+
var UiEventProvider = ({ onEvent, children }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiEventContext.Provider, { value: onEvent, children });
|
|
2217
|
+
function useUiEventEmitter() {
|
|
2218
|
+
return (0, import_react9.useContext)(UiEventContext);
|
|
2219
|
+
}
|
|
2220
|
+
var UiCustomNodeRegistryContext = (0, import_react9.createContext)({});
|
|
2221
|
+
var UiCustomNodeRegistryProvider = ({ renderers, children }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiCustomNodeRegistryContext.Provider, { value: renderers, children });
|
|
2222
|
+
function useUiCustomNodeRegistry() {
|
|
2223
|
+
return (0, import_react9.useContext)(UiCustomNodeRegistryContext);
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
// src/artifacts/ui/nodes.tsx
|
|
2227
|
+
var import_react10 = require("react");
|
|
2228
|
+
var import_react11 = require("motion/react");
|
|
2229
|
+
var import_react12 = require("@assistant-ui/react");
|
|
2230
|
+
|
|
2231
|
+
// src/ui/button.tsx
|
|
2232
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
2233
|
+
var import_radix_ui5 = require("radix-ui");
|
|
2234
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2235
|
+
var buttonVariants = (0, import_class_variance_authority.cva)(
|
|
2236
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
2237
|
+
{
|
|
2238
|
+
variants: {
|
|
2239
|
+
variant: {
|
|
2240
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
2241
|
+
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
2242
|
+
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
2243
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
2244
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
2245
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
2246
|
+
},
|
|
2247
|
+
size: {
|
|
2248
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
2249
|
+
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
2250
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
2251
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
2252
|
+
icon: "size-9",
|
|
2253
|
+
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
2254
|
+
"icon-sm": "size-8",
|
|
2255
|
+
"icon-lg": "size-10"
|
|
2256
|
+
}
|
|
2257
|
+
},
|
|
2258
|
+
defaultVariants: {
|
|
2259
|
+
variant: "default",
|
|
2260
|
+
size: "default"
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
);
|
|
2264
|
+
function Button({
|
|
2265
|
+
className,
|
|
2266
|
+
variant = "default",
|
|
2267
|
+
size = "default",
|
|
2268
|
+
asChild = false,
|
|
2269
|
+
...props
|
|
2270
|
+
}) {
|
|
2271
|
+
const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
|
|
2272
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2273
|
+
Comp,
|
|
2274
|
+
{
|
|
2275
|
+
"data-slot": "button",
|
|
2276
|
+
"data-variant": variant,
|
|
2277
|
+
"data-size": size,
|
|
2278
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
2279
|
+
...props
|
|
2280
|
+
}
|
|
2281
|
+
);
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
// src/artifacts/ui/nodes.tsx
|
|
2285
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2286
|
+
var UiNodeView = ({ node }) => {
|
|
2287
|
+
switch (node.kind) {
|
|
2288
|
+
case "box":
|
|
2289
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(BoxNode, { node });
|
|
2290
|
+
case "text":
|
|
2291
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextNode, { node });
|
|
2292
|
+
case "heading":
|
|
2293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(HeadingNode, { node });
|
|
2294
|
+
case "badge":
|
|
2295
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(BadgeNode, { node });
|
|
2296
|
+
case "button":
|
|
2297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ButtonNode, { node });
|
|
2298
|
+
case "toggle":
|
|
2299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToggleNode, { node });
|
|
2300
|
+
case "slider":
|
|
2301
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SliderNode, { node });
|
|
2302
|
+
case "tooltip":
|
|
2303
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TooltipNode, { node });
|
|
2304
|
+
case "draggable":
|
|
2305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DraggableNode, { node });
|
|
2306
|
+
case "custom":
|
|
2307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CustomNode, { node });
|
|
2308
|
+
default:
|
|
2309
|
+
return null;
|
|
2310
|
+
}
|
|
2311
|
+
};
|
|
2312
|
+
function useActionRunner() {
|
|
2313
|
+
const state = useUiState();
|
|
2314
|
+
const dispatch = useUiDispatch();
|
|
2315
|
+
const runtime = (0, import_react12.useThreadRuntime)();
|
|
2316
|
+
const emit = useUiEventEmitter();
|
|
2317
|
+
return (0, import_react10.useCallback)(
|
|
2318
|
+
(actions) => {
|
|
2319
|
+
if (!actions) return;
|
|
2320
|
+
const list = Array.isArray(actions) ? actions : [actions];
|
|
2321
|
+
for (const action of list) {
|
|
2322
|
+
switch (action.kind) {
|
|
2323
|
+
case "message": {
|
|
2324
|
+
const text = resolveBindable(action.text, state);
|
|
2325
|
+
if (typeof text === "string" && text.length > 0) {
|
|
2326
|
+
runtime?.append({
|
|
2327
|
+
role: "user",
|
|
2328
|
+
content: [{ type: "text", text }]
|
|
2329
|
+
});
|
|
2330
|
+
}
|
|
2331
|
+
break;
|
|
2332
|
+
}
|
|
2333
|
+
case "set": {
|
|
2334
|
+
const value = resolveBindable(action.value, state);
|
|
2335
|
+
dispatch({ type: "set", path: action.path, value });
|
|
2336
|
+
break;
|
|
2337
|
+
}
|
|
2338
|
+
case "toggle": {
|
|
2339
|
+
dispatch({ type: "toggle", path: action.path });
|
|
2340
|
+
break;
|
|
2341
|
+
}
|
|
2342
|
+
case "emit": {
|
|
2343
|
+
emit?.({ name: action.name, payload: action.payload });
|
|
2344
|
+
break;
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
},
|
|
2349
|
+
[state, dispatch, runtime, emit]
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2352
|
+
var ALIGN_CLS = {
|
|
2353
|
+
start: "items-start",
|
|
2354
|
+
center: "items-center",
|
|
2355
|
+
end: "items-end",
|
|
2356
|
+
stretch: "items-stretch"
|
|
2357
|
+
};
|
|
2358
|
+
var JUSTIFY_CLS = {
|
|
2359
|
+
start: "justify-start",
|
|
2360
|
+
center: "justify-center",
|
|
2361
|
+
end: "justify-end",
|
|
2362
|
+
between: "justify-between",
|
|
2363
|
+
around: "justify-around"
|
|
2364
|
+
};
|
|
2365
|
+
var BoxNode = ({ node }) => {
|
|
2366
|
+
const dir = node.direction ?? "col";
|
|
2367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2368
|
+
"div",
|
|
2369
|
+
{
|
|
2370
|
+
className: cn(
|
|
2371
|
+
"aui-ui-box flex",
|
|
2372
|
+
dir === "col" ? "flex-col" : "flex-row",
|
|
2373
|
+
node.wrap && "flex-wrap",
|
|
2374
|
+
node.align && ALIGN_CLS[node.align],
|
|
2375
|
+
node.justify && JUSTIFY_CLS[node.justify],
|
|
2376
|
+
node.className
|
|
2377
|
+
),
|
|
2378
|
+
style: {
|
|
2379
|
+
gap: node.gap !== void 0 ? `${node.gap * 0.25}rem` : void 0,
|
|
2380
|
+
padding: node.padding !== void 0 ? `${node.padding * 0.25}rem` : void 0
|
|
2381
|
+
},
|
|
2382
|
+
children: node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: child }, child.id ?? i))
|
|
2383
|
+
}
|
|
2384
|
+
);
|
|
2385
|
+
};
|
|
2386
|
+
var TEXT_SIZE = {
|
|
2387
|
+
xs: "text-xs",
|
|
2388
|
+
sm: "text-sm",
|
|
2389
|
+
base: "text-base",
|
|
2390
|
+
lg: "text-lg"
|
|
2391
|
+
};
|
|
2392
|
+
var TEXT_WEIGHT = {
|
|
2393
|
+
normal: "font-normal",
|
|
2394
|
+
medium: "font-medium",
|
|
2395
|
+
semibold: "font-semibold",
|
|
2396
|
+
bold: "font-bold"
|
|
2397
|
+
};
|
|
2398
|
+
var TextNode = ({ node }) => {
|
|
2399
|
+
const state = useUiState();
|
|
2400
|
+
const value = resolveBindable(node.value, state);
|
|
2401
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2402
|
+
"span",
|
|
2403
|
+
{
|
|
2404
|
+
className: cn(
|
|
2405
|
+
"aui-ui-text",
|
|
2406
|
+
node.muted && "text-muted-foreground",
|
|
2407
|
+
node.size && TEXT_SIZE[node.size],
|
|
2408
|
+
node.weight && TEXT_WEIGHT[node.weight],
|
|
2409
|
+
node.className
|
|
2410
|
+
),
|
|
2411
|
+
children: value === void 0 || value === null ? "" : String(value)
|
|
2412
|
+
}
|
|
2413
|
+
);
|
|
2414
|
+
};
|
|
2415
|
+
var HEADING_CLS = {
|
|
2416
|
+
1: "text-2xl",
|
|
2417
|
+
2: "text-xl",
|
|
2418
|
+
3: "text-lg",
|
|
2419
|
+
4: "text-base"
|
|
2420
|
+
};
|
|
2421
|
+
var HeadingNode = ({ node }) => {
|
|
2422
|
+
const state = useUiState();
|
|
2423
|
+
const value = String(resolveBindable(node.value, state) ?? "");
|
|
2424
|
+
const level = node.level ?? 2;
|
|
2425
|
+
const cls = cn(
|
|
2426
|
+
"aui-ui-heading font-semibold text-foreground",
|
|
2427
|
+
HEADING_CLS[level],
|
|
2428
|
+
node.className
|
|
2429
|
+
);
|
|
2430
|
+
switch (level) {
|
|
2431
|
+
case 1:
|
|
2432
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h1", { className: cls, children: value });
|
|
2433
|
+
case 2:
|
|
2434
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { className: cls, children: value });
|
|
2435
|
+
case 3:
|
|
2436
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { className: cls, children: value });
|
|
2437
|
+
case 4:
|
|
2438
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h4", { className: cls, children: value });
|
|
2439
|
+
}
|
|
2440
|
+
};
|
|
2441
|
+
var BADGE_TONE = {
|
|
2442
|
+
default: "bg-muted text-foreground",
|
|
2443
|
+
primary: "bg-primary/10 text-primary",
|
|
2444
|
+
success: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
|
|
2445
|
+
warn: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
|
|
2446
|
+
danger: "bg-destructive/10 text-destructive"
|
|
2447
|
+
};
|
|
2448
|
+
var BadgeNode = ({ node }) => {
|
|
2449
|
+
const state = useUiState();
|
|
2450
|
+
const value = String(resolveBindable(node.value, state) ?? "");
|
|
2451
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2452
|
+
"span",
|
|
2453
|
+
{
|
|
2454
|
+
className: cn(
|
|
2455
|
+
"aui-ui-badge inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
|
|
2456
|
+
BADGE_TONE[node.tone ?? "default"],
|
|
2457
|
+
node.className
|
|
2458
|
+
),
|
|
2459
|
+
children: value
|
|
2460
|
+
}
|
|
2461
|
+
);
|
|
2462
|
+
};
|
|
2463
|
+
var ButtonNode = ({ node }) => {
|
|
2464
|
+
const state = useUiState();
|
|
2465
|
+
const run = useActionRunner();
|
|
2466
|
+
const label = String(resolveBindable(node.label, state) ?? "");
|
|
2467
|
+
const disabled = node.disabled !== void 0 ? Boolean(resolveBindable(node.disabled, state)) : false;
|
|
2468
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2469
|
+
Button,
|
|
2470
|
+
{
|
|
2471
|
+
variant: node.variant ?? "default",
|
|
2472
|
+
size: node.size ?? "default",
|
|
2473
|
+
disabled,
|
|
2474
|
+
className: node.className,
|
|
2475
|
+
onClick: () => run(node.onClick),
|
|
2476
|
+
children: label
|
|
2477
|
+
}
|
|
2478
|
+
);
|
|
2479
|
+
};
|
|
2480
|
+
var ToggleNode = ({ node }) => {
|
|
2481
|
+
const state = useUiState();
|
|
2482
|
+
const dispatch = useUiDispatch();
|
|
2483
|
+
const run = useActionRunner();
|
|
2484
|
+
const value = Boolean(getPath(state, node.binding));
|
|
2485
|
+
const label = node.label ? String(resolveBindable(node.label, state) ?? "") : null;
|
|
2486
|
+
const onToggle = () => {
|
|
2487
|
+
dispatch({ type: "toggle", path: node.binding });
|
|
2488
|
+
run(node.onChange);
|
|
2489
|
+
};
|
|
2490
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
2491
|
+
"label",
|
|
2492
|
+
{
|
|
2493
|
+
className: cn(
|
|
2494
|
+
"aui-ui-toggle inline-flex cursor-pointer items-center gap-2 text-sm select-none",
|
|
2495
|
+
node.className
|
|
2496
|
+
),
|
|
2497
|
+
children: [
|
|
2498
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2499
|
+
"button",
|
|
2500
|
+
{
|
|
2501
|
+
type: "button",
|
|
2502
|
+
role: "switch",
|
|
2503
|
+
"aria-checked": value,
|
|
2504
|
+
onClick: onToggle,
|
|
2505
|
+
className: cn(
|
|
2506
|
+
"relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border transition-colors",
|
|
2507
|
+
value ? "border-primary bg-primary" : "border-border bg-muted hover:bg-muted/80"
|
|
2508
|
+
),
|
|
2509
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2510
|
+
"span",
|
|
2511
|
+
{
|
|
2512
|
+
className: cn(
|
|
2513
|
+
"inline-block size-4 transform rounded-full bg-background shadow transition-transform",
|
|
2514
|
+
value ? "translate-x-4" : "translate-x-0.5"
|
|
2515
|
+
),
|
|
2516
|
+
"aria-hidden": true
|
|
2517
|
+
}
|
|
2518
|
+
)
|
|
2519
|
+
}
|
|
2520
|
+
),
|
|
2521
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-foreground/85", children: label })
|
|
2522
|
+
]
|
|
2523
|
+
}
|
|
2524
|
+
);
|
|
2525
|
+
};
|
|
2526
|
+
var SliderNode = ({ node }) => {
|
|
2527
|
+
const state = useUiState();
|
|
2528
|
+
const dispatch = useUiDispatch();
|
|
2529
|
+
const run = useActionRunner();
|
|
2530
|
+
const min = node.min ?? 0;
|
|
2531
|
+
const max = node.max ?? 100;
|
|
2532
|
+
const step = node.step ?? 1;
|
|
2533
|
+
const raw = getPath(state, node.binding);
|
|
2534
|
+
const value = typeof raw === "number" ? raw : min;
|
|
2535
|
+
const showValue = node.showValue ?? true;
|
|
2536
|
+
const label = node.label ? String(resolveBindable(node.label, state) ?? "") : null;
|
|
2537
|
+
const onChange = (e) => {
|
|
2538
|
+
const next = Number(e.target.value);
|
|
2539
|
+
dispatch({ type: "set", path: node.binding, value: next });
|
|
2540
|
+
};
|
|
2541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: cn("aui-ui-slider flex flex-col gap-1", node.className), children: [
|
|
2542
|
+
(label || showValue) && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
|
|
2543
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: label }),
|
|
2544
|
+
showValue && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "font-mono", children: value })
|
|
2545
|
+
] }),
|
|
2546
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2547
|
+
"input",
|
|
2548
|
+
{
|
|
2549
|
+
type: "range",
|
|
2550
|
+
min,
|
|
2551
|
+
max,
|
|
2552
|
+
step,
|
|
2553
|
+
value,
|
|
2554
|
+
onChange,
|
|
2555
|
+
onMouseUp: () => run(node.onChange),
|
|
2556
|
+
onKeyUp: (e) => {
|
|
2557
|
+
if (e.key === "Enter" || e.key === " ") run(node.onChange);
|
|
2558
|
+
},
|
|
2559
|
+
onTouchEnd: () => run(node.onChange),
|
|
2560
|
+
className: "aui-ui-slider-input h-1.5 w-full cursor-pointer appearance-none rounded-full bg-muted accent-primary"
|
|
2561
|
+
}
|
|
2562
|
+
)
|
|
2563
|
+
] });
|
|
2564
|
+
};
|
|
2565
|
+
var TooltipNode = ({ node }) => {
|
|
2566
|
+
const state = useUiState();
|
|
2567
|
+
const content = String(resolveBindable(node.content, state) ?? "");
|
|
2568
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Tooltip, { children: [
|
|
2569
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: cn("aui-ui-tooltip-trigger inline-flex", node.className), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: node.child }) }) }),
|
|
2570
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TooltipContent, { side: node.side ?? "top", children: content })
|
|
2571
|
+
] }) });
|
|
2572
|
+
};
|
|
2573
|
+
var DraggableNode = ({ node }) => {
|
|
2574
|
+
const run = useActionRunner();
|
|
2575
|
+
const snapBack = node.snapBack ?? true;
|
|
2576
|
+
const axis = node.axis ?? "both";
|
|
2577
|
+
const dragProp = axis === "both" ? true : axis;
|
|
2578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2579
|
+
import_react11.motion.div,
|
|
2580
|
+
{
|
|
2581
|
+
drag: dragProp,
|
|
2582
|
+
dragMomentum: false,
|
|
2583
|
+
dragSnapToOrigin: snapBack,
|
|
2584
|
+
whileDrag: { scale: 1.02, cursor: "grabbing" },
|
|
2585
|
+
onDragEnd: () => run(node.onDragEnd),
|
|
2586
|
+
className: cn(
|
|
2587
|
+
"aui-ui-draggable inline-block cursor-grab touch-none",
|
|
2588
|
+
node.className
|
|
2589
|
+
),
|
|
2590
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: node.child })
|
|
2591
|
+
}
|
|
2592
|
+
);
|
|
2593
|
+
};
|
|
2594
|
+
var CustomNode = ({ node }) => {
|
|
2595
|
+
const state = useUiState();
|
|
2596
|
+
const registry = useUiCustomNodeRegistry();
|
|
2597
|
+
const Renderer = registry[node.name];
|
|
2598
|
+
if (!Renderer) return null;
|
|
2599
|
+
const resolvedProps = resolveProps(node.props ?? {}, state);
|
|
2600
|
+
const children = node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: child }, child.id ?? i));
|
|
2601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Renderer, { props: resolvedProps, children });
|
|
2602
|
+
};
|
|
2603
|
+
function resolveProps(props, state) {
|
|
2604
|
+
const out = {};
|
|
2605
|
+
for (const [k, v] of Object.entries(props)) {
|
|
2606
|
+
out[k] = resolveBindable(v, state);
|
|
2607
|
+
}
|
|
2608
|
+
return out;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
// src/artifacts/ui/ui-artifact.tsx
|
|
2612
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2613
|
+
var UiArtifactView = ({ artifact }) => {
|
|
2614
|
+
const [state, dispatch] = (0, import_react13.useReducer)(
|
|
2615
|
+
uiStateReducer,
|
|
2616
|
+
artifact.initialState ?? {}
|
|
2617
|
+
);
|
|
2618
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ArtifactCard, { title: artifact.title, kind: "ui", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(UiStateProvider, { state, dispatch, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "aui-ui-root p-3", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(UiNodeView, { node: artifact.root }) }) }) });
|
|
2619
|
+
};
|
|
2620
|
+
|
|
2621
|
+
// src/artifacts/registry.tsx
|
|
2622
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2623
|
+
var defaultArtifactRenderers = {
|
|
2624
|
+
chart: ChartArtifactView,
|
|
2625
|
+
question: QuestionArtifactView,
|
|
2626
|
+
html: HtmlArtifactView,
|
|
2627
|
+
json: JsonArtifactView,
|
|
2628
|
+
table: TableArtifactView,
|
|
2629
|
+
ui: UiArtifactView
|
|
826
2630
|
};
|
|
827
|
-
var
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
2631
|
+
var ArtifactRegistryContext = (0, import_react14.createContext)(
|
|
2632
|
+
defaultArtifactRenderers
|
|
2633
|
+
);
|
|
2634
|
+
var ArtifactRegistryProvider = ({ renderers, override, children }) => {
|
|
2635
|
+
const merged = (0, import_react14.useMemo)(() => {
|
|
2636
|
+
if (!renderers) return defaultArtifactRenderers;
|
|
2637
|
+
if (override) return renderers;
|
|
2638
|
+
return { ...defaultArtifactRenderers, ...renderers };
|
|
2639
|
+
}, [renderers, override]);
|
|
2640
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ArtifactRegistryContext.Provider, { value: merged, children });
|
|
834
2641
|
};
|
|
835
|
-
|
|
836
|
-
return
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
className: "aui-composer-add-attachment size-8.5 rounded-full p-1 font-semibold text-xs hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30",
|
|
844
|
-
"aria-label": "Add Attachment",
|
|
845
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.PlusIcon, { className: "aui-attachment-add-icon size-5 stroke-[1.5px]" })
|
|
846
|
-
}
|
|
847
|
-
) });
|
|
2642
|
+
function useArtifactRegistry() {
|
|
2643
|
+
return (0, import_react14.useContext)(ArtifactRegistryContext);
|
|
2644
|
+
}
|
|
2645
|
+
var ArtifactView = ({ artifact }) => {
|
|
2646
|
+
const registry = useArtifactRegistry();
|
|
2647
|
+
const Renderer = registry[artifact.type] ?? registry.json;
|
|
2648
|
+
if (!Renderer) return null;
|
|
2649
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Renderer, { artifact });
|
|
848
2650
|
};
|
|
849
2651
|
|
|
850
|
-
// src/
|
|
851
|
-
var
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
2652
|
+
// src/artifacts/parse.ts
|
|
2653
|
+
var ARTIFACT_FENCE_LANGUAGES = /* @__PURE__ */ new Set([
|
|
2654
|
+
"timbal-artifact",
|
|
2655
|
+
"timbal"
|
|
2656
|
+
]);
|
|
2657
|
+
function isArtifactFenceLanguage(language) {
|
|
2658
|
+
return typeof language === "string" && ARTIFACT_FENCE_LANGUAGES.has(language);
|
|
2659
|
+
}
|
|
2660
|
+
function tryParseStructuredText(text) {
|
|
2661
|
+
const trimmed = text.trim();
|
|
2662
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
|
|
2663
|
+
try {
|
|
2664
|
+
return JSON.parse(trimmed);
|
|
2665
|
+
} catch {
|
|
2666
|
+
}
|
|
2667
|
+
try {
|
|
2668
|
+
const asJson = trimmed.replace(/\bTrue\b/g, "true").replace(/\bFalse\b/g, "false").replace(/\bNone\b/g, "null").replace(/'/g, '"');
|
|
2669
|
+
return JSON.parse(asJson);
|
|
2670
|
+
} catch {
|
|
2671
|
+
return null;
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
function parseArtifactFromToolResult(result) {
|
|
2675
|
+
if (result === void 0 || result === null) return null;
|
|
2676
|
+
if (typeof result === "string") {
|
|
2677
|
+
const parsed = tryParseStructuredText(result);
|
|
2678
|
+
if (parsed === null) return null;
|
|
2679
|
+
return parseArtifactFromToolResult(parsed);
|
|
2680
|
+
}
|
|
2681
|
+
if (Array.isArray(result)) {
|
|
2682
|
+
for (const item of result) {
|
|
2683
|
+
if (typeof item === "object" && item !== null && "text" in item) {
|
|
2684
|
+
const text = item.text;
|
|
2685
|
+
if (typeof text === "string") {
|
|
2686
|
+
const fromText = parseArtifactFromToolResult(text);
|
|
2687
|
+
if (fromText) return fromText;
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
return null;
|
|
2692
|
+
}
|
|
2693
|
+
if (typeof result === "object") {
|
|
2694
|
+
const obj = result;
|
|
2695
|
+
if (obj.type === "text" && typeof obj.text === "string") {
|
|
2696
|
+
return parseArtifactFromToolResult(obj.text);
|
|
2697
|
+
}
|
|
2698
|
+
if (obj.type === "thinking" && typeof obj.thinking === "string") {
|
|
2699
|
+
return parseArtifactFromToolResult(obj.thinking);
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
return isArtifact(result) ? result : null;
|
|
2703
|
+
}
|
|
2704
|
+
var FENCE_RE = /```(?:timbal-artifact|timbal)\s*\n([\s\S]*?)\n```/g;
|
|
2705
|
+
function findMarkdownArtifacts(markdown) {
|
|
2706
|
+
const matches = [];
|
|
2707
|
+
FENCE_RE.lastIndex = 0;
|
|
2708
|
+
let m;
|
|
2709
|
+
while ((m = FENCE_RE.exec(markdown)) !== null) {
|
|
2710
|
+
const raw = m[0];
|
|
2711
|
+
const body = m[1];
|
|
2712
|
+
try {
|
|
2713
|
+
const parsed = JSON.parse(body);
|
|
2714
|
+
if (isArtifact(parsed)) {
|
|
2715
|
+
matches.push({
|
|
2716
|
+
artifact: parsed,
|
|
2717
|
+
raw,
|
|
2718
|
+
start: m.index,
|
|
2719
|
+
end: m.index + raw.length
|
|
2720
|
+
});
|
|
2721
|
+
}
|
|
2722
|
+
} catch {
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
return matches;
|
|
2726
|
+
}
|
|
2727
|
+
function splitMarkdownByArtifacts(markdown) {
|
|
2728
|
+
const matches = findMarkdownArtifacts(markdown);
|
|
2729
|
+
if (matches.length === 0) return [{ kind: "text", text: markdown }];
|
|
2730
|
+
const segments = [];
|
|
2731
|
+
let cursor = 0;
|
|
2732
|
+
for (const match of matches) {
|
|
2733
|
+
if (match.start > cursor) {
|
|
2734
|
+
segments.push({ kind: "text", text: markdown.slice(cursor, match.start) });
|
|
2735
|
+
}
|
|
2736
|
+
segments.push({ kind: "artifact", artifact: match.artifact });
|
|
2737
|
+
cursor = match.end;
|
|
2738
|
+
}
|
|
2739
|
+
if (cursor < markdown.length) {
|
|
2740
|
+
segments.push({ kind: "text", text: markdown.slice(cursor) });
|
|
2741
|
+
}
|
|
2742
|
+
return segments;
|
|
2743
|
+
}
|
|
859
2744
|
|
|
860
2745
|
// src/components/syntax-highlighter.tsx
|
|
861
|
-
var import_react6 = require("react");
|
|
862
|
-
var import_core = require("shiki/core");
|
|
863
|
-
var import_javascript = require("shiki/engine/javascript");
|
|
864
2746
|
var import_javascript2 = __toESM(require("shiki/langs/javascript.mjs"), 1);
|
|
865
2747
|
var import_typescript = __toESM(require("shiki/langs/typescript.mjs"), 1);
|
|
866
2748
|
var import_python = __toESM(require("shiki/langs/python.mjs"), 1);
|
|
@@ -880,7 +2762,7 @@ var import_c = __toESM(require("shiki/langs/c.mjs"), 1);
|
|
|
880
2762
|
var import_cpp = __toESM(require("shiki/langs/cpp.mjs"), 1);
|
|
881
2763
|
var import_vitesse_dark = __toESM(require("shiki/themes/vitesse-dark.mjs"), 1);
|
|
882
2764
|
var import_vitesse_light = __toESM(require("shiki/themes/vitesse-light.mjs"), 1);
|
|
883
|
-
var
|
|
2765
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
884
2766
|
var SHIKI_THEME_DARK = "vitesse-dark";
|
|
885
2767
|
var SHIKI_THEME_LIGHT = "vitesse-light";
|
|
886
2768
|
var highlighterPromise = null;
|
|
@@ -918,8 +2800,8 @@ var ShikiSyntaxHighlighter = ({
|
|
|
918
2800
|
language,
|
|
919
2801
|
code
|
|
920
2802
|
}) => {
|
|
921
|
-
const [html, setHtml] = (0,
|
|
922
|
-
(0,
|
|
2803
|
+
const [html, setHtml] = (0, import_react15.useState)(null);
|
|
2804
|
+
(0, import_react15.useEffect)(() => {
|
|
923
2805
|
let cancelled = false;
|
|
924
2806
|
(async () => {
|
|
925
2807
|
try {
|
|
@@ -945,8 +2827,17 @@ var ShikiSyntaxHighlighter = ({
|
|
|
945
2827
|
cancelled = true;
|
|
946
2828
|
};
|
|
947
2829
|
}, [code, language]);
|
|
2830
|
+
if (isArtifactFenceLanguage(language)) {
|
|
2831
|
+
try {
|
|
2832
|
+
const parsed = JSON.parse(code);
|
|
2833
|
+
if (isArtifact(parsed)) {
|
|
2834
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactView, { artifact: parsed });
|
|
2835
|
+
}
|
|
2836
|
+
} catch {
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
948
2839
|
if (html) {
|
|
949
|
-
return /* @__PURE__ */ (0,
|
|
2840
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
950
2841
|
"div",
|
|
951
2842
|
{
|
|
952
2843
|
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 +2845,14 @@ var ShikiSyntaxHighlighter = ({
|
|
|
954
2845
|
}
|
|
955
2846
|
);
|
|
956
2847
|
}
|
|
957
|
-
return /* @__PURE__ */ (0,
|
|
2848
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pre, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Code2, { children: code }) });
|
|
958
2849
|
};
|
|
959
2850
|
var syntax_highlighter_default = ShikiSyntaxHighlighter;
|
|
960
2851
|
|
|
961
2852
|
// src/components/markdown-text.tsx
|
|
962
|
-
var
|
|
2853
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
963
2854
|
var MarkdownTextImpl = () => {
|
|
964
|
-
return /* @__PURE__ */ (0,
|
|
2855
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
965
2856
|
import_react_markdown.MarkdownTextPrimitive,
|
|
966
2857
|
{
|
|
967
2858
|
remarkPlugins: [import_remark_gfm.default, import_remark_math.default],
|
|
@@ -974,27 +2865,28 @@ var MarkdownTextImpl = () => {
|
|
|
974
2865
|
}
|
|
975
2866
|
);
|
|
976
2867
|
};
|
|
977
|
-
var MarkdownText = (0,
|
|
2868
|
+
var MarkdownText = (0, import_react16.memo)(MarkdownTextImpl);
|
|
978
2869
|
var CodeHeader = ({ language, code }) => {
|
|
979
2870
|
const { isCopied, copyToClipboard } = useCopyToClipboard();
|
|
2871
|
+
if (isArtifactFenceLanguage(language)) return null;
|
|
980
2872
|
const onCopy = () => {
|
|
981
2873
|
if (!code || isCopied) return;
|
|
982
2874
|
copyToClipboard(code);
|
|
983
2875
|
};
|
|
984
|
-
return /* @__PURE__ */ (0,
|
|
985
|
-
/* @__PURE__ */ (0,
|
|
986
|
-
/* @__PURE__ */ (0,
|
|
2876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.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: [
|
|
2877
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-wide text-muted-foreground/80 uppercase", children: [
|
|
2878
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40" }),
|
|
987
2879
|
language
|
|
988
2880
|
] }),
|
|
989
|
-
/* @__PURE__ */ (0,
|
|
2881
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
990
2882
|
TooltipIconButton,
|
|
991
2883
|
{
|
|
992
2884
|
tooltip: isCopied ? "Copied!" : "Copy",
|
|
993
2885
|
onClick: onCopy,
|
|
994
2886
|
className: "transition-colors hover:text-foreground",
|
|
995
2887
|
children: [
|
|
996
|
-
!isCopied && /* @__PURE__ */ (0,
|
|
997
|
-
isCopied && /* @__PURE__ */ (0,
|
|
2888
|
+
!isCopied && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react4.CopyIcon, { className: "h-3.5 w-3.5" }),
|
|
2889
|
+
isCopied && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react4.CheckIcon, { className: "h-3.5 w-3.5 text-emerald-500" })
|
|
998
2890
|
]
|
|
999
2891
|
}
|
|
1000
2892
|
)
|
|
@@ -1003,7 +2895,7 @@ var CodeHeader = ({ language, code }) => {
|
|
|
1003
2895
|
var useCopyToClipboard = ({
|
|
1004
2896
|
copiedDuration = 3e3
|
|
1005
2897
|
} = {}) => {
|
|
1006
|
-
const [isCopied, setIsCopied] = (0,
|
|
2898
|
+
const [isCopied, setIsCopied] = (0, import_react16.useState)(false);
|
|
1007
2899
|
const copyToClipboard = (value) => {
|
|
1008
2900
|
if (!value) return;
|
|
1009
2901
|
navigator.clipboard.writeText(value).then(() => {
|
|
@@ -1014,7 +2906,7 @@ var useCopyToClipboard = ({
|
|
|
1014
2906
|
return { isCopied, copyToClipboard };
|
|
1015
2907
|
};
|
|
1016
2908
|
var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownComponents)({
|
|
1017
|
-
h1: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2909
|
+
h1: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1018
2910
|
"h1",
|
|
1019
2911
|
{
|
|
1020
2912
|
className: cn(
|
|
@@ -1024,7 +2916,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1024
2916
|
...props
|
|
1025
2917
|
}
|
|
1026
2918
|
),
|
|
1027
|
-
h2: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2919
|
+
h2: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1028
2920
|
"h2",
|
|
1029
2921
|
{
|
|
1030
2922
|
className: cn(
|
|
@@ -1034,7 +2926,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1034
2926
|
...props
|
|
1035
2927
|
}
|
|
1036
2928
|
),
|
|
1037
|
-
h3: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2929
|
+
h3: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1038
2930
|
"h3",
|
|
1039
2931
|
{
|
|
1040
2932
|
className: cn(
|
|
@@ -1044,7 +2936,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1044
2936
|
...props
|
|
1045
2937
|
}
|
|
1046
2938
|
),
|
|
1047
|
-
h4: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2939
|
+
h4: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1048
2940
|
"h4",
|
|
1049
2941
|
{
|
|
1050
2942
|
className: cn(
|
|
@@ -1054,7 +2946,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1054
2946
|
...props
|
|
1055
2947
|
}
|
|
1056
2948
|
),
|
|
1057
|
-
h5: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2949
|
+
h5: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1058
2950
|
"h5",
|
|
1059
2951
|
{
|
|
1060
2952
|
className: cn(
|
|
@@ -1064,7 +2956,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1064
2956
|
...props
|
|
1065
2957
|
}
|
|
1066
2958
|
),
|
|
1067
|
-
h6: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2959
|
+
h6: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1068
2960
|
"h6",
|
|
1069
2961
|
{
|
|
1070
2962
|
className: cn(
|
|
@@ -1074,7 +2966,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1074
2966
|
...props
|
|
1075
2967
|
}
|
|
1076
2968
|
),
|
|
1077
|
-
p: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2969
|
+
p: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1078
2970
|
"p",
|
|
1079
2971
|
{
|
|
1080
2972
|
className: cn(
|
|
@@ -1084,7 +2976,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1084
2976
|
...props
|
|
1085
2977
|
}
|
|
1086
2978
|
),
|
|
1087
|
-
a: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2979
|
+
a: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1088
2980
|
"a",
|
|
1089
2981
|
{
|
|
1090
2982
|
className: cn(
|
|
@@ -1096,7 +2988,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1096
2988
|
...props
|
|
1097
2989
|
}
|
|
1098
2990
|
),
|
|
1099
|
-
blockquote: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
2991
|
+
blockquote: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1100
2992
|
"blockquote",
|
|
1101
2993
|
{
|
|
1102
2994
|
className: cn(
|
|
@@ -1106,7 +2998,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1106
2998
|
...props
|
|
1107
2999
|
}
|
|
1108
3000
|
),
|
|
1109
|
-
ul: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
3001
|
+
ul: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1110
3002
|
"ul",
|
|
1111
3003
|
{
|
|
1112
3004
|
className: cn(
|
|
@@ -1116,7 +3008,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1116
3008
|
...props
|
|
1117
3009
|
}
|
|
1118
3010
|
),
|
|
1119
|
-
ol: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
3011
|
+
ol: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1120
3012
|
"ol",
|
|
1121
3013
|
{
|
|
1122
3014
|
className: cn(
|
|
@@ -1126,7 +3018,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1126
3018
|
...props
|
|
1127
3019
|
}
|
|
1128
3020
|
),
|
|
1129
|
-
hr: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
3021
|
+
hr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1130
3022
|
"hr",
|
|
1131
3023
|
{
|
|
1132
3024
|
className: cn(
|
|
@@ -1136,14 +3028,14 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1136
3028
|
...props
|
|
1137
3029
|
}
|
|
1138
3030
|
),
|
|
1139
|
-
table: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
3031
|
+
table: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "my-4 w-full overflow-x-auto rounded-lg border border-border/50", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1140
3032
|
"table",
|
|
1141
3033
|
{
|
|
1142
3034
|
className: cn("aui-md-table w-full border-collapse text-sm", className),
|
|
1143
3035
|
...props
|
|
1144
3036
|
}
|
|
1145
3037
|
) }),
|
|
1146
|
-
th: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
3038
|
+
th: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1147
3039
|
"th",
|
|
1148
3040
|
{
|
|
1149
3041
|
className: cn(
|
|
@@ -1153,7 +3045,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1153
3045
|
...props
|
|
1154
3046
|
}
|
|
1155
3047
|
),
|
|
1156
|
-
td: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
3048
|
+
td: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1157
3049
|
"td",
|
|
1158
3050
|
{
|
|
1159
3051
|
className: cn(
|
|
@@ -1163,7 +3055,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1163
3055
|
...props
|
|
1164
3056
|
}
|
|
1165
3057
|
),
|
|
1166
|
-
tr: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
3058
|
+
tr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1167
3059
|
"tr",
|
|
1168
3060
|
{
|
|
1169
3061
|
className: cn(
|
|
@@ -1173,8 +3065,8 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1173
3065
|
...props
|
|
1174
3066
|
}
|
|
1175
3067
|
),
|
|
1176
|
-
li: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
1177
|
-
sup: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
3068
|
+
li: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { className: cn("aui-md-li leading-[1.7]", className), ...props }),
|
|
3069
|
+
sup: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1178
3070
|
"sup",
|
|
1179
3071
|
{
|
|
1180
3072
|
className: cn(
|
|
@@ -1184,7 +3076,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1184
3076
|
...props
|
|
1185
3077
|
}
|
|
1186
3078
|
),
|
|
1187
|
-
pre: ({ className, ...props }) => /* @__PURE__ */ (0,
|
|
3079
|
+
pre: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1188
3080
|
"pre",
|
|
1189
3081
|
{
|
|
1190
3082
|
className: cn(
|
|
@@ -1196,97 +3088,554 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
1196
3088
|
),
|
|
1197
3089
|
code: function Code({ className, ...props }) {
|
|
1198
3090
|
const isCodeBlock = (0, import_react_markdown.useIsMarkdownCodeBlock)();
|
|
1199
|
-
return /* @__PURE__ */ (0,
|
|
3091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1200
3092
|
"code",
|
|
1201
3093
|
{
|
|
1202
|
-
className: cn(
|
|
1203
|
-
!isCodeBlock && "aui-md-inline-code rounded-[5px] border border-border/60 bg-muted/60 px-[0.4em] py-[0.15em] font-mono text-[0.85em] font-medium text-foreground/90 dark:bg-muted/40",
|
|
1204
|
-
className
|
|
1205
|
-
),
|
|
1206
|
-
...props
|
|
3094
|
+
className: cn(
|
|
3095
|
+
!isCodeBlock && "aui-md-inline-code rounded-[5px] border border-border/60 bg-muted/60 px-[0.4em] py-[0.15em] font-mono text-[0.85em] font-medium text-foreground/90 dark:bg-muted/40",
|
|
3096
|
+
className
|
|
3097
|
+
),
|
|
3098
|
+
...props
|
|
3099
|
+
}
|
|
3100
|
+
);
|
|
3101
|
+
},
|
|
3102
|
+
strong: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("strong", { className: cn("font-semibold text-foreground", className), ...props }),
|
|
3103
|
+
em: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("em", { className: cn("italic", className), ...props }),
|
|
3104
|
+
CodeHeader
|
|
3105
|
+
});
|
|
3106
|
+
|
|
3107
|
+
// src/components/tool-fallback.tsx
|
|
3108
|
+
var import_react20 = require("react");
|
|
3109
|
+
var import_lucide_react5 = require("lucide-react");
|
|
3110
|
+
var import_react21 = require("@assistant-ui/react");
|
|
3111
|
+
|
|
3112
|
+
// src/ui/shimmer.tsx
|
|
3113
|
+
var import_react17 = require("motion/react");
|
|
3114
|
+
var import_react18 = require("react");
|
|
3115
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
3116
|
+
var ShimmerComponent = ({
|
|
3117
|
+
children,
|
|
3118
|
+
as: Component = "p",
|
|
3119
|
+
className,
|
|
3120
|
+
duration = 2,
|
|
3121
|
+
spread = 2
|
|
3122
|
+
}) => {
|
|
3123
|
+
const MotionComponent = import_react17.motion.create(
|
|
3124
|
+
Component
|
|
3125
|
+
);
|
|
3126
|
+
const dynamicSpread = (0, import_react18.useMemo)(
|
|
3127
|
+
() => (children?.length ?? 0) * spread,
|
|
3128
|
+
[children, spread]
|
|
3129
|
+
);
|
|
3130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3131
|
+
MotionComponent,
|
|
3132
|
+
{
|
|
3133
|
+
animate: { backgroundPosition: "0% center" },
|
|
3134
|
+
className: cn(
|
|
3135
|
+
"relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent",
|
|
3136
|
+
"[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",
|
|
3137
|
+
className
|
|
3138
|
+
),
|
|
3139
|
+
initial: { backgroundPosition: "100% center" },
|
|
3140
|
+
style: {
|
|
3141
|
+
"--spread": `${dynamicSpread}px`,
|
|
3142
|
+
backgroundImage: "var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))"
|
|
3143
|
+
},
|
|
3144
|
+
transition: {
|
|
3145
|
+
repeat: Number.POSITIVE_INFINITY,
|
|
3146
|
+
duration,
|
|
3147
|
+
ease: "linear"
|
|
3148
|
+
},
|
|
3149
|
+
children
|
|
3150
|
+
}
|
|
3151
|
+
);
|
|
3152
|
+
};
|
|
3153
|
+
var Shimmer = (0, import_react18.memo)(ShimmerComponent);
|
|
3154
|
+
|
|
3155
|
+
// src/components/motion.tsx
|
|
3156
|
+
var import_react19 = require("motion/react");
|
|
3157
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3158
|
+
var luxuryEase = [0.16, 1, 0.3, 1];
|
|
3159
|
+
var TOOL_ENTER_MS = 0.78;
|
|
3160
|
+
var TOOL_EXIT_MS = 0.28;
|
|
3161
|
+
function toolPresenceTransition(reduced) {
|
|
3162
|
+
return {
|
|
3163
|
+
enter: {
|
|
3164
|
+
duration: reduced ? 0.35 : TOOL_ENTER_MS,
|
|
3165
|
+
ease: luxuryEase
|
|
3166
|
+
},
|
|
3167
|
+
exit: {
|
|
3168
|
+
duration: reduced ? 0.2 : TOOL_EXIT_MS,
|
|
3169
|
+
ease: [0.4, 0, 1, 1]
|
|
3170
|
+
}
|
|
3171
|
+
};
|
|
3172
|
+
}
|
|
3173
|
+
function toolMotionState(reduced, entering, variant) {
|
|
3174
|
+
if (reduced) {
|
|
3175
|
+
return entering ? { opacity: 0, y: variant === "executing" ? 8 : 10 } : { opacity: 1, y: 0 };
|
|
3176
|
+
}
|
|
3177
|
+
if (variant === "executing") {
|
|
3178
|
+
return entering ? { opacity: 0, y: 12 } : { opacity: 1, y: 0 };
|
|
3179
|
+
}
|
|
3180
|
+
return entering ? { opacity: 0, y: 14, filter: "blur(10px)" } : { opacity: 1, y: 0, filter: "blur(0px)" };
|
|
3181
|
+
}
|
|
3182
|
+
function ToolMotion({ children, className, motionKey }) {
|
|
3183
|
+
const reduced = (0, import_react19.useReducedMotion)() ?? false;
|
|
3184
|
+
const { enter, exit } = toolPresenceTransition(reduced);
|
|
3185
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3186
|
+
import_react19.motion.div,
|
|
3187
|
+
{
|
|
3188
|
+
className: cn("aui-tool-motion w-full min-w-0", className),
|
|
3189
|
+
initial: toolMotionState(reduced, true, "settled"),
|
|
3190
|
+
animate: toolMotionState(reduced, false, "settled"),
|
|
3191
|
+
exit: reduced ? { opacity: 0, y: 6, transition: exit } : { opacity: 0, y: 8, filter: "blur(6px)", transition: exit },
|
|
3192
|
+
transition: enter,
|
|
3193
|
+
style: { willChange: "opacity, transform, filter" },
|
|
3194
|
+
children
|
|
3195
|
+
},
|
|
3196
|
+
motionKey
|
|
3197
|
+
);
|
|
3198
|
+
}
|
|
3199
|
+
function ToolPresence({
|
|
3200
|
+
presenceKey,
|
|
3201
|
+
children,
|
|
3202
|
+
className,
|
|
3203
|
+
variant = "settled"
|
|
3204
|
+
}) {
|
|
3205
|
+
const reduced = (0, import_react19.useReducedMotion)() ?? false;
|
|
3206
|
+
const { enter, exit } = toolPresenceTransition(reduced);
|
|
3207
|
+
const enterTransition = variant === "executing" ? { duration: reduced ? 0.3 : 0.52, ease: luxuryEase } : enter;
|
|
3208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react19.AnimatePresence, { mode: "wait", initial: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3209
|
+
import_react19.motion.div,
|
|
3210
|
+
{
|
|
3211
|
+
className: cn("aui-tool-presence w-full min-w-0", className),
|
|
3212
|
+
initial: toolMotionState(reduced, true, variant),
|
|
3213
|
+
animate: toolMotionState(reduced, false, variant),
|
|
3214
|
+
exit: reduced ? { opacity: 0, y: 6, transition: exit } : { opacity: 0, y: 8, filter: "blur(6px)", transition: exit },
|
|
3215
|
+
transition: enterTransition,
|
|
3216
|
+
style: {
|
|
3217
|
+
willChange: variant === "executing" ? "opacity, transform" : "opacity, transform, filter"
|
|
3218
|
+
},
|
|
3219
|
+
children
|
|
3220
|
+
},
|
|
3221
|
+
presenceKey
|
|
3222
|
+
) });
|
|
3223
|
+
}
|
|
3224
|
+
function ToolBodyPresence({
|
|
3225
|
+
open,
|
|
3226
|
+
children,
|
|
3227
|
+
className
|
|
3228
|
+
}) {
|
|
3229
|
+
const reduced = (0, import_react19.useReducedMotion)() ?? false;
|
|
3230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3231
|
+
"div",
|
|
3232
|
+
{
|
|
3233
|
+
className: cn(
|
|
3234
|
+
"aui-tool-body grid min-h-0 transition-[grid-template-rows]",
|
|
3235
|
+
open ? reduced ? "duration-200 ease-out" : "duration-[340ms] ease-[cubic-bezier(0.16,1,0.3,1)]" : reduced ? "duration-150 ease-[cubic-bezier(0.4,0,0.2,1)]" : "duration-200 ease-[cubic-bezier(0.4,0,0.2,1)]"
|
|
3236
|
+
),
|
|
3237
|
+
style: { gridTemplateRows: open ? "1fr" : "0fr" },
|
|
3238
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "min-h-0 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3239
|
+
"div",
|
|
3240
|
+
{
|
|
3241
|
+
className: cn(
|
|
3242
|
+
className,
|
|
3243
|
+
"transition-opacity",
|
|
3244
|
+
open ? reduced ? "opacity-100 duration-200 ease-out" : "opacity-100 duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] delay-75" : reduced ? "opacity-0 duration-100 ease-in" : "opacity-0 duration-150 ease-[cubic-bezier(0.4,0,0.2,1)]"
|
|
3245
|
+
),
|
|
3246
|
+
children
|
|
3247
|
+
}
|
|
3248
|
+
) })
|
|
3249
|
+
}
|
|
3250
|
+
);
|
|
3251
|
+
}
|
|
3252
|
+
|
|
3253
|
+
// src/components/tool-fallback.tsx
|
|
3254
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
3255
|
+
function detectRunning({
|
|
3256
|
+
status,
|
|
3257
|
+
result,
|
|
3258
|
+
streamRunning
|
|
3259
|
+
}) {
|
|
3260
|
+
const isError = status?.type === "incomplete" && status.reason !== "cancelled";
|
|
3261
|
+
if (isError) return false;
|
|
3262
|
+
if (status?.type === "running") return true;
|
|
3263
|
+
if (status?.type === "complete") return false;
|
|
3264
|
+
return streamRunning && result === void 0;
|
|
3265
|
+
}
|
|
3266
|
+
function useToolRunning(props) {
|
|
3267
|
+
const { isRunning: streamRunning } = useTimbalRuntime();
|
|
3268
|
+
const partStatus = (0, import_react21.useAuiState)((s) => s.part.status);
|
|
3269
|
+
return detectRunning({
|
|
3270
|
+
status: partStatus ?? props.status,
|
|
3271
|
+
result: props.result,
|
|
3272
|
+
streamRunning
|
|
3273
|
+
});
|
|
3274
|
+
}
|
|
3275
|
+
function formatToolLabel(toolName) {
|
|
3276
|
+
return toolName.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
|
|
3277
|
+
}
|
|
3278
|
+
function formatToolResult(result) {
|
|
3279
|
+
if (typeof result === "string") return result;
|
|
3280
|
+
try {
|
|
3281
|
+
return JSON.stringify(result, null, 2);
|
|
3282
|
+
} catch {
|
|
3283
|
+
return String(result);
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
var TimelineActionLabel = ({ action, detail, shimmer = false }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "inline-flex min-w-0 max-w-full items-baseline gap-1", children: [
|
|
3287
|
+
action ? shimmer ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3288
|
+
Shimmer,
|
|
3289
|
+
{
|
|
3290
|
+
as: "span",
|
|
3291
|
+
className: cn(studioTimelineShimmerActionClass, "aui-tool-shimmer"),
|
|
3292
|
+
duration: 1.8,
|
|
3293
|
+
spread: 2.5,
|
|
3294
|
+
children: action
|
|
3295
|
+
}
|
|
3296
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: studioTimelineActionClass, children: action }) : null,
|
|
3297
|
+
detail ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: studioTimelineDetailClass, children: detail }) : null
|
|
3298
|
+
] });
|
|
3299
|
+
var TimelineHoverChevron = ({ expanded }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3300
|
+
import_lucide_react5.ChevronRightIcon,
|
|
3301
|
+
{
|
|
3302
|
+
className: studioTimelineChevronClass(expanded),
|
|
3303
|
+
"aria-hidden": true
|
|
3304
|
+
}
|
|
3305
|
+
);
|
|
3306
|
+
var ToolPanel = ({ toolName, argsText, result, isError }) => {
|
|
3307
|
+
const [open, setOpen] = (0, import_react20.useState)(false);
|
|
3308
|
+
const detail = formatToolLabel(toolName);
|
|
3309
|
+
const formattedArgs = (0, import_react20.useMemo)(() => {
|
|
3310
|
+
if (!argsText || argsText === "{}") return null;
|
|
3311
|
+
try {
|
|
3312
|
+
return JSON.stringify(JSON.parse(argsText), null, 2);
|
|
3313
|
+
} catch {
|
|
3314
|
+
return argsText;
|
|
3315
|
+
}
|
|
3316
|
+
}, [argsText]);
|
|
3317
|
+
const formattedResult = (0, import_react20.useMemo)(() => {
|
|
3318
|
+
if (result === void 0 || result === null) return null;
|
|
3319
|
+
return formatToolResult(result);
|
|
3320
|
+
}, [result]);
|
|
3321
|
+
const hasBody = Boolean(formattedArgs || formattedResult);
|
|
3322
|
+
const action = isError ? "Failed" : "Used";
|
|
3323
|
+
if (!hasBody) {
|
|
3324
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "aui-tool-row w-full min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TimelineActionLabel, { action, detail }) });
|
|
3325
|
+
}
|
|
3326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "aui-tool-row w-full min-w-0", children: [
|
|
3327
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3328
|
+
"button",
|
|
3329
|
+
{
|
|
3330
|
+
type: "button",
|
|
3331
|
+
onClick: () => setOpen((v) => !v),
|
|
3332
|
+
"aria-expanded": open,
|
|
3333
|
+
"aria-label": `${action} ${detail}`,
|
|
3334
|
+
className: studioTimelineRowButtonClass,
|
|
3335
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
3336
|
+
"span",
|
|
3337
|
+
{
|
|
3338
|
+
className: cn(
|
|
3339
|
+
"inline-flex min-w-0 max-w-full items-center gap-0.5",
|
|
3340
|
+
studioTimelineTextClass,
|
|
3341
|
+
"text-foreground"
|
|
3342
|
+
),
|
|
3343
|
+
children: [
|
|
3344
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TimelineActionLabel, { action, detail }),
|
|
3345
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TimelineHoverChevron, { expanded: open })
|
|
3346
|
+
]
|
|
3347
|
+
}
|
|
3348
|
+
)
|
|
3349
|
+
}
|
|
3350
|
+
),
|
|
3351
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
3352
|
+
ToolBodyPresence,
|
|
3353
|
+
{
|
|
3354
|
+
open,
|
|
3355
|
+
className: cn(studioTimelineBodyPadClass, "gap-2"),
|
|
3356
|
+
children: [
|
|
3357
|
+
formattedArgs ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3358
|
+
"div",
|
|
3359
|
+
{
|
|
3360
|
+
className: cn(
|
|
3361
|
+
studioComposerIoWellClass,
|
|
3362
|
+
"max-h-48 overflow-auto px-2.5 py-2"
|
|
3363
|
+
),
|
|
3364
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("pre", { className: "whitespace-pre-wrap break-words font-mono text-[11px] font-normal leading-relaxed text-foreground", children: formattedArgs })
|
|
3365
|
+
}
|
|
3366
|
+
) : null,
|
|
3367
|
+
formattedResult ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3368
|
+
"div",
|
|
3369
|
+
{
|
|
3370
|
+
className: cn(
|
|
3371
|
+
studioComposerIoWellClass,
|
|
3372
|
+
"max-h-48 overflow-auto px-2.5 py-2"
|
|
3373
|
+
),
|
|
3374
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("pre", { className: "whitespace-pre-wrap break-words font-mono text-[11px] font-normal leading-relaxed text-foreground", children: formattedResult })
|
|
3375
|
+
}
|
|
3376
|
+
) : null
|
|
3377
|
+
]
|
|
3378
|
+
}
|
|
3379
|
+
)
|
|
3380
|
+
] });
|
|
3381
|
+
};
|
|
3382
|
+
var ToolFallbackImpl = ({
|
|
3383
|
+
toolName,
|
|
3384
|
+
argsText,
|
|
3385
|
+
result,
|
|
3386
|
+
status
|
|
3387
|
+
}) => {
|
|
3388
|
+
const isRunning = useToolRunning({ status, result });
|
|
3389
|
+
const isError = status?.type === "incomplete" && status.reason !== "cancelled";
|
|
3390
|
+
const presenceKey = isRunning ? "running" : isError ? "error" : "complete";
|
|
3391
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3392
|
+
ToolPresence,
|
|
3393
|
+
{
|
|
3394
|
+
presenceKey,
|
|
3395
|
+
variant: isRunning ? "executing" : "settled",
|
|
3396
|
+
className: "py-0.5",
|
|
3397
|
+
children: isRunning ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "aui-tool-running", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3398
|
+
TimelineActionLabel,
|
|
3399
|
+
{
|
|
3400
|
+
action: "Using",
|
|
3401
|
+
detail: formatToolLabel(toolName),
|
|
3402
|
+
shimmer: true
|
|
3403
|
+
}
|
|
3404
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3405
|
+
ToolPanel,
|
|
3406
|
+
{
|
|
3407
|
+
toolName,
|
|
3408
|
+
argsText,
|
|
3409
|
+
result,
|
|
3410
|
+
isError
|
|
3411
|
+
}
|
|
3412
|
+
)
|
|
3413
|
+
}
|
|
3414
|
+
);
|
|
3415
|
+
};
|
|
3416
|
+
var ToolFallback = (0, import_react20.memo)(
|
|
3417
|
+
ToolFallbackImpl
|
|
3418
|
+
);
|
|
3419
|
+
ToolFallback.displayName = "ToolFallback";
|
|
3420
|
+
|
|
3421
|
+
// src/artifacts/tool-artifact.tsx
|
|
3422
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
3423
|
+
var ToolArtifactFallback = (props) => {
|
|
3424
|
+
const registry = useArtifactRegistry();
|
|
3425
|
+
const isRunning = useToolRunning({
|
|
3426
|
+
status: props.status,
|
|
3427
|
+
result: props.result
|
|
3428
|
+
});
|
|
3429
|
+
if (!isRunning) {
|
|
3430
|
+
const artifact = parseArtifactFromToolResult(props.result);
|
|
3431
|
+
if (artifact) {
|
|
3432
|
+
const Renderer = registry[artifact.type];
|
|
3433
|
+
if (Renderer) {
|
|
3434
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3435
|
+
ToolMotion,
|
|
3436
|
+
{
|
|
3437
|
+
motionKey: `artifact-${artifact.type}`,
|
|
3438
|
+
className: "aui-tool-artifact",
|
|
3439
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Renderer, { artifact })
|
|
3440
|
+
}
|
|
3441
|
+
);
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ToolFallback, { ...props });
|
|
3446
|
+
};
|
|
3447
|
+
|
|
3448
|
+
// src/components/composer.tsx
|
|
3449
|
+
var import_react22 = require("@assistant-ui/react");
|
|
3450
|
+
var import_lucide_react6 = require("lucide-react");
|
|
3451
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
3452
|
+
var Composer = ({
|
|
3453
|
+
placeholder = "Send a message...",
|
|
3454
|
+
showAttachments = true,
|
|
3455
|
+
toolbar,
|
|
3456
|
+
sendTooltip = "Send message",
|
|
3457
|
+
noAutoFocus,
|
|
3458
|
+
className
|
|
3459
|
+
}) => {
|
|
3460
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3461
|
+
import_react22.ComposerPrimitive.Root,
|
|
3462
|
+
{
|
|
3463
|
+
className: cn(
|
|
3464
|
+
"aui-composer-root relative flex w-full flex-col",
|
|
3465
|
+
className
|
|
3466
|
+
),
|
|
3467
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3468
|
+
import_react22.ComposerPrimitive.AttachmentDropzone,
|
|
3469
|
+
{
|
|
3470
|
+
className: cn(
|
|
3471
|
+
studioComposeInputShellClass,
|
|
3472
|
+
"data-[dragging=true]:border-2 data-[dragging=true]:border-dashed data-[dragging=true]:border-primary data-[dragging=true]:bg-accent/50"
|
|
3473
|
+
),
|
|
3474
|
+
children: [
|
|
3475
|
+
showAttachments && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerAttachments, {}),
|
|
3476
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerInput, { placeholder, autoFocus: !noAutoFocus }),
|
|
3477
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3478
|
+
ComposerToolbar,
|
|
3479
|
+
{
|
|
3480
|
+
showAttachments,
|
|
3481
|
+
toolbar,
|
|
3482
|
+
sendTooltip
|
|
3483
|
+
}
|
|
3484
|
+
)
|
|
3485
|
+
]
|
|
3486
|
+
}
|
|
3487
|
+
)
|
|
3488
|
+
}
|
|
3489
|
+
);
|
|
3490
|
+
};
|
|
3491
|
+
var ComposerInput = ({
|
|
3492
|
+
placeholder,
|
|
3493
|
+
autoFocus
|
|
3494
|
+
}) => {
|
|
3495
|
+
const composer = (0, import_react22.useComposerRuntime)();
|
|
3496
|
+
const onKeyDown = (e) => {
|
|
3497
|
+
if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
|
|
3498
|
+
e.preventDefault();
|
|
3499
|
+
composer.send();
|
|
3500
|
+
}
|
|
3501
|
+
};
|
|
3502
|
+
const onInput = (e) => {
|
|
3503
|
+
const el = e.currentTarget;
|
|
3504
|
+
el.style.height = "auto";
|
|
3505
|
+
el.style.height = `${Math.min(el.scrollHeight, 240)}px`;
|
|
3506
|
+
};
|
|
3507
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3508
|
+
import_react22.ComposerPrimitive.Input,
|
|
3509
|
+
{
|
|
3510
|
+
placeholder,
|
|
3511
|
+
className: "aui-composer-input max-h-60 min-h-14 w-full resize-none bg-transparent px-3 pt-3 pb-1 text-sm outline-none placeholder:text-neutral-400 focus-visible:ring-0 dark:placeholder:text-neutral-500",
|
|
3512
|
+
rows: 1,
|
|
3513
|
+
autoFocus,
|
|
3514
|
+
"aria-label": "Message input",
|
|
3515
|
+
onKeyDown,
|
|
3516
|
+
onInput
|
|
3517
|
+
}
|
|
3518
|
+
);
|
|
3519
|
+
};
|
|
3520
|
+
var ComposerToolbar = ({ showAttachments, toolbar, sendTooltip }) => {
|
|
3521
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-composer-action-wrapper flex items-center justify-between gap-1 px-2.5 pb-2.5", children: [
|
|
3522
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
3523
|
+
showAttachments && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerAddAttachment, {}),
|
|
3524
|
+
toolbar
|
|
3525
|
+
] }),
|
|
3526
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerSendOrCancel, { sendTooltip })
|
|
3527
|
+
] });
|
|
3528
|
+
};
|
|
3529
|
+
var ComposerSendOrCancel = ({ sendTooltip }) => {
|
|
3530
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
3531
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react22.AuiIf, { condition: (s) => !s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react22.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3532
|
+
TooltipIconButton,
|
|
3533
|
+
{
|
|
3534
|
+
tooltip: sendTooltip,
|
|
3535
|
+
variant: "primary",
|
|
3536
|
+
type: "submit",
|
|
3537
|
+
className: "aui-composer-send shrink-0 disabled:opacity-30",
|
|
3538
|
+
"aria-label": "Send message",
|
|
3539
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react6.ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
|
|
3540
|
+
}
|
|
3541
|
+
) }) }),
|
|
3542
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react22.AuiIf, { condition: (s) => s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react22.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3543
|
+
TooltipIconButton,
|
|
3544
|
+
{
|
|
3545
|
+
tooltip: "Stop generating",
|
|
3546
|
+
variant: "primary",
|
|
3547
|
+
className: "aui-composer-cancel shrink-0",
|
|
3548
|
+
"aria-label": "Stop generating",
|
|
3549
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react6.SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
|
|
1207
3550
|
}
|
|
1208
|
-
)
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
em: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("em", { className: cn("italic", className), ...props }),
|
|
1212
|
-
CodeHeader
|
|
1213
|
-
});
|
|
1214
|
-
|
|
1215
|
-
// src/components/tool-fallback.tsx
|
|
1216
|
-
var import_react10 = require("react");
|
|
1217
|
-
var import_lucide_react4 = require("lucide-react");
|
|
3551
|
+
) }) })
|
|
3552
|
+
] });
|
|
3553
|
+
};
|
|
1218
3554
|
|
|
1219
|
-
// src/
|
|
1220
|
-
var
|
|
1221
|
-
var
|
|
1222
|
-
var
|
|
1223
|
-
var
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
className
|
|
1227
|
-
duration = 2,
|
|
1228
|
-
spread = 2
|
|
3555
|
+
// src/components/suggestions.tsx
|
|
3556
|
+
var import_react23 = require("react");
|
|
3557
|
+
var import_react24 = require("@assistant-ui/react");
|
|
3558
|
+
var import_lucide_react7 = require("lucide-react");
|
|
3559
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
3560
|
+
var Suggestions = ({
|
|
3561
|
+
suggestions,
|
|
3562
|
+
className
|
|
1229
3563
|
}) => {
|
|
1230
|
-
const
|
|
1231
|
-
|
|
1232
|
-
)
|
|
1233
|
-
|
|
1234
|
-
() => (children?.length ?? 0) * spread,
|
|
1235
|
-
[children, spread]
|
|
1236
|
-
);
|
|
1237
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1238
|
-
MotionComponent,
|
|
3564
|
+
const items = useResolvedSuggestions(suggestions);
|
|
3565
|
+
if (!items || items.length === 0) return null;
|
|
3566
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3567
|
+
"div",
|
|
1239
3568
|
{
|
|
1240
|
-
animate: { backgroundPosition: "0% center" },
|
|
1241
3569
|
className: cn(
|
|
1242
|
-
"
|
|
1243
|
-
"[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",
|
|
3570
|
+
"aui-thread-suggestions flex w-full flex-col gap-2 pb-2.5",
|
|
1244
3571
|
className
|
|
1245
3572
|
),
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
backgroundImage: "var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))"
|
|
1250
|
-
},
|
|
1251
|
-
transition: {
|
|
1252
|
-
repeat: Number.POSITIVE_INFINITY,
|
|
1253
|
-
duration,
|
|
1254
|
-
ease: "linear"
|
|
1255
|
-
},
|
|
1256
|
-
children
|
|
3573
|
+
role: "list",
|
|
3574
|
+
"aria-label": "Suggested prompts",
|
|
3575
|
+
children: items.map((suggestion, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SuggestionRow, { suggestion }, (suggestion.prompt ?? suggestion.title) + i))
|
|
1257
3576
|
}
|
|
1258
3577
|
);
|
|
1259
3578
|
};
|
|
1260
|
-
var
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
3579
|
+
var SuggestionRow = ({ suggestion }) => {
|
|
3580
|
+
const runtime = (0, import_react24.useThreadRuntime)();
|
|
3581
|
+
const onClick = () => {
|
|
3582
|
+
const text = suggestion.prompt ?? suggestion.title;
|
|
3583
|
+
runtime.append({ role: "user", content: [{ type: "text", text }] });
|
|
3584
|
+
};
|
|
3585
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3586
|
+
"button",
|
|
3587
|
+
{
|
|
3588
|
+
type: "button",
|
|
3589
|
+
role: "listitem",
|
|
3590
|
+
onClick,
|
|
3591
|
+
className: cn("aui-thread-suggestion", studioListRowButtonClass),
|
|
3592
|
+
children: [
|
|
3593
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-icon shrink-0 text-neutral-500 dark:text-muted-foreground", children: suggestion.icon ?? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react7.ArrowUpIcon, { className: "size-4", strokeWidth: 1.75, "aria-hidden": true }) }),
|
|
3594
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "aui-thread-suggestion-text min-w-0 flex-1 text-left", children: [
|
|
3595
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-text-1 block truncate text-sm font-normal text-foreground dark:text-foreground/95", children: suggestion.title }),
|
|
3596
|
+
suggestion.description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-text-2 mt-0.5 block truncate text-xs text-muted-foreground", children: suggestion.description })
|
|
3597
|
+
] })
|
|
3598
|
+
]
|
|
3599
|
+
}
|
|
3600
|
+
);
|
|
1273
3601
|
};
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
)
|
|
1277
|
-
|
|
3602
|
+
function useResolvedSuggestions(source) {
|
|
3603
|
+
const [resolved, setResolved] = (0, import_react23.useState)(
|
|
3604
|
+
() => Array.isArray(source) ? source : void 0
|
|
3605
|
+
);
|
|
3606
|
+
(0, import_react23.useEffect)(() => {
|
|
3607
|
+
if (!source) {
|
|
3608
|
+
setResolved(void 0);
|
|
3609
|
+
return;
|
|
3610
|
+
}
|
|
3611
|
+
if (Array.isArray(source)) {
|
|
3612
|
+
setResolved(source);
|
|
3613
|
+
return;
|
|
3614
|
+
}
|
|
3615
|
+
let cancelled = false;
|
|
3616
|
+
Promise.resolve().then(() => source()).then((value) => {
|
|
3617
|
+
if (!cancelled) setResolved(value);
|
|
3618
|
+
}).catch(() => {
|
|
3619
|
+
if (!cancelled) setResolved([]);
|
|
3620
|
+
});
|
|
3621
|
+
return () => {
|
|
3622
|
+
cancelled = true;
|
|
3623
|
+
};
|
|
3624
|
+
}, [source]);
|
|
3625
|
+
return (0, import_react23.useMemo)(() => resolved, [resolved]);
|
|
3626
|
+
}
|
|
1278
3627
|
|
|
1279
3628
|
// src/components/thread.tsx
|
|
1280
|
-
var
|
|
1281
|
-
var import_lucide_react5 = require("lucide-react");
|
|
1282
|
-
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
3629
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1283
3630
|
var Thread = ({
|
|
1284
3631
|
className,
|
|
1285
3632
|
maxWidth = "44rem",
|
|
1286
3633
|
welcome,
|
|
1287
3634
|
suggestions,
|
|
1288
3635
|
composerPlaceholder = "Send a message...",
|
|
1289
|
-
components
|
|
3636
|
+
components,
|
|
3637
|
+
artifacts,
|
|
3638
|
+
onArtifactEvent
|
|
1290
3639
|
}) => {
|
|
1291
3640
|
const WelcomeSlot = components?.Welcome ?? ThreadWelcome;
|
|
1292
3641
|
const ComposerSlot = components?.Composer ?? Composer;
|
|
@@ -1294,202 +3643,217 @@ var Thread = ({
|
|
|
1294
3643
|
const AssistantMessageSlot = components?.AssistantMessage ?? AssistantMessage;
|
|
1295
3644
|
const EditComposerSlot = components?.EditComposer ?? EditComposer;
|
|
1296
3645
|
const ScrollToBottomSlot = components?.ScrollToBottom ?? ThreadScrollToBottom;
|
|
1297
|
-
|
|
1298
|
-
|
|
3646
|
+
const SuggestionsSlot = components?.Suggestions ?? Suggestions;
|
|
3647
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3648
|
+
ArtifactRegistryProvider,
|
|
1299
3649
|
{
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
),
|
|
1304
|
-
|
|
1305
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1306
|
-
import_react11.ThreadPrimitive.Viewport,
|
|
3650
|
+
renderers: artifacts?.renderers,
|
|
3651
|
+
override: artifacts?.override,
|
|
3652
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UiEventProvider, { onEvent: onArtifactEvent ?? (() => {
|
|
3653
|
+
}), children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3654
|
+
import_react25.ThreadPrimitive.Root,
|
|
1307
3655
|
{
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
3656
|
+
className: cn(
|
|
3657
|
+
"aui-root aui-thread-root @container flex h-full flex-col bg-background",
|
|
3658
|
+
className
|
|
3659
|
+
),
|
|
3660
|
+
style: { ["--thread-max-width"]: maxWidth },
|
|
3661
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3662
|
+
import_react25.ThreadPrimitive.Viewport,
|
|
3663
|
+
{
|
|
3664
|
+
turnAnchor: "bottom",
|
|
3665
|
+
className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4 pt-4",
|
|
3666
|
+
children: [
|
|
3667
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3668
|
+
WelcomeSlot,
|
|
3669
|
+
{
|
|
3670
|
+
config: welcome,
|
|
3671
|
+
suggestions,
|
|
3672
|
+
Suggestions: SuggestionsSlot
|
|
3673
|
+
}
|
|
3674
|
+
),
|
|
3675
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3676
|
+
import_react25.ThreadPrimitive.Messages,
|
|
3677
|
+
{
|
|
3678
|
+
components: {
|
|
3679
|
+
UserMessage: UserMessageSlot,
|
|
3680
|
+
EditComposer: EditComposerSlot,
|
|
3681
|
+
AssistantMessage: AssistantMessageSlot
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
),
|
|
3685
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react25.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: [
|
|
3686
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ScrollToBottomSlot, {}),
|
|
3687
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ComposerSlot, { placeholder: composerPlaceholder })
|
|
3688
|
+
] })
|
|
3689
|
+
]
|
|
3690
|
+
}
|
|
3691
|
+
)
|
|
1327
3692
|
}
|
|
1328
|
-
)
|
|
3693
|
+
) })
|
|
1329
3694
|
}
|
|
1330
3695
|
);
|
|
1331
3696
|
};
|
|
1332
3697
|
var ThreadScrollToBottom = () => {
|
|
1333
|
-
return /* @__PURE__ */ (0,
|
|
3698
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1334
3699
|
TooltipIconButton,
|
|
1335
3700
|
{
|
|
1336
3701
|
tooltip: "Scroll to bottom",
|
|
1337
|
-
variant: "
|
|
1338
|
-
className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center
|
|
1339
|
-
children: /* @__PURE__ */ (0,
|
|
3702
|
+
variant: "secondary",
|
|
3703
|
+
className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center disabled:invisible",
|
|
3704
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.ArrowDownIcon, { className: "size-4" })
|
|
1340
3705
|
}
|
|
1341
3706
|
) });
|
|
1342
3707
|
};
|
|
1343
|
-
var
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "animate-ai-pulse-ring absolute inset-0" }),
|
|
1349
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1350
|
-
"svg",
|
|
1351
|
-
{
|
|
1352
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
1353
|
-
viewBox: "0 0 24 24",
|
|
1354
|
-
fill: "none",
|
|
1355
|
-
stroke: "currentColor",
|
|
1356
|
-
strokeWidth: "1.5",
|
|
1357
|
-
strokeLinecap: "round",
|
|
1358
|
-
strokeLinejoin: "round",
|
|
1359
|
-
className: "animate-ai-breathe relative size-7 text-primary/75",
|
|
1360
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime12.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
|
-
}
|
|
1362
|
-
)
|
|
1363
|
-
] }),
|
|
1364
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.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?" }),
|
|
1365
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.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
|
-
] }) }),
|
|
1367
|
-
suggestions && suggestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ThreadSuggestions, { 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)) });
|
|
3708
|
+
var welcomeStagger = {
|
|
3709
|
+
initial: {},
|
|
3710
|
+
animate: {
|
|
3711
|
+
transition: { staggerChildren: 0.16, delayChildren: 0.12 }
|
|
3712
|
+
}
|
|
1372
3713
|
};
|
|
1373
|
-
var
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
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
|
-
) });
|
|
3714
|
+
var welcomeItem = {
|
|
3715
|
+
initial: { opacity: 0, y: 14 },
|
|
3716
|
+
animate: {
|
|
3717
|
+
opacity: 1,
|
|
3718
|
+
y: 0,
|
|
3719
|
+
transition: { duration: 0.9, ease: luxuryEase }
|
|
3720
|
+
}
|
|
1390
3721
|
};
|
|
1391
|
-
var
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
rows: 1,
|
|
1400
|
-
autoFocus: true,
|
|
1401
|
-
"aria-label": "Message input"
|
|
1402
|
-
}
|
|
1403
|
-
),
|
|
1404
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ComposerAction, {})
|
|
1405
|
-
] }) });
|
|
3722
|
+
var welcomeIcon = {
|
|
3723
|
+
initial: { opacity: 0, y: 10, scale: 0.96 },
|
|
3724
|
+
animate: {
|
|
3725
|
+
opacity: 1,
|
|
3726
|
+
y: 0,
|
|
3727
|
+
scale: 1,
|
|
3728
|
+
transition: { duration: 1.1, ease: luxuryEase }
|
|
3729
|
+
}
|
|
1406
3730
|
};
|
|
1407
|
-
var
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
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,
|
|
3731
|
+
var ThreadWelcome = ({
|
|
3732
|
+
config,
|
|
3733
|
+
suggestions,
|
|
3734
|
+
Suggestions: SuggestionsSlot = Suggestions
|
|
3735
|
+
}) => {
|
|
3736
|
+
const isEmpty = (0, import_react25.useThread)((s) => s.messages.length === 0);
|
|
3737
|
+
if (!isEmpty) return null;
|
|
3738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
|
|
3739
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3740
|
+
import_react26.motion.div,
|
|
1424
3741
|
{
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
3742
|
+
className: "aui-thread-welcome-message flex flex-col items-center justify-center px-4 text-center",
|
|
3743
|
+
variants: welcomeStagger,
|
|
3744
|
+
initial: "initial",
|
|
3745
|
+
animate: "animate",
|
|
3746
|
+
children: [
|
|
3747
|
+
config?.icon && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.motion.div, { variants: welcomeIcon, className: "mb-5", children: config.icon }),
|
|
3748
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3749
|
+
import_react26.motion.h1,
|
|
3750
|
+
{
|
|
3751
|
+
variants: welcomeItem,
|
|
3752
|
+
className: "aui-thread-welcome-message-inner font-semibold text-2xl",
|
|
3753
|
+
children: config?.heading ?? "How can I help you today?"
|
|
3754
|
+
}
|
|
3755
|
+
),
|
|
3756
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3757
|
+
import_react26.motion.p,
|
|
3758
|
+
{
|
|
3759
|
+
variants: welcomeItem,
|
|
3760
|
+
className: "aui-thread-welcome-message-inner mt-2 text-muted-foreground",
|
|
3761
|
+
children: config?.subheading ?? "Send a message to start a conversation."
|
|
3762
|
+
}
|
|
3763
|
+
)
|
|
3764
|
+
]
|
|
1431
3765
|
}
|
|
1432
|
-
) })
|
|
3766
|
+
) }),
|
|
3767
|
+
suggestions && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-thread-welcome-suggestions mx-auto w-full max-w-(--thread-max-width) px-2", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SuggestionsSlot, { suggestions }) })
|
|
1433
3768
|
] });
|
|
1434
3769
|
};
|
|
1435
3770
|
var MessageError = () => {
|
|
1436
|
-
return /* @__PURE__ */ (0,
|
|
3771
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.MessagePrimitive.Error, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.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_runtime27.jsx)(import_react25.ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) });
|
|
1437
3772
|
};
|
|
1438
3773
|
var AssistantMessage = () => {
|
|
1439
|
-
return /* @__PURE__ */ (0,
|
|
1440
|
-
|
|
3774
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3775
|
+
import_react25.MessagePrimitive.Root,
|
|
1441
3776
|
{
|
|
1442
3777
|
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
3778
|
"data-role": "assistant",
|
|
1444
3779
|
children: [
|
|
1445
|
-
/* @__PURE__ */ (0,
|
|
1446
|
-
/* @__PURE__ */ (0,
|
|
1447
|
-
|
|
3780
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed", children: [
|
|
3781
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3782
|
+
import_react25.MessagePrimitive.Parts,
|
|
1448
3783
|
{
|
|
1449
3784
|
components: {
|
|
1450
3785
|
Text: MarkdownText,
|
|
1451
|
-
|
|
3786
|
+
// `Override` (not `Fallback`) replaces the default tool renderer
|
|
3787
|
+
// entirely so we never fall back to the assistant-ui boilerplate.
|
|
3788
|
+
tools: { Override: ToolArtifactFallback }
|
|
1452
3789
|
}
|
|
1453
3790
|
}
|
|
1454
3791
|
),
|
|
1455
|
-
/* @__PURE__ */ (0,
|
|
3792
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MessageError, {})
|
|
1456
3793
|
] }),
|
|
1457
|
-
/* @__PURE__ */ (0,
|
|
3794
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-assistant-message-footer mt-0 ml-1 flex", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AssistantActionBar, {}) })
|
|
1458
3795
|
]
|
|
1459
3796
|
}
|
|
1460
3797
|
);
|
|
1461
3798
|
};
|
|
3799
|
+
var ASSISTANT_ACTION_ICON_CLASS = cn(
|
|
3800
|
+
"size-6 min-h-6 min-w-6 text-muted-foreground/45 hover:text-muted-foreground/80",
|
|
3801
|
+
// The v2 fill span sits inside `group/tbv2 > span:first-child`. We mute it
|
|
3802
|
+
// here so action-bar buttons read as subtle icons rather than full pills.
|
|
3803
|
+
"[&>span:first-child]:bg-transparent",
|
|
3804
|
+
"[&>span:first-child]:group-hover/tbv2:bg-neutral-100/50",
|
|
3805
|
+
"dark:[&>span:first-child]:group-hover/tbv2:bg-white/8"
|
|
3806
|
+
);
|
|
1462
3807
|
var AssistantActionBar = () => {
|
|
1463
|
-
return /* @__PURE__ */ (0,
|
|
1464
|
-
|
|
3808
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3809
|
+
import_react25.ActionBarPrimitive.Root,
|
|
1465
3810
|
{
|
|
1466
3811
|
hideWhenRunning: true,
|
|
1467
3812
|
autohide: "not-last",
|
|
1468
|
-
|
|
1469
|
-
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",
|
|
3813
|
+
className: "aui-assistant-action-bar-root flex items-center gap-0 bg-transparent px-0 py-0.5 text-muted-foreground/60",
|
|
1470
3814
|
children: [
|
|
1471
|
-
/* @__PURE__ */ (0,
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
3815
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.ActionBarPrimitive.Copy, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3816
|
+
TooltipIconButton,
|
|
3817
|
+
{
|
|
3818
|
+
tooltip: "Copy",
|
|
3819
|
+
variant: "ghost",
|
|
3820
|
+
className: ASSISTANT_ACTION_ICON_CLASS,
|
|
3821
|
+
children: [
|
|
3822
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.AuiIf, { condition: (s) => s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.CheckIcon, { className: "size-3" }) }),
|
|
3823
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.AuiIf, { condition: (s) => !s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.CopyIcon, { className: "size-3" }) })
|
|
3824
|
+
]
|
|
3825
|
+
}
|
|
3826
|
+
) }),
|
|
3827
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.ActionBarPrimitive.Reload, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3828
|
+
TooltipIconButton,
|
|
3829
|
+
{
|
|
3830
|
+
tooltip: "Regenerate",
|
|
3831
|
+
variant: "ghost",
|
|
3832
|
+
className: ASSISTANT_ACTION_ICON_CLASS,
|
|
3833
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.RefreshCwIcon, { className: "size-3" })
|
|
3834
|
+
}
|
|
3835
|
+
) }),
|
|
3836
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react25.ActionBarMorePrimitive.Root, { children: [
|
|
3837
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.ActionBarMorePrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1478
3838
|
TooltipIconButton,
|
|
1479
3839
|
{
|
|
1480
3840
|
tooltip: "More",
|
|
1481
|
-
|
|
1482
|
-
|
|
3841
|
+
variant: "ghost",
|
|
3842
|
+
className: cn(
|
|
3843
|
+
ASSISTANT_ACTION_ICON_CLASS,
|
|
3844
|
+
"data-[state=open]:text-muted-foreground/80"
|
|
3845
|
+
),
|
|
3846
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.MoreHorizontalIcon, { className: "size-3" })
|
|
1483
3847
|
}
|
|
1484
3848
|
) }),
|
|
1485
|
-
/* @__PURE__ */ (0,
|
|
1486
|
-
|
|
3849
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3850
|
+
import_react25.ActionBarMorePrimitive.Content,
|
|
1487
3851
|
{
|
|
1488
3852
|
side: "bottom",
|
|
1489
3853
|
align: "start",
|
|
1490
|
-
className: "aui-action-bar-more-content z-50 min-w-
|
|
1491
|
-
children: /* @__PURE__ */ (0,
|
|
1492
|
-
/* @__PURE__ */ (0,
|
|
3854
|
+
className: "aui-action-bar-more-content z-50 min-w-36 overflow-hidden rounded-lg border border-neutral-200 bg-white p-1 text-foreground shadow-md dark:border-white/10 dark:bg-zinc-900",
|
|
3855
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react25.ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none hover:bg-neutral-100 focus:bg-neutral-100 dark:hover:bg-zinc-800 dark:focus:bg-zinc-800", children: [
|
|
3856
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.DownloadIcon, { className: "size-4 shrink-0" }),
|
|
1493
3857
|
"Export as Markdown"
|
|
1494
3858
|
] }) })
|
|
1495
3859
|
}
|
|
@@ -1499,66 +3863,419 @@ var AssistantActionBar = () => {
|
|
|
1499
3863
|
}
|
|
1500
3864
|
);
|
|
1501
3865
|
};
|
|
3866
|
+
var UserMessageText = () => {
|
|
3867
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "whitespace-pre-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.MessagePartPrimitive.Text, { smooth: false }) });
|
|
3868
|
+
};
|
|
1502
3869
|
var UserMessage = () => {
|
|
1503
|
-
return /* @__PURE__ */ (0,
|
|
1504
|
-
|
|
3870
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3871
|
+
import_react25.MessagePrimitive.Root,
|
|
1505
3872
|
{
|
|
1506
|
-
className: "aui-user-message-root
|
|
3873
|
+
className: "aui-user-message-root mx-auto flex w-full max-w-(--thread-max-width) flex-col items-end gap-2 px-2 py-3",
|
|
1507
3874
|
"data-role": "user",
|
|
1508
3875
|
children: [
|
|
1509
|
-
/* @__PURE__ */ (0,
|
|
1510
|
-
/* @__PURE__ */ (0,
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
3876
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UserMessageAttachments, {}),
|
|
3877
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3878
|
+
import_react26.motion.div,
|
|
3879
|
+
{
|
|
3880
|
+
className: "aui-user-message-content relative inline-block max-w-[80%] rounded-2xl bg-neutral-200 px-4 py-2.5 text-foreground dark:bg-neutral-700",
|
|
3881
|
+
initial: { opacity: 0, y: 8, scale: 0.99 },
|
|
3882
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
3883
|
+
transition: { duration: 0.65, ease: luxuryEase },
|
|
3884
|
+
children: [
|
|
3885
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.MessagePrimitive.Parts, { components: { Text: UserMessageText } }),
|
|
3886
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.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_runtime27.jsx)(UserActionBar, {}) })
|
|
3887
|
+
]
|
|
3888
|
+
}
|
|
3889
|
+
)
|
|
1514
3890
|
]
|
|
1515
3891
|
}
|
|
1516
3892
|
);
|
|
1517
3893
|
};
|
|
1518
3894
|
var UserActionBar = () => {
|
|
1519
|
-
return /* @__PURE__ */ (0,
|
|
1520
|
-
|
|
3895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3896
|
+
import_react25.ActionBarPrimitive.Root,
|
|
1521
3897
|
{
|
|
1522
3898
|
hideWhenRunning: true,
|
|
1523
3899
|
autohide: "not-last",
|
|
1524
3900
|
className: "aui-user-action-bar-root flex flex-col items-end",
|
|
1525
|
-
children: /* @__PURE__ */ (0,
|
|
3901
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.ActionBarPrimitive.Edit, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3902
|
+
TooltipIconButton,
|
|
3903
|
+
{
|
|
3904
|
+
tooltip: "Edit",
|
|
3905
|
+
variant: "ghost",
|
|
3906
|
+
className: ASSISTANT_ACTION_ICON_CLASS,
|
|
3907
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.PencilIcon, { className: "size-3" })
|
|
3908
|
+
}
|
|
3909
|
+
) })
|
|
1526
3910
|
}
|
|
1527
3911
|
);
|
|
1528
3912
|
};
|
|
1529
3913
|
var EditComposer = () => {
|
|
1530
|
-
return /* @__PURE__ */ (0,
|
|
1531
|
-
/* @__PURE__ */ (0,
|
|
1532
|
-
|
|
3914
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.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_runtime27.jsxs)(import_react25.ComposerPrimitive.Root, { className: "aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted", children: [
|
|
3915
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3916
|
+
import_react25.ComposerPrimitive.Input,
|
|
1533
3917
|
{
|
|
1534
3918
|
className: "aui-edit-composer-input min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none",
|
|
1535
3919
|
autoFocus: true
|
|
1536
3920
|
}
|
|
1537
3921
|
),
|
|
1538
|
-
/* @__PURE__ */ (0,
|
|
1539
|
-
/* @__PURE__ */ (0,
|
|
1540
|
-
/* @__PURE__ */ (0,
|
|
3922
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end", children: [
|
|
3923
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TimbalV2Button, { variant: "ghost", size: "sm", children: "Cancel" }) }),
|
|
3924
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react25.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TimbalV2Button, { variant: "primary", size: "sm", children: "Update" }) })
|
|
1541
3925
|
] })
|
|
1542
3926
|
] }) });
|
|
1543
3927
|
};
|
|
1544
3928
|
|
|
1545
3929
|
// src/components/chat.tsx
|
|
1546
|
-
var
|
|
3930
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1547
3931
|
function TimbalChat({
|
|
1548
3932
|
workforceId,
|
|
1549
3933
|
baseUrl,
|
|
1550
3934
|
fetch: fetch2,
|
|
3935
|
+
attachments,
|
|
3936
|
+
attachmentsUploadUrl,
|
|
3937
|
+
attachmentsAccept,
|
|
3938
|
+
debug,
|
|
1551
3939
|
...threadProps
|
|
1552
3940
|
}) {
|
|
1553
|
-
return /* @__PURE__ */ (0,
|
|
3941
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3942
|
+
TimbalRuntimeProvider,
|
|
3943
|
+
{
|
|
3944
|
+
workforceId,
|
|
3945
|
+
baseUrl,
|
|
3946
|
+
fetch: fetch2,
|
|
3947
|
+
attachments,
|
|
3948
|
+
attachmentsUploadUrl,
|
|
3949
|
+
attachmentsAccept,
|
|
3950
|
+
debug,
|
|
3951
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Thread, { ...threadProps })
|
|
3952
|
+
}
|
|
3953
|
+
);
|
|
1554
3954
|
}
|
|
1555
3955
|
|
|
3956
|
+
// src/artifacts/agent-instructions.ts
|
|
3957
|
+
var ARTIFACT_AGENT_INSTRUCTIONS = `
|
|
3958
|
+
## Rich artifacts (Timbal chat UI)
|
|
3959
|
+
|
|
3960
|
+
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.
|
|
3961
|
+
|
|
3962
|
+
### Delivery channels (either works)
|
|
3963
|
+
|
|
3964
|
+
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.
|
|
3965
|
+
2. **Inline markdown fence** \u2014 embed the same JSON inside a fenced block:
|
|
3966
|
+
|
|
3967
|
+
\`\`\`timbal-artifact
|
|
3968
|
+
{"type":"chart","data":[{"month":"Jan","sales":120}]}
|
|
3969
|
+
\`\`\`
|
|
3970
|
+
|
|
3971
|
+
The alias \`\`\`timbal\`\`\` is also accepted.
|
|
3972
|
+
|
|
3973
|
+
### Built-in artifact types
|
|
3974
|
+
|
|
3975
|
+
| \`type\` | Use for |
|
|
3976
|
+
|---|---|
|
|
3977
|
+
| \`chart\` | Bar, line, area, or pie charts. Fields: \`data\`, optional \`chartType\`, \`xKey\`, \`dataKey\`, \`title\`, \`unit\`. |
|
|
3978
|
+
| \`table\` | Tabular data. Fields: \`rows\`, optional \`columns\`, \`title\`. |
|
|
3979
|
+
| \`question\` | In-thread multiple choice. Fields: \`options: [{ id, label, description? }]\`, optional \`prompt\`, \`multi\`. User replies are sent back as a normal user message. |
|
|
3980
|
+
| \`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). |
|
|
3981
|
+
| \`json\` | Fallback structured view. Fields: \`data\`, optional \`title\`. |
|
|
3982
|
+
| \`ui\` | **Interactive UI** composed from a fixed node palette (hover, click, drag). See below. |
|
|
3983
|
+
|
|
3984
|
+
### When to use \`type: "html"\`
|
|
3985
|
+
|
|
3986
|
+
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\`.
|
|
3987
|
+
|
|
3988
|
+
- Inline \`<style>\`, \`<script>\`, SVG, and canvas are supported.
|
|
3989
|
+
- Default \`sandboxed: true\` runs in an isolated iframe with scripts enabled.
|
|
3990
|
+
- Set \`sandboxed: false\` only for trusted content that needs external CDN scripts/styles or full DOM freedom.
|
|
3991
|
+
- Prefer \`ui\` when controls should send chat messages or host events; prefer \`html\` for self-contained mini-apps and visual demos.
|
|
3992
|
+
|
|
3993
|
+
### When to use \`type: "ui"\`
|
|
3994
|
+
|
|
3995
|
+
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.
|
|
3996
|
+
|
|
3997
|
+
Each \`ui\` artifact has:
|
|
3998
|
+
|
|
3999
|
+
- \`initialState\` \u2014 optional object seeding local state (per widget instance).
|
|
4000
|
+
- \`root\` \u2014 a single node tree (see node kinds below).
|
|
4001
|
+
- optional \`title\` \u2014 card heading.
|
|
4002
|
+
|
|
4003
|
+
**Bindings:** anywhere a primitive is accepted, you may use \`{ "$bind": "dotted.path" }\` to read from \`initialState\` / local state (e.g. \`{ "$bind": "qty" }\`).
|
|
4004
|
+
|
|
4005
|
+
**Actions:** nodes may attach \`onClick\`, \`onChange\`, or \`onDragEnd\` with one action or an array:
|
|
4006
|
+
|
|
4007
|
+
| Action | Shape | Effect |
|
|
4008
|
+
|---|---|---|
|
|
4009
|
+
| User message | \`{ "kind": "message", "text": "..." }\` or \`{ "kind": "message", "text": { "$bind": "path" } }\` | Sends text as the next user message. |
|
|
4010
|
+
| Set state | \`{ "kind": "set", "path": "foo", "value": 1 }\` | Writes local widget state. |
|
|
4011
|
+
| Toggle boolean | \`{ "kind": "toggle", "path": "enabled" }\` | Flips a boolean at \`path\`. |
|
|
4012
|
+
| Host event | \`{ "kind": "emit", "name": "event-name", "payload": { ... } }\` | Bubbles to the host app (\`onArtifactEvent\` on \`<Thread>\`). |
|
|
4013
|
+
|
|
4014
|
+
### \`ui\` node palette (\`root.kind\`)
|
|
4015
|
+
|
|
4016
|
+
| \`kind\` | Purpose | Key fields |
|
|
4017
|
+
|---|---|---|
|
|
4018
|
+
| \`box\` | Layout container | \`children\`, \`direction\` (\`row\`/\`col\`), \`gap\`, \`padding\`, \`align\`, \`justify\`, \`wrap\` |
|
|
4019
|
+
| \`text\` | Body text | \`value\`, optional \`muted\`, \`size\`, \`weight\` |
|
|
4020
|
+
| \`heading\` | Heading | \`value\`, optional \`level\` (1\u20134) |
|
|
4021
|
+
| \`badge\` | Pill label | \`value\`, optional \`tone\` (\`default\`, \`primary\`, \`success\`, \`warn\`, \`danger\`) |
|
|
4022
|
+
| \`button\` | Clickable button | \`label\`, optional \`variant\`, \`size\`, \`disabled\`, \`onClick\` |
|
|
4023
|
+
| \`toggle\` | Boolean switch | \`binding\` (state path), optional \`label\`, \`onChange\` |
|
|
4024
|
+
| \`slider\` | Numeric range | \`binding\`, optional \`min\`, \`max\`, \`step\`, \`label\`, \`showValue\`, \`onChange\` |
|
|
4025
|
+
| \`tooltip\` | Hover tooltip | \`content\`, \`child\` (single node), optional \`side\` |
|
|
4026
|
+
| \`draggable\` | Drag gesture | \`child\`, optional \`axis\` (\`x\`/\`y\`/\`both\`), \`snapBack\`, \`onDragEnd\` |
|
|
4027
|
+
| \`custom\` | Host-registered widget | \`name\`, optional \`props\`, \`children\` \u2014 only if the app registered that name |
|
|
4028
|
+
|
|
4029
|
+
### Example \`ui\` artifact
|
|
4030
|
+
|
|
4031
|
+
\`\`\`json
|
|
4032
|
+
{
|
|
4033
|
+
"type": "ui",
|
|
4034
|
+
"title": "Configure plan",
|
|
4035
|
+
"initialState": { "qty": 1, "premium": false },
|
|
4036
|
+
"root": {
|
|
4037
|
+
"kind": "box",
|
|
4038
|
+
"direction": "col",
|
|
4039
|
+
"gap": 3,
|
|
4040
|
+
"children": [
|
|
4041
|
+
{ "kind": "heading", "value": "Choose quantity", "level": 3 },
|
|
4042
|
+
{
|
|
4043
|
+
"kind": "tooltip",
|
|
4044
|
+
"content": "Drag to adjust quantity",
|
|
4045
|
+
"child": {
|
|
4046
|
+
"kind": "slider",
|
|
4047
|
+
"binding": "qty",
|
|
4048
|
+
"min": 1,
|
|
4049
|
+
"max": 50,
|
|
4050
|
+
"label": "Quantity",
|
|
4051
|
+
"onChange": { "kind": "emit", "name": "qty-changed" }
|
|
4052
|
+
}
|
|
4053
|
+
},
|
|
4054
|
+
{ "kind": "toggle", "binding": "premium", "label": "Premium support" },
|
|
4055
|
+
{
|
|
4056
|
+
"kind": "button",
|
|
4057
|
+
"label": "Confirm",
|
|
4058
|
+
"onClick": { "kind": "message", "text": { "$bind": "qty" } }
|
|
4059
|
+
}
|
|
4060
|
+
]
|
|
4061
|
+
}
|
|
4062
|
+
}
|
|
4063
|
+
\`\`\`
|
|
4064
|
+
|
|
4065
|
+
### Rules
|
|
4066
|
+
|
|
4067
|
+
- Always set \`type\` to a built-in value above unless the app documented a custom type.
|
|
4068
|
+
- Prefer \`ui\` over \`html\` when actions must bubble to the host chat (\`message\`, \`emit\`).
|
|
4069
|
+
- Prefer \`question\` for simple A/B/C choices; use \`ui\` when you need sliders, toggles, drag, or multi-control layouts.
|
|
4070
|
+
- Keep \`data\` arrays reasonably small (charts/tables).
|
|
4071
|
+
|
|
4072
|
+
### After calling an artifact tool (critical)
|
|
4073
|
+
|
|
4074
|
+
When you call a tool that returns an artifact (\`make_chart\`, \`ask_question\`, \`show_table\`, \`show_html\`, \`make_ui_demo\`, etc.):
|
|
4075
|
+
|
|
4076
|
+
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.
|
|
4077
|
+
2. **Do not** emit a matching \`\`\`timbal-artifact\`\`\` block for the same payload \u2014 pick **one** channel (tool result only).
|
|
4078
|
+
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.
|
|
4079
|
+
4. Treat the widget as visible to the user; refer to it as "above" / "the chart" / "the choices" \u2014 never reproduce its contents.
|
|
4080
|
+
`.trim();
|
|
4081
|
+
|
|
1556
4082
|
// src/index.ts
|
|
1557
|
-
var
|
|
4083
|
+
var import_react29 = require("@assistant-ui/react");
|
|
4084
|
+
|
|
4085
|
+
// src/hooks/use-workforces.ts
|
|
4086
|
+
var import_react27 = require("react");
|
|
4087
|
+
function useWorkforces(options = {}) {
|
|
4088
|
+
const { baseUrl = "/api", fetch: fetchFn, pickInitial } = options;
|
|
4089
|
+
const [workforces, setWorkforces] = (0, import_react27.useState)([]);
|
|
4090
|
+
const [selectedId, setSelectedId] = (0, import_react27.useState)("");
|
|
4091
|
+
const [isLoading, setIsLoading] = (0, import_react27.useState)(true);
|
|
4092
|
+
const [error, setError] = (0, import_react27.useState)(null);
|
|
4093
|
+
const fetchFnRef = (0, import_react27.useRef)(fetchFn ?? authFetch);
|
|
4094
|
+
(0, import_react27.useEffect)(() => {
|
|
4095
|
+
fetchFnRef.current = fetchFn ?? authFetch;
|
|
4096
|
+
}, [fetchFn]);
|
|
4097
|
+
const pickInitialRef = (0, import_react27.useRef)(pickInitial);
|
|
4098
|
+
(0, import_react27.useEffect)(() => {
|
|
4099
|
+
pickInitialRef.current = pickInitial;
|
|
4100
|
+
}, [pickInitial]);
|
|
4101
|
+
const load = (0, import_react27.useMemo)(() => {
|
|
4102
|
+
return async () => {
|
|
4103
|
+
setIsLoading(true);
|
|
4104
|
+
setError(null);
|
|
4105
|
+
try {
|
|
4106
|
+
const res = await fetchFnRef.current(`${baseUrl}/workforce`);
|
|
4107
|
+
if (!res.ok) throw new Error(`Failed to load workforces (${res.status})`);
|
|
4108
|
+
const data = await res.json();
|
|
4109
|
+
setWorkforces(data);
|
|
4110
|
+
setSelectedId((current) => {
|
|
4111
|
+
if (current && data.some((w) => idOf(w) === current)) return current;
|
|
4112
|
+
const initial = pickInitialRef.current?.(data) ?? data.find((w) => w.type === "agent") ?? data[0];
|
|
4113
|
+
return initial ? idOf(initial) : "";
|
|
4114
|
+
});
|
|
4115
|
+
} catch (err) {
|
|
4116
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
4117
|
+
} finally {
|
|
4118
|
+
setIsLoading(false);
|
|
4119
|
+
}
|
|
4120
|
+
};
|
|
4121
|
+
}, [baseUrl]);
|
|
4122
|
+
(0, import_react27.useEffect)(() => {
|
|
4123
|
+
load();
|
|
4124
|
+
}, [load]);
|
|
4125
|
+
const selected = (0, import_react27.useMemo)(
|
|
4126
|
+
() => workforces.find((w) => idOf(w) === selectedId),
|
|
4127
|
+
[workforces, selectedId]
|
|
4128
|
+
);
|
|
4129
|
+
return {
|
|
4130
|
+
workforces,
|
|
4131
|
+
selectedId,
|
|
4132
|
+
setSelectedId,
|
|
4133
|
+
selected,
|
|
4134
|
+
isLoading,
|
|
4135
|
+
error,
|
|
4136
|
+
refresh: load
|
|
4137
|
+
};
|
|
4138
|
+
}
|
|
4139
|
+
function idOf(item) {
|
|
4140
|
+
return item.id ?? item.uid ?? item.name ?? "";
|
|
4141
|
+
}
|
|
4142
|
+
|
|
4143
|
+
// src/components/workforce-selector.tsx
|
|
4144
|
+
var import_lucide_react9 = require("lucide-react");
|
|
4145
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
4146
|
+
var WorkforceSelector = ({
|
|
4147
|
+
workforces,
|
|
4148
|
+
value,
|
|
4149
|
+
onChange,
|
|
4150
|
+
hideWhenSingle = true,
|
|
4151
|
+
className,
|
|
4152
|
+
placeholder = "Select agent"
|
|
4153
|
+
}) => {
|
|
4154
|
+
if (workforces.length === 0) return null;
|
|
4155
|
+
if (hideWhenSingle && workforces.length === 1) return null;
|
|
4156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
4157
|
+
"div",
|
|
4158
|
+
{
|
|
4159
|
+
className: cn(
|
|
4160
|
+
"aui-workforce-selector relative inline-flex items-center",
|
|
4161
|
+
studioTopbarPillHeightClass,
|
|
4162
|
+
studioSecondaryChromeClass,
|
|
4163
|
+
"rounded-full",
|
|
4164
|
+
className
|
|
4165
|
+
),
|
|
4166
|
+
children: [
|
|
4167
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
4168
|
+
"select",
|
|
4169
|
+
{
|
|
4170
|
+
className: "aui-workforce-selector-input h-full cursor-pointer appearance-none rounded-full border-none bg-transparent pr-8 pl-3.5 text-sm font-medium text-foreground outline-none focus:outline-none",
|
|
4171
|
+
value,
|
|
4172
|
+
onChange: (e) => onChange(e.target.value),
|
|
4173
|
+
"aria-label": placeholder,
|
|
4174
|
+
children: [
|
|
4175
|
+
!value && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "", children: placeholder }),
|
|
4176
|
+
workforces.map((w) => {
|
|
4177
|
+
const id = idOf2(w);
|
|
4178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: id, children: w.name ?? id }, id);
|
|
4179
|
+
})
|
|
4180
|
+
]
|
|
4181
|
+
}
|
|
4182
|
+
),
|
|
4183
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4184
|
+
import_lucide_react9.ChevronDownIcon,
|
|
4185
|
+
{
|
|
4186
|
+
className: "aui-workforce-selector-icon pointer-events-none absolute right-3 size-3.5 text-muted-foreground/70",
|
|
4187
|
+
"aria-hidden": true
|
|
4188
|
+
}
|
|
4189
|
+
)
|
|
4190
|
+
]
|
|
4191
|
+
}
|
|
4192
|
+
);
|
|
4193
|
+
};
|
|
4194
|
+
function idOf2(item) {
|
|
4195
|
+
return item.id ?? item.uid ?? item.name ?? "";
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
// src/components/chat-shell.tsx
|
|
4199
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
4200
|
+
var TimbalChatShell = ({
|
|
4201
|
+
workforceId,
|
|
4202
|
+
brand,
|
|
4203
|
+
headerActions,
|
|
4204
|
+
hideWorkforceSelector,
|
|
4205
|
+
className,
|
|
4206
|
+
headerClassName,
|
|
4207
|
+
baseUrl,
|
|
4208
|
+
fetch: fetch2,
|
|
4209
|
+
...chatProps
|
|
4210
|
+
}) => {
|
|
4211
|
+
const { workforces, selectedId, setSelectedId } = useWorkforces({
|
|
4212
|
+
baseUrl,
|
|
4213
|
+
fetch: fetch2
|
|
4214
|
+
});
|
|
4215
|
+
const effectiveId = workforceId ?? selectedId;
|
|
4216
|
+
const showSelector = !hideWorkforceSelector && !workforceId && workforces.length > 0;
|
|
4217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
4218
|
+
"div",
|
|
4219
|
+
{
|
|
4220
|
+
className: cn(
|
|
4221
|
+
"aui-chat-shell relative flex h-dvh flex-col overflow-hidden bg-background",
|
|
4222
|
+
className
|
|
4223
|
+
),
|
|
4224
|
+
style: studioChromeShellStyle,
|
|
4225
|
+
children: [
|
|
4226
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
4227
|
+
"div",
|
|
4228
|
+
{
|
|
4229
|
+
className: cn(
|
|
4230
|
+
"pointer-events-none absolute inset-0 z-0",
|
|
4231
|
+
studioPlaygroundGradientClass
|
|
4232
|
+
),
|
|
4233
|
+
"aria-hidden": true
|
|
4234
|
+
}
|
|
4235
|
+
),
|
|
4236
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
4237
|
+
"header",
|
|
4238
|
+
{
|
|
4239
|
+
className: cn(
|
|
4240
|
+
"aui-chat-shell-header relative z-10 flex shrink-0 items-center justify-between px-4 pt-[var(--studio-topbar-gap)] pb-2",
|
|
4241
|
+
headerClassName
|
|
4242
|
+
),
|
|
4243
|
+
style: { minHeight: "var(--studio-topbar-height)" },
|
|
4244
|
+
children: [
|
|
4245
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
4246
|
+
brand,
|
|
4247
|
+
showSelector && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
4248
|
+
WorkforceSelector,
|
|
4249
|
+
{
|
|
4250
|
+
workforces,
|
|
4251
|
+
value: selectedId,
|
|
4252
|
+
onChange: setSelectedId
|
|
4253
|
+
}
|
|
4254
|
+
)
|
|
4255
|
+
] }),
|
|
4256
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex shrink-0 items-center gap-1", children: headerActions })
|
|
4257
|
+
]
|
|
4258
|
+
}
|
|
4259
|
+
),
|
|
4260
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
4261
|
+
TimbalChat,
|
|
4262
|
+
{
|
|
4263
|
+
workforceId: effectiveId,
|
|
4264
|
+
baseUrl,
|
|
4265
|
+
fetch: fetch2,
|
|
4266
|
+
className: "relative z-10 min-h-0 flex-1 bg-transparent",
|
|
4267
|
+
...chatProps
|
|
4268
|
+
},
|
|
4269
|
+
effectiveId
|
|
4270
|
+
)
|
|
4271
|
+
]
|
|
4272
|
+
}
|
|
4273
|
+
);
|
|
4274
|
+
};
|
|
1558
4275
|
|
|
1559
4276
|
// src/auth/provider.tsx
|
|
1560
|
-
var
|
|
1561
|
-
var
|
|
4277
|
+
var import_react28 = require("react");
|
|
4278
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1562
4279
|
function isInsideIframe() {
|
|
1563
4280
|
try {
|
|
1564
4281
|
return typeof window !== "undefined" && window.self !== window.top;
|
|
@@ -1566,9 +4283,9 @@ function isInsideIframe() {
|
|
|
1566
4283
|
return true;
|
|
1567
4284
|
}
|
|
1568
4285
|
}
|
|
1569
|
-
var SessionContext = (0,
|
|
4286
|
+
var SessionContext = (0, import_react28.createContext)(void 0);
|
|
1570
4287
|
var useSession = () => {
|
|
1571
|
-
const context = (0,
|
|
4288
|
+
const context = (0, import_react28.useContext)(SessionContext);
|
|
1572
4289
|
if (context === void 0) {
|
|
1573
4290
|
throw new Error("useSession must be used within a SessionProvider");
|
|
1574
4291
|
}
|
|
@@ -1578,10 +4295,10 @@ var SessionProvider = ({
|
|
|
1578
4295
|
children,
|
|
1579
4296
|
enabled = true
|
|
1580
4297
|
}) => {
|
|
1581
|
-
const [user, setUser] = (0,
|
|
1582
|
-
const [loading, setLoading] = (0,
|
|
1583
|
-
const [embedded] = (0,
|
|
1584
|
-
(0,
|
|
4298
|
+
const [user, setUser] = (0, import_react28.useState)(null);
|
|
4299
|
+
const [loading, setLoading] = (0, import_react28.useState)(enabled);
|
|
4300
|
+
const [embedded] = (0, import_react28.useState)(isInsideIframe);
|
|
4301
|
+
(0, import_react28.useEffect)(() => {
|
|
1585
4302
|
if (!enabled) {
|
|
1586
4303
|
setLoading(false);
|
|
1587
4304
|
return;
|
|
@@ -1642,7 +4359,7 @@ var SessionProvider = ({
|
|
|
1642
4359
|
messageCleanup?.();
|
|
1643
4360
|
};
|
|
1644
4361
|
}, [enabled, embedded]);
|
|
1645
|
-
const logout = (0,
|
|
4362
|
+
const logout = (0, import_react28.useCallback)(() => {
|
|
1646
4363
|
clearTokens();
|
|
1647
4364
|
setUser(null);
|
|
1648
4365
|
const returnTo = encodeURIComponent(
|
|
@@ -1652,7 +4369,7 @@ var SessionProvider = ({
|
|
|
1652
4369
|
() => window.location.href = `/api/auth/login?return_to=${returnTo}`
|
|
1653
4370
|
);
|
|
1654
4371
|
}, []);
|
|
1655
|
-
return /* @__PURE__ */ (0,
|
|
4372
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1656
4373
|
SessionContext.Provider,
|
|
1657
4374
|
{
|
|
1658
4375
|
value: {
|
|
@@ -1668,8 +4385,8 @@ var SessionProvider = ({
|
|
|
1668
4385
|
};
|
|
1669
4386
|
|
|
1670
4387
|
// src/auth/guard.tsx
|
|
1671
|
-
var
|
|
1672
|
-
var
|
|
4388
|
+
var import_lucide_react10 = require("lucide-react");
|
|
4389
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1673
4390
|
var AuthGuard = ({
|
|
1674
4391
|
children,
|
|
1675
4392
|
requireAuth = false,
|
|
@@ -1680,7 +4397,7 @@ var AuthGuard = ({
|
|
|
1680
4397
|
return children;
|
|
1681
4398
|
}
|
|
1682
4399
|
if (loading) {
|
|
1683
|
-
return /* @__PURE__ */ (0,
|
|
4400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react10.Loader2, { className: "w-8 h-8 animate-spin" }) });
|
|
1684
4401
|
}
|
|
1685
4402
|
if (requireAuth && !isAuthenticated && !isEmbedded) {
|
|
1686
4403
|
const returnTo = encodeURIComponent(
|
|
@@ -1693,15 +4410,26 @@ var AuthGuard = ({
|
|
|
1693
4410
|
};
|
|
1694
4411
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1695
4412
|
0 && (module.exports = {
|
|
4413
|
+
ARTIFACT_AGENT_INSTRUCTIONS,
|
|
4414
|
+
ARTIFACT_FENCE_LANGUAGES,
|
|
4415
|
+
ActionBarMorePrimitive,
|
|
1696
4416
|
ActionBarPrimitive,
|
|
4417
|
+
ArtifactCard,
|
|
4418
|
+
ArtifactRegistryProvider,
|
|
4419
|
+
ArtifactView,
|
|
4420
|
+
AssistantRuntimeProvider,
|
|
4421
|
+
AuiIf,
|
|
1697
4422
|
AuthGuard,
|
|
1698
4423
|
Avatar,
|
|
1699
4424
|
AvatarFallback,
|
|
1700
4425
|
AvatarImage,
|
|
1701
4426
|
Button,
|
|
4427
|
+
ChartArtifactView,
|
|
4428
|
+
Composer,
|
|
1702
4429
|
ComposerAddAttachment,
|
|
1703
4430
|
ComposerAttachments,
|
|
1704
4431
|
ComposerPrimitive,
|
|
4432
|
+
DEFAULT_UPLOAD_ACCEPT,
|
|
1705
4433
|
Dialog,
|
|
1706
4434
|
DialogClose,
|
|
1707
4435
|
DialogContent,
|
|
@@ -1709,35 +4437,119 @@ var AuthGuard = ({
|
|
|
1709
4437
|
DialogPortal,
|
|
1710
4438
|
DialogTitle,
|
|
1711
4439
|
DialogTrigger,
|
|
4440
|
+
ErrorPrimitive,
|
|
4441
|
+
HtmlArtifactView,
|
|
4442
|
+
JsonArtifactView,
|
|
1712
4443
|
MarkdownText,
|
|
4444
|
+
MessagePartPrimitive,
|
|
1713
4445
|
MessagePrimitive,
|
|
4446
|
+
QuestionArtifactView,
|
|
4447
|
+
STUDIO_INSET_LEFT,
|
|
4448
|
+
STUDIO_PILL_HEIGHT,
|
|
4449
|
+
STUDIO_SIDEBAR_GAP,
|
|
4450
|
+
STUDIO_SIDEBAR_WIDTH,
|
|
4451
|
+
STUDIO_TOPBAR_GAP,
|
|
4452
|
+
STUDIO_TOPBAR_HEIGHT,
|
|
1714
4453
|
SessionProvider,
|
|
1715
4454
|
Shimmer,
|
|
4455
|
+
Suggestions,
|
|
1716
4456
|
SyntaxHighlighter,
|
|
4457
|
+
TIMBAL_V2_BORDER,
|
|
4458
|
+
TIMBAL_V2_FILL,
|
|
4459
|
+
TIMBAL_V2_LABEL,
|
|
4460
|
+
TIMBAL_V2_PILL_SURFACE,
|
|
4461
|
+
TIMBAL_V2_SECONDARY_CHROME,
|
|
4462
|
+
TIMBAL_V2_SHADOW,
|
|
4463
|
+
TIMBAL_V2_SIZE_HEIGHT,
|
|
4464
|
+
TIMBAL_V2_SIZE_ICON,
|
|
4465
|
+
TIMBAL_V2_SIZE_LABEL_PX,
|
|
4466
|
+
TableArtifactView,
|
|
1717
4467
|
Thread,
|
|
1718
4468
|
ThreadPrimitive,
|
|
1719
4469
|
TimbalChat,
|
|
4470
|
+
TimbalChatShell,
|
|
1720
4471
|
TimbalRuntimeProvider,
|
|
4472
|
+
TimbalV2Button,
|
|
4473
|
+
ToolArtifactFallback,
|
|
4474
|
+
ToolBodyPresence,
|
|
1721
4475
|
ToolFallback,
|
|
4476
|
+
ToolMotion,
|
|
4477
|
+
ToolPresence,
|
|
1722
4478
|
Tooltip,
|
|
1723
4479
|
TooltipContent,
|
|
1724
4480
|
TooltipIconButton,
|
|
1725
4481
|
TooltipProvider,
|
|
1726
4482
|
TooltipTrigger,
|
|
4483
|
+
UiArtifactView,
|
|
4484
|
+
UiCustomNodeRegistryProvider,
|
|
4485
|
+
UiEventProvider,
|
|
4486
|
+
UiNodeView,
|
|
1727
4487
|
UserMessageAttachments,
|
|
4488
|
+
WorkforceSelector,
|
|
1728
4489
|
authFetch,
|
|
1729
4490
|
buttonVariants,
|
|
1730
4491
|
clearTokens,
|
|
1731
4492
|
cn,
|
|
4493
|
+
createDefaultAttachmentAdapter,
|
|
4494
|
+
createUploadAttachmentAdapter,
|
|
4495
|
+
defaultArtifactRenderers,
|
|
1732
4496
|
fetchCurrentUser,
|
|
4497
|
+
findMarkdownArtifacts,
|
|
1733
4498
|
getAccessToken,
|
|
4499
|
+
getPath,
|
|
1734
4500
|
getRefreshToken,
|
|
4501
|
+
isArtifact,
|
|
4502
|
+
isArtifactFenceLanguage,
|
|
4503
|
+
isUiBinding,
|
|
4504
|
+
luxuryEase,
|
|
4505
|
+
parseArtifactFromToolResult,
|
|
4506
|
+
parseSSELine,
|
|
1735
4507
|
refreshAccessToken,
|
|
4508
|
+
resolveAttachmentAdapter,
|
|
4509
|
+
resolveBindable,
|
|
1736
4510
|
setAccessToken,
|
|
4511
|
+
setPath,
|
|
1737
4512
|
setRefreshToken,
|
|
4513
|
+
splitMarkdownByArtifacts,
|
|
4514
|
+
studioArtifactShellClass,
|
|
4515
|
+
studioChromeShellStyle,
|
|
4516
|
+
studioComposeInputShellClass,
|
|
4517
|
+
studioComposerIoWellClass,
|
|
4518
|
+
studioIntegrationBorder,
|
|
4519
|
+
studioIntegrationCardClass,
|
|
4520
|
+
studioIntegrationIconTileClass,
|
|
4521
|
+
studioIntegrationSurfaceSolid,
|
|
4522
|
+
studioListRowButtonClass,
|
|
4523
|
+
studioPillSurfaceClass,
|
|
4524
|
+
studioPlaygroundGradientClass,
|
|
4525
|
+
studioQuestionOptionClass,
|
|
4526
|
+
studioQuestionOptionSelectedClass,
|
|
4527
|
+
studioSecondaryChromeClass,
|
|
4528
|
+
studioTimelineActionClass,
|
|
4529
|
+
studioTimelineBodyPadClass,
|
|
4530
|
+
studioTimelineChevronClass,
|
|
4531
|
+
studioTimelineDetailClass,
|
|
4532
|
+
studioTimelineRowButtonClass,
|
|
4533
|
+
studioTimelineShimmerActionClass,
|
|
4534
|
+
studioTimelineTextClass,
|
|
4535
|
+
studioToolCardShellClass,
|
|
4536
|
+
studioTopbarIconPillClass,
|
|
4537
|
+
studioTopbarPillHeightClass,
|
|
4538
|
+
toolPresenceTransition,
|
|
4539
|
+
useArtifactRegistry,
|
|
4540
|
+
useAuiState,
|
|
1738
4541
|
useComposerRuntime,
|
|
1739
4542
|
useMessageRuntime,
|
|
4543
|
+
useResolvedSuggestions,
|
|
1740
4544
|
useSession,
|
|
1741
4545
|
useThread,
|
|
1742
|
-
useThreadRuntime
|
|
4546
|
+
useThreadRuntime,
|
|
4547
|
+
useTimbalRuntime,
|
|
4548
|
+
useTimbalStream,
|
|
4549
|
+
useToolRunning,
|
|
4550
|
+
useUiCustomNodeRegistry,
|
|
4551
|
+
useUiDispatch,
|
|
4552
|
+
useUiEventEmitter,
|
|
4553
|
+
useUiState,
|
|
4554
|
+
useWorkforces
|
|
1743
4555
|
});
|