@pactor-app/chat 1.44.0 → 1.46.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/dist/index.js CHANGED
@@ -1,3 +1,18 @@
1
+ import {
2
+ ArtifactPanel,
3
+ Bubble,
4
+ Composer,
5
+ Sender,
6
+ Suggestion,
7
+ Welcome,
8
+ buildArtifactBlob,
9
+ buildArtifactTree,
10
+ downloadArtifact,
11
+ registerChatComponents,
12
+ resolveArtifactFilename,
13
+ saveBlob
14
+ } from "./chunk-TBPUSGKL.js";
15
+
1
16
  // src/model.ts
2
17
  var idCounter = 0;
3
18
  function createChatId(prefix = "chat") {
@@ -332,94 +347,6 @@ var ArtifactStore = class {
332
347
  }
333
348
  };
334
349
 
335
- // src/artifact-download.ts
336
- var KIND_EXTENSIONS = {
337
- markdown: "md",
338
- text: "txt",
339
- code: "txt",
340
- dsl: "json"
341
- };
342
- function resolveArtifactFilename(artifact) {
343
- const title = artifact.title.trim() || "artifact";
344
- if (/\.[A-Za-z0-9]+$/.test(title)) {
345
- return title;
346
- }
347
- const ext = resolveArtifactFileType(artifact) ?? KIND_EXTENSIONS[artifact.kind];
348
- return `${title}.${ext}`;
349
- }
350
- function dataUrlToBlob(dataUrl) {
351
- const comma = dataUrl.indexOf(",");
352
- const meta = dataUrl.slice(0, comma);
353
- const payload = dataUrl.slice(comma + 1);
354
- const mime = /^data:([^;,]+)/.exec(meta)?.[1] ?? "application/octet-stream";
355
- if (meta.includes(";base64")) {
356
- const binary = atob(payload);
357
- const bytes = new Uint8Array(binary.length);
358
- for (let i = 0; i < binary.length; i++) {
359
- bytes[i] = binary.charCodeAt(i);
360
- }
361
- return new Blob([bytes], { type: mime });
362
- }
363
- return new Blob([decodeURIComponent(payload)], { type: mime });
364
- }
365
- function isRemoteUrl(raw) {
366
- return /^https?:\/\//.test(raw.trim());
367
- }
368
- function buildArtifactBlob(artifact) {
369
- if (artifact.kind === "dsl" && typeof artifact.content === "object") {
370
- return new Blob([JSON.stringify(artifact.content, null, 2)], {
371
- type: "application/json"
372
- });
373
- }
374
- const raw = String(artifact.content);
375
- if (isImageArtifact(artifact)) {
376
- const trimmed = raw.trim();
377
- if (trimmed.startsWith("data:")) {
378
- return dataUrlToBlob(trimmed);
379
- }
380
- if (trimmed.startsWith("<svg") || trimmed.startsWith("<?xml")) {
381
- return new Blob([raw], { type: "image/svg+xml" });
382
- }
383
- if (isRemoteUrl(trimmed)) {
384
- return null;
385
- }
386
- }
387
- const ext = resolveArtifactFileType(artifact);
388
- const mime = ext === "md" || artifact.kind === "markdown" ? "text/markdown" : "text/plain";
389
- return new Blob([raw], { type: `${mime};charset=utf-8` });
390
- }
391
- function saveBlob(blob, filename) {
392
- const url = URL.createObjectURL(blob);
393
- const anchor = document.createElement("a");
394
- anchor.href = url;
395
- anchor.download = filename;
396
- document.body.appendChild(anchor);
397
- anchor.click();
398
- anchor.remove();
399
- setTimeout(() => URL.revokeObjectURL(url), 1e3);
400
- }
401
- async function downloadArtifact(artifact) {
402
- const filename = resolveArtifactFilename(artifact);
403
- const raw = String(artifact.content ?? "").trim();
404
- if (isImageArtifact(artifact) && isRemoteUrl(raw)) {
405
- try {
406
- const response = await fetch(raw);
407
- if (!response.ok) {
408
- throw new Error(`HTTP ${response.status}`);
409
- }
410
- saveBlob(await response.blob(), filename);
411
- return;
412
- } catch {
413
- window.open(raw, "_blank", "noopener");
414
- return;
415
- }
416
- }
417
- const blob = buildArtifactBlob(artifact);
418
- if (blob) {
419
- saveBlob(blob, filename);
420
- }
421
- }
422
-
423
350
  // src/events.ts
