@pactor-app/chat 1.15.5 → 1.16.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 +7 -3
- package/dist/index.cjs +504 -33
- package/dist/index.d.cts +152 -39
- package/dist/index.d.ts +152 -39
- package/dist/index.js +495 -33
- package/package.json +6 -6
- package/styles.css +193 -6
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ARTIFACT_IMAGE_EXTENSIONS: () => ARTIFACT_IMAGE_EXTENSIONS,
|
|
23
24
|
ActivityTrace: () => ActivityTrace,
|
|
24
25
|
AppShell: () => AppShell,
|
|
25
26
|
ArtifactPanel: () => ArtifactPanel,
|
|
@@ -43,7 +44,10 @@ __export(index_exports, {
|
|
|
43
44
|
MessageBubble: () => MessageBubble,
|
|
44
45
|
PartRenderer: () => PartRenderer,
|
|
45
46
|
applyChatEvent: () => applyChatEvent,
|
|
47
|
+
buildArtifactBlob: () => buildArtifactBlob,
|
|
48
|
+
buildArtifactTree: () => buildArtifactTree,
|
|
46
49
|
buildChatScope: () => buildChatScope,
|
|
50
|
+
collectArtifacts: () => collectArtifacts,
|
|
47
51
|
collectMessageText: () => collectMessageText,
|
|
48
52
|
createChatComponentRegistry: () => createChatComponentRegistry,
|
|
49
53
|
createChatId: () => createChatId,
|
|
@@ -52,14 +56,20 @@ __export(index_exports, {
|
|
|
52
56
|
createManualDriver: () => createManualDriver,
|
|
53
57
|
createSafeRegistry: () => createSafeRegistry,
|
|
54
58
|
detectStreamingMode: () => detectStreamingMode,
|
|
59
|
+
downloadArtifact: () => downloadArtifact,
|
|
55
60
|
guardChatDsl: () => guardChatDsl,
|
|
61
|
+
isImageArtifact: () => isImageArtifact,
|
|
62
|
+
mergeArtifacts: () => mergeArtifacts,
|
|
56
63
|
pairToolTraces: () => pairToolTraces,
|
|
57
64
|
registerCapabilityAction: () => registerCapabilityAction,
|
|
58
65
|
registerChatComponent: () => registerChatComponent,
|
|
59
66
|
registerChatLayout: () => registerChatLayout,
|
|
60
67
|
registerChatShellComponent: () => registerChatShellComponent,
|
|
68
|
+
resolveArtifactFileType: () => resolveArtifactFileType,
|
|
69
|
+
resolveArtifactFilename: () => resolveArtifactFilename,
|
|
61
70
|
runChatTurn: () => runChatTurn,
|
|
62
71
|
runRegenerateTurn: () => runRegenerateTurn,
|
|
72
|
+
saveBlob: () => saveBlob,
|
|
63
73
|
useChatAutoScroll: () => useChatAutoScroll,
|
|
64
74
|
useChatServices: () => useChatServices,
|
|
65
75
|
useSidebarDrawer: () => useSidebarDrawer,
|
|
@@ -187,35 +197,113 @@ var ConversationStore = class {
|
|
|
187
197
|
};
|
|
188
198
|
|
|
189
199
|
// src/artifact.ts
|
|
200
|
+
var ARTIFACT_IMAGE_EXTENSIONS = [
|
|
201
|
+
"png",
|
|
202
|
+
"jpg",
|
|
203
|
+
"jpeg",
|
|
204
|
+
"gif",
|
|
205
|
+
"svg",
|
|
206
|
+
"webp",
|
|
207
|
+
"avif",
|
|
208
|
+
"bmp",
|
|
209
|
+
"ico"
|
|
210
|
+
];
|
|
211
|
+
function resolveArtifactFileType(artifact) {
|
|
212
|
+
const declared = artifact.fileType?.trim().toLowerCase().replace(/^\./, "");
|
|
213
|
+
if (declared) {
|
|
214
|
+
return declared;
|
|
215
|
+
}
|
|
216
|
+
const match = /\.([A-Za-z0-9]+)$/.exec(artifact.title.trim());
|
|
217
|
+
return match ? match[1].toLowerCase() : null;
|
|
218
|
+
}
|
|
219
|
+
function isImageArtifact(artifact) {
|
|
220
|
+
const ext = resolveArtifactFileType(artifact);
|
|
221
|
+
return ext !== null && ARTIFACT_IMAGE_EXTENSIONS.includes(ext);
|
|
222
|
+
}
|
|
223
|
+
function collectArtifacts(messages) {
|
|
224
|
+
const order = [];
|
|
225
|
+
const byId = /* @__PURE__ */ new Map();
|
|
226
|
+
for (const message of messages) {
|
|
227
|
+
for (const part of message.parts) {
|
|
228
|
+
if (part.type !== "artifact" || !part.artifact) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (part.status !== void 0 && part.status !== "ready") {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (!byId.has(part.artifact.id)) {
|
|
235
|
+
order.push(part.artifact.id);
|
|
236
|
+
}
|
|
237
|
+
byId.set(part.artifact.id, part.artifact);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return order.map((id) => byId.get(id));
|
|
241
|
+
}
|
|
242
|
+
function mergeArtifacts(stream, opened) {
|
|
243
|
+
const openedById = new Map(opened.map((item) => [item.id, item]));
|
|
244
|
+
const merged = stream.map((item) => openedById.get(item.id) ?? item);
|
|
245
|
+
for (const item of opened) {
|
|
246
|
+
if (!stream.some((s) => s.id === item.id)) {
|
|
247
|
+
merged.push(item);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return merged;
|
|
251
|
+
}
|
|
190
252
|
var ArtifactStore = class {
|
|
191
253
|
constructor() {
|
|
192
|
-
this.
|
|
254
|
+
this.artifacts = [];
|
|
255
|
+
this.activeId = null;
|
|
193
256
|
this.listeners = /* @__PURE__ */ new Set();
|
|
194
257
|
}
|
|
195
|
-
/**
|
|
258
|
+
/** 当前激活产出物(未打开时为 null;引用在不变时保持稳定) */
|
|
196
259
|
get() {
|
|
197
|
-
|
|
260
|
+
if (this.activeId === null) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
return this.artifacts.find((item) => item.id === this.activeId) ?? null;
|
|
198
264
|
}
|
|
199
|
-
/**
|
|
265
|
+
/** 全部产出物(插入序;数组不可变,引用稳定) */
|
|
266
|
+
list() {
|
|
267
|
+
return this.artifacts;
|
|
268
|
+
}
|
|
269
|
+
/** 打开(或按 id 替换)产出物并激活 */
|
|
200
270
|
open(artifact) {
|
|
201
|
-
this.
|
|
271
|
+
const index = this.artifacts.findIndex((item) => item.id === artifact.id);
|
|
272
|
+
this.artifacts = index === -1 ? [...this.artifacts, artifact] : this.artifacts.map((item, i) => i === index ? artifact : item);
|
|
273
|
+
this.activeId = artifact.id;
|
|
274
|
+
this.notify();
|
|
275
|
+
}
|
|
276
|
+
/** 切换激活项(未知 id 告警并忽略,不抛错) */
|
|
277
|
+
activate(id) {
|
|
278
|
+
if (this.activeId === id) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (!this.artifacts.some((item) => item.id === id)) {
|
|
282
|
+
console.warn("[@pactor-app/chat] unknown artifact id, activate ignored");
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
this.activeId = id;
|
|
202
286
|
this.notify();
|
|
203
287
|
}
|
|
204
|
-
/**
|
|
288
|
+
/** 部分更新当前激活产出物(id 不可改);未 open 时告警并忽略 */
|
|
205
289
|
update(patch) {
|
|
206
|
-
|
|
290
|
+
const current = this.get();
|
|
291
|
+
if (!current) {
|
|
207
292
|
console.warn("[@pactor-app/chat] artifact not open, update ignored");
|
|
208
293
|
return;
|
|
209
294
|
}
|
|
210
|
-
|
|
295
|
+
const next = { ...current, ...patch, id: current.id };
|
|
296
|
+
this.artifacts = this.artifacts.map(
|
|
297
|
+
(item) => item.id === current.id ? next : item
|
|
298
|
+
);
|
|
211
299
|
this.notify();
|
|
212
300
|
}
|
|
213
|
-
/**
|
|
301
|
+
/** 关闭面板:清空激活项,列表保留(未打开时幂等,不重复通知) */
|
|
214
302
|
close() {
|
|
215
|
-
if (this.
|
|
303
|
+
if (this.activeId === null) {
|
|
216
304
|
return;
|
|
217
305
|
}
|
|
218
|
-
this.
|
|
306
|
+
this.activeId = null;
|
|
219
307
|
this.notify();
|
|
220
308
|
}
|
|
221
309
|
/** 订阅变更;返回退订函数 */
|
|
@@ -232,6 +320,94 @@ var ArtifactStore = class {
|
|
|
232
320
|
}
|
|
233
321
|
};
|
|
234
322
|
|
|
323
|
+
// src/artifact-download.ts
|
|
324
|
+
var KIND_EXTENSIONS = {
|
|
325
|
+
markdown: "md",
|
|
326
|
+
text: "txt",
|
|
327
|
+
code: "txt",
|
|
328
|
+
dsl: "json"
|
|
329
|
+
};
|
|
330
|
+
function resolveArtifactFilename(artifact) {
|
|
331
|
+
const title = artifact.title.trim() || "artifact";
|
|
332
|
+
if (/\.[A-Za-z0-9]+$/.test(title)) {
|
|
333
|
+
return title;
|
|
334
|
+
}
|
|
335
|
+
const ext = resolveArtifactFileType(artifact) ?? KIND_EXTENSIONS[artifact.kind];
|
|
336
|
+
return `${title}.${ext}`;
|
|
337
|
+
}
|
|
338
|
+
function dataUrlToBlob(dataUrl) {
|
|
339
|
+
const comma = dataUrl.indexOf(",");
|
|
340
|
+
const meta = dataUrl.slice(0, comma);
|
|
341
|
+
const payload = dataUrl.slice(comma + 1);
|
|
342
|
+
const mime = /^data:([^;,]+)/.exec(meta)?.[1] ?? "application/octet-stream";
|
|
343
|
+
if (meta.includes(";base64")) {
|
|
344
|
+
const binary = atob(payload);
|
|
345
|
+
const bytes = new Uint8Array(binary.length);
|
|
346
|
+
for (let i = 0; i < binary.length; i++) {
|
|
347
|
+
bytes[i] = binary.charCodeAt(i);
|
|
348
|
+
}
|
|
349
|
+
return new Blob([bytes], { type: mime });
|
|
350
|
+
}
|
|
351
|
+
return new Blob([decodeURIComponent(payload)], { type: mime });
|
|
352
|
+
}
|
|
353
|
+
function isRemoteUrl(raw) {
|
|
354
|
+
return /^https?:\/\//.test(raw.trim());
|
|
355
|
+
}
|
|
356
|
+
function buildArtifactBlob(artifact) {
|
|
357
|
+
if (artifact.kind === "dsl" && typeof artifact.content === "object") {
|
|
358
|
+
return new Blob([JSON.stringify(artifact.content, null, 2)], {
|
|
359
|
+
type: "application/json"
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
const raw = String(artifact.content);
|
|
363
|
+
if (isImageArtifact(artifact)) {
|
|
364
|
+
const trimmed = raw.trim();
|
|
365
|
+
if (trimmed.startsWith("data:")) {
|
|
366
|
+
return dataUrlToBlob(trimmed);
|
|
367
|
+
}
|
|
368
|
+
if (trimmed.startsWith("<svg") || trimmed.startsWith("<?xml")) {
|
|
369
|
+
return new Blob([raw], { type: "image/svg+xml" });
|
|
370
|
+
}
|
|
371
|
+
if (isRemoteUrl(trimmed)) {
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const ext = resolveArtifactFileType(artifact);
|
|
376
|
+
const mime = ext === "md" || artifact.kind === "markdown" ? "text/markdown" : "text/plain";
|
|
377
|
+
return new Blob([raw], { type: `${mime};charset=utf-8` });
|
|
378
|
+
}
|
|
379
|
+
function saveBlob(blob, filename) {
|
|
380
|
+
const url = URL.createObjectURL(blob);
|
|
381
|
+
const anchor = document.createElement("a");
|
|
382
|
+
anchor.href = url;
|
|
383
|
+
anchor.download = filename;
|
|
384
|
+
document.body.appendChild(anchor);
|
|
385
|
+
anchor.click();
|
|
386
|
+
anchor.remove();
|
|
387
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
388
|
+
}
|
|
389
|
+
async function downloadArtifact(artifact) {
|
|
390
|
+
const filename = resolveArtifactFilename(artifact);
|
|
391
|
+
const raw = String(artifact.content ?? "").trim();
|
|
392
|
+
if (isImageArtifact(artifact) && isRemoteUrl(raw)) {
|
|
393
|
+
try {
|
|
394
|
+
const response = await fetch(raw);
|
|
395
|
+
if (!response.ok) {
|
|
396
|
+
throw new Error(`HTTP ${response.status}`);
|
|
397
|
+
}
|
|
398
|
+
saveBlob(await response.blob(), filename);
|
|
399
|
+
return;
|
|
400
|
+
} catch {
|
|
401
|
+
window.open(raw, "_blank", "noopener");
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
const blob = buildArtifactBlob(artifact);
|
|
406
|
+
if (blob) {
|
|
407
|
+
saveBlob(blob, filename);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
235
411
|
// src/events.ts
|
|
236
412
|
function applyChatEvent(store, event) {
|
|
237
413
|
switch (event.type) {
|
|
@@ -1104,6 +1280,12 @@ function ensureChatChromeActions(actions) {
|
|
|
1104
1280
|
function invokeChatPanelClose() {
|
|
1105
1281
|
handlers.panelClose?.();
|
|
1106
1282
|
}
|
|
1283
|
+
function invokeChatPanelToggleList() {
|
|
1284
|
+
handlers.panelToggleList?.();
|
|
1285
|
+
}
|
|
1286
|
+
function invokeChatPanelDownload() {
|
|
1287
|
+
handlers.panelDownload?.();
|
|
1288
|
+
}
|
|
1107
1289
|
|
|
1108
1290
|
// src/view/chrome/ChromeSlot.tsx
|
|
1109
1291
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -1314,10 +1496,47 @@ function ChatPanelCloseButton() {
|
|
|
1314
1496
|
}
|
|
1315
1497
|
);
|
|
1316
1498
|
}
|
|
1317
|
-
var PANEL_HEADER_INTERNAL_COMPONENTS = {
|
|
1499
|
+
var PANEL_HEADER_INTERNAL_COMPONENTS = {
|
|
1500
|
+
ChatPanelCloseButton,
|
|
1501
|
+
ChatPanelDownloadButton,
|
|
1502
|
+
ChatPanelListButton
|
|
1503
|
+
};
|
|
1504
|
+
function ChatPanelListButton() {
|
|
1505
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1506
|
+
"button",
|
|
1507
|
+
{
|
|
1508
|
+
type: "button",
|
|
1509
|
+
className: "pactor-chat-icon-button pactor-chat-inspector__list-toggle",
|
|
1510
|
+
title: "\u4EA7\u7269\u76EE\u5F55",
|
|
1511
|
+
"aria-label": "\u4EA7\u7269\u76EE\u5F55",
|
|
1512
|
+
onClick: () => invokeChatPanelToggleList(),
|
|
1513
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_components3.Icon, { name: "arrow-left", size: 16 })
|
|
1514
|
+
}
|
|
1515
|
+
);
|
|
1516
|
+
}
|
|
1517
|
+
function ChatPanelDownloadButton() {
|
|
1518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1519
|
+
"button",
|
|
1520
|
+
{
|
|
1521
|
+
type: "button",
|
|
1522
|
+
className: "pactor-chat-icon-button pactor-chat-inspector__download",
|
|
1523
|
+
title: "\u4E0B\u8F7D\u4EA7\u7269",
|
|
1524
|
+
"aria-label": "\u4E0B\u8F7D\u4EA7\u7269",
|
|
1525
|
+
onClick: () => invokeChatPanelDownload(),
|
|
1526
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_components3.Icon, { name: "download", size: 16 })
|
|
1527
|
+
}
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1318
1530
|
function buildPanelHeaderFragment(props) {
|
|
1319
1531
|
return {
|
|
1320
|
-
requires: [
|
|
1532
|
+
requires: [
|
|
1533
|
+
"Flex",
|
|
1534
|
+
"Text",
|
|
1535
|
+
"Badge",
|
|
1536
|
+
"ChatPanelCloseButton",
|
|
1537
|
+
"ChatPanelDownloadButton",
|
|
1538
|
+
"ChatPanelListButton"
|
|
1539
|
+
],
|
|
1321
1540
|
node: {
|
|
1322
1541
|
type: "Flex",
|
|
1323
1542
|
props: {
|
|
@@ -1331,6 +1550,7 @@ function buildPanelHeaderFragment(props) {
|
|
|
1331
1550
|
type: "Flex",
|
|
1332
1551
|
props: { align: "center", gap: "small" },
|
|
1333
1552
|
children: [
|
|
1553
|
+
...props.showListButton ? [{ type: "ChatPanelListButton" }] : [],
|
|
1334
1554
|
{
|
|
1335
1555
|
type: "Text",
|
|
1336
1556
|
props: {
|
|
@@ -1349,7 +1569,14 @@ function buildPanelHeaderFragment(props) {
|
|
|
1349
1569
|
}
|
|
1350
1570
|
]
|
|
1351
1571
|
},
|
|
1352
|
-
{
|
|
1572
|
+
{
|
|
1573
|
+
type: "Flex",
|
|
1574
|
+
props: { align: "center", gap: "small" },
|
|
1575
|
+
children: [
|
|
1576
|
+
...props.showDownload ? [{ type: "ChatPanelDownloadButton" }] : [],
|
|
1577
|
+
{ type: "ChatPanelCloseButton" }
|
|
1578
|
+
]
|
|
1579
|
+
}
|
|
1353
1580
|
]
|
|
1354
1581
|
}
|
|
1355
1582
|
};
|
|
@@ -1400,10 +1627,126 @@ function ArtifactDslContent({
|
|
|
1400
1627
|
const guarded = guardChatDsl(node, runtime.context.components);
|
|
1401
1628
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_runtime4.DslRenderer, { context: runtime.context, engine: runtime.engine, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ArtifactDslGuard, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ArtifactDslNode, { node: guarded }) }) });
|
|
1402
1629
|
}
|
|
1630
|
+
function ArtifactKindIcon({ kind }) {
|
|
1631
|
+
const name = kind === "code" ? "code" : kind === "dsl" ? "layout-grid" : "file-text";
|
|
1632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_components4.Icon, { name, size: 13 });
|
|
1633
|
+
}
|
|
1634
|
+
function buildArtifactTree(artifacts) {
|
|
1635
|
+
const root = { name: "", path: "", children: [] };
|
|
1636
|
+
for (const artifact of artifacts) {
|
|
1637
|
+
const segments = artifact.id.split("/").filter(Boolean);
|
|
1638
|
+
let node = root;
|
|
1639
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1640
|
+
const path = segments.slice(0, i + 1).join("/");
|
|
1641
|
+
let child = node.children.find(
|
|
1642
|
+
(item) => item.path === path && item.artifact === void 0
|
|
1643
|
+
);
|
|
1644
|
+
if (!child) {
|
|
1645
|
+
child = { name: segments[i], path, children: [] };
|
|
1646
|
+
node.children.push(child);
|
|
1647
|
+
}
|
|
1648
|
+
node = child;
|
|
1649
|
+
}
|
|
1650
|
+
node.children.push({
|
|
1651
|
+
name: artifact.title,
|
|
1652
|
+
path: artifact.id,
|
|
1653
|
+
artifact,
|
|
1654
|
+
children: []
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
const sortLevel = (nodes) => {
|
|
1658
|
+
nodes.sort((a, b) => {
|
|
1659
|
+
const dirDelta = Number(b.artifact === void 0) - Number(a.artifact === void 0);
|
|
1660
|
+
return dirDelta !== 0 ? dirDelta : a.name.localeCompare(b.name);
|
|
1661
|
+
});
|
|
1662
|
+
for (const item of nodes) {
|
|
1663
|
+
sortLevel(item.children);
|
|
1664
|
+
}
|
|
1665
|
+
};
|
|
1666
|
+
sortLevel(root.children);
|
|
1667
|
+
return root.children;
|
|
1668
|
+
}
|
|
1669
|
+
function ArtifactListView({
|
|
1670
|
+
nodes,
|
|
1671
|
+
activeId,
|
|
1672
|
+
onSelect
|
|
1673
|
+
}) {
|
|
1674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "pactor-chat-inspector__list", children: nodes.map((node) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1675
|
+
ArtifactTreeRow,
|
|
1676
|
+
{
|
|
1677
|
+
node,
|
|
1678
|
+
activeId,
|
|
1679
|
+
onSelect
|
|
1680
|
+
},
|
|
1681
|
+
node.path
|
|
1682
|
+
)) });
|
|
1683
|
+
}
|
|
1684
|
+
function ArtifactTreeRow({
|
|
1685
|
+
node,
|
|
1686
|
+
activeId,
|
|
1687
|
+
onSelect
|
|
1688
|
+
}) {
|
|
1689
|
+
const [open, setOpen] = (0, import_react6.useState)(true);
|
|
1690
|
+
if (node.artifact) {
|
|
1691
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1692
|
+
"button",
|
|
1693
|
+
{
|
|
1694
|
+
type: "button",
|
|
1695
|
+
className: "pactor-chat-inspector__list-item",
|
|
1696
|
+
"data-active": node.artifact.id === activeId,
|
|
1697
|
+
onClick: () => onSelect?.(node.artifact),
|
|
1698
|
+
children: [
|
|
1699
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ArtifactKindIcon, { kind: node.artifact.kind }),
|
|
1700
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "pactor-chat-inspector__list-item-title", children: node.artifact.title }),
|
|
1701
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "pactor-chat-inspector__kind", children: node.artifact.kind })
|
|
1702
|
+
]
|
|
1703
|
+
}
|
|
1704
|
+
) });
|
|
1705
|
+
}
|
|
1706
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { children: [
|
|
1707
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1708
|
+
"button",
|
|
1709
|
+
{
|
|
1710
|
+
type: "button",
|
|
1711
|
+
className: "pactor-chat-inspector__list-folder",
|
|
1712
|
+
"aria-expanded": open,
|
|
1713
|
+
"data-open": open,
|
|
1714
|
+
onClick: () => setOpen((value) => !value),
|
|
1715
|
+
children: [
|
|
1716
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "pactor-chat-trace__chevron", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_components4.Icon, { name: "chevron-right", size: 12 }) }),
|
|
1717
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_components4.Icon, { name: "folder", size: 13 }),
|
|
1718
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: node.name })
|
|
1719
|
+
]
|
|
1720
|
+
}
|
|
1721
|
+
),
|
|
1722
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pactor-chat-inspector__list-children", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1723
|
+
ArtifactListView,
|
|
1724
|
+
{
|
|
1725
|
+
nodes: node.children,
|
|
1726
|
+
activeId,
|
|
1727
|
+
onSelect
|
|
1728
|
+
}
|
|
1729
|
+
) })
|
|
1730
|
+
] });
|
|
1731
|
+
}
|
|
1732
|
+
function ArtifactImageContent({ artifact }) {
|
|
1733
|
+
const raw = String(artifact.content).trim();
|
|
1734
|
+
const src = raw.startsWith("<svg") || raw.startsWith("<?xml") ? `data:image/svg+xml;utf8,${encodeURIComponent(raw)}` : raw;
|
|
1735
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pactor-chat-inspector__image", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src, alt: artifact.title }) });
|
|
1736
|
+
}
|
|
1403
1737
|
function ArtifactContent({
|
|
1404
1738
|
artifact,
|
|
1405
|
-
runtime
|
|
1739
|
+
runtime,
|
|
1740
|
+
viewers
|
|
1406
1741
|
}) {
|
|
1742
|
+
const ext = resolveArtifactFileType(artifact);
|
|
1743
|
+
const custom = (ext ? viewers?.[ext] : void 0) ?? viewers?.[artifact.kind];
|
|
1744
|
+
if (custom) {
|
|
1745
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: custom(artifact) });
|
|
1746
|
+
}
|
|
1747
|
+
if (isImageArtifact(artifact)) {
|
|
1748
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ArtifactImageContent, { artifact });
|
|
1749
|
+
}
|
|
1407
1750
|
switch (artifact.kind) {
|
|
1408
1751
|
case "markdown":
|
|
1409
1752
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_markdown2.MarkdownRenderer, { content: String(artifact.content) });
|
|
@@ -1422,17 +1765,41 @@ function ArtifactContent({
|
|
|
1422
1765
|
}
|
|
1423
1766
|
function ArtifactPanel({
|
|
1424
1767
|
artifact,
|
|
1768
|
+
artifacts,
|
|
1769
|
+
activeArtifactId,
|
|
1770
|
+
onSelectArtifact,
|
|
1425
1771
|
inspector,
|
|
1426
1772
|
onClose,
|
|
1427
1773
|
safeRegistry,
|
|
1428
1774
|
user,
|
|
1775
|
+
artifactViewers,
|
|
1429
1776
|
className
|
|
1430
1777
|
}) {
|
|
1431
1778
|
const runtime = useArtifactRuntime(safeRegistry, user);
|
|
1779
|
+
const [view, setView] = (0, import_react6.useState)("content");
|
|
1780
|
+
const activeId = activeArtifactId ?? artifact?.id;
|
|
1781
|
+
(0, import_react6.useEffect)(() => {
|
|
1782
|
+
setView("content");
|
|
1783
|
+
}, [activeId]);
|
|
1784
|
+
const showListButton = artifacts !== void 0 && artifacts.length > 0;
|
|
1785
|
+
const toggleListRef = (0, import_react6.useRef)(() => {
|
|
1786
|
+
});
|
|
1787
|
+
toggleListRef.current = () => setView((value) => value === "list" ? "content" : "list");
|
|
1432
1788
|
const closeRef = (0, import_react6.useRef)(onClose);
|
|
1433
1789
|
closeRef.current = onClose;
|
|
1790
|
+
const artifactRef = (0, import_react6.useRef)(artifact);
|
|
1791
|
+
artifactRef.current = artifact;
|
|
1434
1792
|
(0, import_react6.useEffect)(() => {
|
|
1435
|
-
setChatChromeHandlers({
|
|
1793
|
+
setChatChromeHandlers({
|
|
1794
|
+
panelClose: () => closeRef.current?.(),
|
|
1795
|
+
panelToggleList: () => toggleListRef.current(),
|
|
1796
|
+
panelDownload: () => {
|
|
1797
|
+
const current = artifactRef.current;
|
|
1798
|
+
if (current) {
|
|
1799
|
+
void downloadArtifact(current);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
});
|
|
1436
1803
|
}, []);
|
|
1437
1804
|
const panelRef = (0, import_react6.useRef)(null);
|
|
1438
1805
|
const [width, setWidth] = (0, import_react6.useState)(null);
|
|
@@ -1451,7 +1818,7 @@ function ArtifactPanel({
|
|
|
1451
1818
|
document.body.style.userSelect = "none";
|
|
1452
1819
|
const onMove = (moveEvent) => {
|
|
1453
1820
|
const next = startWidth + (startX - moveEvent.clientX);
|
|
1454
|
-
setWidth(Math.round(Math.min(Math.max(next,
|
|
1821
|
+
setWidth(Math.round(Math.min(Math.max(next, 320), maxWidth)));
|
|
1455
1822
|
};
|
|
1456
1823
|
const onUp = () => {
|
|
1457
1824
|
document.body.style.userSelect = prevUserSelect;
|
|
@@ -1484,12 +1851,36 @@ function ArtifactPanel({
|
|
|
1484
1851
|
{
|
|
1485
1852
|
fragment: buildPanelHeaderFragment({
|
|
1486
1853
|
title: artifact?.title ?? "\u4EA7\u51FA\u7269",
|
|
1487
|
-
kind: artifact?.kind ?? "text"
|
|
1854
|
+
kind: artifact?.kind ?? "text",
|
|
1855
|
+
showListButton,
|
|
1856
|
+
showDownload: artifact != null
|
|
1488
1857
|
}),
|
|
1489
1858
|
components: PANEL_HEADER_INTERNAL_COMPONENTS,
|
|
1490
1859
|
fallback: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1860
|
+
showListButton ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1861
|
+
"button",
|
|
1862
|
+
{
|
|
1863
|
+
type: "button",
|
|
1864
|
+
className: "pactor-chat-icon-button pactor-chat-inspector__list-toggle",
|
|
1865
|
+
title: "\u4EA7\u7269\u76EE\u5F55",
|
|
1866
|
+
"aria-label": "\u4EA7\u7269\u76EE\u5F55",
|
|
1867
|
+
onClick: () => toggleListRef.current(),
|
|
1868
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_components4.Icon, { name: "arrow-left", size: 16, strokeWidth: 1.7 })
|
|
1869
|
+
}
|
|
1870
|
+
) : null,
|
|
1491
1871
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "pactor-chat-inspector__title", children: artifact?.title ?? "\u4EA7\u51FA\u7269" }),
|
|
1492
1872
|
artifact ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "pactor-chat-inspector__kind", children: artifact.kind }) : null,
|
|
1873
|
+
artifact ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1874
|
+
"button",
|
|
1875
|
+
{
|
|
1876
|
+
type: "button",
|
|
1877
|
+
className: "pactor-chat-icon-button pactor-chat-inspector__download",
|
|
1878
|
+
title: "\u4E0B\u8F7D\u4EA7\u7269",
|
|
1879
|
+
"aria-label": "\u4E0B\u8F7D\u4EA7\u7269",
|
|
1880
|
+
onClick: () => void downloadArtifact(artifact),
|
|
1881
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_components4.Icon, { name: "download", size: 16, strokeWidth: 1.7 })
|
|
1882
|
+
}
|
|
1883
|
+
) : null,
|
|
1493
1884
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1494
1885
|
"button",
|
|
1495
1886
|
{
|
|
@@ -1503,7 +1894,38 @@ function ArtifactPanel({
|
|
|
1503
1894
|
] })
|
|
1504
1895
|
}
|
|
1505
1896
|
) }),
|
|
1506
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pactor-chat-
|
|
1897
|
+
artifacts !== void 0 && artifacts.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pactor-chat-inspector__tabs", role: "tablist", children: artifacts.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1898
|
+
"button",
|
|
1899
|
+
{
|
|
1900
|
+
type: "button",
|
|
1901
|
+
role: "tab",
|
|
1902
|
+
"aria-selected": item.id === activeId,
|
|
1903
|
+
"data-active": item.id === activeId,
|
|
1904
|
+
className: "pactor-chat-inspector__tab",
|
|
1905
|
+
title: item.title,
|
|
1906
|
+
onClick: () => onSelectArtifact?.(item),
|
|
1907
|
+
children: [
|
|
1908
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ArtifactKindIcon, { kind: item.kind }),
|
|
1909
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "pactor-chat-inspector__tab-title", children: item.title })
|
|
1910
|
+
]
|
|
1911
|
+
},
|
|
1912
|
+
item.id
|
|
1913
|
+
)) }) : null,
|
|
1914
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pactor-chat-inspector__body", children: view === "list" && artifacts !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1915
|
+
ArtifactListView,
|
|
1916
|
+
{
|
|
1917
|
+
nodes: buildArtifactTree(artifacts),
|
|
1918
|
+
activeId,
|
|
1919
|
+
onSelect: onSelectArtifact
|
|
1920
|
+
}
|
|
1921
|
+
) : inspector !== void 0 && inspector !== null ? inspector : artifact ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1922
|
+
ArtifactContent,
|
|
1923
|
+
{
|
|
1924
|
+
artifact,
|
|
1925
|
+
runtime,
|
|
1926
|
+
viewers: artifactViewers
|
|
1927
|
+
}
|
|
1928
|
+
) : null })
|
|
1507
1929
|
]
|
|
1508
1930
|
}
|
|
1509
1931
|
);
|
|
@@ -2529,7 +2951,11 @@ var import_react12 = require("react");
|
|
|
2529
2951
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2530
2952
|
function usePinnedCollapse(autoOpen) {
|
|
2531
2953
|
const [state, setState] = (0, import_react12.useState)("auto");
|
|
2532
|
-
const
|
|
2954
|
+
const autoCollapsedRef = (0, import_react12.useRef)(false);
|
|
2955
|
+
if (state === "auto" && !autoOpen) {
|
|
2956
|
+
autoCollapsedRef.current = true;
|
|
2957
|
+
}
|
|
2958
|
+
const open = state === "auto" ? autoOpen && !autoCollapsedRef.current : state === "pinned-open";
|
|
2533
2959
|
const toggle = () => {
|
|
2534
2960
|
setState(open ? "pinned-closed" : "pinned-open");
|
|
2535
2961
|
};
|
|
@@ -2680,6 +3106,7 @@ function ActivityTrace({ message }) {
|
|
|
2680
3106
|
);
|
|
2681
3107
|
const answerPhase = mode === "responding" || !streaming;
|
|
2682
3108
|
const { open, toggle } = usePinnedCollapse(!answerPhase);
|
|
3109
|
+
const collapsible = entries.length > 0 || thinkingParts.length > 0;
|
|
2683
3110
|
const mountTimeRef = (0, import_react12.useRef)(0);
|
|
2684
3111
|
if (mountTimeRef.current === 0) {
|
|
2685
3112
|
mountTimeRef.current = Date.now();
|
|
@@ -2701,10 +3128,10 @@ function ActivityTrace({ message }) {
|
|
|
2701
3128
|
elapsed,
|
|
2702
3129
|
"s"
|
|
2703
3130
|
] }),
|
|
2704
|
-
|
|
3131
|
+
collapsible && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "pactor-chat-trace__chevron", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_components8.Icon, { name: "chevron-right", size: 12 }) })
|
|
2705
3132
|
] });
|
|
2706
3133
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "pactor-chat-trace", "data-open": open, children: [
|
|
2707
|
-
|
|
3134
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2708
3135
|
"button",
|
|
2709
3136
|
{
|
|
2710
3137
|
type: "button",
|
|
@@ -2714,15 +3141,17 @@ function ActivityTrace({ message }) {
|
|
|
2714
3141
|
children: header
|
|
2715
3142
|
}
|
|
2716
3143
|
) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "pactor-chat-trace__header", children: header }),
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
3144
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
3145
|
+
entries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "pactor-chat-trace__entries", children: entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TraceRow, { entry }, entry.callIndex)) }),
|
|
3146
|
+
thinkingParts.map((part, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3147
|
+
ThinkingCard,
|
|
3148
|
+
{
|
|
3149
|
+
part,
|
|
3150
|
+
answerPhase
|
|
3151
|
+
},
|
|
3152
|
+
part.id ?? index
|
|
3153
|
+
))
|
|
3154
|
+
] })
|
|
2726
3155
|
] });
|
|
2727
3156
|
}
|
|
2728
3157
|
|
|
@@ -3671,6 +4100,8 @@ function ChatComposition({
|
|
|
3671
4100
|
onSend,
|
|
3672
4101
|
artifact,
|
|
3673
4102
|
panelOpen,
|
|
4103
|
+
artifacts: artifactsProp,
|
|
4104
|
+
onSelectArtifact,
|
|
3674
4105
|
onPanelClose,
|
|
3675
4106
|
inspector,
|
|
3676
4107
|
onArtifact,
|
|
@@ -3691,8 +4122,28 @@ function ChatComposition({
|
|
|
3691
4122
|
(listener) => artifactStore.subscribe(listener),
|
|
3692
4123
|
() => artifactStore.get()
|
|
3693
4124
|
);
|
|
4125
|
+
const storeArtifacts = (0, import_react17.useSyncExternalStore)(
|
|
4126
|
+
(listener) => artifactStore.subscribe(listener),
|
|
4127
|
+
() => artifactStore.list()
|
|
4128
|
+
);
|
|
4129
|
+
const messages = (0, import_react17.useSyncExternalStore)(
|
|
4130
|
+
(listener) => store.subscribe(listener),
|
|
4131
|
+
() => store.getMessages()
|
|
4132
|
+
);
|
|
4133
|
+
const streamArtifacts = (0, import_react17.useMemo)(() => collectArtifacts(messages), [messages]);
|
|
4134
|
+
const mergedArtifacts = (0, import_react17.useMemo)(
|
|
4135
|
+
() => mergeArtifacts(streamArtifacts, storeArtifacts),
|
|
4136
|
+
[streamArtifacts, storeArtifacts]
|
|
4137
|
+
);
|
|
3694
4138
|
const effectiveArtifact = panelControlled ? artifact ?? null : storeArtifact;
|
|
3695
4139
|
const effectivePanelOpen = panelControlled ? panelOpen ?? artifact != null : storeArtifact !== null;
|
|
4140
|
+
const effectiveArtifacts = artifactsProp ?? mergedArtifacts;
|
|
4141
|
+
const handleSelectArtifact = (next) => {
|
|
4142
|
+
onSelectArtifact?.(next);
|
|
4143
|
+
if (!panelControlled) {
|
|
4144
|
+
artifactStore.open(next);
|
|
4145
|
+
}
|
|
4146
|
+
};
|
|
3696
4147
|
const handlePanelClose = () => {
|
|
3697
4148
|
onPanelClose?.();
|
|
3698
4149
|
if (!panelControlled) {
|
|
@@ -3834,10 +4285,14 @@ function ChatComposition({
|
|
|
3834
4285
|
ArtifactPanel,
|
|
3835
4286
|
{
|
|
3836
4287
|
artifact: effectiveArtifact,
|
|
4288
|
+
artifacts: effectiveArtifacts,
|
|
4289
|
+
activeArtifactId: effectiveArtifact?.id,
|
|
4290
|
+
onSelectArtifact: handleSelectArtifact,
|
|
3837
4291
|
inspector,
|
|
3838
4292
|
onClose: handlePanelClose,
|
|
3839
4293
|
safeRegistry: services.safeRegistry,
|
|
3840
|
-
user: services.user
|
|
4294
|
+
user: services.user,
|
|
4295
|
+
artifactViewers: services.artifactViewers
|
|
3841
4296
|
}
|
|
3842
4297
|
)
|
|
3843
4298
|
] }) : null
|
|
@@ -3880,6 +4335,7 @@ function createChatWorkspace(services) {
|
|
|
3880
4335
|
inspector,
|
|
3881
4336
|
onArtifact,
|
|
3882
4337
|
onOpenArtifact,
|
|
4338
|
+
onSelectArtifact,
|
|
3883
4339
|
headerActions,
|
|
3884
4340
|
editableTitle,
|
|
3885
4341
|
onExport,
|
|
@@ -3920,6 +4376,7 @@ function createChatWorkspace(services) {
|
|
|
3920
4376
|
inspector: inspector ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DslNodeSlot, { node: inspector }) : void 0,
|
|
3921
4377
|
onArtifact,
|
|
3922
4378
|
onOpenArtifact,
|
|
4379
|
+
onSelectArtifact,
|
|
3923
4380
|
headerActions,
|
|
3924
4381
|
editableTitle,
|
|
3925
4382
|
onExport,
|
|
@@ -4129,6 +4586,7 @@ function Chat({
|
|
|
4129
4586
|
inspector,
|
|
4130
4587
|
onArtifact,
|
|
4131
4588
|
onOpenArtifact,
|
|
4589
|
+
onSelectArtifact,
|
|
4132
4590
|
className,
|
|
4133
4591
|
onSend,
|
|
4134
4592
|
onMenuSelect
|
|
@@ -4193,7 +4651,8 @@ function Chat({
|
|
|
4193
4651
|
onPanelClose,
|
|
4194
4652
|
inspector: resolveSlot(inspector),
|
|
4195
4653
|
onArtifact,
|
|
4196
|
-
onOpenArtifact
|
|
4654
|
+
onOpenArtifact,
|
|
4655
|
+
onSelectArtifact
|
|
4197
4656
|
}
|
|
4198
4657
|
);
|
|
4199
4658
|
}
|
|
@@ -4204,6 +4663,7 @@ function ChatDslAdapter({
|
|
|
4204
4663
|
onPanelClose,
|
|
4205
4664
|
onArtifact,
|
|
4206
4665
|
onOpenArtifact,
|
|
4666
|
+
onSelectArtifact,
|
|
4207
4667
|
onModelChange,
|
|
4208
4668
|
onContextsChange,
|
|
4209
4669
|
onMessageAction,
|
|
@@ -4222,6 +4682,7 @@ function ChatDslAdapter({
|
|
|
4222
4682
|
onPanelClose: onPanelClose ? () => onPanelClose({}) : void 0,
|
|
4223
4683
|
onArtifact: onArtifact ? (artifact) => onArtifact({ artifact }) : void 0,
|
|
4224
4684
|
onOpenArtifact: onOpenArtifact ? (artifact) => onOpenArtifact({ artifact }) : void 0,
|
|
4685
|
+
onSelectArtifact: onSelectArtifact ? (artifact) => onSelectArtifact({ artifact }) : void 0,
|
|
4225
4686
|
onModelChange: onModelChange ? (model) => onModelChange({ model }) : void 0,
|
|
4226
4687
|
onContextsChange: onContextsChange ? (contexts) => onContextsChange({ contexts }) : void 0,
|
|
4227
4688
|
onMessageAction: onMessageAction ? (action, message) => onMessageAction({ action, message }) : void 0,
|
|
@@ -4260,6 +4721,7 @@ function registerChatLayout(layoutRegistry) {
|
|
|
4260
4721
|
}
|
|
4261
4722
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4262
4723
|
0 && (module.exports = {
|
|
4724
|
+
ARTIFACT_IMAGE_EXTENSIONS,
|
|
4263
4725
|
ActivityTrace,
|
|
4264
4726
|
AppShell,
|
|
4265
4727
|
ArtifactPanel,
|
|
@@ -4283,7 +4745,10 @@ function registerChatLayout(layoutRegistry) {
|
|
|
4283
4745
|
MessageBubble,
|
|
4284
4746
|
PartRenderer,
|
|
4285
4747
|
applyChatEvent,
|
|
4748
|
+
buildArtifactBlob,
|
|
4749
|
+
buildArtifactTree,
|
|
4286
4750
|
buildChatScope,
|
|
4751
|
+
collectArtifacts,
|
|
4287
4752
|
collectMessageText,
|
|
4288
4753
|
createChatComponentRegistry,
|
|
4289
4754
|
createChatId,
|
|
@@ -4292,14 +4757,20 @@ function registerChatLayout(layoutRegistry) {
|
|
|
4292
4757
|
createManualDriver,
|
|
4293
4758
|
createSafeRegistry,
|
|
4294
4759
|
detectStreamingMode,
|
|
4760
|
+
downloadArtifact,
|
|
4295
4761
|
guardChatDsl,
|
|
4762
|
+
isImageArtifact,
|
|
4763
|
+
mergeArtifacts,
|
|
4296
4764
|
pairToolTraces,
|
|
4297
4765
|
registerCapabilityAction,
|
|
4298
4766
|
registerChatComponent,
|
|
4299
4767
|
registerChatLayout,
|
|
4300
4768
|
registerChatShellComponent,
|
|
4769
|
+
resolveArtifactFileType,
|
|
4770
|
+
resolveArtifactFilename,
|
|
4301
4771
|
runChatTurn,
|
|
4302
4772
|
runRegenerateTurn,
|
|
4773
|
+
saveBlob,
|
|
4303
4774
|
useChatAutoScroll,
|
|
4304
4775
|
useChatServices,
|
|
4305
4776
|
useSidebarDrawer,
|