@aparte/core 0.16.7 → 0.16.9
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/client/aparte-client.d.ts +57 -2
- package/dist/client/aparte-client.d.ts.map +1 -1
- package/dist/client/lifecycle-events.d.ts +8 -1
- package/dist/client/lifecycle-events.d.ts.map +1 -1
- package/dist/client/stream-adapter.d.ts +8 -0
- package/dist/client/stream-adapter.d.ts.map +1 -1
- package/dist/components/bubble/aparte-chat-bubble.d.ts +39 -18
- package/dist/components/bubble/aparte-chat-bubble.d.ts.map +1 -1
- package/dist/components/chat/aparte-chat.d.ts +32 -25
- package/dist/components/chat/aparte-chat.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-action.d.ts +1 -1
- package/dist/components/composer/aparte-composer-add-attachment.d.ts +1 -1
- package/dist/components/composer/aparte-composer-attachments.d.ts +1 -1
- package/dist/components/composer/aparte-composer-attachments.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-cancel.d.ts +2 -2
- package/dist/components/composer/aparte-composer-cancel.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-input.d.ts +6 -6
- package/dist/components/composer/aparte-composer-send.d.ts +3 -3
- package/dist/components/composer/aparte-composer-send.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer.d.ts +9 -2
- package/dist/components/composer/aparte-composer.d.ts.map +1 -1
- package/dist/components/context/aparte-context.d.ts +0 -1
- package/dist/components/context/aparte-context.d.ts.map +1 -1
- package/dist/components/conversation-list/aparte-conversation-list.d.ts +11 -6
- package/dist/components/conversation-list/aparte-conversation-list.d.ts.map +1 -1
- package/dist/components/elicitation/aparte-elicitation.d.ts +20 -18
- package/dist/components/elicitation/aparte-elicitation.d.ts.map +1 -1
- package/dist/components/scroll-rail/aparte-scroll-rail.d.ts +11 -3
- package/dist/components/scroll-rail/aparte-scroll-rail.d.ts.map +1 -1
- package/dist/components/sidebar/aparte-sidebar.d.ts +16 -2
- package/dist/components/sidebar/aparte-sidebar.d.ts.map +1 -1
- package/dist/components/split/aparte-split.d.ts +9 -4
- package/dist/components/split/aparte-split.d.ts.map +1 -1
- package/dist/components/status/aparte-chat-status.d.ts +44 -5
- package/dist/components/status/aparte-chat-status.d.ts.map +1 -1
- package/dist/components/viewport/aparte-chat-viewport.d.ts +27 -4
- package/dist/components/viewport/aparte-chat-viewport.d.ts.map +1 -1
- package/dist/config/icon-provider.d.ts +6 -0
- package/dist/config/icon-provider.d.ts.map +1 -1
- package/dist/config/locale.d.ts +3 -1
- package/dist/config/locale.d.ts.map +1 -1
- package/dist/custom-elements.json +13010 -12737
- package/dist/{dialog-triggers-Dw_DIlQ7.js → dialog-triggers-CApC7K1I.js} +119 -44
- package/dist/dialog-triggers-CApC7K1I.js.map +1 -0
- package/dist/elicitation/panel.d.ts.map +1 -1
- package/dist/generated/element-attributes.d.ts +13 -3
- package/dist/generated/element-attributes.d.ts.map +1 -1
- package/dist/{glyphs-DQTeOj4w.js → glyphs-C8z2oJUg.js} +36 -27
- package/dist/{glyphs-DQTeOj4w.js.map → glyphs-C8z2oJUg.js.map} +1 -1
- package/dist/icons/extended.d.ts +0 -6
- package/dist/icons/extended.d.ts.map +1 -1
- package/dist/icons/glyphs.d.ts +13 -4
- package/dist/icons/glyphs.d.ts.map +1 -1
- package/dist/icons.js +28 -31
- package/dist/icons.js.map +1 -1
- package/dist/index.css +946 -386
- package/dist/index.js +321 -89
- package/dist/index.js.map +1 -1
- package/dist/index.node.js +1 -1
- package/dist/interop/element-props.d.ts.map +1 -1
- package/dist/primitives/icon/aparte-icon.d.ts +1 -1
- package/dist/primitives/progress-spinner/aparte-progress-spinner.d.ts +2 -3
- package/dist/primitives/progress-spinner/aparte-progress-spinner.d.ts.map +1 -1
- package/dist/primitives/select/aparte-optgroup.d.ts +1 -1
- package/dist/primitives/select/aparte-optgroup.d.ts.map +1 -1
- package/dist/primitives/select/aparte-option.d.ts +4 -4
- package/dist/primitives/select/aparte-option.d.ts.map +1 -1
- package/dist/primitives/select/aparte-select.d.ts +43 -12
- package/dist/primitives/select/aparte-select.d.ts.map +1 -1
- package/dist/renderers/segments/code.d.ts.map +1 -1
- package/dist/renderers/segments/error.d.ts.map +1 -1
- package/dist/renderers/segments/thinking.d.ts.map +1 -1
- package/dist/renderers/segments/tool-call.d.ts.map +1 -1
- package/dist/types/events.d.ts +4 -2
- package/dist/types/events.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/dialog-triggers-Dw_DIlQ7.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as APARTE_ICON_GLYPHS } from "./glyphs-
|
|
1
|
+
import { A as APARTE_ICON_GLYPHS } from "./glyphs-C8z2oJUg.js";
|
|
2
2
|
import { runStreamAgent } from "@aparte/engine";
|
|
3
3
|
function contentToText(content) {
|
|
4
4
|
if (typeof content === "string") return content;
|
|
@@ -97,7 +97,7 @@ const APARTE_DEFAULT_LOCALE = {
|
|
|
97
97
|
elicitationAnswerLabel: "Your answer",
|
|
98
98
|
approvalInstructionPlaceholder: "Or tell it what to do instead…",
|
|
99
99
|
approvalAsk: "Run {tool}?",
|
|
100
|
-
approvalWaiting: "
|
|
100
|
+
approvalWaiting: "Waiting",
|
|
101
101
|
scrollToBottom: "Scroll to bottom",
|
|
102
102
|
suggestionsLabel: "Suggested prompts",
|
|
103
103
|
contextLabel: "Context window",
|
|
@@ -115,6 +115,7 @@ const APARTE_DEFAULT_LOCALE = {
|
|
|
115
115
|
removeAttachment: "Remove {name}",
|
|
116
116
|
selectSearchPlaceholder: "Search…",
|
|
117
117
|
selectSearchLabel: "Search options",
|
|
118
|
+
loading: "Loading…",
|
|
118
119
|
download: "Download",
|
|
119
120
|
previewPending: "Press Preview to run this artifact.",
|
|
120
121
|
sandboxError: "The sandbox failed during generation.",
|
|
@@ -2484,14 +2485,16 @@ const thinkingRenderer = {
|
|
|
2484
2485
|
* only part that is genuinely about reasoning rather than about disclosure.
|
|
2485
2486
|
* `.aparte-thinking-label` stays too: `relabel` below queries it.
|
|
2486
2487
|
*/
|
|
2487
|
-
render: (segment) => `<details class="aparte-segment aparte-segment-thinking aparte-accordion__item" data-segment-id="${escapeHtml(segment.id)}" ${segment.collapsed === false ? "open" : ""}><summary class="aparte-accordion__header aparte-thinking-header"><span class="aparte-thinking-label">${escapeHtml(segment.label || contextConfig().t("thinking"))}</span>${contextConfig().getIcon("expand")}</summary><div class="aparte-accordion__panel aparte-thinking-content">${contextConfig().renderMarkdown(segment.content)}</div></details>`,
|
|
2488
|
+
render: (segment) => `<details class="aparte-segment aparte-segment-thinking aparte-accordion__item" data-segment-id="${escapeHtml(segment.id)}" ${segment.collapsed === false ? "open" : ""}><summary class="aparte-accordion__header aparte-thinking-header"><span class="aparte-thinking-label">${escapeHtml(segment.label || contextConfig().t("thinking"))}</span><span class="aparte-accordion__icon">${contextConfig().getIcon("expand")}</span></summary><div class="aparte-accordion__panel aparte-thinking-content" role="region" tabindex="0" aria-label="${escapeAttr(segment.label || contextConfig().t("thinking"))}">${contextConfig().renderMarkdown(segment.content)}</div></details>`,
|
|
2488
2489
|
/**
|
|
2489
2490
|
* The default label is the only config-derived text here — and `segment.label`
|
|
2490
2491
|
* still wins, exactly as in `render`, because that string is the app's.
|
|
2491
2492
|
*/
|
|
2492
2493
|
relabel: (el2, segment) => {
|
|
2494
|
+
const text = segment.label || contextConfig().t("thinking");
|
|
2493
2495
|
const label = el2.querySelector(".aparte-thinking-label");
|
|
2494
|
-
if (label) label.textContent =
|
|
2496
|
+
if (label) label.textContent = text;
|
|
2497
|
+
el2.querySelector(".aparte-thinking-content")?.setAttribute("aria-label", text);
|
|
2495
2498
|
},
|
|
2496
2499
|
update: (el2, segment) => {
|
|
2497
2500
|
const contentEl = el2.querySelector(".aparte-thinking-content");
|
|
@@ -2585,6 +2588,10 @@ function streamHighlight(element, paneSelector, content, lang, segId) {
|
|
|
2585
2588
|
}).catch(() => {
|
|
2586
2589
|
});
|
|
2587
2590
|
}
|
|
2591
|
+
function nameButton(button, label) {
|
|
2592
|
+
button.setAttribute("aria-label", label);
|
|
2593
|
+
button.setAttribute("title", label);
|
|
2594
|
+
}
|
|
2588
2595
|
const codeRenderer = {
|
|
2589
2596
|
type: "code",
|
|
2590
2597
|
render: (segment) => `
|
|
@@ -2592,7 +2599,7 @@ const codeRenderer = {
|
|
|
2592
2599
|
<div class="aparte-code-header">
|
|
2593
2600
|
${segment.filename ? `<span class="aparte-code-filename">${escapeHtml(segment.filename)}</span>` : `<span class="aparte-code-header-filler"></span>`}
|
|
2594
2601
|
<span class="aparte-code-language">${escapeHtml(segment.language || "")}</span>
|
|
2595
|
-
<button class="aparte-btn aparte-btn--icon aparte-btn--sm aparte-code-copy" data-action="copy" title="${escapeAttr(contextConfig().t("copy"))}">
|
|
2602
|
+
<button type="button" class="aparte-btn aparte-btn--icon aparte-btn--sm aparte-code-copy" data-action="copy" aria-label="${escapeAttr(contextConfig().t("copy"))}" title="${escapeAttr(contextConfig().t("copy"))}">
|
|
2596
2603
|
${contextConfig().getIcon("copy")}
|
|
2597
2604
|
</button>
|
|
2598
2605
|
</div>
|
|
@@ -2605,7 +2612,7 @@ const codeRenderer = {
|
|
|
2605
2612
|
relabel: (element) => {
|
|
2606
2613
|
const copyBtn = element.querySelector(".aparte-code-copy");
|
|
2607
2614
|
if (!copyBtn || copyBtn.dataset.copied) return;
|
|
2608
|
-
copyBtn
|
|
2615
|
+
nameButton(copyBtn, contextConfig().t("copy"));
|
|
2609
2616
|
copyBtn.innerHTML = contextConfig().getIcon("copy");
|
|
2610
2617
|
},
|
|
2611
2618
|
setup: (element, segment) => {
|
|
@@ -2623,11 +2630,11 @@ const codeRenderer = {
|
|
|
2623
2630
|
void copyText(source).catch(() => {
|
|
2624
2631
|
});
|
|
2625
2632
|
copyBtn.innerHTML = contextConfig(copyBtn).getIcon("check");
|
|
2626
|
-
copyBtn
|
|
2633
|
+
nameButton(copyBtn, contextConfig(copyBtn).t("copied"));
|
|
2627
2634
|
copyBtn.dataset.copied = "1";
|
|
2628
2635
|
setTimeout(() => {
|
|
2629
2636
|
copyBtn.innerHTML = contextConfig(copyBtn).getIcon("copy");
|
|
2630
|
-
copyBtn
|
|
2637
|
+
nameButton(copyBtn, contextConfig(copyBtn).t("copy"));
|
|
2631
2638
|
delete copyBtn.dataset.copied;
|
|
2632
2639
|
}, 1500);
|
|
2633
2640
|
});
|
|
@@ -2662,13 +2669,11 @@ const errorRenderer = {
|
|
|
2662
2669
|
}
|
|
2663
2670
|
return `
|
|
2664
2671
|
<div class="aparte-segment aparte-alert aparte-alert--danger aparte-segment-error" data-segment-id="${escapeHtml(segment.id)}">
|
|
2665
|
-
<
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
<div class="aparte-error-message">${escapeHtml(segment.content)}</div>
|
|
2671
|
-
${segment.details ? `<div class="aparte-error-details">${escapeHtml(segment.details)}</div>` : ""}
|
|
2672
|
+
<span class="aparte-alert__icon">${contextConfig().getIcon("error") || "⚠"}</span>
|
|
2673
|
+
<div class="aparte-alert__body">
|
|
2674
|
+
<div class="aparte-alert__title">${escapeHtml(contextConfig().t("error"))}</div>
|
|
2675
|
+
<div class="aparte-alert__message">${escapeHtml(segment.content)}</div>
|
|
2676
|
+
${segment.details ? `<pre class="aparte-segment-error__details">${escapeHtml(segment.details)}</pre>` : ""}
|
|
2672
2677
|
</div>
|
|
2673
2678
|
</div>
|
|
2674
2679
|
`;
|
|
@@ -2683,9 +2688,9 @@ const errorRenderer = {
|
|
|
2683
2688
|
* language it arrived in. Relabelling it would be inventing content.
|
|
2684
2689
|
*/
|
|
2685
2690
|
relabel: (element) => {
|
|
2686
|
-
const wrap = element.querySelector(".aparte-
|
|
2691
|
+
const wrap = element.querySelector(".aparte-alert__icon");
|
|
2687
2692
|
if (wrap) wrap.innerHTML = contextConfig().getIcon("error") || "⚠";
|
|
2688
|
-
const title = element.querySelector(".aparte-
|
|
2693
|
+
const title = element.querySelector(".aparte-alert__title");
|
|
2689
2694
|
if (title) title.textContent = contextConfig().t("error");
|
|
2690
2695
|
},
|
|
2691
2696
|
getStyles: () => ``
|
|
@@ -2705,7 +2710,7 @@ function stateBadge(segment) {
|
|
|
2705
2710
|
const cfg = contextConfig();
|
|
2706
2711
|
const status = segment.status ?? "pending";
|
|
2707
2712
|
const word = (key) => escapeHtml(cfg.t(key));
|
|
2708
|
-
if (status === "awaiting-approval") return word("approvalWaiting")
|
|
2713
|
+
if (status === "awaiting-approval") return `${cfg.getIcon("pause")}${word("approvalWaiting")}`;
|
|
2709
2714
|
if (status === "pending") return word("toolRunning");
|
|
2710
2715
|
if (status === "resolved") return `${cfg.getIcon("check")}${word("toolCompleted")}`;
|
|
2711
2716
|
if (status === "rejected") return `${cfg.getIcon("close")}${word("toolRejected")}`;
|
|
@@ -4380,13 +4385,13 @@ class AparteChatHost {
|
|
|
4380
4385
|
});
|
|
4381
4386
|
}
|
|
4382
4387
|
}
|
|
4383
|
-
function dispatchLifecycleEvent(target, name, detail) {
|
|
4384
|
-
const id = target.id || void 0;
|
|
4388
|
+
function dispatchLifecycleEvent(target, name, detail, targetId) {
|
|
4389
|
+
const id = targetId ?? (target.id || void 0);
|
|
4385
4390
|
const stamped = detail && typeof detail === "object" ? { targetId: id, ...detail } : detail;
|
|
4386
4391
|
target.dispatchEvent(new CustomEvent(name, { bubbles: true, composed: true, detail: stamped }));
|
|
4387
4392
|
}
|
|
4388
4393
|
function createStreamAdapter(opts) {
|
|
4389
|
-
const { target, config, messageId } = opts;
|
|
4394
|
+
const { target, config, messageId, targetId } = opts;
|
|
4390
4395
|
let parser = new AparteStreamParser({ blocks: config.getStreamBlocks() });
|
|
4391
4396
|
let streaming = /* @__PURE__ */ new Set();
|
|
4392
4397
|
let thinkingId = null;
|
|
@@ -4474,7 +4479,7 @@ function createStreamAdapter(opts) {
|
|
|
4474
4479
|
}
|
|
4475
4480
|
case "tool-awaiting-approval":
|
|
4476
4481
|
target.updateSegment?.(`tool-${e.toolCallId}`, { status: "awaiting-approval" });
|
|
4477
|
-
dispatchLifecycleEvent(target, "aparte-tool-approval-request", { toolCallId: e.toolCallId, toolName: e.name, input: e.input });
|
|
4482
|
+
dispatchLifecycleEvent(target, "aparte-tool-approval-request", { toolCallId: e.toolCallId, toolName: e.name, input: e.input }, targetId);
|
|
4478
4483
|
break;
|
|
4479
4484
|
case "tool-approved":
|
|
4480
4485
|
target.updateSegment?.(`tool-${e.toolCallId}`, { status: "pending" });
|
|
@@ -4508,7 +4513,7 @@ function createStreamAdapter(opts) {
|
|
|
4508
4513
|
}
|
|
4509
4514
|
break;
|
|
4510
4515
|
case "run-aborted":
|
|
4511
|
-
dispatchLifecycleEvent(target, "aparte-message-aborted", { messageId });
|
|
4516
|
+
dispatchLifecycleEvent(target, "aparte-message-aborted", { messageId }, targetId);
|
|
4512
4517
|
break;
|
|
4513
4518
|
case "run-done":
|
|
4514
4519
|
target.updateMessage?.(messageId, { status: "completed" });
|
|
@@ -4685,12 +4690,20 @@ function buildEnumField(field, onChange, fallbackLabel, settle) {
|
|
|
4685
4690
|
wrap.appendChild(list);
|
|
4686
4691
|
const controls = () => Array.from(list.querySelectorAll(".aparte-elic-control"));
|
|
4687
4692
|
const other = () => list.querySelector('input[value="__other__"]');
|
|
4693
|
+
let arrowed = false;
|
|
4694
|
+
list.addEventListener("keydown", (e) => {
|
|
4695
|
+
arrowed = e.key.startsWith("Arrow");
|
|
4696
|
+
});
|
|
4697
|
+
list.addEventListener("click", () => {
|
|
4698
|
+
arrowed = false;
|
|
4699
|
+
});
|
|
4688
4700
|
list.addEventListener("change", () => {
|
|
4689
4701
|
const o = other();
|
|
4690
4702
|
if (o && otherText) {
|
|
4691
4703
|
otherText.style.display = o.checked ? "" : "none";
|
|
4692
|
-
if (o.checked) otherText.focus();
|
|
4704
|
+
if (o.checked && !arrowed) otherText.focus();
|
|
4693
4705
|
}
|
|
4706
|
+
arrowed = false;
|
|
4694
4707
|
onChange();
|
|
4695
4708
|
});
|
|
4696
4709
|
otherText?.addEventListener("input", onChange);
|
|
@@ -5308,6 +5321,7 @@ class AparteClient {
|
|
|
5308
5321
|
* sequence, so it can't drift between the three entry points.
|
|
5309
5322
|
*/
|
|
5310
5323
|
async _streamTurn(targetElement, messageId, provider, messages, modelId, authConfig, opts) {
|
|
5324
|
+
const chatId = this._targetIdOf(targetElement);
|
|
5311
5325
|
const registeredTools = this._toolsForCurrentModel();
|
|
5312
5326
|
let baseRequest = {
|
|
5313
5327
|
messages,
|
|
@@ -5323,22 +5337,22 @@ class AparteClient {
|
|
|
5323
5337
|
baseRequest = { ...baseRequest, tools: void 0 };
|
|
5324
5338
|
}
|
|
5325
5339
|
if (this._isAborted) {
|
|
5326
|
-
dispatchLifecycleEvent(targetElement, "aparte-message-aborted", { messageId });
|
|
5340
|
+
dispatchLifecycleEvent(targetElement, "aparte-message-aborted", { messageId }, chatId);
|
|
5327
5341
|
this._updateMessage(targetElement, messageId, { status: "completed" });
|
|
5328
5342
|
return;
|
|
5329
5343
|
}
|
|
5330
|
-
dispatchLifecycleEvent(targetElement, "aparte-message-start", { messageId, role: "assistant" });
|
|
5344
|
+
dispatchLifecycleEvent(targetElement, "aparte-message-start", { messageId, role: "assistant" }, chatId);
|
|
5331
5345
|
const streamController = new AbortController();
|
|
5332
5346
|
try {
|
|
5333
5347
|
const usage = await this._streamLoop(targetElement, messageId, provider, baseRequest, authConfig, streamController);
|
|
5334
5348
|
if (this._isAborted || streamController.signal.aborted) {
|
|
5335
5349
|
this._updateMessage(targetElement, messageId, { status: "completed" });
|
|
5336
5350
|
} else {
|
|
5337
|
-
dispatchLifecycleEvent(targetElement, "aparte-message-done", { messageId, role: "assistant", usage });
|
|
5351
|
+
dispatchLifecycleEvent(targetElement, "aparte-message-done", { messageId, role: "assistant", usage }, chatId);
|
|
5338
5352
|
}
|
|
5339
5353
|
} catch (error) {
|
|
5340
5354
|
if (this._isAborted || streamController.signal.aborted) {
|
|
5341
|
-
dispatchLifecycleEvent(targetElement, "aparte-message-aborted", { messageId });
|
|
5355
|
+
dispatchLifecycleEvent(targetElement, "aparte-message-aborted", { messageId }, chatId);
|
|
5342
5356
|
this._updateMessage(targetElement, messageId, { status: "completed" });
|
|
5343
5357
|
return;
|
|
5344
5358
|
}
|
|
@@ -5526,13 +5540,64 @@ class AparteClient {
|
|
|
5526
5540
|
return null;
|
|
5527
5541
|
}
|
|
5528
5542
|
/**
|
|
5529
|
-
*
|
|
5543
|
+
* Which chat a render target BELONGS to — the id the lifecycle events must carry.
|
|
5544
|
+
*
|
|
5545
|
+
* Not `target.id`: the target is whatever renders, and an `<aparte-chat>` shell
|
|
5546
|
+
* delegates that to its `.viewport`, which has no id. So every lifecycle event on
|
|
5547
|
+
* a shell-shaped chat went out unstamped, and the receive side reads a missing id
|
|
5548
|
+
* as "for every chat on the page" — deliberately, so a single-chat page needs no
|
|
5549
|
+
* wiring. On a two-chat page one chat's turn therefore drove every composer.
|
|
5550
|
+
*
|
|
5551
|
+
* The climb is the same rule `aparte-composer._ownTargetId` uses on the receive
|
|
5552
|
+
* side, and it has to be, or the two would disagree about which chat is which:
|
|
5553
|
+
* the nearest `aparte-chat` / `[data-aparte-chat]` ancestor (or the element
|
|
5554
|
+
* itself) that HAS an id. Deliberately not `chatBoundaryOf` — that returns the
|
|
5555
|
+
* boundary whether or not it is identified, and an id-less boundary must fall
|
|
5556
|
+
* through to the next one up rather than answer "no id".
|
|
5557
|
+
*/
|
|
5558
|
+
_targetIdOf(el2) {
|
|
5559
|
+
let node = el2 ?? null;
|
|
5560
|
+
while (node) {
|
|
5561
|
+
const tag = node.tagName?.toLowerCase();
|
|
5562
|
+
const isHost = tag === "aparte-chat" || node.hasAttribute?.("data-aparte-chat");
|
|
5563
|
+
if (isHost && node.id) return node.id;
|
|
5564
|
+
node = node.parentElement;
|
|
5565
|
+
}
|
|
5566
|
+
return el2?.id || void 0;
|
|
5567
|
+
}
|
|
5568
|
+
/**
|
|
5569
|
+
* Convert AparteMessage[] to AparteChatMessage[] for re-submission (retry, edit).
|
|
5570
|
+
*
|
|
5571
|
+
* The SLICE is each caller's own business — retry cuts before the reply it is
|
|
5572
|
+
* regenerating, edit cuts after the message being reworded, send cuts at the last
|
|
5573
|
+
* answered turn. What a message CONTRIBUTES to the wire is not: send, retry and
|
|
5574
|
+
* edit must not disagree about it, and they did. This one had no filter at all,
|
|
5575
|
+
* so a failed turn and a turn stopped before its first token both went out as
|
|
5576
|
+
* `{ role: 'assistant', content: '' }` — a claim the assistant said nothing, which
|
|
5577
|
+
* some providers reject outright and the rest read as an empty reply worth
|
|
5578
|
+
* imitating.
|
|
5530
5579
|
*/
|
|
5531
5580
|
_messagesToChatMessages(messages) {
|
|
5532
|
-
return
|
|
5581
|
+
return this._wireHistory(messages);
|
|
5582
|
+
}
|
|
5583
|
+
/**
|
|
5584
|
+
* The one rule for what a message contributes to the wire.
|
|
5585
|
+
*
|
|
5586
|
+
* Not the slice — the contribution: a role the wire has (`user`/`assistant`), a
|
|
5587
|
+
* turn that neither failed nor is still in flight, and text that is not empty.
|
|
5588
|
+
*
|
|
5589
|
+
* `_wireText` (not `m.content`): assistant replies stream their text into
|
|
5590
|
+
* `segments`, leaving `content` as '', so without flattening every reply would be
|
|
5591
|
+
* empty here and the drop below would swallow the whole transcript.
|
|
5592
|
+
*/
|
|
5593
|
+
_wireHistory(messages) {
|
|
5594
|
+
return messages.filter((m) => {
|
|
5595
|
+
if (m.role !== "user" && m.role !== "assistant") return false;
|
|
5596
|
+
return m.status !== "error" && !AparteClient._inFlight(m);
|
|
5597
|
+
}).map((m) => ({
|
|
5533
5598
|
role: m.role,
|
|
5534
5599
|
content: this._wireText(m)
|
|
5535
|
-
}));
|
|
5600
|
+
})).filter((m) => m.content.length > 0);
|
|
5536
5601
|
}
|
|
5537
5602
|
/** The "no model selected" warning is said once per client, not once per dropped send. */
|
|
5538
5603
|
_warnedNoModel = false;
|
|
@@ -5666,22 +5731,30 @@ class AparteClient {
|
|
|
5666
5731
|
messages.push({ role: "user", content: userMsg });
|
|
5667
5732
|
return messages;
|
|
5668
5733
|
}
|
|
5734
|
+
/**
|
|
5735
|
+
* A turn that has not finished yet. `status` is OPTIONAL on `AparteMessage`, so
|
|
5736
|
+
* the question the history gates can ask is "is this still in flight?", never
|
|
5737
|
+
* "is this completed?".
|
|
5738
|
+
*
|
|
5739
|
+
* The gates below used to ask the second one, and a host that SEEDS a transcript
|
|
5740
|
+
* — restoring a saved conversation, hydrating a server-rendered one — has no
|
|
5741
|
+
* reason to invent a status for turns that are already over. With none, the
|
|
5742
|
+
* cutoff never advanced past 0 and the whole transcript was sliced away: the
|
|
5743
|
+
* model got the new question with no context, and nothing in the UI said so,
|
|
5744
|
+
* because the viewport still showed every message.
|
|
5745
|
+
*/
|
|
5746
|
+
static _inFlight(m) {
|
|
5747
|
+
return m.status === "streaming" || m.status === "pending";
|
|
5748
|
+
}
|
|
5669
5749
|
_toHistoryMessages(messages) {
|
|
5670
5750
|
let cutoff = 0;
|
|
5671
5751
|
for (let i = 0; i < messages.length; i++) {
|
|
5672
5752
|
const m = messages[i];
|
|
5673
|
-
if (m.role === "assistant" && m.status
|
|
5753
|
+
if (m.role === "assistant" && m.status !== "error" && !AparteClient._inFlight(m)) {
|
|
5674
5754
|
cutoff = i + 1;
|
|
5675
5755
|
}
|
|
5676
5756
|
}
|
|
5677
|
-
return messages.slice(0, cutoff)
|
|
5678
|
-
if (m.role === "user") return m.status !== "error";
|
|
5679
|
-
if (m.role === "assistant") return m.status === "completed";
|
|
5680
|
-
return false;
|
|
5681
|
-
}).map((m) => ({
|
|
5682
|
-
role: m.role,
|
|
5683
|
-
content: this._wireText(m)
|
|
5684
|
-
})).filter((m) => m.content.length > 0);
|
|
5757
|
+
return this._wireHistory(messages.slice(0, cutoff));
|
|
5685
5758
|
}
|
|
5686
5759
|
/**
|
|
5687
5760
|
* A message's text as the MODEL should read it — the one mapper both history
|
|
@@ -5854,10 +5927,12 @@ ${content}
|
|
|
5854
5927
|
*/
|
|
5855
5928
|
async _runViaStreamRunner(streamRunner, targetElement, messageId, provider, baseRequest, authConfig, streamController) {
|
|
5856
5929
|
const signal = streamController.signal;
|
|
5930
|
+
const chatId = this._targetIdOf(targetElement);
|
|
5857
5931
|
const adapter = createStreamAdapter({
|
|
5858
5932
|
target: targetElement,
|
|
5859
5933
|
config: this._config,
|
|
5860
|
-
messageId
|
|
5934
|
+
messageId,
|
|
5935
|
+
...chatId ? { targetId: chatId } : {}
|
|
5861
5936
|
});
|
|
5862
5937
|
const prefixSegments = baseRequest._meta?.["prefixSegments"];
|
|
5863
5938
|
const emitter = (event) => {
|
|
@@ -5950,7 +6025,7 @@ ${content}
|
|
|
5950
6025
|
segments: [errorSegment]
|
|
5951
6026
|
});
|
|
5952
6027
|
}
|
|
5953
|
-
dispatchLifecycleEvent(target, "aparte-message-error", { messageId, error });
|
|
6028
|
+
dispatchLifecycleEvent(target, "aparte-message-error", { messageId, error }, this._targetIdOf(target));
|
|
5954
6029
|
}
|
|
5955
6030
|
}
|
|
5956
6031
|
function findHead(node) {
|
|
@@ -6264,7 +6339,7 @@ function applyElementProps(el2, props, transformValue = (value) => value) {
|
|
|
6264
6339
|
if (value === null || value === void 0) el2.style.removeProperty(key);
|
|
6265
6340
|
else if (typeof value === "object" || typeof value === "function") el2.style.removeProperty(key);
|
|
6266
6341
|
else el2.style.setProperty(key, String(value));
|
|
6267
|
-
} else if (key.startsWith("on")) {
|
|
6342
|
+
} else if (key.toLowerCase().startsWith("on")) {
|
|
6268
6343
|
el2.removeAttribute(key);
|
|
6269
6344
|
} else if (value === null || value === void 0 || value === false) {
|
|
6270
6345
|
el2.removeAttribute(key);
|
|
@@ -6402,4 +6477,4 @@ export {
|
|
|
6402
6477
|
collectRendererStyles as y,
|
|
6403
6478
|
contentToText as z
|
|
6404
6479
|
};
|
|
6405
|
-
//# sourceMappingURL=dialog-triggers-
|
|
6480
|
+
//# sourceMappingURL=dialog-triggers-CApC7K1I.js.map
|