@aparte/core 0.23.0 → 0.24.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/client/aparte-client.d.ts +5 -0
- package/dist/client/aparte-client.d.ts.map +1 -1
- package/dist/client/stream-adapter.d.ts.map +1 -1
- package/dist/components/conversation-list/aparte-conversation-list.d.ts +38 -0
- package/dist/components/conversation-list/aparte-conversation-list.d.ts.map +1 -1
- package/dist/components/conversation-list/index.d.ts +1 -1
- package/dist/components/conversation-list/index.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/config/aparte-config.d.ts +10 -0
- package/dist/config/aparte-config.d.ts.map +1 -1
- package/dist/config/locale.d.ts +4 -0
- package/dist/config/locale.d.ts.map +1 -1
- package/dist/config/tool-table.d.ts +2 -0
- package/dist/config/tool-table.d.ts.map +1 -1
- package/dist/conversations/conversation-controller.d.ts +19 -0
- package/dist/conversations/conversation-controller.d.ts.map +1 -1
- package/dist/conversations/conversation-status.d.ts +27 -0
- package/dist/conversations/conversation-status.d.ts.map +1 -0
- package/dist/custom-elements.json +10301 -9868
- package/dist/{dialog-triggers-3G9TqG9g.js → dialog-triggers-BqXRdHWZ.js} +296 -63
- package/dist/dialog-triggers-BqXRdHWZ.js.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +58 -4
- package/dist/index.js.map +1 -1
- package/dist/index.node.d.ts +2 -2
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +1 -1
- package/dist/index.node.js.map +1 -1
- package/dist/interop/element-props.d.ts +1 -1
- package/dist/interop/element-props.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/event-map.d.ts +4 -2
- package/dist/types/event-map.d.ts.map +1 -1
- package/dist/types/events.d.ts +15 -0
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/tools.d.ts +39 -0
- package/dist/types/tools.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/dialog-triggers-3G9TqG9g.js.map +0 -1
|
@@ -173,6 +173,8 @@ const APARTE_DEFAULT_LOCALE = {
|
|
|
173
173
|
archiveConversation: "Archive",
|
|
174
174
|
unarchiveConversation: "Unarchive",
|
|
175
175
|
conversationActions: "Conversation actions",
|
|
176
|
+
conversationRunning: "Answering",
|
|
177
|
+
conversationWaiting: "Waiting for you",
|
|
176
178
|
renameConversation: "Rename",
|
|
177
179
|
conversationTitle: "Conversation title",
|
|
178
180
|
pinConversation: "Pin",
|
|
@@ -1102,12 +1104,20 @@ function createStreamAdapter(opts) {
|
|
|
1102
1104
|
};
|
|
1103
1105
|
let thinkingContent = "";
|
|
1104
1106
|
let thinkingCollapsed = false;
|
|
1107
|
+
const settleThinking = (fold) => {
|
|
1108
|
+
if (!thinkingId || thinkingCollapsed) return;
|
|
1109
|
+
const chatConfig = typeof Element !== "undefined" && target instanceof Element ? resolveConfig(target) : config;
|
|
1110
|
+
const keepOpen = !fold || chatConfig.getSegmentDefaults("thinking")?.collapsed === false;
|
|
1111
|
+
target.updateSegment?.(thinkingId, keepOpen ? { isStreaming: false } : { collapsed: true, isStreaming: false });
|
|
1112
|
+
thinkingCollapsed = true;
|
|
1113
|
+
};
|
|
1105
1114
|
return (e) => {
|
|
1106
1115
|
switch (e.type) {
|
|
1107
1116
|
case "run-start":
|
|
1108
1117
|
target.updateMessage?.(messageId, { status: "streaming" });
|
|
1109
1118
|
break;
|
|
1110
1119
|
case "turn-start":
|
|
1120
|
+
settleThinking(false);
|
|
1111
1121
|
parser = new AparteStreamParser({ blocks: config.getStreamBlocks() });
|
|
1112
1122
|
streaming = /* @__PURE__ */ new Set();
|
|
1113
1123
|
thinkingId = null;
|
|
@@ -1120,7 +1130,8 @@ function createStreamAdapter(opts) {
|
|
|
1120
1130
|
const seg = {
|
|
1121
1131
|
id: `think-${uuid()}`,
|
|
1122
1132
|
type: "thinking",
|
|
1123
|
-
content: thinkingContent
|
|
1133
|
+
content: thinkingContent,
|
|
1134
|
+
isStreaming: true
|
|
1124
1135
|
};
|
|
1125
1136
|
thinkingId = seg.id;
|
|
1126
1137
|
streaming.add(seg.id);
|
|
@@ -1131,12 +1142,7 @@ function createStreamAdapter(opts) {
|
|
|
1131
1142
|
break;
|
|
1132
1143
|
}
|
|
1133
1144
|
case "text-delta": {
|
|
1134
|
-
|
|
1135
|
-
const chatConfig = typeof Element !== "undefined" && target instanceof Element ? resolveConfig(target) : config;
|
|
1136
|
-
const keepOpen = chatConfig.getSegmentDefaults("thinking")?.collapsed === false;
|
|
1137
|
-
target.updateSegment?.(thinkingId, keepOpen ? { isStreaming: false } : { collapsed: true, isStreaming: false });
|
|
1138
|
-
thinkingCollapsed = true;
|
|
1139
|
-
}
|
|
1145
|
+
settleThinking(true);
|
|
1140
1146
|
const result = parser.parse(e.delta);
|
|
1141
1147
|
for (const segment of result.segments) {
|
|
1142
1148
|
if (!streaming.has(segment.id)) {
|
|
@@ -1166,6 +1172,7 @@ function createStreamAdapter(opts) {
|
|
|
1166
1172
|
break;
|
|
1167
1173
|
}
|
|
1168
1174
|
case "tool-start": {
|
|
1175
|
+
settleThinking(false);
|
|
1169
1176
|
const toolSeg = {
|
|
1170
1177
|
id: `tool-${e.toolCallId}`,
|
|
1171
1178
|
type: "tool_call",
|
|
@@ -1890,6 +1897,12 @@ class ToolTable {
|
|
|
1890
1897
|
}
|
|
1891
1898
|
return this.any !== void 0 ? { value: this.any, level: "any" } : void 0;
|
|
1892
1899
|
}
|
|
1900
|
+
/** Every value registered, whatever its matcher. */
|
|
1901
|
+
values() {
|
|
1902
|
+
const out = [...this.exact.values(), ...[...this.patterns.values()].map((p) => p.value)];
|
|
1903
|
+
if (this.any !== void 0) out.push(this.any);
|
|
1904
|
+
return out;
|
|
1905
|
+
}
|
|
1893
1906
|
clear() {
|
|
1894
1907
|
this.exact.clear();
|
|
1895
1908
|
this.patterns.clear();
|
|
@@ -1915,6 +1928,7 @@ function renderingVersionOf(cfg) {
|
|
|
1915
1928
|
function bumpRenderingVersion(cfg) {
|
|
1916
1929
|
renderingVersions.set(cfg, renderingVersionOf(cfg) + 1);
|
|
1917
1930
|
}
|
|
1931
|
+
const ELEMENT_SHAPING = ["hidden", "open", "details", "quiet"];
|
|
1918
1932
|
function drawingOf(provider, name) {
|
|
1919
1933
|
if (!provider || !(name in provider) || name in Object.prototype) return void 0;
|
|
1920
1934
|
const fn = provider[name];
|
|
@@ -2943,21 +2957,35 @@ class AparteConfig {
|
|
|
2943
2957
|
* @example
|
|
2944
2958
|
* // A consumer chat: the reply is what matters; the calls stay in the history.
|
|
2945
2959
|
* aparteGlobalConfig.registerToolDisplay('*', { hidden: true });
|
|
2960
|
+
*
|
|
2961
|
+
* @example
|
|
2962
|
+
* // The line, and no raw JSON behind it: nothing, or a detail of the app's own.
|
|
2963
|
+
* aparteGlobalConfig.registerToolDisplay('read_file', { label: 'Reading a file', details: false });
|
|
2964
|
+
* aparteGlobalConfig.registerToolDisplay('web_search', {
|
|
2965
|
+
* label: 'Searched the web',
|
|
2966
|
+
* details: (segment) => sourcesList(segment.result),
|
|
2967
|
+
* });
|
|
2946
2968
|
*/
|
|
2947
2969
|
registerToolDisplay(match, display) {
|
|
2948
2970
|
const before = this._toolDisplays.get(match);
|
|
2949
2971
|
const next = { ...before, ...display };
|
|
2950
2972
|
this._toolDisplays.set(match, next);
|
|
2951
|
-
|
|
2973
|
+
const shapes = ELEMENT_SHAPING.some((field) => before?.[field] !== next[field]) || before === void 0 && this._anotherShapes(next);
|
|
2974
|
+
if (shapes) bumpRenderingVersion(this);
|
|
2952
2975
|
this._notify();
|
|
2953
2976
|
}
|
|
2954
2977
|
/** Forget the display registered under this matcher. */
|
|
2955
2978
|
unregisterToolDisplay(match) {
|
|
2956
2979
|
const before = this._toolDisplays.get(match);
|
|
2957
2980
|
this._toolDisplays.delete(match);
|
|
2958
|
-
|
|
2981
|
+
const shapes = ELEMENT_SHAPING.some((field) => before?.[field] !== void 0) || before !== void 0 && this._anotherShapes(before);
|
|
2982
|
+
if (shapes) bumpRenderingVersion(this);
|
|
2959
2983
|
this._notify();
|
|
2960
2984
|
}
|
|
2985
|
+
/** Whether an entry other than `own` sets a field that shapes a row. */
|
|
2986
|
+
_anotherShapes(own) {
|
|
2987
|
+
return this._toolDisplays.values().some((entry) => entry !== own && ELEMENT_SHAPING.some((field) => entry[field] !== void 0));
|
|
2988
|
+
}
|
|
2961
2989
|
/** How a tool named `toolName` is shown — the entry that applies to it — or undefined. */
|
|
2962
2990
|
getToolDisplay(toolName) {
|
|
2963
2991
|
return this._toolDisplays.resolve(toolName)?.value;
|
|
@@ -3406,10 +3434,12 @@ function labelOf(segment) {
|
|
|
3406
3434
|
if (ms === void 0) return cfg.t("thought");
|
|
3407
3435
|
return cfg.t("thoughtFor").replace("{duration}", () => formatDuration(ms, cfg.getLocale().tag || void 0));
|
|
3408
3436
|
}
|
|
3437
|
+
const arriving = (segment) => segment.isStreaming === true;
|
|
3409
3438
|
function setLabel(el2, segment) {
|
|
3410
3439
|
const text = labelOf(segment);
|
|
3411
3440
|
const label = el2.querySelector(".aparte-thinking-label");
|
|
3412
3441
|
if (label && label.textContent !== text) label.textContent = text;
|
|
3442
|
+
label?.classList.toggle("aparte-shimmer", arriving(segment));
|
|
3413
3443
|
el2.querySelector(".aparte-thinking-content")?.setAttribute("aria-label", text);
|
|
3414
3444
|
}
|
|
3415
3445
|
const thinkingRenderer = {
|
|
@@ -3442,7 +3472,7 @@ const thinkingRenderer = {
|
|
|
3442
3472
|
* only part that is genuinely about reasoning rather than about disclosure.
|
|
3443
3473
|
* `.aparte-thinking-label` stays too: `relabel` below queries it.
|
|
3444
3474
|
*/
|
|
3445
|
-
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(labelOf(segment))}</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(labelOf(segment))}">${contextConfig().renderMarkdown(segment.content)}</div></details>`,
|
|
3475
|
+
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${escapeAttr(arriving(segment) ? " aparte-shimmer" : "")}">${escapeHtml(labelOf(segment))}</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(labelOf(segment))}">${contextConfig().renderMarkdown(segment.content)}</div></details>`,
|
|
3446
3476
|
/**
|
|
3447
3477
|
* The default label is the only config-derived text here — and `segment.label`
|
|
3448
3478
|
* still wins, exactly as in `render`, because that string is the app's.
|
|
@@ -3742,6 +3772,72 @@ function outcomeOf(segment) {
|
|
|
3742
3772
|
if (segment.status === "rejected" && segment.refusal) return null;
|
|
3743
3773
|
return { key: "toolOutput", text };
|
|
3744
3774
|
}
|
|
3775
|
+
function behindOf(segment) {
|
|
3776
|
+
const details = contextConfig().getToolDisplay(segment.toolCall?.name ?? "")?.details;
|
|
3777
|
+
if (details === false) return { kind: "none" };
|
|
3778
|
+
if (typeof details !== "function") return { kind: "parts" };
|
|
3779
|
+
try {
|
|
3780
|
+
const out = details(segment);
|
|
3781
|
+
if (!out) return { kind: "none" };
|
|
3782
|
+
return { kind: "body", body: typeof out === "string" ? contextConfig().sanitizeHtml(out) : out };
|
|
3783
|
+
} catch {
|
|
3784
|
+
return { kind: "none" };
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
const appDetailOf = (element) => element.querySelector(':scope > .aparte-tool-detail[data-details="app"]');
|
|
3788
|
+
function setBody(element, body) {
|
|
3789
|
+
const detail = element.querySelector(".aparte-tool-detail");
|
|
3790
|
+
if (!detail) return;
|
|
3791
|
+
if (typeof body === "string") detail.innerHTML = body;
|
|
3792
|
+
else detail.replaceChildren(body);
|
|
3793
|
+
drawnBodies.set(detail, serialized(body));
|
|
3794
|
+
}
|
|
3795
|
+
const drawnBodies = /* @__PURE__ */ new WeakMap();
|
|
3796
|
+
const serialized = (body) => typeof body === "string" ? body : body.outerHTML;
|
|
3797
|
+
function relabelBody(detail, body) {
|
|
3798
|
+
if (typeof body !== "string" && detail.contains(body)) {
|
|
3799
|
+
drawnBodies.set(detail, body.outerHTML);
|
|
3800
|
+
return;
|
|
3801
|
+
}
|
|
3802
|
+
const before = drawnBodies.get(detail);
|
|
3803
|
+
const now = serialized(body);
|
|
3804
|
+
if (before === now) return;
|
|
3805
|
+
const next = document.createElement("div");
|
|
3806
|
+
if (typeof body === "string") next.innerHTML = body;
|
|
3807
|
+
else next.append(body);
|
|
3808
|
+
const prev = document.createElement("div");
|
|
3809
|
+
if (before !== void 0) prev.innerHTML = before;
|
|
3810
|
+
if (before !== void 0 && sameShape(prev, next) && sameShape(prev, detail)) patchChanges(detail, prev, next);
|
|
3811
|
+
else detail.replaceChildren(...Array.from(next.childNodes));
|
|
3812
|
+
drawnBodies.set(detail, now);
|
|
3813
|
+
}
|
|
3814
|
+
function sameShape(a, b) {
|
|
3815
|
+
if (a.childNodes.length !== b.childNodes.length) return false;
|
|
3816
|
+
for (let i = 0; i < a.childNodes.length; i++) {
|
|
3817
|
+
const x = a.childNodes[i];
|
|
3818
|
+
const y = b.childNodes[i];
|
|
3819
|
+
if (x.nodeType !== y.nodeType || x.nodeName !== y.nodeName || !sameShape(x, y)) return false;
|
|
3820
|
+
}
|
|
3821
|
+
return true;
|
|
3822
|
+
}
|
|
3823
|
+
function patchChanges(live, prev, next) {
|
|
3824
|
+
for (let i = 0; i < live.childNodes.length; i++) {
|
|
3825
|
+
const l = live.childNodes[i];
|
|
3826
|
+
const p = prev.childNodes[i];
|
|
3827
|
+
const n = next.childNodes[i];
|
|
3828
|
+
if (l instanceof Element && p instanceof Element && n instanceof Element) {
|
|
3829
|
+
for (const { name, value } of Array.from(n.attributes)) {
|
|
3830
|
+
if (p.getAttribute(name) !== value) l.setAttribute(name, value);
|
|
3831
|
+
}
|
|
3832
|
+
for (const { name } of Array.from(p.attributes)) {
|
|
3833
|
+
if (!n.hasAttribute(name)) l.removeAttribute(name);
|
|
3834
|
+
}
|
|
3835
|
+
patchChanges(l, p, n);
|
|
3836
|
+
} else if (p.nodeValue !== n.nodeValue) {
|
|
3837
|
+
l.nodeValue = n.nodeValue;
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3745
3841
|
function setNote(element, segment) {
|
|
3746
3842
|
const el2 = element.querySelector(".aparte-tool-note");
|
|
3747
3843
|
if (!el2) return;
|
|
@@ -3848,6 +3944,23 @@ function iconOf(segment) {
|
|
|
3848
3944
|
const key = cfg.getToolDisplay(segment.toolCall?.name ?? "")?.icon;
|
|
3849
3945
|
return (key ? cfg.getIcon(key) : void 0) || cfg.getIcon("tool");
|
|
3850
3946
|
}
|
|
3947
|
+
const isQuiet = (segment) => contextConfig().getToolDisplay(segment.toolCall?.name ?? "")?.quiet === true;
|
|
3948
|
+
function quietOf(segment) {
|
|
3949
|
+
const status = segment.status ?? "pending";
|
|
3950
|
+
const quiet = isQuiet(segment);
|
|
3951
|
+
return {
|
|
3952
|
+
shimmer: quiet && status === "pending",
|
|
3953
|
+
spinner: !quiet && status === "pending",
|
|
3954
|
+
stateHidden: quiet && (status === "pending" || status === "resolved")
|
|
3955
|
+
};
|
|
3956
|
+
}
|
|
3957
|
+
function setQuiet(element, segment) {
|
|
3958
|
+
const quiet = quietOf(segment);
|
|
3959
|
+
element.toggleAttribute("data-quiet", isQuiet(segment));
|
|
3960
|
+
element.querySelector(".aparte-tool-spinner")?.toggleAttribute("hidden", !quiet.spinner);
|
|
3961
|
+
element.querySelector(".aparte-tool-name")?.classList.toggle("aparte-shimmer", quiet.shimmer);
|
|
3962
|
+
element.querySelector(".aparte-tool-state")?.classList.toggle("aparte-sr-only", quiet.stateHidden);
|
|
3963
|
+
}
|
|
3851
3964
|
function setName(element, segment) {
|
|
3852
3965
|
const el2 = element.querySelector(".aparte-tool-name");
|
|
3853
3966
|
if (!el2) return;
|
|
@@ -3855,68 +3968,85 @@ function setName(element, segment) {
|
|
|
3855
3968
|
if (el2.textContent !== text) el2.textContent = text;
|
|
3856
3969
|
el2.classList.toggle("aparte-tool-name--label", isLabel);
|
|
3857
3970
|
}
|
|
3858
|
-
function pillMarkup(segment
|
|
3971
|
+
function pillMarkup(segment) {
|
|
3859
3972
|
const badge = stateBadge(segment);
|
|
3860
3973
|
const icon = iconOf(segment);
|
|
3861
3974
|
const target = toolTarget(segment);
|
|
3862
3975
|
const note = noteOf(segment);
|
|
3863
3976
|
const name = nameOf(segment);
|
|
3977
|
+
const quiet = quietOf(segment);
|
|
3864
3978
|
return `
|
|
3865
3979
|
<span class="aparte-tool-label">
|
|
3866
3980
|
<span class="aparte-tool-icon">${icon}</span>
|
|
3867
|
-
<span class="aparte-tool-name${name.isLabel ? " aparte-tool-name--label" : ""}">${escapeHtml(name.text)}</span>
|
|
3981
|
+
<span class="aparte-tool-name${name.isLabel ? " aparte-tool-name--label" : ""}${quiet.shimmer ? " aparte-shimmer" : ""}">${escapeHtml(name.text)}</span>
|
|
3868
3982
|
<span class="aparte-tool-target"${target ? "" : " hidden"}>${escapeHtml(target)}</span>
|
|
3869
3983
|
</span>
|
|
3870
|
-
<span class="aparte-spinner aparte-tool-spinner" aria-hidden="true"${
|
|
3871
|
-
<span class="aparte-tool-state">${badge}</span>
|
|
3984
|
+
<span class="aparte-spinner aparte-tool-spinner" aria-hidden="true"${quiet.spinner ? "" : " hidden"}></span>
|
|
3985
|
+
<span class="aparte-tool-state${quiet.stateHidden ? " aparte-sr-only" : ""}">${badge}</span>
|
|
3872
3986
|
<span class="aparte-tool-note"${note ? ` title="${escapeAttr(note)}"` : " hidden"}>${escapeHtml(note)}</span>`;
|
|
3873
3987
|
}
|
|
3874
3988
|
function placeholderMarkup(segment) {
|
|
3875
3989
|
return `<div class="aparte-segment aparte-segment-tool-call" data-segment-id="${escapeHtml(segment.id)}" data-status="${escapeAttr(segment.status ?? "pending")}" data-tool-call-id="${escapeAttr(segment.toolCall?.id ?? "")}" data-tool-name="${escapeAttr(segment.toolCall?.name ?? "tool")}" hidden></div>`;
|
|
3876
3990
|
}
|
|
3877
3991
|
const isPlaceholder = (element) => element.hidden && element.classList.contains("aparte-segment-tool-call") && element.childElementCount === 0;
|
|
3992
|
+
function drawDefault(segment, behind) {
|
|
3993
|
+
const name = segment.toolCall?.name ?? "tool";
|
|
3994
|
+
const status = segment.status ?? "pending";
|
|
3995
|
+
const toolCallId = segment.toolCall?.id ?? "";
|
|
3996
|
+
const pill = pillMarkup(segment);
|
|
3997
|
+
const quiet = isQuiet(segment) ? " data-quiet" : "";
|
|
3998
|
+
const toggle = contextConfig().getIcon("expand");
|
|
3999
|
+
const input = behind.kind === "parts" ? describeInput(segment) : "";
|
|
4000
|
+
const outcome = behind.kind === "parts" ? outcomeOf(segment) : null;
|
|
4001
|
+
if (behind.kind === "none" || behind.kind === "parts" && !input && !outcome) {
|
|
4002
|
+
return `
|
|
4003
|
+
<div class="aparte-segment aparte-segment-tool-call" data-segment-id="${escapeHtml(segment.id)}" data-status="${escapeAttr(status)}" data-tool-call-id="${escapeAttr(toolCallId)}" data-tool-name="${escapeAttr(name)}"${quiet}><div class="aparte-tool-line">${pill}</div>
|
|
4004
|
+
</div>
|
|
4005
|
+
`;
|
|
4006
|
+
}
|
|
4007
|
+
const cfg = contextConfig();
|
|
4008
|
+
const copy = copyButtonMarkup("aparte-tool-copy");
|
|
4009
|
+
const open = segment.collapsed !== void 0 ? !segment.collapsed : cfg.getToolDisplay(name)?.open === true;
|
|
4010
|
+
if (behind.kind === "body") {
|
|
4011
|
+
const tpl = document.createElement("template");
|
|
4012
|
+
tpl.innerHTML = `
|
|
4013
|
+
<details class="aparte-segment aparte-segment-tool-call" data-segment-id="${escapeHtml(segment.id)}" data-status="${escapeAttr(status)}" data-tool-call-id="${escapeAttr(toolCallId)}" data-tool-name="${escapeAttr(name)}"${quiet}${open ? " open" : ""}>
|
|
4014
|
+
<summary class="aparte-tool-summary"><span class="aparte-tool-toggle">${toggle}</span>${pill}</summary>
|
|
4015
|
+
<div class="aparte-tool-detail" data-details="app"></div>
|
|
4016
|
+
</details>`.trim();
|
|
4017
|
+
const row = tpl.content.firstElementChild;
|
|
4018
|
+
setBody(row, behind.body);
|
|
4019
|
+
return row;
|
|
4020
|
+
}
|
|
4021
|
+
return `
|
|
4022
|
+
<details class="aparte-segment aparte-segment-tool-call" data-segment-id="${escapeHtml(segment.id)}" data-status="${escapeAttr(status)}" data-tool-call-id="${escapeAttr(toolCallId)}" data-tool-name="${escapeAttr(name)}"${quiet}${open ? " open" : ""}>
|
|
4023
|
+
<summary class="aparte-tool-summary"><span class="aparte-tool-toggle">${toggle}</span>${pill}</summary>
|
|
4024
|
+
<div class="aparte-tool-detail">
|
|
4025
|
+
${input ? `
|
|
4026
|
+
<div class="aparte-tool-part" data-part="input">
|
|
4027
|
+
<div class="aparte-tool-part-head"><span class="aparte-tool-part-label">${escapeHtml(cfg.t("toolInput"))}</span>${copy}</div>
|
|
4028
|
+
<div class="aparte-tool-part-body" role="region" tabindex="0" aria-label="${escapeAttr(cfg.t("toolInput"))}"><pre><code>${escapeHtml(input)}</code></pre></div>
|
|
4029
|
+
</div>` : ""}
|
|
4030
|
+
${outcome ? `
|
|
4031
|
+
<div class="aparte-tool-part" data-part="output">
|
|
4032
|
+
<div class="aparte-tool-part-head"><span class="aparte-tool-part-label">${escapeHtml(cfg.t(outcome.key))}</span>${copy}</div>
|
|
4033
|
+
<div class="aparte-tool-part-body" role="region" tabindex="0" aria-label="${escapeAttr(cfg.t(outcome.key))}"><pre><code>${escapeHtml(outcome.text)}</code></pre></div>
|
|
4034
|
+
</div>` : ""}
|
|
4035
|
+
</div>
|
|
4036
|
+
</details>
|
|
4037
|
+
`;
|
|
4038
|
+
}
|
|
3878
4039
|
const toolCallRenderer = {
|
|
3879
4040
|
type: "tool_call",
|
|
3880
4041
|
render: (segment) => {
|
|
3881
4042
|
const name = segment.toolCall?.name ?? "tool";
|
|
3882
|
-
const status = segment.status ?? "pending";
|
|
3883
|
-
const toolCallId = segment.toolCall?.id ?? "";
|
|
3884
4043
|
if (contextConfig().isToolHidden(name)) return placeholderMarkup(segment);
|
|
3885
4044
|
const customRenderer = contextConfig().getToolRenderer(name);
|
|
3886
4045
|
if (customRenderer) {
|
|
3887
4046
|
injectToolRendererStyles(name, customRenderer);
|
|
3888
4047
|
return customRenderer.render(segment) || placeholderMarkup(segment);
|
|
3889
4048
|
}
|
|
3890
|
-
|
|
3891
|
-
const toggle = contextConfig().getIcon("expand");
|
|
3892
|
-
const input = describeInput(segment);
|
|
3893
|
-
const outcome = outcomeOf(segment);
|
|
3894
|
-
if (!input && !outcome) {
|
|
3895
|
-
return `
|
|
3896
|
-
<div class="aparte-segment aparte-segment-tool-call" data-segment-id="${escapeHtml(segment.id)}" data-status="${escapeAttr(status)}" data-tool-call-id="${escapeAttr(toolCallId)}" data-tool-name="${escapeAttr(name)}">${pill}
|
|
3897
|
-
</div>
|
|
3898
|
-
`;
|
|
3899
|
-
}
|
|
3900
|
-
const cfg = contextConfig();
|
|
3901
|
-
const copy = copyButtonMarkup("aparte-tool-copy");
|
|
3902
|
-
const open = segment.collapsed !== void 0 ? !segment.collapsed : cfg.getToolDisplay(name)?.open === true;
|
|
3903
|
-
return `
|
|
3904
|
-
<details class="aparte-segment aparte-segment-tool-call" data-segment-id="${escapeHtml(segment.id)}" data-status="${escapeAttr(status)}" data-tool-call-id="${escapeAttr(toolCallId)}" data-tool-name="${escapeAttr(name)}"${open ? " open" : ""}>
|
|
3905
|
-
<summary class="aparte-tool-summary"><span class="aparte-tool-toggle">${toggle}</span>${pill}</summary>
|
|
3906
|
-
<div class="aparte-tool-detail">
|
|
3907
|
-
${input ? `
|
|
3908
|
-
<div class="aparte-tool-part" data-part="input">
|
|
3909
|
-
<div class="aparte-tool-part-head"><span class="aparte-tool-part-label">${escapeHtml(cfg.t("toolInput"))}</span>${copy}</div>
|
|
3910
|
-
<div class="aparte-tool-part-body" role="region" tabindex="0" aria-label="${escapeAttr(cfg.t("toolInput"))}"><pre><code>${escapeHtml(input)}</code></pre></div>
|
|
3911
|
-
</div>` : ""}
|
|
3912
|
-
${outcome ? `
|
|
3913
|
-
<div class="aparte-tool-part" data-part="output">
|
|
3914
|
-
<div class="aparte-tool-part-head"><span class="aparte-tool-part-label">${escapeHtml(cfg.t(outcome.key))}</span>${copy}</div>
|
|
3915
|
-
<div class="aparte-tool-part-body" role="region" tabindex="0" aria-label="${escapeAttr(cfg.t(outcome.key))}"><pre><code>${escapeHtml(outcome.text)}</code></pre></div>
|
|
3916
|
-
</div>` : ""}
|
|
3917
|
-
</div>
|
|
3918
|
-
</details>
|
|
3919
|
-
`;
|
|
4049
|
+
return drawDefault(segment, behindOf(segment));
|
|
3920
4050
|
},
|
|
3921
4051
|
/**
|
|
3922
4052
|
* The pill's glyphs, and the label it wears while a person is deciding.
|
|
@@ -3949,8 +4079,14 @@ const toolCallRenderer = {
|
|
|
3949
4079
|
if (outputLabel && outcome) outputLabel.textContent = cfg.t(outcome.key);
|
|
3950
4080
|
if (outcome) element.querySelector('[data-part="output"] .aparte-tool-part-body')?.setAttribute("aria-label", cfg.t(outcome.key));
|
|
3951
4081
|
for (const button of element.querySelectorAll(".aparte-tool-copy")) relabelCopyButton(button);
|
|
4082
|
+
const appDetail = appDetailOf(element);
|
|
4083
|
+
if (appDetail) {
|
|
4084
|
+
const behind = behindOf(segment);
|
|
4085
|
+
if (behind.kind === "body") relabelBody(appDetail, behind.body);
|
|
4086
|
+
}
|
|
3952
4087
|
const statusEl = element.querySelector(".aparte-tool-state");
|
|
3953
4088
|
if (statusEl) statusEl.innerHTML = stateBadge(segment);
|
|
4089
|
+
setQuiet(element, segment);
|
|
3954
4090
|
},
|
|
3955
4091
|
/**
|
|
3956
4092
|
* Patch in place. NEVER re-render, and never touch `open`.
|
|
@@ -3972,32 +4108,45 @@ const toolCallRenderer = {
|
|
|
3972
4108
|
element.setAttribute("data-status", status);
|
|
3973
4109
|
return;
|
|
3974
4110
|
}
|
|
3975
|
-
const input = describeInput(segment);
|
|
3976
|
-
const outcome = outcomeOf(segment);
|
|
3977
|
-
const wantsDetail = !!input || !!outcome;
|
|
3978
4111
|
const custom = contextConfig().getToolRenderer(segment.toolCall?.name);
|
|
3979
4112
|
if (custom?.update && !hidden && !isPlaceholder(element)) {
|
|
3980
4113
|
custom.update(element, segment);
|
|
3981
4114
|
return;
|
|
3982
4115
|
}
|
|
3983
|
-
|
|
3984
|
-
const out = toolCallRenderer.render(segment);
|
|
4116
|
+
const rebuild = (out) => {
|
|
3985
4117
|
const tpl = document.createElement("template");
|
|
3986
4118
|
tpl.innerHTML = typeof out === "string" ? out.trim() : "";
|
|
3987
4119
|
const rebuilt = typeof out === "string" ? tpl.content.firstElementChild : out;
|
|
3988
4120
|
if (rebuilt) {
|
|
4121
|
+
if (!rebuilt.hasAttribute("data-segment-id")) rebuilt.setAttribute("data-segment-id", segment.id);
|
|
3989
4122
|
element.replaceWith(rebuilt);
|
|
3990
4123
|
toolCallRenderer.setup?.(rebuilt, segment);
|
|
3991
4124
|
}
|
|
4125
|
+
};
|
|
4126
|
+
if (custom || hidden || isPlaceholder(element)) {
|
|
4127
|
+
rebuild(toolCallRenderer.render(segment));
|
|
4128
|
+
return;
|
|
4129
|
+
}
|
|
4130
|
+
const behind = behindOf(segment);
|
|
4131
|
+
const input = behind.kind === "parts" ? describeInput(segment) : "";
|
|
4132
|
+
const outcome = behind.kind === "parts" ? outcomeOf(segment) : null;
|
|
4133
|
+
const wantsDetail = behind.kind === "body" || !!input || !!outcome;
|
|
4134
|
+
const holdsAppDetail = !!appDetailOf(element);
|
|
4135
|
+
if (wantsDetail !== (element.tagName === "DETAILS") || wantsDetail && behind.kind === "body" !== holdsAppDetail) {
|
|
4136
|
+
rebuild(drawDefault(segment, behind));
|
|
3992
4137
|
return;
|
|
3993
4138
|
}
|
|
3994
4139
|
element.setAttribute("data-status", status);
|
|
3995
4140
|
const badge = element.querySelector(".aparte-tool-state");
|
|
3996
4141
|
if (badge) badge.innerHTML = stateBadge(segment);
|
|
3997
|
-
element
|
|
4142
|
+
setQuiet(element, segment);
|
|
3998
4143
|
setName(element, segment);
|
|
3999
4144
|
setTarget(element, segment);
|
|
4000
4145
|
setNote(element, segment);
|
|
4146
|
+
if (behind.kind === "body") {
|
|
4147
|
+
setBody(element, behind.body);
|
|
4148
|
+
return;
|
|
4149
|
+
}
|
|
4001
4150
|
setPart(element, "input", input, "toolInput");
|
|
4002
4151
|
setPart(element, "output", outcome?.text ?? "", outcome?.key ?? "toolOutput");
|
|
4003
4152
|
highlightParts(element);
|
|
@@ -4607,6 +4756,21 @@ function revokeAttachmentUrls(attachments) {
|
|
|
4607
4756
|
if (attachment.url?.startsWith("blob:")) URL.revokeObjectURL(attachment.url);
|
|
4608
4757
|
}
|
|
4609
4758
|
}
|
|
4759
|
+
const known = /* @__PURE__ */ new Map();
|
|
4760
|
+
function rememberConversationStatus(id, status) {
|
|
4761
|
+
if (status) known.set(id, status);
|
|
4762
|
+
else known.delete(id);
|
|
4763
|
+
}
|
|
4764
|
+
function tellConversationStatus(id, status) {
|
|
4765
|
+
rememberConversationStatus(id, status);
|
|
4766
|
+
try {
|
|
4767
|
+
window.dispatchEvent(new CustomEvent("aparte-conversation-status", { detail: { id, status } }));
|
|
4768
|
+
} catch {
|
|
4769
|
+
}
|
|
4770
|
+
}
|
|
4771
|
+
function conversationStatusOf(id) {
|
|
4772
|
+
return known.get(id) ?? null;
|
|
4773
|
+
}
|
|
4610
4774
|
const MAX_COMPACTION_SAVE_WAITS = 6;
|
|
4611
4775
|
class AparteConversationController {
|
|
4612
4776
|
_binding;
|
|
@@ -4615,6 +4779,10 @@ class AparteConversationController {
|
|
|
4615
4779
|
_isStreaming = false;
|
|
4616
4780
|
_isLoadingConversation = false;
|
|
4617
4781
|
_ensureInFlight = null;
|
|
4782
|
+
/** The conversation the turn in flight started in, and what the lists were told of it. */
|
|
4783
|
+
_turn = null;
|
|
4784
|
+
/** The reply the turn in flight writes into, from its `aparte-message-start`. */
|
|
4785
|
+
_turnMessage = null;
|
|
4618
4786
|
_onSendCapture = null;
|
|
4619
4787
|
_onPathChanged = null;
|
|
4620
4788
|
_onMessageStart = null;
|
|
@@ -4622,6 +4790,7 @@ class AparteConversationController {
|
|
|
4622
4790
|
_onMessageError = null;
|
|
4623
4791
|
_onMessageAborted = null;
|
|
4624
4792
|
_onMessagePaused = null;
|
|
4793
|
+
_onMessageResumed = null;
|
|
4625
4794
|
_onSelectConversation = null;
|
|
4626
4795
|
_onCompactDone = null;
|
|
4627
4796
|
_unsubscribeManager = null;
|
|
@@ -4702,6 +4871,33 @@ class AparteConversationController {
|
|
|
4702
4871
|
"[aparte] This chat resolves its own config, but the conversation manager was registered on aparteGlobalConfig — so nothing is being persisted. Pass the same config to init(): `init(adapter, myConfig)`, using the config you gave the chat."
|
|
4703
4872
|
);
|
|
4704
4873
|
}
|
|
4874
|
+
/**
|
|
4875
|
+
* Tell every conversation list on the page what the turn is doing, through
|
|
4876
|
+
* `aparte-conversation-status` on `window` — the mirror of the list's
|
|
4877
|
+
* `aparte-conversation-select`, which this controller hears. Always about the
|
|
4878
|
+
* conversation the turn started in: the person may have opened another since. A turn
|
|
4879
|
+
* that starts before its conversation exists (a first message) is told once it does.
|
|
4880
|
+
*/
|
|
4881
|
+
_setTurn(status) {
|
|
4882
|
+
if (!status) {
|
|
4883
|
+
if (this._turn) tellConversationStatus(this._turn.id, null);
|
|
4884
|
+
this._turn = null;
|
|
4885
|
+
return;
|
|
4886
|
+
}
|
|
4887
|
+
const id = this._turn?.id ?? (status === "running" ? this._activeId ?? this._manager()?.activeId ?? null : null);
|
|
4888
|
+
if (!id) return;
|
|
4889
|
+
this._turn = { id, status };
|
|
4890
|
+
tellConversationStatus(id, status);
|
|
4891
|
+
}
|
|
4892
|
+
/**
|
|
4893
|
+
* Whether a lifecycle event is about the turn in flight. A turn a newer send replaced
|
|
4894
|
+
* (a chip, a retry, an edit) says it stopped AFTER the new one started: its end must not
|
|
4895
|
+
* end the new turn's state. An event without a message id is taken as this turn's.
|
|
4896
|
+
*/
|
|
4897
|
+
_ofThisTurn(e) {
|
|
4898
|
+
const id = e.detail?.messageId;
|
|
4899
|
+
return !id || !this._turnMessage || id === this._turnMessage;
|
|
4900
|
+
}
|
|
4705
4901
|
/**
|
|
4706
4902
|
* Attach event listeners to the binding host. Returns an unbind function.
|
|
4707
4903
|
*/
|
|
@@ -4732,29 +4928,42 @@ class AparteConversationController {
|
|
|
4732
4928
|
}
|
|
4733
4929
|
};
|
|
4734
4930
|
host.addEventListener("aparte-path-changed", this._onPathChanged);
|
|
4735
|
-
this._onMessageStart = () => {
|
|
4931
|
+
this._onMessageStart = (e) => {
|
|
4736
4932
|
this._isStreaming = true;
|
|
4933
|
+
this._turnMessage = e.detail?.messageId ?? null;
|
|
4934
|
+
this._setTurn("running");
|
|
4737
4935
|
};
|
|
4738
|
-
|
|
4936
|
+
const ended = (e) => {
|
|
4937
|
+
if (!this._ofThisTurn(e)) return;
|
|
4739
4938
|
this._isStreaming = false;
|
|
4939
|
+
this._setTurn(null);
|
|
4940
|
+
this._turnMessage = null;
|
|
4941
|
+
};
|
|
4942
|
+
this._onMessageDone = (e) => {
|
|
4943
|
+
ended(e);
|
|
4740
4944
|
queueMicrotask(() => this._persistActive());
|
|
4741
4945
|
};
|
|
4742
|
-
this._onMessageError = () => {
|
|
4743
|
-
|
|
4946
|
+
this._onMessageError = (e) => {
|
|
4947
|
+
ended(e);
|
|
4744
4948
|
queueMicrotask(() => this._persistActive());
|
|
4745
4949
|
};
|
|
4746
|
-
this._onMessageAborted = () => {
|
|
4747
|
-
|
|
4950
|
+
this._onMessageAborted = (e) => {
|
|
4951
|
+
ended(e);
|
|
4748
4952
|
queueMicrotask(() => this._persistActive());
|
|
4749
4953
|
};
|
|
4750
|
-
this._onMessagePaused = () => {
|
|
4954
|
+
this._onMessagePaused = (e) => {
|
|
4955
|
+
if (this._ofThisTurn(e)) this._setTurn("waiting");
|
|
4751
4956
|
queueMicrotask(() => this._persistActive());
|
|
4752
4957
|
};
|
|
4958
|
+
this._onMessageResumed = (e) => {
|
|
4959
|
+
if (this._ofThisTurn(e)) this._setTurn("running");
|
|
4960
|
+
};
|
|
4753
4961
|
host.addEventListener("aparte-message-start", this._onMessageStart);
|
|
4754
4962
|
host.addEventListener("aparte-message-done", this._onMessageDone);
|
|
4755
4963
|
host.addEventListener("aparte-message-error", this._onMessageError);
|
|
4756
4964
|
host.addEventListener("aparte-message-aborted", this._onMessageAborted);
|
|
4757
4965
|
host.addEventListener("aparte-message-paused", this._onMessagePaused);
|
|
4966
|
+
host.addEventListener("aparte-message-resumed", this._onMessageResumed);
|
|
4758
4967
|
this._onSelectConversation = (e) => {
|
|
4759
4968
|
const evt = e;
|
|
4760
4969
|
const targetId = evt.detail?.targetId;
|
|
@@ -4781,6 +4990,9 @@ class AparteConversationController {
|
|
|
4781
4990
|
this._bound = false;
|
|
4782
4991
|
this._subscribedTo = null;
|
|
4783
4992
|
this._persistActive();
|
|
4993
|
+
if (this._turn?.status === "running") this._setTurn(null);
|
|
4994
|
+
this._turn = null;
|
|
4995
|
+
this._turnMessage = null;
|
|
4784
4996
|
this._stopHydrationRetry?.();
|
|
4785
4997
|
this._stopHydrationRetry = null;
|
|
4786
4998
|
const host = this._binding.host;
|
|
@@ -4812,6 +5024,10 @@ class AparteConversationController {
|
|
|
4812
5024
|
host.removeEventListener("aparte-message-paused", this._onMessagePaused);
|
|
4813
5025
|
this._onMessagePaused = null;
|
|
4814
5026
|
}
|
|
5027
|
+
if (this._onMessageResumed) {
|
|
5028
|
+
host.removeEventListener("aparte-message-resumed", this._onMessageResumed);
|
|
5029
|
+
this._onMessageResumed = null;
|
|
5030
|
+
}
|
|
4815
5031
|
if (this._onCompactDone && typeof window !== "undefined") {
|
|
4816
5032
|
window.removeEventListener("aparte-compact-done", this._onCompactDone);
|
|
4817
5033
|
this._onCompactDone = null;
|
|
@@ -4840,6 +5056,8 @@ class AparteConversationController {
|
|
|
4840
5056
|
const isSwitch = id !== this._activeId;
|
|
4841
5057
|
const manager = this._manager();
|
|
4842
5058
|
if (isSwitch && this._isStreaming) {
|
|
5059
|
+
if (this._turn?.status === "waiting") this._turn = null;
|
|
5060
|
+
else this._setTurn(null);
|
|
4843
5061
|
this._persistActive();
|
|
4844
5062
|
try {
|
|
4845
5063
|
window.dispatchEvent(new CustomEvent("aparte-abort", {
|
|
@@ -5021,6 +5239,7 @@ class AparteConversationController {
|
|
|
5021
5239
|
}
|
|
5022
5240
|
this._activeId = convId;
|
|
5023
5241
|
this._options.onConversationCreated?.(convId);
|
|
5242
|
+
if (this._isStreaming && !this._turn) this._setTurn("running");
|
|
5024
5243
|
} else if (this._activeId !== null && this._activeId !== convId) {
|
|
5025
5244
|
await manager.addMessage(convId, userMsg).catch(() => {
|
|
5026
5245
|
});
|
|
@@ -6685,6 +6904,7 @@ class AparteClient {
|
|
|
6685
6904
|
return;
|
|
6686
6905
|
}
|
|
6687
6906
|
dispatchLifecycleEvent(targetElement, "aparte-message-start", { messageId, role: "assistant" }, chatId);
|
|
6907
|
+
if (opts?.resume) dispatchLifecycleEvent(targetElement, "aparte-message-paused", { messageId }, chatId);
|
|
6688
6908
|
if (!opts?.resume && provider.id) {
|
|
6689
6909
|
this._updateMessage(targetElement, messageId, {
|
|
6690
6910
|
model: {
|
|
@@ -6697,6 +6917,7 @@ class AparteClient {
|
|
|
6697
6917
|
const streamController = new AbortController();
|
|
6698
6918
|
if (this._streamController !== streamController) this._streamController?.abort();
|
|
6699
6919
|
this._streamController = streamController;
|
|
6920
|
+
this._turnsInFlight.add(messageId);
|
|
6700
6921
|
try {
|
|
6701
6922
|
let result = opts?.resume ? { usage: void 0, suspended: opts.resume } : await this._streamLoop(targetElement, messageId, provider, baseRequest, authConfig, streamController);
|
|
6702
6923
|
const maxResumes = this.options.maxTurns ?? 10;
|
|
@@ -6728,6 +6949,7 @@ class AparteClient {
|
|
|
6728
6949
|
};
|
|
6729
6950
|
const messages2 = this._resumeMessages(targetElement, messageId, baseRequest.messages);
|
|
6730
6951
|
this._spendPause(targetElement, messageId);
|
|
6952
|
+
dispatchLifecycleEvent(targetElement, "aparte-message-resumed", { messageId }, chatId);
|
|
6731
6953
|
result = await this._streamLoop(
|
|
6732
6954
|
targetElement,
|
|
6733
6955
|
messageId,
|
|
@@ -6754,8 +6976,15 @@ class AparteClient {
|
|
|
6754
6976
|
}
|
|
6755
6977
|
const aparteError = AparteError.from(error, AparteErrorCode.UNKNOWN_ERROR);
|
|
6756
6978
|
this._handleLifecycleError(targetElement, messageId, aparteError);
|
|
6979
|
+
} finally {
|
|
6980
|
+
this._turnsInFlight.delete(messageId);
|
|
6757
6981
|
}
|
|
6758
6982
|
}
|
|
6983
|
+
/**
|
|
6984
|
+
* Replies a turn is running into right now, a pause it waits on included: a second
|
|
6985
|
+
* load of their conversation must not start them again (`resumeDeferred`).
|
|
6986
|
+
*/
|
|
6987
|
+
_turnsInFlight = /* @__PURE__ */ new Set();
|
|
6759
6988
|
/**
|
|
6760
6989
|
* Handle aparte-retry — add a sibling branch to the assistant message and re-stream
|
|
6761
6990
|
* using the same conversation history minus the retried reply.
|
|
@@ -7627,7 +7856,7 @@ ${content}
|
|
|
7627
7856
|
const last = [...messages].reverse().find((m) => m.role === "assistant");
|
|
7628
7857
|
const open = (last?.segments ?? []).filter(isOpenDeferred);
|
|
7629
7858
|
const ticket = open.find((s) => s.deferred?.ticket)?.deferred?.ticket;
|
|
7630
|
-
if (!last || open.length === 0 || !ticket || this._resuming.has(last.id)) return false;
|
|
7859
|
+
if (!last || open.length === 0 || !ticket || this._resuming.has(last.id) || this._turnsInFlight.has(last.id)) return false;
|
|
7631
7860
|
const config = this._config.getModelConfig();
|
|
7632
7861
|
const recorded = last.model && this._config.getAIProvider(last.model.providerId) ? last.model : void 0;
|
|
7633
7862
|
const providerId = recorded?.providerId ?? config.defaultProvider;
|
|
@@ -8060,6 +8289,7 @@ const APARTE_DEFAULT_UI_EVENTS = [
|
|
|
8060
8289
|
"aparte-message-error",
|
|
8061
8290
|
"aparte-message-aborted",
|
|
8062
8291
|
"aparte-message-paused",
|
|
8292
|
+
"aparte-message-resumed",
|
|
8063
8293
|
"aparte-tool-approval-request"
|
|
8064
8294
|
];
|
|
8065
8295
|
function applyElementProps(el2, props, transformValue = (value) => value) {
|
|
@@ -8188,8 +8418,11 @@ export {
|
|
|
8188
8418
|
isTerminalStatus as al,
|
|
8189
8419
|
adoptMessageSegments as am,
|
|
8190
8420
|
APARTE_DERIVED_SEGMENTS as an,
|
|
8191
|
-
|
|
8192
|
-
|
|
8421
|
+
rememberConversationStatus as ao,
|
|
8422
|
+
tellConversationStatus as ap,
|
|
8423
|
+
conversationStatusOf as aq,
|
|
8424
|
+
chatBoundaryOf as ar,
|
|
8425
|
+
rootOf as as,
|
|
8193
8426
|
APARTE_DEFAULT_BUBBLE_ACTIONS as b,
|
|
8194
8427
|
APARTE_DEFAULT_HOST_HANDLERS as c,
|
|
8195
8428
|
APARTE_DEFAULT_ICON_FALLBACKS as d,
|
|
@@ -8216,4 +8449,4 @@ export {
|
|
|
8216
8449
|
collectRendererStyles as y,
|
|
8217
8450
|
contentToText as z
|
|
8218
8451
|
};
|
|
8219
|
-
//# sourceMappingURL=dialog-triggers-
|
|
8452
|
+
//# sourceMappingURL=dialog-triggers-BqXRdHWZ.js.map
|