424
351
  function applyChatEvent(store, event) {
425
352
  switch (event.type) {
@@ -1059,11 +986,11 @@ function useChatAutoScroll({
1059
986
  }
1060
987
 
1061
988
  // src/chat-composition.tsx
1062
- import { useRenderer as useRenderer4 } from "@pactor-app/runtime";
989
+ import { useRenderer as useRenderer3 } from "@pactor-app/runtime";
1063
990
  import {
1064
- Component as Component3,
991
+ Component as Component2,
1065
992
  isValidElement,
1066
- useMemo as useMemo4,
993
+ useMemo as useMemo3,
1067
994
  useRef as useRef13,
1068
995
  useState as useState16,
1069
996
  useSyncExternalStore as useSyncExternalStore2
@@ -1123,64 +1050,8 @@ function AppShell({
1123
1050
  );
1124
1051
  }
1125
1052
 
1126
- // src/view/ArtifactPanel.tsx
1127
- import { Icon as Icon4 } from "@pactor-app/ui/components";
1128
- import { Registry as Registry2 } from "@pactor-app/core";
1129
- import { MarkdownRenderer as MarkdownRenderer2 } from "@pactor-app/markdown";
1130
- import { DslRenderer as DslRenderer2, useRenderer as useRenderer3 } from "@pactor-app/runtime";
1131
- import {
1132
- Component as Component2,
1133
- useEffect as useEffect3,
1134
- useMemo,
1135
- useRef as useRef4,
1136
- useState as useState6
1137
- } from "react";
1138
-
1139
- // src/view/PartRenderer.tsx
1140
- import { Icon as Icon2 } from "@pactor-app/ui/components";
1141
- import { MarkdownRenderer } from "@pactor-app/markdown";
1142
- import { DslRenderer, useRenderer as useRenderer2 } from "@pactor-app/runtime";
1143
-
1144
- // src/hooks/use-throttled-value.ts
1053
+ // src/view/ChatArtifactPanel.tsx
1145
1054
  import { useEffect as useEffect2, useRef as useRef3, useState as useState4 } from "react";
1146
- function useThrottledValue(value, intervalMs, enabled) {
1147
- const [shown, setShown] = useState4(value);
1148
- const lastUpdateRef = useRef3(0);
1149
- const timerRef = useRef3(void 0);
1150
- useEffect2(() => {
1151
- if (!enabled) {
1152
- if (timerRef.current) {
1153
- clearTimeout(timerRef.current);
1154
- timerRef.current = void 0;
1155
- }
1156
- setShown(value);
1157
- return;
1158
- }
1159
- const now = Date.now();
1160
- const elapsed = now - lastUpdateRef.current;
1161
- if (elapsed >= intervalMs) {
1162
- lastUpdateRef.current = now;
1163
- setShown(value);
1164
- return;
1165
- }
1166
- timerRef.current = setTimeout(() => {
1167
- lastUpdateRef.current = Date.now();
1168
- setShown(value);
1169
- timerRef.current = void 0;
1170
- }, intervalMs - elapsed);
1171
- return () => {
1172
- if (timerRef.current) {
1173
- clearTimeout(timerRef.current);
1174
- timerRef.current = void 0;
1175
- }
1176
- };
1177
- }, [value, intervalMs, enabled]);
1178
- return enabled ? shown : value;
1179
- }
1180
-
1181
- // src/view/chrome/artifact-card.tsx
1182
- import { Icon } from "@pactor-app/ui/components";
1183
- import { useState as useState5 } from "react";
1184
1055
 
1185
1056
  // src/view/chrome/actions.ts
1186
1057
  var handlers = {};
@@ -1273,112 +1144,10 @@ function invokeChatPanelDownload() {
1273
1144
  handlers.panelDownload?.();
1274
1145
  }
1275
1146
 
1276
- // src/view/chrome/artifact-card.tsx
1277
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
1278
- function artifactCardMeta(artifact) {
1279
- const ext = resolveArtifactFileType(artifact);
1280
- const typeLabel = (ext ?? artifact.kind).toUpperCase();
1281
- const sizeLabel = formatArtifactSize(artifact.meta?.["size"]);
1282
- return [sizeLabel, typeLabel].filter(Boolean).join(" \xB7 ");
1283
- }
1284
- function ChatArtifactCard({
1285
- artifact
1286
- }) {
1287
- const icon = resolveArtifactIcon(artifact);
1288
- const meta = artifactCardMeta(artifact);
1289
- return /* @__PURE__ */ jsxs(
1290
- "button",
1291
- {
1292
- type: "button",
1293
- className: `pactor-chat-artifact-card pactor-chat-artifact-card--${icon.tone}`,
1294
- "data-artifact-kind": artifact.kind,
1295
- "aria-label": `\u5728\u9762\u677F\u4E2D\u6253\u5F00\uFF1A${artifact.title}`,
1296
- title: `\u5728\u9762\u677F\u4E2D\u6253\u5F00\uFF1A${artifact.title}`,
1297
- onClick: () => invokeChatOpenArtifact(artifact),
1298
- children: [
1299
- /* @__PURE__ */ jsx2("span", { className: "pactor-chat-artifact-card__icon", children: /* @__PURE__ */ jsx2(Icon, { name: icon.name, size: 20 }) }),
1300
- /* @__PURE__ */ jsxs("span", { className: "pactor-chat-artifact-card__text", children: [
1301
- /* @__PURE__ */ jsx2("span", { className: "pactor-chat-artifact-card__title", children: artifact.title }),
1302
- meta ? /* @__PURE__ */ jsx2("span", { className: "pactor-chat-artifact-card__meta", children: meta }) : null
1303
- ] }),
1304
- /* @__PURE__ */ jsx2("span", { className: "pactor-chat-artifact-card__arrow", children: /* @__PURE__ */ jsx2(Icon, { name: "arrow-up-right", size: 14 }) })
1305
- ]
1306
- }
1307
- );
1308
- }
1309
- var ARTIFACT_CARD_INTERNAL_COMPONENTS = {
1310
- ChatArtifactCard,
1311
- ChatArtifactCardGroup
1312
- };
1313
- var ARTIFACT_CARD_GROUP_LIMIT = 4;
1314
- function ChatArtifactCardGroup({
1315
- artifacts
1316
- }) {
1317
- const [expanded, setExpanded] = useState5(false);
1318
- const overflow = artifacts.length > ARTIFACT_CARD_GROUP_LIMIT;
1319
- const visible = overflow && !expanded ? artifacts.slice(0, ARTIFACT_CARD_GROUP_LIMIT) : artifacts;
1320
- return /* @__PURE__ */ jsxs("div", { className: "pactor-chat-artifact-group", children: [
1321
- visible.map((artifact) => /* @__PURE__ */ jsx2(ChatArtifactCard, { artifact }, artifact.id)),
1322
- overflow ? /* @__PURE__ */ jsxs("div", { className: "pactor-chat-artifact-group__footer", children: [
1323
- /* @__PURE__ */ jsxs(
1324
- "button",
1325
- {
1326
- type: "button",
1327
- className: "pactor-chat-artifact-group__toggle",
1328
- "aria-expanded": expanded,
1329
- onClick: () => setExpanded((value) => !value),
1330
- children: [
1331
- /* @__PURE__ */ jsx2(
1332
- Icon,
1333
- {
1334
- name: expanded ? "chevron-up" : "chevron-down",
1335
- size: 12
1336
- }
1337
- ),
1338
- expanded ? "\u6536\u8D77" : "\u5C55\u5F00"
1339
- ]
1340
- }
1341
- ),
1342
- /* @__PURE__ */ jsxs(
1343
- "button",
1344
- {
1345
- type: "button",
1346
- className: "pactor-chat-artifact-group__all",
1347
- onClick: () => invokeChatOpenArtifactList(),
1348
- children: [
1349
- "\u67E5\u770B\u6240\u6709\u4EA7\u7269(",
1350
- artifacts.length,
1351
- ")",
1352
- /* @__PURE__ */ jsx2(Icon, { name: "chevron-right", size: 12 })
1353
- ]
1354
- }
1355
- )
1356
- ] }) : null
1357
- ] });
1358
- }
1359
- function buildArtifactCardFragment(artifact) {
1360
- return {
1361
- requires: ["ChatArtifactCard"],
1362
- node: {
1363
- type: "ChatArtifactCard",
1364
- props: { artifact }
1365
- }
1366
- };
1367
- }
1368
- function buildArtifactCardGroupFragment(artifacts) {
1369
- return {
1370
- requires: ["ChatArtifactCardGroup"],
1371
- node: {
1372
- type: "ChatArtifactCardGroup",
1373
- props: { artifacts }
1374
- }
1375
- };
1376
- }
1377
-
1378
1147
  // src/view/chrome/ChromeSlot.tsx
1379
1148
  import { useRenderer } from "@pactor-app/runtime";
1380
1149
  import { Component } from "react";
1381
- import { Fragment, jsx as jsx3 } from "react/jsx-runtime";
1150
+ import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
1382
1151
  var warnedMissing = /* @__PURE__ */ new Set();
1383
1152
  function warnMissingOnce(key, detail) {
1384
1153
  if (!warnedMissing.has(key)) {
@@ -1396,7 +1165,7 @@ function ChromeSlotInner({
1396
1165
  try {
1397
1166
  renderer = useRenderer();
1398
1167
  } catch {
1399
- return /* @__PURE__ */ jsx3(Fragment, { children: fallback });
1168
+ return /* @__PURE__ */ jsx2(Fragment, { children: fallback });
1400
1169
  }
1401
1170
  ensureChatChromeActions(renderer.context.actions);
1402
1171
  if (components) {
@@ -1407,7 +1176,7 @@ function ChromeSlotInner({
1407
1176
  `conflict:${name}`,
1408
1177
  `[@pactor-app/chat] chrome \u5185\u90E8\u7EC4\u4EF6\u540D\u300C${name}\u300D\u88AB\u5BBF\u4E3B\u5360\u7528\uFF0C\u5DF2\u56DE\u9000\u5185\u5EFA\u5B9E\u73B0`
1409
1178
  );
1410
- return /* @__PURE__ */ jsx3(Fragment, { children: fallback });
1179
+ return /* @__PURE__ */ jsx2(Fragment, { children: fallback });
1411
1180
  }
1412
1181
  if (existing === void 0) {
1413
1182
  renderer.context.components.register(
@@ -1425,10 +1194,10 @@ function ChromeSlotInner({
1425
1194
  `${fragment.node.type}:${missing.join(",")}`,
1426
1195
  `[@pactor-app/chat] chrome DSL \u7247\u6BB5\u6240\u9700\u7EC4\u4EF6\u7C7B\u578B\u7F3A\u5931\uFF08${missing.join(" / ")}\uFF09\uFF0C\u5DF2\u56DE\u9000\u5185\u5EFA\u5B9E\u73B0`
1427
1196
  );
1428
- return /* @__PURE__ */ jsx3(Fragment, { children: fallback });
1197
+ return /* @__PURE__ */ jsx2(Fragment, { children: fallback });
1429
1198
  }
1430
- const rendered = /* @__PURE__ */ jsx3("div", { className: "pactor-chat-chrome", children: renderer.renderChildren([fragment.node]) });
1431
- return wrap ? /* @__PURE__ */ jsx3(Fragment, { children: wrap(rendered) }) : rendered;
1199
+ const rendered = /* @__PURE__ */ jsx2("div", { className: "pactor-chat-chrome", children: renderer.renderChildren([fragment.node]) });
1200
+ return wrap ? /* @__PURE__ */ jsx2(Fragment, { children: wrap(rendered) }) : rendered;
1432
1201
  }
1433
1202
  var ChromeSlotGuard = class extends Component {
1434
1203
  constructor() {
@@ -1443,116 +1212,13 @@ var ChromeSlotGuard = class extends Component {
1443
1212
  }
1444
1213
  };
1445
1214
  function ChromeSlot(props) {
1446
- return /* @__PURE__ */ jsx3(ChromeSlotGuard, { fallback: props.fallback, children: /* @__PURE__ */ jsx3(ChromeSlotInner, { ...props }) });
1447
- }
1448
-
1449
- // src/view/chrome/feedback.tsx
1450
- function buildErrorFragment(message) {
1451
- return {
1452
- requires: ["Alert"],
1453
- node: {
1454
- type: "Alert",
1455
- props: { variant: "error", message }
1456
- }
1457
- };
1458
- }
1459
- function buildStatusFragment(text) {
1460
- return {
1461
- requires: ["Text"],
1462
- node: {
1463
- type: "Text",
1464
- props: { type: "secondary", text }
1465
- }
1466
- };
1467
- }
1468
-
1469
- // src/view/PartRenderer.tsx
1470
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1471
- function ChatDenied({ deniedType }) {
1472
- return /* @__PURE__ */ jsxs2("div", { className: "pactor-chat-denied", "data-pactor-chat-denied": deniedType, children: [
1473
- "\u8BE5\u7EC4\u4EF6\u4E0D\u5141\u8BB8\u5728 Chat \u4E2D\u4F7F\u7528",
1474
- deniedType ? `\uFF1A${deniedType}` : ""
1475
- ] });
1476
- }
1477
- function ChatDslNode({
1478
- node,
1479
- scope
1480
- }) {
1481
- const renderer = useRenderer2();
1482
- const extraScope = scope ? buildChatScope(scope) : void 0;
1483
- return /* @__PURE__ */ jsx4(Fragment2, { children: renderer.renderChildren([node], extraScope) });
1484
- }
1485
- function SmoothText({ content, streaming }) {
1486
- const shown = useSmoothStreamText(content, streaming);
1487
- return /* @__PURE__ */ jsx4("div", { className: "pactor-chat-text", children: shown });
1488
- }
1489
- function SmoothMarkdown({ content, streaming }) {
1490
- const shown = useSmoothStreamText(content, streaming);
1491
- const throttled = useThrottledValue(shown, 100, streaming);
1492
- return /* @__PURE__ */ jsx4(MarkdownRenderer, { content: throttled });
1493
- }
1494
- function PartRenderer({ part, runtime, scope, streaming = false }) {
1495
- switch (part.type) {
1496
- case "text":
1497
- return /* @__PURE__ */ jsx4(SmoothText, { content: part.content, streaming });
1498
- case "markdown":
1499
- return /* @__PURE__ */ jsx4(SmoothMarkdown, { content: part.content, streaming });
1500
- case "thinking":
1501
- case "tool-call":
1502
- case "tool-result":
1503
- return null;
1504
- case "dsl": {
1505
- if (!part.schema || !runtime) {
1506
- return /* @__PURE__ */ jsx4(
1507
- ChromeSlot,
1508
- {
1509
- fragment: buildStatusFragment(
1510
- part.schema ? "DSL \u6E32\u67D3\u4E0D\u53EF\u7528\uFF08\u672A\u6CE8\u5165 Safe Registry\uFF09" : "\u5185\u5BB9\u751F\u6210\u4E2D\u2026"
1511
- ),
1512
- fallback: /* @__PURE__ */ jsx4("div", { className: "pactor-chat-dsl-pending", children: part.schema ? "DSL \u6E32\u67D3\u4E0D\u53EF\u7528\uFF08\u672A\u6CE8\u5165 Safe Registry\uFF09" : "\u5185\u5BB9\u751F\u6210\u4E2D\u2026" })
1513
- }
1514
- );
1515
- }
1516
- const guarded = guardChatDsl(part.schema, runtime.context.components);
1517
- return /* @__PURE__ */ jsx4("div", { className: "pactor-chat-dsl", children: /* @__PURE__ */ jsx4(DslRenderer, { context: runtime.context, engine: runtime.engine, children: /* @__PURE__ */ jsx4(ChatDslNode, { node: guarded, scope }) }) });
1518
- }
1519
- case "error":
1520
- return /* @__PURE__ */ jsx4(
1521
- ChromeSlot,
1522
- {
1523
- fragment: buildErrorFragment(part.message),
1524
- fallback: /* @__PURE__ */ jsxs2("div", { className: "pactor-chat-error", role: "alert", children: [
1525
- /* @__PURE__ */ jsx4(Icon2, { name: "error", size: 14 }),
1526
- /* @__PURE__ */ jsx4("span", { children: part.message })
1527
- ] })
1528
- }
1529
- );
1530
- case "status":
1531
- return /* @__PURE__ */ jsx4(
1532
- ChromeSlot,
1533
- {
1534
- fragment: buildStatusFragment(part.text),
1535
- fallback: /* @__PURE__ */ jsx4("div", { className: "pactor-chat-status", children: part.text })
1536
- }
1537
- );
1538
- case "artifact":
1539
- return /* @__PURE__ */ jsx4(
1540
- ChromeSlot,
1541
- {
1542
- fragment: buildArtifactCardFragment(part.artifact),
1543
- components: ARTIFACT_CARD_INTERNAL_COMPONENTS,
1544
- fallback: /* @__PURE__ */ jsx4(ChatArtifactCard, { artifact: part.artifact })
1545
- }
1546
- );
1547
- default:
1548
- return null;
1549
- }
1215
+ return /* @__PURE__ */ jsx2(ChromeSlotGuard, { fallback: props.fallback, children: /* @__PURE__ */ jsx2(ChromeSlotInner, { ...props }) });
1550
1216
  }
1551
1217
 
1552
1218
  // src/view/chrome/panel-header.tsx
1553
- import { DropdownMenu, Icon as Icon3 } from "@pactor-app/ui/components";
1219
+ import { DropdownMenu, Icon } from "@pactor-app/ui/components";
1554
1220
  import { createContext, useContext } from "react";
1555
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1221
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
1556
1222
  var ChatPanelContext = createContext(
1557
1223
  null
1558
1224
  );
@@ -1560,7 +1226,7 @@ function artifactIconName(artifact) {
1560
1226
  return artifact ? resolveArtifactIconName(artifact) : "file";
1561
1227
  }
1562
1228
  function ChatPanelCloseButton() {
1563
- return /* @__PURE__ */ jsx5(
1229
+ return /* @__PURE__ */ jsx3(
1564
1230
  "button",
1565
1231
  {
1566
1232
  type: "button",
@@ -1568,7 +1234,7 @@ function ChatPanelCloseButton() {
1568
1234
  title: "\u5173\u95ED\u9762\u677F",
1569
1235
  "aria-label": "\u5173\u95ED\u9762\u677F",
1570
1236
  onClick: () => invokeChatPanelClose(),
1571
- children: /* @__PURE__ */ jsx5(Icon3, { name: "x", size: 16 })
1237
+ children: /* @__PURE__ */ jsx3(Icon, { name: "x", size: 16 })
1572
1238
  }
1573
1239
  );
1574
1240
  }
@@ -1577,7 +1243,7 @@ function ChatPanelListButton() {
1577
1243
  if (ctx?.view === "list") {
1578
1244
  return null;
1579
1245
  }
1580
- return /* @__PURE__ */ jsx5(
1246
+ return /* @__PURE__ */ jsx3(
1581
1247
  "button",
1582
1248
  {
1583
1249
  type: "button",
@@ -1585,12 +1251,12 @@ function ChatPanelListButton() {
1585
1251
  title: "\u4EA7\u7269\u76EE\u5F55",
1586
1252
  "aria-label": "\u4EA7\u7269\u76EE\u5F55",
1587
1253
  onClick: () => invokeChatPanelToggleList(),
1588
- children: /* @__PURE__ */ jsx5(Icon3, { name: "arrow-left", size: 16 })
1254
+ children: /* @__PURE__ */ jsx3(Icon, { name: "arrow-left", size: 16 })
1589
1255
  }
1590
1256
  );
1591
1257
  }
1592
1258
  function ChatPanelDownloadButton() {
1593
- return /* @__PURE__ */ jsx5(
1259
+ return /* @__PURE__ */ jsx3(
1594
1260
  "button",
1595
1261
  {
1596
1262
  type: "button",
@@ -1598,7 +1264,7 @@ function ChatPanelDownloadButton() {
1598
1264
  title: "\u4E0B\u8F7D\u4EA7\u7269",
1599
1265
  "aria-label": "\u4E0B\u8F7D\u4EA7\u7269",
1600
1266
  onClick: () => invokeChatPanelDownload(),
1601
- children: /* @__PURE__ */ jsx5(Icon3, { name: "download", size: 16 })
1267
+ children: /* @__PURE__ */ jsx3(Icon, { name: "download", size: 16 })
1602
1268
  }
1603
1269
  );
1604
1270
  }
@@ -1609,7 +1275,7 @@ function ChatPanelArtifactMenu() {
1609
1275
  }
1610
1276
  const active = ctx.artifacts.find((item) => item.id === ctx.activeId);
1611
1277
  const inList = ctx.view === "list";
1612
- return /* @__PURE__ */ jsx5(
1278
+ return /* @__PURE__ */ jsx3(
1613
1279
  DropdownMenu,
1614
1280
  {
1615
1281
  items: ctx.artifacts.map((item) => ({
@@ -1623,21 +1289,21 @@ function ChatPanelArtifactMenu() {
1623
1289
  ctx.onSelectArtifact?.(target);
1624
1290
  }
1625
1291
  },
1626
- children: /* @__PURE__ */ jsxs3(
1292
+ children: /* @__PURE__ */ jsxs(
1627
1293
  "span",
1628
1294
  {
1629
1295
  className: "pactor-chat-inspector__menu-trigger",
1630
1296
  "data-view": ctx.view,
1631
1297
  children: [
1632
- /* @__PURE__ */ jsx5(
1633
- Icon3,
1298
+ /* @__PURE__ */ jsx3(
1299
+ Icon,
1634
1300
  {
1635
1301
  name: inList ? "folder" : artifactIconName(active),
1636
1302
  size: 13
1637
1303
  }
1638
1304
  ),
1639
- /* @__PURE__ */ jsx5("span", { className: "pactor-chat-inspector__title", children: inList ? "\u4EA7\u7269\u76EE\u5F55" : active?.title ?? "\u4EA7\u51FA\u7269" }),
1640
- /* @__PURE__ */ jsx5(Icon3, { name: "chevron-down", size: 12 })
1305
+ /* @__PURE__ */ jsx3("span", { className: "pactor-chat-inspector__title", children: inList ? "\u4EA7\u7269\u76EE\u5F55" : active?.title ?? "\u4EA7\u51FA\u7269" }),
1306
+ /* @__PURE__ */ jsx3(Icon, { name: "chevron-down", size: 12 })
1641
1307
  ]
1642
1308
  }
1643
1309
  )
@@ -1708,187 +1374,9 @@ function buildPanelHeaderFragment(props) {
1708
1374
  };
1709
1375
  }
1710
1376
 
1711
- // src/view/ArtifactPanel.tsx
1712
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1713
- function useArtifactRuntime(safeRegistry, user) {
1714
- return useMemo(() => {
1715
- if (!safeRegistry) {
1716
- return void 0;
1717
- }
1718
- const components = new Registry2("ChatArtifactRegistry");
1719
- components.register(CHAT_DENIED_TYPE, ChatDenied);
1720
- for (const name of safeRegistry.list()) {
1721
- components.register(name, safeRegistry.get(name));
1722
- }
1723
- return createChatRuntime({ safeRegistry: components, user });
1724
- }, [safeRegistry, user]);
1725
- }
1726
- var ArtifactDslGuard = class extends Component2 {
1727
- constructor() {
1728
- super(...arguments);
1729
- this.state = { failed: false };
1730
- }
1731
- static getDerivedStateFromError() {
1732
- return { failed: true };
1733
- }
1734
- componentDidCatch(error) {
1735
- console.warn("[@pactor-app/chat] DSL \u4EA7\u51FA\u7269\u6E32\u67D3\u5931\u8D25\uFF0C\u5DF2\u964D\u7EA7\u5C55\u793A", error);
1736
- }
1737
- render() {
1738
- return this.state.failed ? /* @__PURE__ */ jsx6("div", { className: "pactor-chat-denied", children: "DSL \u4EA7\u51FA\u7269\u6E32\u67D3\u5931\u8D25\uFF0C\u5DF2\u964D\u7EA7\u5C55\u793A" }) : this.props.children;
1739
- }
1740
- };
1741
- function ArtifactDslNode({ node }) {
1742
- const { renderChildren } = useRenderer3();
1743
- return /* @__PURE__ */ jsx6(Fragment3, { children: renderChildren([node]) });
1744
- }
1745
- function ArtifactDslContent({
1746
- content,
1747
- runtime
1748
- }) {
1749
- const node = typeof content === "object" && content !== null && !Array.isArray(content) && typeof content.type === "string" ? content : void 0;
1750
- if (!node || !runtime) {
1751
- return /* @__PURE__ */ jsx6("div", { className: "pactor-chat-denied", children: node ? "DSL \u9884\u89C8\u4E0D\u53EF\u7528\uFF08\u672A\u6CE8\u5165 Safe Registry\uFF09" : "DSL \u4EA7\u51FA\u7269\u5185\u5BB9\u65E0\u6548" });
1752
- }
1753
- const guarded = guardChatDsl(node, runtime.context.components);
1754
- return /* @__PURE__ */ jsx6(DslRenderer2, { context: runtime.context, engine: runtime.engine, children: /* @__PURE__ */ jsx6(ArtifactDslGuard, { children: /* @__PURE__ */ jsx6(ArtifactDslNode, { node: guarded }) }) });
1755
- }
1756
- function ArtifactKindIcon({ artifact }) {
1757
- return /* @__PURE__ */ jsx6(Icon4, { name: resolveArtifactIconName(artifact), size: 13 });
1758
- }
1759
- function buildArtifactTree(artifacts) {
1760
- const root = { name: "", path: "", children: [] };
1761
- for (const artifact of artifacts) {
1762
- const segments = artifact.id.split("/").filter(Boolean);
1763
- let node = root;
1764
- for (let i = 0; i < segments.length - 1; i++) {
1765
- const path = segments.slice(0, i + 1).join("/");
1766
- let child = node.children.find(
1767
- (item) => item.path === path && item.artifact === void 0
1768
- );
1769
- if (!child) {
1770
- child = { name: segments[i], path, children: [] };
1771
- node.children.push(child);
1772
- }
1773
- node = child;
1774
- }
1775
- node.children.push({
1776
- name: artifact.title,
1777
- path: artifact.id,
1778
- artifact,
1779
- children: []
1780
- });
1781
- }
1782
- const sortLevel = (nodes) => {
1783
- nodes.sort((a, b) => {
1784
- const dirDelta = Number(b.artifact === void 0) - Number(a.artifact === void 0);
1785
- return dirDelta !== 0 ? dirDelta : a.name.localeCompare(b.name);
1786
- });
1787
- for (const item of nodes) {
1788
- sortLevel(item.children);
1789
- }
1790
- };
1791
- sortLevel(root.children);
1792
- return root.children;
1793
- }
1794
- function ArtifactListView({
1795
- nodes,
1796
- activeId,
1797
- onSelect
1798
- }) {
1799
- return /* @__PURE__ */ jsx6("ul", { className: "pactor-chat-inspector__list", children: nodes.map((node) => /* @__PURE__ */ jsx6(
1800
- ArtifactTreeRow,
1801
- {
1802
- node,
1803
- activeId,
1804
- onSelect
1805
- },
1806
- node.path
1807
- )) });
1808
- }
1809
- function ArtifactTreeRow({
1810
- node,
1811
- activeId,
1812
- onSelect
1813
- }) {
1814
- const [open, setOpen] = useState6(true);
1815
- if (node.artifact) {
1816
- return /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsxs4(
1817
- "button",
1818
- {
1819
- type: "button",
1820
- className: "pactor-chat-inspector__list-item",
1821
- "data-active": node.artifact.id === activeId,
1822
- onClick: () => onSelect?.(node.artifact),
1823
- children: [
1824
- /* @__PURE__ */ jsx6(ArtifactKindIcon, { artifact: node.artifact }),
1825
- /* @__PURE__ */ jsx6("span", { className: "pactor-chat-inspector__list-item-title", children: node.artifact.title }),
1826
- /* @__PURE__ */ jsx6("span", { className: "pactor-chat-inspector__kind", children: node.artifact.kind })
1827
- ]
1828
- }
1829
- ) });
1830
- }
1831
- return /* @__PURE__ */ jsxs4("li", { children: [
1832
- /* @__PURE__ */ jsxs4(
1833
- "button",
1834
- {
1835
- type: "button",
1836
- className: "pactor-chat-inspector__list-folder",
1837
- "aria-expanded": open,
1838
- "data-open": open,
1839
- onClick: () => setOpen((value) => !value),
1840
- children: [
1841
- /* @__PURE__ */ jsx6("span", { className: "pactor-chat-trace__chevron", children: /* @__PURE__ */ jsx6(Icon4, { name: "chevron-right", size: 12 }) }),
1842
- /* @__PURE__ */ jsx6(Icon4, { name: "folder", size: 13 }),
1843
- /* @__PURE__ */ jsx6("span", { children: node.name })
1844
- ]
1845
- }
1846
- ),
1847
- open && /* @__PURE__ */ jsx6("div", { className: "pactor-chat-inspector__list-children", children: /* @__PURE__ */ jsx6(
1848
- ArtifactListView,
1849
- {
1850
- nodes: node.children,
1851
- activeId,
1852
- onSelect
1853
- }
1854
- ) })
1855
- ] });
1856
- }
1857
- function ArtifactImageContent({ artifact }) {
1858
- const raw = String(artifact.content).trim();
1859
- const src = raw.startsWith("<svg") || raw.startsWith("<?xml") ? `data:image/svg+xml;utf8,${encodeURIComponent(raw)}` : raw;
1860
- return /* @__PURE__ */ jsx6("div", { className: "pactor-chat-inspector__image", children: /* @__PURE__ */ jsx6("img", { src, alt: artifact.title }) });
1861
- }
1862
- function ArtifactContent({
1863
- artifact,
1864
- runtime,
1865
- viewers
1866
- }) {
1867
- const ext = resolveArtifactFileType(artifact);
1868
- const custom = (ext ? viewers?.[ext] : void 0) ?? viewers?.[artifact.kind];
1869
- if (custom) {
1870
- return /* @__PURE__ */ jsx6(Fragment3, { children: custom(artifact) });
1871
- }
1872
- if (isImageArtifact(artifact)) {
1873
- return /* @__PURE__ */ jsx6(ArtifactImageContent, { artifact });
1874
- }
1875
- switch (artifact.kind) {
1876
- case "markdown":
1877
- return /* @__PURE__ */ jsx6(MarkdownRenderer2, { content: String(artifact.content) });
1878
- case "code":
1879
- return /* @__PURE__ */ jsxs4("div", { className: "pactor-chat-inspector__code", children: [
1880
- artifact.language ? /* @__PURE__ */ jsx6("span", { className: "pactor-chat-inspector__code-lang", children: artifact.language }) : null,
1881
- /* @__PURE__ */ jsx6("pre", { children: /* @__PURE__ */ jsx6("code", { children: String(artifact.content) }) })
1882
- ] });
1883
- case "text":
1884
- return /* @__PURE__ */ jsx6("pre", { className: "pactor-chat-inspector__text", children: String(artifact.content) });
1885
- case "dsl":
1886
- return /* @__PURE__ */ jsx6(ArtifactDslContent, { content: artifact.content, runtime });
1887
- default:
1888
- return null;
1889
- }
1890
- }
1891
- function ArtifactPanel({
1377
+ // src/view/ChatArtifactPanel.tsx
1378
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1379
+ function ArtifactPanel2({
1892
1380
  artifact,
1893
1381
  artifacts,
1894
1382
  activeArtifactId,
@@ -1897,72 +1385,52 @@ function ArtifactPanel({
1897
1385
  onViewRequestConsumed,
1898
1386
  inspector,
1899
1387
  onClose,
1388
+ onDownload,
1900
1389
  safeRegistry,
1901
1390
  user,
1902
1391
  artifactViewers,
1903
1392
  className
1904
1393
  }) {
1905
- const runtime = useArtifactRuntime(safeRegistry, user);
1906
- const [view, setView] = useState6("content");
1394
+ const [view, setView] = useState4("content");
1907
1395
  const activeId = activeArtifactId ?? artifact?.id;
1908
- useEffect3(() => {
1909
- setView("content");
1910
- }, [activeId]);
1911
- useEffect3(() => {
1912
- if (viewRequest != null) {
1913
- setView("list");
1914
- onViewRequestConsumed?.();
1915
- }
1916
- }, [viewRequest]);
1917
- const showListButton = artifacts !== void 0 && artifacts.length > 0;
1918
- const showMenu = artifacts !== void 0 && artifacts.length > 0;
1919
- const toggleListRef = useRef4(() => {
1920
- });
1921
- toggleListRef.current = () => setView((value) => value === "list" ? "content" : "list");
1922
- const closeRef = useRef4(onClose);
1396
+ const hasArtifacts = artifacts !== void 0 && artifacts.length > 0;
1397
+ const headerTitle = view === "list" ? "\u4EA7\u7269\u76EE\u5F55" : artifact?.title ?? "\u4EA7\u51FA\u7269";
1398
+ const closeRef = useRef3(onClose);
1923
1399
  closeRef.current = onClose;
1924
- const artifactRef = useRef4(artifact);
1400
+ const artifactRef = useRef3(artifact);
1925
1401
  artifactRef.current = artifact;
1926
- useEffect3(() => {
1402
+ const downloadRef = useRef3(onDownload);
1403
+ downloadRef.current = onDownload;
1404
+ useEffect2(() => {
1927
1405
  setChatChromeHandlers({
1928
1406
  panelClose: () => closeRef.current?.(),
1929
- panelToggleList: () => toggleListRef.current(),
1407
+ panelToggleList: () => setView((value) => value === "list" ? "content" : "list"),
1930
1408
  panelDownload: () => {
1931
1409
  const current = artifactRef.current;
1932
1410
  if (current) {
1933
- void downloadArtifact(current);
1411
+ if (downloadRef.current) {
1412
+ downloadRef.current(current);
1413
+ } else {
1414
+ void downloadArtifact(current);
1415
+ }
1934
1416
  }
1935
1417
  }
1936
1418
  });
1937
1419
  }, []);
1938
- const panelRef = useRef4(null);
1939
- const [width, setWidth] = useState6(null);
1940
- const handleResizeStart = (event) => {
1941
- event.preventDefault();
1942
- const panel = panelRef.current;
1943
- if (!panel) {
1944
- return;
1420
+ const handleSelectArtifact = (id) => {
1421
+ const target = artifacts?.find((item) => item.id === id);
1422
+ if (target) {
1423
+ onSelectArtifact?.(target);
1945
1424
  }
1946
- const startWidth = panel.getBoundingClientRect().width;
1947
- const startX = event.clientX;
1948
- const prevUserSelect = document.body.style.userSelect;
1949
- document.body.style.userSelect = "none";
1950
- const onMove = (moveEvent) => {
1951
- const hostRect = panel.parentElement?.getBoundingClientRect();
1952
- const hostWidth = hostRect !== void 0 && hostRect.width > 0 ? hostRect.width : window.innerWidth;
1953
- const maxWidth = Math.min(600, hostWidth * 2 / 3);
1954
- const next = startWidth + (startX - moveEvent.clientX);
1955
- setWidth(Math.round(Math.min(Math.max(next, 480), maxWidth)));
1956
- };
1957
- const onUp = () => {
1958
- document.body.style.userSelect = prevUserSelect;
1959
- document.removeEventListener("pointermove", onMove);
1960
- document.removeEventListener("pointerup", onUp);
1961
- };
1962
- document.addEventListener("pointermove", onMove);
1963
- document.addEventListener("pointerup", onUp);
1964
1425
  };
1965
- return /* @__PURE__ */ jsx6(
1426
+ const headerFallback = /* @__PURE__ */ jsxs2(Fragment2, { children: [
1427
+ hasArtifacts ? /* @__PURE__ */ jsx4(ChatPanelListButton, {}) : null,
1428
+ hasArtifacts ? /* @__PURE__ */ jsx4(ChatPanelArtifactMenu, {}) : /* @__PURE__ */ jsx4("span", { className: "pactor-chat-inspector__title", children: headerTitle }),
1429
+ view !== "list" && artifact ? /* @__PURE__ */ jsx4("span", { className: "pactor-chat-inspector__kind", children: artifact.kind }) : null,
1430
+ artifact != null ? /* @__PURE__ */ jsx4(ChatPanelDownloadButton, {}) : null,
1431
+ /* @__PURE__ */ jsx4(ChatPanelCloseButton, {})
1432
+ ] });
1433
+ return /* @__PURE__ */ jsx4(
1966
1434
  ChatPanelContext.Provider,
1967
1435
  {
1968
1436
  value: {
@@ -1971,61 +1439,40 @@ function ArtifactPanel({
1971
1439
  view,
1972
1440
  onSelectArtifact
1973
1441
  },
1974
- children: /* @__PURE__ */ jsxs4(
1975
- "aside",
1442
+ children: /* @__PURE__ */ jsx4(
1443
+ ArtifactPanel,
1976
1444
  {
1977
- ref: panelRef,
1978
- className: `pactor-chat-inspector${className ? ` ${className}` : ""}`,
1979
- "data-kind": artifact?.kind,
1980
- style: width !== null ? { width: `${width}px` } : void 0,
1981
- children: [
1982
- /* @__PURE__ */ jsx6(
1983
- "div",
1984
- {
1985
- className: "pactor-chat-inspector__resize",
1986
- role: "separator",
1987
- "aria-orientation": "vertical",
1988
- "aria-label": "\u62D6\u52A8\u8C03\u6574\u9762\u677F\u5BBD\u5EA6",
1989
- onPointerDown: handleResizeStart
1990
- }
1991
- ),
1992
- /* @__PURE__ */ jsx6("div", { className: "pactor-chat-inspector__header", children: /* @__PURE__ */ jsx6(
1993
- ChromeSlot,
1994
- {
1995
- fragment: buildPanelHeaderFragment({
1996
- title: view === "list" ? "\u4EA7\u7269\u76EE\u5F55" : artifact?.title ?? "\u4EA7\u51FA\u7269",
1997
- kind: artifact?.kind ?? "text",
1998
- showListButton,
1999
- showDownload: artifact != null,
2000
- showMenu,
2001
- view
2002
- }),
2003
- components: PANEL_HEADER_INTERNAL_COMPONENTS,
2004
- fallback: /* @__PURE__ */ jsxs4(Fragment3, { children: [
2005
- showListButton ? /* @__PURE__ */ jsx6(ChatPanelListButton, {}) : null,
2006
- showMenu ? /* @__PURE__ */ jsx6(ChatPanelArtifactMenu, {}) : /* @__PURE__ */ jsx6("span", { className: "pactor-chat-inspector__title", children: view === "list" ? "\u4EA7\u7269\u76EE\u5F55" : artifact?.title ?? "\u4EA7\u51FA\u7269" }),
2007
- view !== "list" && artifact ? /* @__PURE__ */ jsx6("span", { className: "pactor-chat-inspector__kind", children: artifact.kind }) : null,
2008
- artifact ? /* @__PURE__ */ jsx6(ChatPanelDownloadButton, {}) : null,
2009
- /* @__PURE__ */ jsx6(ChatPanelCloseButton, {})
2010
- ] })
2011
- }
2012
- ) }),
2013
- /* @__PURE__ */ jsx6("div", { className: "pactor-chat-inspector__body", children: view === "list" && artifacts !== void 0 ? /* @__PURE__ */ jsx6(
2014
- ArtifactListView,
2015
- {
2016
- nodes: buildArtifactTree(artifacts),
2017
- activeId,
2018
- onSelect: onSelectArtifact
2019
- }
2020
- ) : inspector !== void 0 && inspector !== null ? inspector : artifact ? /* @__PURE__ */ jsx6(
2021
- ArtifactContent,
2022
- {
2023
- artifact,
2024
- runtime,
2025
- viewers: artifactViewers
2026
- }
2027
- ) : null })
2028
- ]
1445
+ artifact,
1446
+ artifacts,
1447
+ activeArtifactId,
1448
+ onSelectArtifact: handleSelectArtifact,
1449
+ view,
1450
+ onViewChange: setView,
1451
+ viewRequest,
1452
+ onViewRequestConsumed,
1453
+ inspector,
1454
+ onClose,
1455
+ onDownload,
1456
+ safeRegistry,
1457
+ user,
1458
+ artifactViewers,
1459
+ resizable: true,
1460
+ className: className ? `pactor-chat-inspector ${className}` : "pactor-chat-inspector",
1461
+ header: /* @__PURE__ */ jsx4("div", { className: "pactor-chat-inspector__header", children: /* @__PURE__ */ jsx4(
1462
+ ChromeSlot,
1463
+ {
1464
+ fragment: buildPanelHeaderFragment({
1465
+ title: headerTitle,
1466
+ kind: artifact?.kind ?? "text",
1467
+ showListButton: hasArtifacts,
1468
+ showDownload: artifact != null,
1469
+ showMenu: hasArtifacts,
1470
+ view
1471
+ }),
1472
+ components: PANEL_HEADER_INTERNAL_COMPONENTS,
1473
+ fallback: headerFallback
1474
+ }
1475
+ ) })
2029
1476
  }
2030
1477
  )
2031
1478
  }
@@ -2033,22 +1480,21 @@ function ArtifactPanel({
2033
1480
  }
2034
1481
 
2035
1482
  // src/view/ChatView.tsx
2036
- import { Icon as Icon11 } from "@pactor-app/ui/components";
2037
- import { Registry as Registry3 } from "@pactor-app/core";
2038
- import { useEffect as useEffect9, useMemo as useMemo3, useRef as useRef11, useState as useState14, useSyncExternalStore } from "react";
1483
+ import { Icon as Icon8 } from "@pactor-app/ui/components";
1484
+ import { Registry as Registry2 } from "@pactor-app/core";
1485
+ import { useEffect as useEffect9, useMemo as useMemo2, useRef as useRef11, useState as useState14, useSyncExternalStore } from "react";
2039
1486
 
2040
- // src/view/Composer.tsx
2041
- import { Icon as Icon7 } from "@pactor-app/ui/components";
2042
- import { useLayoutEffect as useLayoutEffect3, useMemo as useMemo2, useRef as useRef7, useState as useState10 } from "react";
1487
+ // src/view/ChatComposer.tsx
1488
+ import { useLayoutEffect as useLayoutEffect3, useMemo, useRef as useRef6, useState as useState8 } from "react";
2043
1489
 
2044
1490
  // src/view/AnchoredPopover.tsx
2045
1491
  import {
2046
- useEffect as useEffect4,
1492
+ useEffect as useEffect3,
2047
1493
  useLayoutEffect as useLayoutEffect2,
2048
- useRef as useRef5,
2049
- useState as useState7
1494
+ useRef as useRef4,
1495
+ useState as useState5
2050
1496
  } from "react";
2051
- import { jsx as jsx7 } from "react/jsx-runtime";
1497
+ import { jsx as jsx5 } from "react/jsx-runtime";
2052
1498
  function AnchoredPopover({
2053
1499
  anchorRect,
2054
1500
  onClose,
@@ -2057,8 +1503,8 @@ function AnchoredPopover({
2057
1503
  role = "dialog",
2058
1504
  sideOffset = 8
2059
1505
  }) {
2060
- const ref = useRef5(null);
2061
- const [position, setPosition] = useState7(null);
1506
+ const ref = useRef4(null);
1507
+ const [position, setPosition] = useState5(null);
2062
1508
  useLayoutEffect2(() => {
2063
1509
  const element = ref.current;
2064
1510
  if (!element) return;
@@ -2077,7 +1523,7 @@ function AnchoredPopover({
2077
1523
  }
2078
1524
  );
2079
1525
  }, [anchorRect, sideOffset]);
2080
- useEffect4(() => {
1526
+ useEffect3(() => {
2081
1527
  const onKeyDown = (event) => {
2082
1528
  if (event.key !== "Escape") return;
2083
1529
  const element = ref.current;
@@ -2105,7 +1551,7 @@ function AnchoredPopover({
2105
1551
  position?.below ? "pactor-chat-popover--below" : "",
2106
1552
  className ?? ""
2107
1553
  ].filter(Boolean).join(" ");
2108
- return /* @__PURE__ */ jsx7(
1554
+ return /* @__PURE__ */ jsx5(
2109
1555
  "div",
2110
1556
  {
2111
1557
  ref,
@@ -2123,9 +1569,13 @@ function AnchoredPopover({
2123
1569
  );
2124
1570
  }
2125
1571
 
1572
+ // src/view/chrome/composer.tsx
1573
+ import { Icon as Icon3 } from "@pactor-app/ui/components";
1574
+ import { createContext as createContext2, useContext as useContext2 } from "react";
1575
+
2126
1576
  // src/view/ModelChip.tsx
2127
- import { Icon as Icon5 } from "@pactor-app/ui/components";
2128
- import { useEffect as useEffect5, useRef as useRef6, useState as useState8 } from "react";
1577
+ import { Icon as Icon2 } from "@pactor-app/ui/components";
1578
+ import { useEffect as useEffect4, useRef as useRef5, useState as useState6 } from "react";
2129
1579
 
2130
1580
  // src/view/chrome/model-select.tsx
2131
1581
  function buildModelSelectFragment(props) {
@@ -2151,17 +1601,17 @@ function buildModelSelectFragment(props) {
2151
1601
  }
2152
1602
 
2153
1603
  // src/view/ModelChip.tsx
2154
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1604
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
2155
1605
  function ModelChip({
2156
1606
  models,
2157
1607
  model,
2158
1608
  onModelChange
2159
1609
  }) {
2160
- const chipRef = useRef6(null);
2161
- const [anchor, setAnchor] = useState8(null);
1610
+ const chipRef = useRef5(null);
1611
+ const [anchor, setAnchor] = useState6(null);
2162
1612
  const currentOption = models.find((option) => option.value === model) ?? models[0];
2163
- return /* @__PURE__ */ jsxs5(Fragment4, { children: [
2164
- /* @__PURE__ */ jsxs5(
1613
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
1614
+ /* @__PURE__ */ jsxs3(
2165
1615
  "button",
2166
1616
  {
2167
1617
  ref: chipRef,
@@ -2171,18 +1621,18 @@ function ModelChip({
2171
1621
  "aria-label": "\u9009\u62E9\u6A21\u578B",
2172
1622
  onClick: () => setAnchor(chipRef.current.getBoundingClientRect()),
2173
1623
  children: [
2174
- /* @__PURE__ */ jsx8("span", { className: "pactor-chat-model-chip__label", children: currentOption.label }),
2175
- /* @__PURE__ */ jsx8(Icon5, { name: "chevrons-up-down", size: 12 })
1624
+ /* @__PURE__ */ jsx6("span", { className: "pactor-chat-model-chip__label", children: currentOption.label }),
1625
+ /* @__PURE__ */ jsx6(Icon2, { name: "chevrons-up-down", size: 12 })
2176
1626
  ]
2177
1627
  }
2178
1628
  ),
2179
- anchor && /* @__PURE__ */ jsx8(
1629
+ anchor && /* @__PURE__ */ jsx6(
2180
1630
  AnchoredPopover,
2181
1631
  {
2182
1632
  anchorRect: anchor,
2183
1633
  onClose: () => setAnchor(null),
2184
1634
  role: "listbox",
2185
- children: models.map((option) => /* @__PURE__ */ jsxs5(
1635
+ children: models.map((option) => /* @__PURE__ */ jsxs3(
2186
1636
  "button",
2187
1637
  {
2188
1638
  type: "button",
@@ -2194,8 +1644,8 @@ function ModelChip({
2194
1644
  setAnchor(null);
2195
1645
  },
2196
1646
  children: [
2197
- /* @__PURE__ */ jsx8("span", { className: "pactor-chat-popover__item-label", children: option.label }),
2198
- option.value === currentOption.value && /* @__PURE__ */ jsx8(Icon5, { name: "check", size: 13, className: "pactor-chat-popover__item-check" })
1647
+ /* @__PURE__ */ jsx6("span", { className: "pactor-chat-popover__item-label", children: option.label }),
1648
+ option.value === currentOption.value && /* @__PURE__ */ jsx6(Icon2, { name: "check", size: 13, className: "pactor-chat-popover__item-check" })
2199
1649
  ]
2200
1650
  },
2201
1651
  option.value
@@ -2209,26 +1659,24 @@ function ModelSelect({
2209
1659
  model,
2210
1660
  onModelChange
2211
1661
  }) {
2212
- const changeRef = useRef6(onModelChange);
1662
+ const changeRef = useRef5(onModelChange);
2213
1663
  changeRef.current = onModelChange;
2214
- useEffect5(() => {
1664
+ useEffect4(() => {
2215
1665
  setChatChromeHandlers({
2216
1666
  modelChange: (value) => changeRef.current?.(value)
2217
1667
  });
2218
1668
  }, []);
2219
- return /* @__PURE__ */ jsx8(
1669
+ return /* @__PURE__ */ jsx6(
2220
1670
  ChromeSlot,
2221
1671
  {
2222
1672
  fragment: buildModelSelectFragment({ models, model }),
2223
- fallback: /* @__PURE__ */ jsx8(ModelChip, { models, model, onModelChange })
1673
+ fallback: /* @__PURE__ */ jsx6(ModelChip, { models, model, onModelChange })
2224
1674
  }
2225
1675
  );
2226
1676
  }
2227
1677
 
2228
1678
  // src/view/chrome/composer.tsx
2229
- import { Icon as Icon6 } from "@pactor-app/ui/components";
2230
- import { createContext as createContext2, useContext as useContext2 } from "react";
2231
- import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1679
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2232
1680
  var ComposerBridgeContext = createContext2(
2233
1681
  null
2234
1682
  );
@@ -2258,21 +1706,21 @@ function ComposerAttachments({
2258
1706
  if (attachments.length === 0) {
2259
1707
  return null;
2260
1708
  }
2261
- return /* @__PURE__ */ jsx9("div", { className: "pactor-chat-composer__attachments", children: attachments.map((attachment) => {
1709
+ return /* @__PURE__ */ jsx7("div", { className: "pactor-chat-composer__attachments", children: attachments.map((attachment) => {
2262
1710
  const isImage = attachment.mimeType.startsWith("image/");
2263
- return /* @__PURE__ */ jsxs6(
1711
+ return /* @__PURE__ */ jsxs4(
2264
1712
  "div",
2265
1713
  {
2266
1714
  className: "pactor-chat-composer__attachment",
2267
1715
  "data-attachment-id": attachment.id,
2268
1716
  onClick: () => onClick?.(attachment),
2269
1717
  children: [
2270
- isImage && attachment.url ? /* @__PURE__ */ jsx9("span", { className: "pactor-chat-composer__attachment-thumb", children: /* @__PURE__ */ jsx9("img", { src: attachment.url, alt: attachment.name }) }) : /* @__PURE__ */ jsxs6("span", { className: "pactor-chat-composer__attachment-info", children: [
2271
- /* @__PURE__ */ jsx9(Icon6, { name: "file-text", size: 14 }),
2272
- /* @__PURE__ */ jsx9("span", { className: "pactor-chat-composer__attachment-name", children: attachment.name }),
2273
- attachment.size !== void 0 && /* @__PURE__ */ jsx9("span", { className: "pactor-chat-composer__attachment-size", children: formatSize(attachment.size) })
1718
+ isImage && attachment.url ? /* @__PURE__ */ jsx7("span", { className: "pactor-chat-composer__attachment-thumb", children: /* @__PURE__ */ jsx7("img", { src: attachment.url, alt: attachment.name }) }) : /* @__PURE__ */ jsxs4("span", { className: "pactor-chat-composer__attachment-info", children: [
1719
+ /* @__PURE__ */ jsx7(Icon3, { name: "file-text", size: 14 }),
1720
+ /* @__PURE__ */ jsx7("span", { className: "pactor-chat-composer__attachment-name", children: attachment.name }),
1721
+ attachment.size !== void 0 && /* @__PURE__ */ jsx7("span", { className: "pactor-chat-composer__attachment-size", children: formatSize(attachment.size) })
2274
1722
  ] }),
2275
- /* @__PURE__ */ jsx9(
1723
+ /* @__PURE__ */ jsx7(
2276
1724
  "button",
2277
1725
  {
2278
1726
  type: "button",
@@ -2283,7 +1731,7 @@ function ComposerAttachments({
2283
1731
  event.stopPropagation();
2284
1732
  onRemove(attachment.id);
2285
1733
  },
2286
- children: /* @__PURE__ */ jsx9(Icon6, { name: "x", size: 12 })
1734
+ children: /* @__PURE__ */ jsx7(Icon3, { name: "x", size: 12 })
2287
1735
  }
2288
1736
  )
2289
1737
  ]
@@ -2299,14 +1747,14 @@ function ComposerContextChips({
2299
1747
  if (chips.length === 0) {
2300
1748
  return null;
2301
1749
  }
2302
- return /* @__PURE__ */ jsx9("div", { className: "pactor-chat-composer__contexts", children: chips.map((chip) => /* @__PURE__ */ jsxs6(
1750
+ return /* @__PURE__ */ jsx7("div", { className: "pactor-chat-composer__contexts", children: chips.map((chip) => /* @__PURE__ */ jsxs4(
2303
1751
  "span",
2304
1752
  {
2305
1753
  className: "pactor-chat-context-chip",
2306
1754
  "data-context-id": chip.id,
2307
1755
  children: [
2308
- /* @__PURE__ */ jsx9("span", { className: "pactor-chat-context-chip__label", children: chip.label }),
2309
- /* @__PURE__ */ jsx9(
1756
+ /* @__PURE__ */ jsx7("span", { className: "pactor-chat-context-chip__label", children: chip.label }),
1757
+ /* @__PURE__ */ jsx7(
2310
1758
  "button",
2311
1759
  {
2312
1760
  type: "button",
@@ -2314,7 +1762,7 @@ function ComposerContextChips({
2314
1762
  title: `\u79FB\u9664\u4E0A\u4E0B\u6587 ${chip.label}`,
2315
1763
  "aria-label": `\u79FB\u9664\u4E0A\u4E0B\u6587 ${chip.label}`,
2316
1764
  onClick: () => onRemove(chip),
2317
- children: /* @__PURE__ */ jsx9(Icon6, { name: "x", size: 12 })
1765
+ children: /* @__PURE__ */ jsx7(Icon3, { name: "x", size: 12 })
2318
1766
  }
2319
1767
  )
2320
1768
  ]
@@ -2324,8 +1772,8 @@ function ComposerContextChips({
2324
1772
  }
2325
1773
  function ChatComposerHeader() {
2326
1774
  const bridge = useComposerBridge();
2327
- return /* @__PURE__ */ jsxs6(Fragment5, { children: [
2328
- bridge.attachments !== void 0 && /* @__PURE__ */ jsx9(
1775
+ return /* @__PURE__ */ jsxs4(Fragment4, { children: [
1776
+ bridge.attachments !== void 0 && /* @__PURE__ */ jsx7(
2329
1777
  ComposerAttachments,
2330
1778
  {
2331
1779
  attachments: bridge.attachments,
@@ -2333,7 +1781,7 @@ function ChatComposerHeader() {
2333
1781
  onClick: bridge.attachmentClick
2334
1782
  }
2335
1783
  ),
2336
- bridge.contextChips !== void 0 && /* @__PURE__ */ jsx9(
1784
+ bridge.contextChips !== void 0 && /* @__PURE__ */ jsx7(
2337
1785
  ComposerContextChips,
2338
1786
  {
2339
1787
  chips: bridge.contextChips,
@@ -2344,9 +1792,9 @@ function ChatComposerHeader() {
2344
1792
  }
2345
1793
  function ChatComposerToolbarStart() {
2346
1794
  const bridge = useComposerBridge();
2347
- return /* @__PURE__ */ jsxs6(Fragment5, { children: [
1795
+ return /* @__PURE__ */ jsxs4(Fragment4, { children: [
2348
1796
  bridge.toolbarStart,
2349
- bridge.showPlus && /* @__PURE__ */ jsx9(
1797
+ bridge.showPlus && /* @__PURE__ */ jsx7(
2350
1798
  "button",
2351
1799
  {
2352
1800
  type: "button",
@@ -2354,10 +1802,10 @@ function ChatComposerToolbarStart() {
2354
1802
  title: "\u66F4\u591A\u529F\u80FD",
2355
1803
  "aria-label": "\u66F4\u591A\u529F\u80FD",
2356
1804
  onClick: (event) => bridge.plusClick(event.currentTarget.getBoundingClientRect()),
2357
- children: /* @__PURE__ */ jsx9(Icon6, { name: "plus", size: 14 })
1805
+ children: /* @__PURE__ */ jsx7(Icon3, { name: "plus", size: 14 })
2358
1806
  }
2359
1807
  ),
2360
- bridge.showAttach && /* @__PURE__ */ jsx9(
1808
+ bridge.showAttach && /* @__PURE__ */ jsx7(
2361
1809
  "button",
2362
1810
  {
2363
1811
  type: "button",
@@ -2365,15 +1813,15 @@ function ChatComposerToolbarStart() {
2365
1813
  title: "\u6DFB\u52A0\u9644\u4EF6",
2366
1814
  "aria-label": "\u6DFB\u52A0\u9644\u4EF6",
2367
1815
  onClick: bridge.openFilePicker,
2368
- children: /* @__PURE__ */ jsx9(Icon6, { name: "paperclip", size: 14 })
1816
+ children: /* @__PURE__ */ jsx7(Icon3, { name: "paperclip", size: 14 })
2369
1817
  }
2370
1818
  )
2371
1819
  ] });
2372
1820
  }
2373
1821
  function ChatComposerToolbarEnd() {
2374
1822
  const bridge = useComposerBridge();
2375
- return /* @__PURE__ */ jsxs6(Fragment5, { children: [
2376
- bridge.modelChipEnabled && /* @__PURE__ */ jsx9(
1823
+ return /* @__PURE__ */ jsxs4(Fragment4, { children: [
1824
+ bridge.modelChipEnabled && /* @__PURE__ */ jsx7(
2377
1825
  ModelSelect,
2378
1826
  {
2379
1827
  models: bridge.models,
@@ -2382,7 +1830,7 @@ function ChatComposerToolbarEnd() {
2382
1830
  }
2383
1831
  ),
2384
1832
  bridge.toolbarEnd,
2385
- /* @__PURE__ */ jsx9(
1833
+ /* @__PURE__ */ jsx7(
2386
1834
  "button",
2387
1835
  {
2388
1836
  type: "button",
@@ -2391,14 +1839,14 @@ function ChatComposerToolbarEnd() {
2391
1839
  "aria-label": bridge.streaming ? "\u505C\u6B62\u751F\u6210" : "\u53D1\u9001",
2392
1840
  disabled: bridge.streaming ? false : bridge.disabled || !bridge.text.trim(),
2393
1841
  onClick: bridge.streaming ? bridge.stop : bridge.send,
2394
- children: bridge.streaming ? /* @__PURE__ */ jsx9(Icon6, { name: "square", size: 14, className: "pactor-chat-icon-fill" }) : /* @__PURE__ */ jsx9(Icon6, { name: "arrow-up", size: 16 })
1842
+ children: bridge.streaming ? /* @__PURE__ */ jsx7(Icon3, { name: "square", size: 14, className: "pactor-chat-icon-fill" }) : /* @__PURE__ */ jsx7(Icon3, { name: "arrow-up", size: 16 })
2395
1843
  }
2396
1844
  )
2397
1845
  ] });
2398
1846
  }
2399
1847
  function ChatComposerFooter() {
2400
1848
  const bridge = useComposerBridge();
2401
- return /* @__PURE__ */ jsx9(Fragment5, { children: bridge.composerFooter });
1849
+ return /* @__PURE__ */ jsx7(Fragment4, { children: bridge.composerFooter });
2402
1850
  }
2403
1851
  var COMPOSER_INTERNAL_COMPONENTS = {
2404
1852
  ChatComposerHeader,
@@ -2439,8 +1887,8 @@ function buildComposerFragment(props) {
2439
1887
  }
2440
1888
 
2441
1889
  // src/view/context-sources.tsx
2442
- import { useEffect as useEffect6, useState as useState9 } from "react";
2443
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1890
+ import { useEffect as useEffect5, useState as useState7 } from "react";
1891
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2444
1892
  function sourceCacheKey(source) {
2445
1893
  return `${source.service ?? ""}:${JSON.stringify(source.params ?? {})}`;
2446
1894
  }
@@ -2475,8 +1923,8 @@ function ContextSourceList({
2475
1923
  cache,
2476
1924
  onSelect
2477
1925
  }) {
2478
- const [resolutions, setResolutions] = useState9([]);
2479
- useEffect6(() => {
1926
+ const [resolutions, setResolutions] = useState7([]);
1927
+ useEffect5(() => {
2480
1928
  let cancelled = false;
2481
1929
  const initial = sources.map(
2482
1930
  (source) => source.items ? { status: "ready", items: source.items } : { status: "loading" }
@@ -2521,12 +1969,12 @@ function ContextSourceList({
2521
1969
  totalMatched += items.length;
2522
1970
  return { source, resolution, items };
2523
1971
  });
2524
- return /* @__PURE__ */ jsxs7("div", { className: "pactor-chat-source-list", children: [
2525
- groups.map(({ source, resolution, items }) => /* @__PURE__ */ jsxs7("div", { className: "pactor-chat-source-list__group", children: [
2526
- sources.length > 1 && /* @__PURE__ */ jsx10("div", { className: "pactor-chat-source-list__group-label", children: source.label }),
2527
- resolution.status === "loading" && /* @__PURE__ */ jsx10("div", { className: "pactor-chat-source-list__hint", children: "\u52A0\u8F7D\u4E2D\u2026" }),
2528
- resolution.status === "error" && /* @__PURE__ */ jsx10("div", { className: "pactor-chat-source-list__error", role: "alert", children: resolution.message }),
2529
- items.map((item) => /* @__PURE__ */ jsx10(
1972
+ return /* @__PURE__ */ jsxs5("div", { className: "pactor-chat-source-list", children: [
1973
+ groups.map(({ source, resolution, items }) => /* @__PURE__ */ jsxs5("div", { className: "pactor-chat-source-list__group", children: [
1974
+ sources.length > 1 && /* @__PURE__ */ jsx8("div", { className: "pactor-chat-source-list__group-label", children: source.label }),
1975
+ resolution.status === "loading" && /* @__PURE__ */ jsx8("div", { className: "pactor-chat-source-list__hint", children: "\u52A0\u8F7D\u4E2D\u2026" }),
1976
+ resolution.status === "error" && /* @__PURE__ */ jsx8("div", { className: "pactor-chat-source-list__error", role: "alert", children: resolution.message }),
1977
+ items.map((item) => /* @__PURE__ */ jsx8(
2530
1978
  "button",
2531
1979
  {
2532
1980
  type: "button",
@@ -2537,13 +1985,12 @@ function ContextSourceList({
2537
1985
  item.id
2538
1986
  ))
2539
1987
  ] }, `${source.trigger}:${source.label}`)),
2540
- totalMatched === 0 && groups.every(({ resolution }) => resolution.status === "ready") && /* @__PURE__ */ jsx10("div", { className: "pactor-chat-source-list__hint", children: "\u65E0\u5339\u914D\u9879" })
1988
+ totalMatched === 0 && groups.every(({ resolution }) => resolution.status === "ready") && /* @__PURE__ */ jsx8("div", { className: "pactor-chat-source-list__hint", children: "\u65E0\u5339\u914D\u9879" })
2541
1989
  ] });
2542
1990
  }
2543
1991
 
2544
- // src/view/Composer.tsx
2545
- import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
2546
- var MAX_INPUT_HEIGHT = 200;
1992
+ // src/view/ChatComposer.tsx
1993
+ import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2547
1994
  function detectMention(text, caret) {
2548
1995
  const beforeCaret = text.slice(0, caret);
2549
1996
  const match = /(?:^|\s)@([^\s@]*)$/.exec(beforeCaret);
@@ -2552,7 +1999,15 @@ function detectMention(text, caret) {
2552
1999
  function collectDropFiles(event) {
2553
2000
  return event.dataTransfer ? Array.from(event.dataTransfer.files) : [];
2554
2001
  }
2555
- function Composer({
2002
+ function toAttachmentItem(attachment) {
2003
+ return {
2004
+ id: attachment.id,
2005
+ name: attachment.name,
2006
+ fileType: attachment.mimeType,
2007
+ fileSize: attachment.size
2008
+ };
2009
+ }
2010
+ function Composer2({
2556
2011
  onSend,
2557
2012
  streaming = false,
2558
2013
  onStop,
@@ -2576,26 +2031,23 @@ function Composer({
2576
2031
  composerFooter,
2577
2032
  hideToolbar = false
2578
2033
  }) {
2579
- const [text, setText] = useState10("");
2580
- const [dragOver, setDragOver] = useState10(false);
2581
- const inputRef = useRef7(null);
2582
- const fileInputRef = useRef7(null);
2583
- const plusButtonRef = useRef7(null);
2584
- const composingRef = useRef7(false);
2034
+ const [text, setText] = useState8("");
2035
+ const [dragOver, setDragOver] = useState8(false);
2036
+ const fileInputRef = useRef6(null);
2585
2037
  const modelChipEnabled = models !== void 0 && models.length > 0;
2586
- const mentionSources = useMemo2(
2038
+ const mentionSources = useMemo(
2587
2039
  () => contextSources?.filter((source) => source.trigger === "@") ?? [],
2588
2040
  [contextSources]
2589
2041
  );
2590
- const plusSources = useMemo2(
2042
+ const plusSources = useMemo(
2591
2043
  () => contextSources?.filter((source) => source.trigger === "+") ?? [],
2592
2044
  [contextSources]
2593
2045
  );
2594
2046
  const builtinMentionEnabled = onMentionTrigger === void 0 && mentionSources.length > 0;
2595
2047
  const builtinPlusEnabled = onPlusMenu === void 0 && plusSources.length > 0;
2596
- const [mentionState, setMentionState] = useState10(null);
2597
- const [plusAnchor, setPlusAnchor] = useState10(null);
2598
- const sourceCacheRef = useRef7(null);
2048
+ const [mentionState, setMentionState] = useState8(null);
2049
+ const [plusAnchor, setPlusAnchor] = useState8(null);
2050
+ const sourceCacheRef = useRef6(null);
2599
2051
  if (sourceCacheRef.current === null) {
2600
2052
  sourceCacheRef.current = /* @__PURE__ */ new Map();
2601
2053
  }
@@ -2614,13 +2066,6 @@ function Composer({
2614
2066
  setMentionState(null);
2615
2067
  setPlusAnchor(null);
2616
2068
  };
2617
- useLayoutEffect3(() => {
2618
- const input = inputRef.current;
2619
- if (input) {
2620
- input.style.height = "auto";
2621
- input.style.height = `${Math.min(input.scrollHeight, MAX_INPUT_HEIGHT)}px`;
2622
- }
2623
- }, [text]);
2624
2069
  const send = () => {
2625
2070
  const value = text.trim();
2626
2071
  if (!value || disabled) {
@@ -2629,7 +2074,7 @@ function Composer({
2629
2074
  onSend?.(value);
2630
2075
  setText("");
2631
2076
  };
2632
- const sendRef = useRef7(send);
2077
+ const sendRef = useRef6(send);
2633
2078
  sendRef.current = send;
2634
2079
  useLayoutEffect3(() => {
2635
2080
  setChatChromeHandlers({ composerSubmit: () => sendRef.current() });
@@ -2647,13 +2092,6 @@ function Composer({
2647
2092
  }
2648
2093
  }
2649
2094
  };
2650
- const handleChange = (event) => {
2651
- syncText(
2652
- event.target.value,
2653
- event.target.selectionStart ?? event.target.value.length,
2654
- event.target.getBoundingClientRect()
2655
- );
2656
- };
2657
2095
  const handleBubbleChange = (event) => {
2658
2096
  const target = event.target;
2659
2097
  if (!(target instanceof HTMLTextAreaElement)) {
@@ -2688,8 +2126,20 @@ function Composer({
2688
2126
  }
2689
2127
  }
2690
2128
  };
2691
- const showToolbar = !hideToolbar && (toolbarStart !== void 0 || toolbarEnd !== void 0 || onPlusMenu !== void 0 || builtinPlusEnabled || onAttachFiles !== void 0 || modelChipEnabled);
2692
- const fileInputNode = onAttachFiles ? /* @__PURE__ */ jsx11(
2129
+ const showPlus = onPlusMenu !== void 0 || builtinPlusEnabled;
2130
+ const handlePlusClick = (anchorRect) => {
2131
+ if (onPlusMenu) {
2132
+ onPlusMenu(anchorRect);
2133
+ } else {
2134
+ setPlusAnchor(anchorRect);
2135
+ }
2136
+ };
2137
+ const removeChip = (chip) => onContextChipsChange?.(
2138
+ (contextChips ?? []).filter(
2139
+ (existing) => !(existing.id === chip.id && existing.trigger === chip.trigger)
2140
+ )
2141
+ );
2142
+ const fileInputNode = onAttachFiles ? /* @__PURE__ */ jsx9(
2693
2143
  "input",
2694
2144
  {
2695
2145
  ref: fileInputRef,
@@ -2705,14 +2155,14 @@ function Composer({
2705
2155
  }
2706
2156
  }
2707
2157
  ) : null;
2708
- const popoverNodes = /* @__PURE__ */ jsxs8(Fragment6, { children: [
2709
- builtinMentionEnabled && mentionState && /* @__PURE__ */ jsx11(
2158
+ const popoverNodes = /* @__PURE__ */ jsxs6(Fragment5, { children: [
2159
+ builtinMentionEnabled && mentionState && /* @__PURE__ */ jsx9(
2710
2160
  AnchoredPopover,
2711
2161
  {
2712
2162
  anchorRect: mentionState.anchorRect,
2713
2163
  onClose: () => setMentionState(null),
2714
2164
  role: "listbox",
2715
- children: /* @__PURE__ */ jsx11(
2165
+ children: /* @__PURE__ */ jsx9(
2716
2166
  ContextSourceList,
2717
2167
  {
2718
2168
  sources: mentionSources,
@@ -2724,13 +2174,13 @@ function Composer({
2724
2174
  )
2725
2175
  }
2726
2176
  ),
2727
- builtinPlusEnabled && plusAnchor && /* @__PURE__ */ jsx11(
2177
+ builtinPlusEnabled && plusAnchor && /* @__PURE__ */ jsx9(
2728
2178
  AnchoredPopover,
2729
2179
  {
2730
2180
  anchorRect: plusAnchor,
2731
2181
  onClose: () => setPlusAnchor(null),
2732
2182
  role: "listbox",
2733
- children: /* @__PURE__ */ jsx11(
2183
+ children: /* @__PURE__ */ jsx9(
2734
2184
  ContextSourceList,
2735
2185
  {
2736
2186
  sources: plusSources,
@@ -2743,122 +2193,44 @@ function Composer({
2743
2193
  }
2744
2194
  )
2745
2195
  ] });
2746
- const fallback = /* @__PURE__ */ jsxs8(
2196
+ const fallback = /* @__PURE__ */ jsxs6(
2747
2197
  "div",
2748
2198
  {
2749
- className: `pactor-chat-composer${dragOver ? " pactor-chat-composer--dragover" : ""}`,
2750
- ...dragHandlers,
2199
+ className: "pactor-chat-composer pactor-chat-composer--dsl",
2200
+ onChange: handleBubbleChange,
2751
2201
  children: [
2752
- attachments !== void 0 && /* @__PURE__ */ jsx11(
2753
- ComposerAttachments,
2754
- {
2755
- attachments,
2756
- onRemove: (id) => onAttachmentsChange?.(attachments.filter((a) => a.id !== id)),
2757
- onClick: onAttachmentClick
2758
- }
2759
- ),
2760
- contextChips !== void 0 && /* @__PURE__ */ jsx11(
2761
- ComposerContextChips,
2202
+ contextChips !== void 0 && /* @__PURE__ */ jsx9(ComposerContextChips, { chips: contextChips, onRemove: removeChip }),
2203
+ /* @__PURE__ */ jsx9(
2204
+ Composer,
2762
2205
  {
2763
- chips: contextChips,
2764
- onRemove: (chip) => onContextChipsChange?.(
2765
- contextChips.filter(
2766
- (existing) => !(existing.id === chip.id && existing.trigger === chip.trigger)
2767
- )
2768
- )
2206
+ value: text,
2207
+ placeholder,
2208
+ disabled,
2209
+ streaming,
2210
+ onStop,
2211
+ attachments: attachments?.map(toAttachmentItem),
2212
+ onRemoveAttachment: attachments !== void 0 ? (id) => onAttachmentsChange?.(
2213
+ (attachments ?? []).filter((a) => a.id !== id)
2214
+ ) : void 0,
2215
+ onAttachmentClick: onAttachmentClick ? (item) => {
2216
+ const target = attachments?.find((a) => a.id === item.id);
2217
+ if (target) {
2218
+ onAttachmentClick(target);
2219
+ }
2220
+ } : void 0,
2221
+ onAttachFiles,
2222
+ onChange: setText,
2223
+ onSubmit: () => send(),
2224
+ toolbarStart,
2225
+ toolbarEnd,
2226
+ footer: composerFooter,
2227
+ hideToolbar,
2228
+ onPlusMenu: showPlus ? handlePlusClick : void 0,
2229
+ models,
2230
+ model,
2231
+ onModelChange
2769
2232
  }
2770
2233
  ),
2771
- /* @__PURE__ */ jsxs8("div", { className: "pactor-chat-composer__row", children: [
2772
- /* @__PURE__ */ jsx11(
2773
- "textarea",
2774
- {
2775
- ref: inputRef,
2776
- className: "pactor-chat-composer__input",
2777
- rows: 1,
2778
- value: text,
2779
- placeholder,
2780
- disabled,
2781
- onChange: handleChange,
2782
- onCompositionStart: () => {
2783
- composingRef.current = true;
2784
- },
2785
- onCompositionEnd: () => {
2786
- composingRef.current = false;
2787
- },
2788
- onPaste: (event) => {
2789
- if (handlePasteFiles(event.clipboardData)) {
2790
- event.preventDefault();
2791
- }
2792
- },
2793
- onKeyDown: (event) => {
2794
- if (event.nativeEvent.isComposing || composingRef.current) {
2795
- return;
2796
- }
2797
- if (event.key === "Enter" && !event.shiftKey) {
2798
- event.preventDefault();
2799
- send();
2800
- }
2801
- }
2802
- }
2803
- ),
2804
- hideToolbar ? null : /* @__PURE__ */ jsx11(
2805
- "button",
2806
- {
2807
- type: "button",
2808
- className: `pactor-chat-composer__button${streaming ? " pactor-chat-composer__button--stop" : ""}`,
2809
- title: streaming ? "\u505C\u6B62\u751F\u6210" : "\u53D1\u9001",
2810
- "aria-label": streaming ? "\u505C\u6B62\u751F\u6210" : "\u53D1\u9001",
2811
- disabled: streaming ? false : disabled || !text.trim(),
2812
- onClick: streaming ? onStop : send,
2813
- children: streaming ? /* @__PURE__ */ jsx11(Icon7, { name: "square", size: 14, className: "pactor-chat-icon-fill" }) : /* @__PURE__ */ jsx11(Icon7, { name: "arrow-up", size: 16 })
2814
- }
2815
- )
2816
- ] }),
2817
- showToolbar && /* @__PURE__ */ jsxs8("div", { className: "pactor-chat-composer__toolbar", children: [
2818
- toolbarStart,
2819
- /* @__PURE__ */ jsx11("span", { className: "pactor-chat-composer__toolbar-spacer" }),
2820
- (onPlusMenu || builtinPlusEnabled) && /* @__PURE__ */ jsx11(
2821
- "button",
2822
- {
2823
- ref: plusButtonRef,
2824
- type: "button",
2825
- className: "pactor-chat-icon-button",
2826
- title: "\u66F4\u591A\u529F\u80FD",
2827
- "aria-label": "\u66F4\u591A\u529F\u80FD",
2828
- onClick: () => {
2829
- const rect = plusButtonRef.current.getBoundingClientRect();
2830
- if (onPlusMenu) {
2831
- onPlusMenu(rect);
2832
- } else {
2833
- setPlusAnchor(rect);
2834
- }
2835
- },
2836
- children: /* @__PURE__ */ jsx11(Icon7, { name: "plus", size: 14 })
2837
- }
2838
- ),
2839
- onAttachFiles && /* @__PURE__ */ jsx11(
2840
- "button",
2841
- {
2842
- type: "button",
2843
- className: "pactor-chat-icon-button",
2844
- title: "\u6DFB\u52A0\u9644\u4EF6",
2845
- "aria-label": "\u6DFB\u52A0\u9644\u4EF6",
2846
- onClick: () => fileInputRef.current?.click(),
2847
- children: /* @__PURE__ */ jsx11(Icon7, { name: "paperclip", size: 14 })
2848
- }
2849
- ),
2850
- modelChipEnabled && /* @__PURE__ */ jsx11(
2851
- ModelSelect,
2852
- {
2853
- models,
2854
- model,
2855
- onModelChange
2856
- }
2857
- ),
2858
- toolbarEnd
2859
- ] }),
2860
- composerFooter !== void 0 && composerFooter !== null ? /* @__PURE__ */ jsx11("div", { className: "pactor-chat-composer__footer", children: composerFooter }) : null,
2861
- fileInputNode,
2862
2234
  popoverNodes
2863
2235
  ]
2864
2236
  }
@@ -2874,29 +2246,19 @@ function Composer({
2874
2246
  composerFooter,
2875
2247
  models,
2876
2248
  model,
2877
- showPlus: onPlusMenu !== void 0 || builtinPlusEnabled,
2249
+ showPlus,
2878
2250
  showAttach: onAttachFiles !== void 0,
2879
2251
  modelChipEnabled,
2880
2252
  send,
2881
2253
  stop: onStop,
2882
- openFilePicker: () => fileInputRef.current?.click(),
2883
- plusClick: (rect) => {
2884
- if (onPlusMenu) {
2885
- onPlusMenu(rect);
2886
- } else {
2887
- setPlusAnchor(rect);
2888
- }
2889
- },
2254
+ openFilePicker: () => fileInputRef.current?.click(),
2255
+ plusClick: handlePlusClick,
2890
2256
  removeAttachment: (id) => onAttachmentsChange?.((attachments ?? []).filter((a) => a.id !== id)),
2891
2257
  attachmentClick: onAttachmentClick,
2892
- removeChip: (chip) => onContextChipsChange?.(
2893
- (contextChips ?? []).filter(
2894
- (existing) => !(existing.id === chip.id && existing.trigger === chip.trigger)
2895
- )
2896
- ),
2258
+ removeChip,
2897
2259
  modelChange: onModelChange
2898
2260
  };
2899
- return /* @__PURE__ */ jsx11(
2261
+ return /* @__PURE__ */ jsx9(
2900
2262
  ChromeSlot,
2901
2263
  {
2902
2264
  fragment: buildComposerFragment({
@@ -2907,7 +2269,7 @@ function Composer({
2907
2269
  }),
2908
2270
  components: COMPOSER_INTERNAL_COMPONENTS,
2909
2271
  fallback,
2910
- wrap: (children) => /* @__PURE__ */ jsx11(ComposerBridgeContext.Provider, { value: bridge, children: /* @__PURE__ */ jsxs8(
2272
+ wrap: (children) => /* @__PURE__ */ jsx9(ComposerBridgeContext.Provider, { value: bridge, children: /* @__PURE__ */ jsxs6(
2911
2273
  "div",
2912
2274
  {
2913
2275
  className: `pactor-chat-composer pactor-chat-composer--dsl${dragOver ? " pactor-chat-composer--dragover" : ""}`,
@@ -2989,7 +2351,7 @@ function buildEmptyStateFragment(props) {
2989
2351
  }
2990
2352
 
2991
2353
  // src/view/EmptyState.tsx
2992
- import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2354
+ import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2993
2355
  var DEFAULT_CHAT_GREETING = "\u4F60\u597D\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u4F60\uFF1F";
2994
2356
  function suggestionLabel2(suggestion) {
2995
2357
  return typeof suggestion === "string" ? suggestion : suggestion.label;
@@ -3003,19 +2365,29 @@ function EmptyStateFallback({
3003
2365
  onSuggestionClick,
3004
2366
  greeting
3005
2367
  }) {
3006
- return /* @__PURE__ */ jsxs9(Fragment7, { children: [
3007
- /* @__PURE__ */ jsx12("div", { className: "pactor-chat-empty__greeting", children: greeting }),
3008
- subtitle && /* @__PURE__ */ jsx12("div", { className: "pactor-chat-empty__subtitle", children: subtitle }),
3009
- suggestions && suggestions.length > 0 && /* @__PURE__ */ jsx12("div", { className: "pactor-chat-empty__suggestions", children: suggestions.map((suggestion) => /* @__PURE__ */ jsx12(
3010
- "button",
2368
+ return /* @__PURE__ */ jsxs7(Fragment6, { children: [
2369
+ /* @__PURE__ */ jsx10(
2370
+ Welcome,
3011
2371
  {
3012
- type: "button",
3013
- className: "pactor-chat-empty__suggestion",
3014
- onClick: () => onSuggestionClick?.(suggestionPrompt2(suggestion)),
3015
- children: suggestionLabel2(suggestion)
3016
- },
3017
- suggestionLabel2(suggestion)
3018
- )) })
2372
+ title: greeting,
2373
+ description: subtitle,
2374
+ icon: null,
2375
+ titleClassName: "pactor-chat-empty__greeting",
2376
+ descriptionClassName: "pactor-chat-empty__subtitle"
2377
+ }
2378
+ ),
2379
+ suggestions && suggestions.length > 0 && /* @__PURE__ */ jsx10(
2380
+ Suggestion,
2381
+ {
2382
+ items: suggestions.map((suggestion) => ({
2383
+ label: suggestionLabel2(suggestion),
2384
+ value: suggestionPrompt2(suggestion)
2385
+ })),
2386
+ justify: "center",
2387
+ className: "pactor-chat-empty__suggestions",
2388
+ onSelect: (value) => onSuggestionClick?.(value)
2389
+ }
2390
+ )
3019
2391
  ] });
3020
2392
  }
3021
2393
  function EmptyState({
@@ -3024,11 +2396,11 @@ function EmptyState({
3024
2396
  suggestions,
3025
2397
  onSuggestionClick
3026
2398
  }) {
3027
- return /* @__PURE__ */ jsx12("div", { className: "pactor-chat-empty", children: /* @__PURE__ */ jsx12(
2399
+ return /* @__PURE__ */ jsx10("div", { className: "pactor-chat-empty", children: /* @__PURE__ */ jsx10(
3028
2400
  ChromeSlot,
3029
2401
  {
3030
2402
  fragment: buildEmptyStateFragment({ greeting, subtitle, suggestions }),
3031
- fallback: /* @__PURE__ */ jsx12(
2403
+ fallback: /* @__PURE__ */ jsx10(
3032
2404
  EmptyStateFallback,
3033
2405
  {
3034
2406
  greeting,
@@ -3043,15 +2415,53 @@ function EmptyState({
3043
2415
 
3044
2416
  // src/view/MessageBubble.tsx
3045
2417
  import { useRef as useRef10, useState as useState13 } from "react";
3046
- import { Icon as Icon10 } from "@pactor-app/ui/components";
3047
2418
 
3048
2419
  // src/view/ActivityTrace.tsx
3049
- import { Icon as Icon8 } from "@pactor-app/ui/components";
3050
- import { MarkdownRenderer as MarkdownRenderer3 } from "@pactor-app/markdown";
3051
- import { useEffect as useEffect7, useRef as useRef8, useState as useState11 } from "react";
3052
- import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
2420
+ import { Icon as Icon4 } from "@pactor-app/ui/components";
2421
+ import { MarkdownRenderer } from "@pactor-app/markdown";
2422
+ import { useEffect as useEffect7, useRef as useRef8, useState as useState10 } from "react";
2423
+
2424
+ // src/hooks/use-throttled-value.ts
2425
+ import { useEffect as useEffect6, useRef as useRef7, useState as useState9 } from "react";
2426
+ function useThrottledValue(value, intervalMs, enabled) {
2427
+ const [shown, setShown] = useState9(value);
2428
+ const lastUpdateRef = useRef7(0);
2429
+ const timerRef = useRef7(void 0);
2430
+ useEffect6(() => {
2431
+ if (!enabled) {
2432
+ if (timerRef.current) {
2433
+ clearTimeout(timerRef.current);
2434
+ timerRef.current = void 0;
2435
+ }
2436
+ setShown(value);
2437
+ return;
2438
+ }
2439
+ const now = Date.now();
2440
+ const elapsed = now - lastUpdateRef.current;
2441
+ if (elapsed >= intervalMs) {
2442
+ lastUpdateRef.current = now;
2443
+ setShown(value);
2444
+ return;
2445
+ }
2446
+ timerRef.current = setTimeout(() => {
2447
+ lastUpdateRef.current = Date.now();
2448
+ setShown(value);
2449
+ timerRef.current = void 0;
2450
+ }, intervalMs - elapsed);
2451
+ return () => {
2452
+ if (timerRef.current) {
2453
+ clearTimeout(timerRef.current);
2454
+ timerRef.current = void 0;
2455
+ }
2456
+ };
2457
+ }, [value, intervalMs, enabled]);
2458
+ return enabled ? shown : value;
2459
+ }
2460
+
2461
+ // src/view/ActivityTrace.tsx
2462
+ import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
3053
2463
  function usePinnedCollapse(autoOpen) {
3054
- const [state, setState] = useState11("auto");
2464
+ const [state, setState] = useState10("auto");
3055
2465
  const autoCollapsedRef = useRef8(false);
3056
2466
  if (state === "auto" && !autoOpen) {
3057
2467
  autoCollapsedRef.current = true;
@@ -3081,7 +2491,7 @@ function statusText(message, mode, toolCount) {
3081
2491
  }
3082
2492
  function useElapsedSeconds(startedAt, active) {
3083
2493
  const compute = () => Math.max(0, Math.floor((Date.now() - startedAt) / 1e3));
3084
- const [elapsed, setElapsed] = useState11(compute);
2494
+ const [elapsed, setElapsed] = useState10(compute);
3085
2495
  useEffect7(() => {
3086
2496
  if (!active) {
3087
2497
  setElapsed(compute());
@@ -3096,15 +2506,15 @@ function useElapsedSeconds(startedAt, active) {
3096
2506
  }
3097
2507
  function TraceStatusIcon({ status }) {
3098
2508
  if (status === "running") {
3099
- return /* @__PURE__ */ jsx13(Icon8, { name: "loading", size: 13, className: "pactor-chat-spin" });
2509
+ return /* @__PURE__ */ jsx11(Icon4, { name: "loading", size: 13, className: "pactor-chat-spin" });
3100
2510
  }
3101
2511
  if (status === "success") {
3102
- return /* @__PURE__ */ jsx13(Icon8, { name: "check-circle", size: 13 });
2512
+ return /* @__PURE__ */ jsx11(Icon4, { name: "check-circle", size: 13 });
3103
2513
  }
3104
2514
  if (status === "failed") {
3105
- return /* @__PURE__ */ jsx13(Icon8, { name: "x-circle", size: 13 });
2515
+ return /* @__PURE__ */ jsx11(Icon4, { name: "x-circle", size: 13 });
3106
2516
  }
3107
- return /* @__PURE__ */ jsx13(Icon8, { name: "clock", size: 13 });
2517
+ return /* @__PURE__ */ jsx11(Icon4, { name: "clock", size: 13 });
3108
2518
  }
3109
2519
  function summarizeArgs(args) {
3110
2520
  if (args === void 0) {
@@ -3133,16 +2543,16 @@ function formatDetail(value) {
3133
2543
  }
3134
2544
  }
3135
2545
  function TraceRow({ entry }) {
3136
- const [open, setOpen] = useState11(false);
2546
+ const [open, setOpen] = useState10(false);
3137
2547
  const summary = summarizeArgs(entry.args);
3138
- return /* @__PURE__ */ jsxs10(
2548
+ return /* @__PURE__ */ jsxs8(
3139
2549
  "div",
3140
2550
  {
3141
2551
  className: "pactor-chat-trace__entry",
3142
2552
  "data-status": entry.status,
3143
2553
  "data-open": open,
3144
2554
  children: [
3145
- /* @__PURE__ */ jsxs10(
2555
+ /* @__PURE__ */ jsxs8(
3146
2556
  "button",
3147
2557
  {
3148
2558
  type: "button",
@@ -3150,16 +2560,16 @@ function TraceRow({ entry }) {
3150
2560
  "aria-expanded": open,
3151
2561
  onClick: () => setOpen((value) => !value),
3152
2562
  children: [
3153
- /* @__PURE__ */ jsx13("span", { className: "pactor-chat-trace__chevron", children: /* @__PURE__ */ jsx13(Icon8, { name: "chevron-right", size: 12 }) }),
3154
- /* @__PURE__ */ jsx13("span", { className: "pactor-chat-trace__entry-icon", children: /* @__PURE__ */ jsx13(TraceStatusIcon, { status: entry.status }) }),
3155
- /* @__PURE__ */ jsx13("span", { className: "pactor-chat-trace__entry-title", children: entry.title ?? entry.name }),
3156
- summary && /* @__PURE__ */ jsx13("span", { className: "pactor-chat-trace__entry-args", children: summary })
2563
+ /* @__PURE__ */ jsx11("span", { className: "pactor-chat-trace__chevron", children: /* @__PURE__ */ jsx11(Icon4, { name: "chevron-right", size: 12 }) }),
2564
+ /* @__PURE__ */ jsx11("span", { className: "pactor-chat-trace__entry-icon", children: /* @__PURE__ */ jsx11(TraceStatusIcon, { status: entry.status }) }),
2565
+ /* @__PURE__ */ jsx11("span", { className: "pactor-chat-trace__entry-title", children: entry.title ?? entry.name }),
2566
+ summary && /* @__PURE__ */ jsx11("span", { className: "pactor-chat-trace__entry-args", children: summary })
3157
2567
  ]
3158
2568
  }
3159
2569
  ),
3160
- open && /* @__PURE__ */ jsxs10("div", { className: "pactor-chat-trace__entry-body", children: [
3161
- entry.args !== void 0 && /* @__PURE__ */ jsx13("pre", { className: "pactor-chat-trace__entry-detail", children: formatDetail(entry.args) }),
3162
- /* @__PURE__ */ jsx13("pre", { className: "pactor-chat-trace__entry-detail", children: entry.status === "failed" ? entry.error ?? "\u6267\u884C\u5931\u8D25" : formatDetail(entry.result) })
2570
+ open && /* @__PURE__ */ jsxs8("div", { className: "pactor-chat-trace__entry-body", children: [
2571
+ entry.args !== void 0 && /* @__PURE__ */ jsx11("pre", { className: "pactor-chat-trace__entry-detail", children: formatDetail(entry.args) }),
2572
+ /* @__PURE__ */ jsx11("pre", { className: "pactor-chat-trace__entry-detail", children: entry.status === "failed" ? entry.error ?? "\u6267\u884C\u5931\u8D25" : formatDetail(entry.result) })
3163
2573
  ] })
3164
2574
  ]
3165
2575
  }
@@ -3172,14 +2582,14 @@ function ThinkingCard({
3172
2582
  const partStreaming = part.status === "streaming";
3173
2583
  const shown = useThrottledValue(part.content, 120, partStreaming);
3174
2584
  const { open, toggle } = usePinnedCollapse(partStreaming && !answerPhase);
3175
- return /* @__PURE__ */ jsxs10(
2585
+ return /* @__PURE__ */ jsxs8(
3176
2586
  "div",
3177
2587
  {
3178
2588
  className: "pactor-chat-thinking",
3179
2589
  "data-open": open,
3180
2590
  "data-streaming": partStreaming,
3181
2591
  children: [
3182
- /* @__PURE__ */ jsxs10(
2592
+ /* @__PURE__ */ jsxs8(
3183
2593
  "button",
3184
2594
  {
3185
2595
  type: "button",
@@ -3187,13 +2597,13 @@ function ThinkingCard({
3187
2597
  "aria-expanded": open,
3188
2598
  onClick: toggle,
3189
2599
  children: [
3190
- /* @__PURE__ */ jsx13("span", { className: "pactor-chat-trace__chevron", children: /* @__PURE__ */ jsx13(Icon8, { name: "chevron-right", size: 12 }) }),
3191
- /* @__PURE__ */ jsx13("span", { className: "pactor-chat-thinking__icon", children: partStreaming ? /* @__PURE__ */ jsx13(Icon8, { name: "loading", size: 13, className: "pactor-chat-spin" }) : /* @__PURE__ */ jsx13(Icon8, { name: "brain", size: 13 }) }),
3192
- /* @__PURE__ */ jsx13("span", { children: "\u601D\u8003\u8FC7\u7A0B" })
2600
+ /* @__PURE__ */ jsx11("span", { className: "pactor-chat-trace__chevron", children: /* @__PURE__ */ jsx11(Icon4, { name: "chevron-right", size: 12 }) }),
2601
+ /* @__PURE__ */ jsx11("span", { className: "pactor-chat-thinking__icon", children: partStreaming ? /* @__PURE__ */ jsx11(Icon4, { name: "loading", size: 13, className: "pactor-chat-spin" }) : /* @__PURE__ */ jsx11(Icon4, { name: "brain", size: 13 }) }),
2602
+ /* @__PURE__ */ jsx11("span", { children: "\u601D\u8003\u8FC7\u7A0B" })
3193
2603
  ]
3194
2604
  }
3195
2605
  ),
3196
- open && /* @__PURE__ */ jsx13("div", { className: "pactor-chat-thinking__body", children: partStreaming ? /* @__PURE__ */ jsx13("div", { className: "pactor-chat-thinking__text", children: shown }) : /* @__PURE__ */ jsx13(MarkdownRenderer3, { content: part.content }) })
2606
+ open && /* @__PURE__ */ jsx11("div", { className: "pactor-chat-thinking__body", children: partStreaming ? /* @__PURE__ */ jsx11("div", { className: "pactor-chat-thinking__text", children: shown }) : /* @__PURE__ */ jsx11(MarkdownRenderer, { content: part.content }) })
3197
2607
  ]
3198
2608
  }
3199
2609
  );
@@ -3216,23 +2626,23 @@ function ActivityTrace({ message }) {
3216
2626
  message.createdAt ?? mountTimeRef.current,
3217
2627
  streaming
3218
2628
  );
3219
- const header = /* @__PURE__ */ jsxs10(Fragment8, { children: [
3220
- /* @__PURE__ */ jsx13("span", { className: "pactor-chat-trace__status-icon", children: streaming ? /* @__PURE__ */ jsx13(Icon8, { name: "loading", size: 13, className: "pactor-chat-spin" }) : /* @__PURE__ */ jsx13(Icon8, { name: "check-circle", size: 13 }) }),
3221
- /* @__PURE__ */ jsx13(
2629
+ const header = /* @__PURE__ */ jsxs8(Fragment7, { children: [
2630
+ /* @__PURE__ */ jsx11("span", { className: "pactor-chat-trace__status-icon", children: streaming ? /* @__PURE__ */ jsx11(Icon4, { name: "loading", size: 13, className: "pactor-chat-spin" }) : /* @__PURE__ */ jsx11(Icon4, { name: "check-circle", size: 13 }) }),
2631
+ /* @__PURE__ */ jsx11(
3222
2632
  "span",
3223
2633
  {
3224
2634
  className: `pactor-chat-trace__status-text${streaming ? " pactor-chat-trace__status-text--breathing" : ""}`,
3225
2635
  children: statusText(message, mode, entries.length)
3226
2636
  }
3227
2637
  ),
3228
- /* @__PURE__ */ jsxs10("span", { className: "pactor-chat-trace__elapsed", children: [
2638
+ /* @__PURE__ */ jsxs8("span", { className: "pactor-chat-trace__elapsed", children: [
3229
2639
  elapsed,
3230
2640
  "s"
3231
2641
  ] }),
3232
- collapsible && /* @__PURE__ */ jsx13("span", { className: "pactor-chat-trace__chevron", children: /* @__PURE__ */ jsx13(Icon8, { name: "chevron-right", size: 12 }) })
2642
+ collapsible && /* @__PURE__ */ jsx11("span", { className: "pactor-chat-trace__chevron", children: /* @__PURE__ */ jsx11(Icon4, { name: "chevron-right", size: 12 }) })
3233
2643
  ] });
3234
- return /* @__PURE__ */ jsxs10("div", { className: "pactor-chat-trace", "data-open": open, children: [
3235
- collapsible ? /* @__PURE__ */ jsx13(
2644
+ return /* @__PURE__ */ jsxs8("div", { className: "pactor-chat-trace", "data-open": open, children: [
2645
+ collapsible ? /* @__PURE__ */ jsx11(
3236
2646
  "button",
3237
2647
  {
3238
2648
  type: "button",
@@ -3241,10 +2651,10 @@ function ActivityTrace({ message }) {
3241
2651
  onClick: toggle,
3242
2652
  children: header
3243
2653
  }
3244
- ) : /* @__PURE__ */ jsx13("div", { className: "pactor-chat-trace__header", children: header }),
3245
- open && /* @__PURE__ */ jsxs10(Fragment8, { children: [
3246
- entries.length > 0 && /* @__PURE__ */ jsx13("div", { className: "pactor-chat-trace__entries", children: entries.map((entry) => /* @__PURE__ */ jsx13(TraceRow, { entry }, entry.callIndex)) }),
3247
- thinkingParts.map((part, index) => /* @__PURE__ */ jsx13(
2654
+ ) : /* @__PURE__ */ jsx11("div", { className: "pactor-chat-trace__header", children: header }),
2655
+ open && /* @__PURE__ */ jsxs8(Fragment7, { children: [
2656
+ entries.length > 0 && /* @__PURE__ */ jsx11("div", { className: "pactor-chat-trace__entries", children: entries.map((entry) => /* @__PURE__ */ jsx11(TraceRow, { entry }, entry.callIndex)) }),
2657
+ thinkingParts.map((part, index) => /* @__PURE__ */ jsx11(
3248
2658
  ThinkingCard,
3249
2659
  {
3250
2660
  part,
@@ -3256,8 +2666,112 @@ function ActivityTrace({ message }) {
3256
2666
  ] });
3257
2667
  }
3258
2668
 
2669
+ // src/view/chrome/artifact-card.tsx
2670
+ import { Icon as Icon5 } from "@pactor-app/ui/components";
2671
+ import { useState as useState11 } from "react";
2672
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2673
+ function artifactCardMeta(artifact) {
2674
+ const ext = resolveArtifactFileType(artifact);
2675
+ const typeLabel = (ext ?? artifact.kind).toUpperCase();
2676
+ const sizeLabel = formatArtifactSize(artifact.meta?.["size"]);
2677
+ return [sizeLabel, typeLabel].filter(Boolean).join(" \xB7 ");
2678
+ }
2679
+ function ChatArtifactCard({
2680
+ artifact
2681
+ }) {
2682
+ const icon = resolveArtifactIcon(artifact);
2683
+ const meta = artifactCardMeta(artifact);
2684
+ return /* @__PURE__ */ jsxs9(
2685
+ "button",
2686
+ {
2687
+ type: "button",
2688
+ className: `pactor-chat-artifact-card pactor-chat-artifact-card--${icon.tone}`,
2689
+ "data-artifact-kind": artifact.kind,
2690
+ "aria-label": `\u5728\u9762\u677F\u4E2D\u6253\u5F00\uFF1A${artifact.title}`,
2691
+ title: `\u5728\u9762\u677F\u4E2D\u6253\u5F00\uFF1A${artifact.title}`,
2692
+ onClick: () => invokeChatOpenArtifact(artifact),
2693
+ children: [
2694
+ /* @__PURE__ */ jsx12("span", { className: "pactor-chat-artifact-card__icon", children: /* @__PURE__ */ jsx12(Icon5, { name: icon.name, size: 20 }) }),
2695
+ /* @__PURE__ */ jsxs9("span", { className: "pactor-chat-artifact-card__text", children: [
2696
+ /* @__PURE__ */ jsx12("span", { className: "pactor-chat-artifact-card__title", children: artifact.title }),
2697
+ meta ? /* @__PURE__ */ jsx12("span", { className: "pactor-chat-artifact-card__meta", children: meta }) : null
2698
+ ] }),
2699
+ /* @__PURE__ */ jsx12("span", { className: "pactor-chat-artifact-card__arrow", children: /* @__PURE__ */ jsx12(Icon5, { name: "arrow-up-right", size: 14 }) })
2700
+ ]
2701
+ }
2702
+ );
2703
+ }
2704
+ var ARTIFACT_CARD_INTERNAL_COMPONENTS = {
2705
+ ChatArtifactCard,
2706
+ ChatArtifactCardGroup
2707
+ };
2708
+ var ARTIFACT_CARD_GROUP_LIMIT = 4;
2709
+ function ChatArtifactCardGroup({
2710
+ artifacts
2711
+ }) {
2712
+ const [expanded, setExpanded] = useState11(false);
2713
+ const overflow = artifacts.length > ARTIFACT_CARD_GROUP_LIMIT;
2714
+ const visible = overflow && !expanded ? artifacts.slice(0, ARTIFACT_CARD_GROUP_LIMIT) : artifacts;
2715
+ return /* @__PURE__ */ jsxs9("div", { className: "pactor-chat-artifact-group", children: [
2716
+ visible.map((artifact) => /* @__PURE__ */ jsx12(ChatArtifactCard, { artifact }, artifact.id)),
2717
+ overflow ? /* @__PURE__ */ jsxs9("div", { className: "pactor-chat-artifact-group__footer", children: [
2718
+ /* @__PURE__ */ jsxs9(
2719
+ "button",
2720
+ {
2721
+ type: "button",
2722
+ className: "pactor-chat-artifact-group__toggle",
2723
+ "aria-expanded": expanded,
2724
+ onClick: () => setExpanded((value) => !value),
2725
+ children: [
2726
+ /* @__PURE__ */ jsx12(
2727
+ Icon5,
2728
+ {
2729
+ name: expanded ? "chevron-up" : "chevron-down",
2730
+ size: 12
2731
+ }
2732
+ ),
2733
+ expanded ? "\u6536\u8D77" : "\u5C55\u5F00"
2734
+ ]
2735
+ }
2736
+ ),
2737
+ /* @__PURE__ */ jsxs9(
2738
+ "button",
2739
+ {
2740
+ type: "button",
2741
+ className: "pactor-chat-artifact-group__all",
2742
+ onClick: () => invokeChatOpenArtifactList(),
2743
+ children: [
2744
+ "\u67E5\u770B\u6240\u6709\u4EA7\u7269(",
2745
+ artifacts.length,
2746
+ ")",
2747
+ /* @__PURE__ */ jsx12(Icon5, { name: "chevron-right", size: 12 })
2748
+ ]
2749
+ }
2750
+ )
2751
+ ] }) : null
2752
+ ] });
2753
+ }
2754
+ function buildArtifactCardFragment(artifact) {
2755
+ return {
2756
+ requires: ["ChatArtifactCard"],
2757
+ node: {
2758
+ type: "ChatArtifactCard",
2759
+ props: { artifact }
2760
+ }
2761
+ };
2762
+ }
2763
+ function buildArtifactCardGroupFragment(artifacts) {
2764
+ return {
2765
+ requires: ["ChatArtifactCardGroup"],
2766
+ node: {
2767
+ type: "ChatArtifactCardGroup",
2768
+ props: { artifacts }
2769
+ }
2770
+ };
2771
+ }
2772
+
3259
2773
  // src/view/MessageActions.tsx
3260
- import { Icon as Icon9 } from "@pactor-app/ui/components";
2774
+ import { Icon as Icon6 } from "@pactor-app/ui/components";
3261
2775
  import { useEffect as useEffect8, useRef as useRef9, useState as useState12 } from "react";
3262
2776
 
3263
2777
  // src/view/chrome/message-actions.tsx
@@ -3311,7 +2825,7 @@ function buildMessageActionsFragment(args) {
3311
2825
  }
3312
2826
 
3313
2827
  // src/view/MessageActions.tsx
3314
- import { jsx as jsx14 } from "react/jsx-runtime";
2828
+ import { jsx as jsx13 } from "react/jsx-runtime";
3315
2829
  var BUILTIN_ACTION_DEFAULTS = {
3316
2830
  copy: {
3317
2831
  label: "\u590D\u5236",
@@ -3464,7 +2978,7 @@ function MessageActions({
3464
2978
  const copiedFeedback = action.builtin === "copy" && copied;
3465
2979
  const label = copiedFeedback ? "\u5DF2\u590D\u5236" : action.label;
3466
2980
  const iconName = copiedFeedback ? "check" : action.icon;
3467
- return /* @__PURE__ */ jsx14(
2981
+ return /* @__PURE__ */ jsx13(
3468
2982
  "button",
3469
2983
  {
3470
2984
  type: "button",
@@ -3473,16 +2987,16 @@ function MessageActions({
3473
2987
  "aria-label": label,
3474
2988
  "data-message-action": action.id,
3475
2989
  onClick: () => dispatch(action),
3476
- children: iconName !== void 0 ? /* @__PURE__ */ jsx14(Icon9, { name: iconName, size: 14 }) : /* @__PURE__ */ jsx14(Icon9, { name: "help-circle", size: 14 })
2990
+ children: iconName !== void 0 ? /* @__PURE__ */ jsx13(Icon6, { name: iconName, size: 14 }) : /* @__PURE__ */ jsx13(Icon6, { name: "help-circle", size: 14 })
3477
2991
  },
3478
2992
  action.id
3479
2993
  );
3480
2994
  });
3481
- return /* @__PURE__ */ jsx14(
2995
+ return /* @__PURE__ */ jsx13(
3482
2996
  "div",
3483
2997
  {
3484
2998
  className: `pactor-chat-message__actions${forceVisible ? " pactor-chat-message__actions--visible" : ""}`,
3485
- children: /* @__PURE__ */ jsx14(
2999
+ children: /* @__PURE__ */ jsx13(
3486
3000
  ChromeSlot,
3487
3001
  {
3488
3002
  fragment: buildMessageActionsFragment({
@@ -3497,6 +3011,114 @@ function MessageActions({
3497
3011
  );
3498
3012
  }
3499
3013
 
3014
+ // src/view/PartRenderer.tsx
3015
+ import { Icon as Icon7 } from "@pactor-app/ui/components";
3016
+ import { MarkdownRenderer as MarkdownRenderer2 } from "@pactor-app/markdown";
3017
+ import { DslRenderer, useRenderer as useRenderer2 } from "@pactor-app/runtime";
3018
+
3019
+ // src/view/chrome/feedback.tsx
3020
+ function buildErrorFragment(message) {
3021
+ return {
3022
+ requires: ["Alert"],
3023
+ node: {
3024
+ type: "Alert",
3025
+ props: { variant: "error", message }
3026
+ }
3027
+ };
3028
+ }
3029
+ function buildStatusFragment(text) {
3030
+ return {
3031
+ requires: ["Text"],
3032
+ node: {
3033
+ type: "Text",
3034
+ props: { type: "secondary", text }
3035
+ }
3036
+ };
3037
+ }
3038
+
3039
+ // src/view/PartRenderer.tsx
3040
+ import { Fragment as Fragment8, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
3041
+ function ChatDenied({ deniedType }) {
3042
+ return /* @__PURE__ */ jsxs10("div", { className: "pactor-chat-denied", "data-pactor-chat-denied": deniedType, children: [
3043
+ "\u8BE5\u7EC4\u4EF6\u4E0D\u5141\u8BB8\u5728 Chat \u4E2D\u4F7F\u7528",
3044
+ deniedType ? `\uFF1A${deniedType}` : ""
3045
+ ] });
3046
+ }
3047
+ function ChatDslNode({
3048
+ node,
3049
+ scope
3050
+ }) {
3051
+ const renderer = useRenderer2();
3052
+ const extraScope = scope ? buildChatScope(scope) : void 0;
3053
+ return /* @__PURE__ */ jsx14(Fragment8, { children: renderer.renderChildren([node], extraScope) });
3054
+ }
3055
+ function SmoothText({ content, streaming }) {
3056
+ const shown = useSmoothStreamText(content, streaming);
3057
+ return /* @__PURE__ */ jsx14("div", { className: "pactor-chat-text", children: shown });
3058
+ }
3059
+ function SmoothMarkdown({ content, streaming }) {
3060
+ const shown = useSmoothStreamText(content, streaming);
3061
+ const throttled = useThrottledValue(shown, 100, streaming);
3062
+ return /* @__PURE__ */ jsx14(MarkdownRenderer2, { content: throttled });
3063
+ }
3064
+ function PartRenderer({ part, runtime, scope, streaming = false }) {
3065
+ switch (part.type) {
3066
+ case "text":
3067
+ return /* @__PURE__ */ jsx14(SmoothText, { content: part.content, streaming });
3068
+ case "markdown":
3069
+ return /* @__PURE__ */ jsx14(SmoothMarkdown, { content: part.content, streaming });
3070
+ case "thinking":
3071
+ case "tool-call":
3072
+ case "tool-result":
3073
+ return null;
3074
+ case "dsl": {
3075
+ if (!part.schema || !runtime) {
3076
+ return /* @__PURE__ */ jsx14(
3077
+ ChromeSlot,
3078
+ {
3079
+ fragment: buildStatusFragment(
3080
+ part.schema ? "DSL \u6E32\u67D3\u4E0D\u53EF\u7528\uFF08\u672A\u6CE8\u5165 Safe Registry\uFF09" : "\u5185\u5BB9\u751F\u6210\u4E2D\u2026"
3081
+ ),
3082
+ fallback: /* @__PURE__ */ jsx14("div", { className: "pactor-chat-dsl-pending", children: part.schema ? "DSL \u6E32\u67D3\u4E0D\u53EF\u7528\uFF08\u672A\u6CE8\u5165 Safe Registry\uFF09" : "\u5185\u5BB9\u751F\u6210\u4E2D\u2026" })
3083
+ }
3084
+ );
3085
+ }
3086
+ const guarded = guardChatDsl(part.schema, runtime.context.components);
3087
+ return /* @__PURE__ */ jsx14("div", { className: "pactor-chat-dsl", children: /* @__PURE__ */ jsx14(DslRenderer, { context: runtime.context, engine: runtime.engine, children: /* @__PURE__ */ jsx14(ChatDslNode, { node: guarded, scope }) }) });
3088
+ }
3089
+ case "error":
3090
+ return /* @__PURE__ */ jsx14(
3091
+ ChromeSlot,
3092
+ {
3093
+ fragment: buildErrorFragment(part.message),
3094
+ fallback: /* @__PURE__ */ jsxs10("div", { className: "pactor-chat-error", role: "alert", children: [
3095
+ /* @__PURE__ */ jsx14(Icon7, { name: "error", size: 14 }),
3096
+ /* @__PURE__ */ jsx14("span", { children: part.message })
3097
+ ] })
3098
+ }
3099
+ );
3100
+ case "status":
3101
+ return /* @__PURE__ */ jsx14(
3102
+ ChromeSlot,
3103
+ {
3104
+ fragment: buildStatusFragment(part.text),
3105
+ fallback: /* @__PURE__ */ jsx14("div", { className: "pactor-chat-status", children: part.text })
3106
+ }
3107
+ );
3108
+ case "artifact":
3109
+ return /* @__PURE__ */ jsx14(
3110
+ ChromeSlot,
3111
+ {
3112
+ fragment: buildArtifactCardFragment(part.artifact),
3113
+ components: ARTIFACT_CARD_INTERNAL_COMPONENTS,
3114
+ fallback: /* @__PURE__ */ jsx14(ChatArtifactCard, { artifact: part.artifact })
3115
+ }
3116
+ );
3117
+ default:
3118
+ return null;
3119
+ }
3120
+ }
3121
+
3500
3122
  // src/view/MessageBubble.tsx
3501
3123
  import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
3502
3124
  function groupArtifactParts(parts) {
@@ -3584,18 +3206,15 @@ function isAgentIconUrl(icon) {
3584
3206
  return /^(https?:|data:|\/)/.test(icon);
3585
3207
  }
3586
3208
  function AgentHeader({ agent }) {
3587
- return /* @__PURE__ */ jsxs11("div", { className: "pactor-chat-message__agent", children: [
3588
- agent.icon !== void 0 && (isAgentIconUrl(agent.icon) ? /* @__PURE__ */ jsx15(
3589
- "img",
3590
- {
3591
- className: "pactor-chat-message__agent-icon",
3592
- src: agent.icon,
3593
- alt: "",
3594
- "aria-hidden": true
3595
- }
3596
- ) : /* @__PURE__ */ jsx15("span", { className: "pactor-chat-message__agent-icon", "aria-hidden": true, children: /* @__PURE__ */ jsx15(Icon10, { name: agent.icon }) })),
3597
- /* @__PURE__ */ jsx15("span", { className: "pactor-chat-message__agent-name", children: agent.name })
3598
- ] });
3209
+ return /* @__PURE__ */ jsx15(
3210
+ Sender,
3211
+ {
3212
+ name: agent.name,
3213
+ avatar: agent.icon !== void 0 && isAgentIconUrl(agent.icon) ? agent.icon : void 0,
3214
+ icon: agent.icon !== void 0 && !isAgentIconUrl(agent.icon) ? agent.icon : void 0,
3215
+ hideAvatar: agent.icon === void 0
3216
+ }
3217
+ );
3599
3218
  }
3600
3219
  function MessageBubble({
3601
3220
  message,
@@ -3627,6 +3246,30 @@ function MessageBubble({
3627
3246
  ));
3628
3247
  const showTime = message.role === "assistant" && !live && message.createdAt !== void 0;
3629
3248
  const agentIdentity = message.role === "assistant" ? message.agent ?? agent : void 0;
3249
+ const bodyContent = /* @__PURE__ */ jsxs11("div", { className: "pactor-chat-message__body", children: [
3250
+ agentIdentity && /* @__PURE__ */ jsx15(AgentHeader, { agent: agentIdentity }),
3251
+ showTrace && /* @__PURE__ */ jsx15(ActivityTrace, { message }),
3252
+ message.parts.length === 0 && message.status === "pending" && message.role !== "assistant" ? /* @__PURE__ */ jsx15("span", { className: "pactor-chat-message__pending", children: "\u2026" }) : groupArtifactParts(message.parts).map(
3253
+ (segment, index) => Array.isArray(segment) ? /* @__PURE__ */ jsx15(
3254
+ ChromeSlot,
3255
+ {
3256
+ fragment: buildArtifactCardGroupFragment(segment),
3257
+ components: ARTIFACT_CARD_INTERNAL_COMPONENTS,
3258
+ fallback: /* @__PURE__ */ jsx15(ChatArtifactCardGroup, { artifacts: segment })
3259
+ },
3260
+ `artifacts:${segment[0].id}`
3261
+ ) : /* @__PURE__ */ jsx15(
3262
+ PartRenderer,
3263
+ {
3264
+ part: segment,
3265
+ runtime,
3266
+ scope: bubbleScope,
3267
+ streaming
3268
+ },
3269
+ segment.id ?? index
3270
+ )
3271
+ )
3272
+ ] });
3630
3273
  return /* @__PURE__ */ jsxs11(
3631
3274
  "div",
3632
3275
  {
@@ -3644,30 +3287,8 @@ function MessageBubble({
3644
3287
  },
3645
3288
  onCancel: () => setEditing(false)
3646
3289
  }
3647
- ) : /* @__PURE__ */ jsxs11("div", { className: "pactor-chat-message__body", children: [
3648
- agentIdentity && /* @__PURE__ */ jsx15(AgentHeader, { agent: agentIdentity }),
3649
- showTrace && /* @__PURE__ */ jsx15(ActivityTrace, { message }),
3650
- message.parts.length === 0 && message.status === "pending" && message.role !== "assistant" ? /* @__PURE__ */ jsx15("span", { className: "pactor-chat-message__pending", children: "\u2026" }) : groupArtifactParts(message.parts).map(
3651
- (segment, index) => Array.isArray(segment) ? /* @__PURE__ */ jsx15(
3652
- ChromeSlot,
3653
- {
3654
- fragment: buildArtifactCardGroupFragment(segment),
3655
- components: ARTIFACT_CARD_INTERNAL_COMPONENTS,
3656
- fallback: /* @__PURE__ */ jsx15(ChatArtifactCardGroup, { artifacts: segment })
3657
- },
3658
- `artifacts:${segment[0].id}`
3659
- ) : /* @__PURE__ */ jsx15(
3660
- PartRenderer,
3661
- {
3662
- part: segment,
3663
- runtime,
3664
- scope: bubbleScope,
3665
- streaming
3666
- },
3667
- segment.id ?? index
3668
- )
3669
- )
3670
- ] }),
3290
+ ) : message.role === "user" ? /* @__PURE__ */ jsx15(Bubble, { align: "end", variant: "tinted", children: bodyContent }) : bodyContent,
3291
+ " ",
3671
3292
  !editing && (showTime ? /* @__PURE__ */ jsxs11("div", { className: "pactor-chat-message__footer", children: [
3672
3293
  /* @__PURE__ */ jsx15(
3673
3294
  MessageActions,
@@ -3769,11 +3390,11 @@ function ChatView({
3769
3390
  const isStreaming = messages.some(
3770
3391
  (message) => message.status === "pending" || message.status === "streaming"
3771
3392
  );
3772
- const runtime = useMemo3(() => {
3393
+ const runtime = useMemo2(() => {
3773
3394
  if (!safeRegistry) {
3774
3395
  return void 0;
3775
3396
  }
3776
- const components = new Registry3("ChatComponentRegistry");
3397
+ const components = new Registry2("ChatComponentRegistry");
3777
3398
  components.register(CHAT_DENIED_TYPE, ChatDenied);
3778
3399
  for (const name of safeRegistry.list()) {
3779
3400
  components.register(name, safeRegistry.get(name));
@@ -3786,7 +3407,7 @@ function ChatView({
3786
3407
  user
3787
3408
  });
3788
3409
  }, [safeRegistry, capabilities, permission, confirm, user]);
3789
- const scope = useMemo3(
3410
+ const scope = useMemo2(
3790
3411
  () => ({ conversation: { id: conversationId }, params }),
3791
3412
  [conversationId, params]
3792
3413
  );
@@ -3884,7 +3505,7 @@ function ChatView({
3884
3505
  const regenerableMessageId = lastMessage?.role === "assistant" && lastMessage.status === "completed" ? lastMessage.id : void 0;
3885
3506
  const isEmpty = messages.length === 0;
3886
3507
  const composerNode = /* @__PURE__ */ jsx16(
3887
- Composer,
3508
+ Composer2,
3888
3509
  {
3889
3510
  onSend: handleSend,
3890
3511
  streaming: isStreaming,
@@ -3953,7 +3574,7 @@ function ChatView({
3953
3574
  className: "pactor-chat-scroll-bottom",
3954
3575
  onClick: scrollToBottom,
3955
3576
  children: [
3956
- /* @__PURE__ */ jsx16(Icon11, { name: "arrow-down", size: 13 }),
3577
+ /* @__PURE__ */ jsx16(Icon8, { name: "arrow-down", size: 13 }),
3957
3578
  "\u56DE\u5230\u5E95\u90E8"
3958
3579
  ]
3959
3580
  }
@@ -3966,7 +3587,7 @@ function ChatView({
3966
3587
  }
3967
3588
 
3968
3589
  // src/view/WorkspaceHeader.tsx
3969
- import { Icon as Icon12 } from "@pactor-app/ui/components";
3590
+ import { Icon as Icon9 } from "@pactor-app/ui/components";
3970
3591
  import { useEffect as useEffect10, useRef as useRef12, useState as useState15 } from "react";
3971
3592
 
3972
3593
  // src/export-markdown.ts
@@ -4127,7 +3748,7 @@ function WorkspaceHeader({
4127
3748
  title: "\u5BFC\u51FA Markdown",
4128
3749
  "aria-label": "\u5BFC\u51FA Markdown",
4129
3750
  onClick: handleExport,
4130
- children: /* @__PURE__ */ jsx17(Icon12, { name: "download", size: 15 })
3751
+ children: /* @__PURE__ */ jsx17(Icon9, { name: "download", size: 15 })
4131
3752
  },
4132
3753
  "export"
4133
3754
  ),
@@ -4139,7 +3760,7 @@ function WorkspaceHeader({
4139
3760
  title: theme === "dark" ? "\u5207\u6362\u4E3A\u6D45\u8272" : "\u5207\u6362\u4E3A\u6DF1\u8272",
4140
3761
  "aria-label": "\u5207\u6362\u660E\u6697\u4E3B\u9898",
4141
3762
  onClick: handleTheme,
4142
- children: theme === "dark" ? /* @__PURE__ */ jsx17(Icon12, { name: "sun", size: 15 }) : /* @__PURE__ */ jsx17(Icon12, { name: "moon", size: 15 })
3763
+ children: theme === "dark" ? /* @__PURE__ */ jsx17(Icon9, { name: "sun", size: 15 }) : /* @__PURE__ */ jsx17(Icon9, { name: "moon", size: 15 })
4143
3764
  },
4144
3765
  "theme"
4145
3766
  ),
@@ -4151,7 +3772,7 @@ function WorkspaceHeader({
4151
3772
  title: "\u6E05\u7A7A\u4F1A\u8BDD",
4152
3773
  "aria-label": "\u6E05\u7A7A\u4F1A\u8BDD",
4153
3774
  onClick: handleClear,
4154
- children: /* @__PURE__ */ jsx17(Icon12, { name: "trash", size: 15 })
3775
+ children: /* @__PURE__ */ jsx17(Icon9, { name: "trash", size: 15 })
4155
3776
  },
4156
3777
  "clear"
4157
3778
  )
@@ -4213,10 +3834,10 @@ function WorkspaceHeader({
4213
3834
  // src/chat-composition.tsx
4214
3835
  import { Fragment as Fragment9, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
4215
3836
  function DslNodeSlotInner({ node }) {
4216
- const { renderChildren } = useRenderer4();
3837
+ const { renderChildren } = useRenderer3();
4217
3838
  return renderChildren([node]);
4218
3839
  }
4219
- var DslSlotGuard = class extends Component3 {
3840
+ var DslSlotGuard = class extends Component2 {
4220
3841
  constructor() {
4221
3842
  super(...arguments);
4222
3843
  this.state = { failed: false };
@@ -4315,8 +3936,8 @@ function ChatComposition({
4315
3936
  (listener) => store.subscribe(listener),
4316
3937
  () => store.getMessages()
4317
3938
  );
4318
- const streamArtifacts = useMemo4(() => collectArtifacts(messages), [messages]);
4319
- const mergedArtifacts = useMemo4(
3939
+ const streamArtifacts = useMemo3(() => collectArtifacts(messages), [messages]);
3940
+ const mergedArtifacts = useMemo3(
4320
3941
  () => mergeArtifacts(streamArtifacts, storeArtifacts),
4321
3942
  [streamArtifacts, storeArtifacts]
4322
3943
  );
@@ -4484,7 +4105,7 @@ function ChatComposition({
4484
4105
  }
4485
4106
  ),
4486
4107
  /* @__PURE__ */ jsx18(
4487
- ArtifactPanel,
4108
+ ArtifactPanel2,
4488
4109
  {
4489
4110
  artifact: effectiveArtifact,
4490
4111
  artifacts: effectiveArtifacts,
@@ -4604,7 +4225,7 @@ function createChatWorkspace(services) {
4604
4225
  }
4605
4226
 
4606
4227
  // src/view/Chat.tsx
4607
- import { createComponentRegistry, Icon as Icon13, RailTooltip } from "@pactor-app/ui/components";
4228
+ import { createComponentRegistry, Icon as Icon10, RailTooltip } from "@pactor-app/ui/components";
4608
4229
  import { Fragment as Fragment10, useEffect as useEffect11, useRef as useRef14 } from "react";
4609
4230
 
4610
4231
  // src/view/chrome/menu.tsx
@@ -4733,7 +4354,7 @@ function ChatSidebarMenu({
4733
4354
  drawer?.close();
4734
4355
  },
4735
4356
  children: [
4736
- item.icon !== void 0 ? /* @__PURE__ */ jsx22("span", { className: "pactor-chat-menu__icon", children: /* @__PURE__ */ jsx22(Icon13, { name: item.icon, size: 15, strokeWidth: 1.7 }) }) : null,
4357
+ item.icon !== void 0 ? /* @__PURE__ */ jsx22("span", { className: "pactor-chat-menu__icon", children: /* @__PURE__ */ jsx22(Icon10, { name: item.icon, size: 15, strokeWidth: 1.7 }) }) : null,
4737
4358
  /* @__PURE__ */ jsx22("span", { className: "pactor-chat-menu__label", children: item.label }),
4738
4359
  item.dot === true ? /* @__PURE__ */ jsx22("span", { className: "pactor-chat-menu__dot", "aria-hidden": true }) : null,
4739
4360
  item.badge !== void 0 ? /* @__PURE__ */ jsx22("span", { className: "pactor-chat-menu__badge", children: item.badge }) : null
@@ -4913,6 +4534,7 @@ function registerChatComponent(registry) {
4913
4534
  }
4914
4535
  function createChatComponentRegistry() {
4915
4536
  const registry = createComponentRegistry();
4537
+ registerChatComponents(registry);
4916
4538
  registerChatComponent(registry);
4917
4539
  return registry;
4918
4540
  }
@@ -4935,7 +4557,7 @@ export {
4935
4557
  ARTIFACT_IMAGE_EXTENSIONS,
4936
4558
  ActivityTrace,
4937
4559
  AppShell,
4938
- ArtifactPanel,
4560
+ ArtifactPanel2 as ArtifactPanel,
4939
4561
  ArtifactStore,
4940
4562
  CHAT_COMPONENT_TYPE,
4941
4563
  CHAT_DENIED_TYPE,
@@ -4949,7 +4571,7 @@ export {
4949
4571
  ChatShell,
4950
4572
  ChatSidebarMenu,
4951
4573
  ChatView,
4952
- Composer,
4574
+ Composer2 as Composer,
4953
4575
  ConversationStore,
4954
4576
  DEFAULT_CHAT_GREETING,
4955
4577
  EmptyState,