@aparte/core 0.24.0 → 0.25.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 +3 -0
- package/dist/client/aparte-client.d.ts.map +1 -1
- package/dist/components/bubble/aparte-chat-bubble.d.ts +64 -0
- package/dist/components/bubble/aparte-chat-bubble.d.ts.map +1 -1
- package/dist/components/chat/aparte-chat.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-action.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-add-attachment.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-attachments.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-cancel.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-input.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-send.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-toolbar.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer.d.ts.map +1 -1
- package/dist/components/context/aparte-context.d.ts.map +1 -1
- package/dist/components/conversation-list/aparte-conversation-list.d.ts.map +1 -1
- package/dist/components/elicitation/aparte-elicitation.d.ts.map +1 -1
- package/dist/components/scroll-rail/aparte-scroll-rail.d.ts.map +1 -1
- package/dist/components/sidebar/aparte-sidebar.d.ts.map +1 -1
- package/dist/components/split/aparte-split.d.ts.map +1 -1
- package/dist/components/status/aparte-chat-status.d.ts.map +1 -1
- package/dist/components/suggestions/aparte-suggestions.d.ts.map +1 -1
- package/dist/components/viewport/aparte-chat-viewport.d.ts.map +1 -1
- package/dist/config/aparte-config.d.ts +30 -1
- package/dist/config/aparte-config.d.ts.map +1 -1
- package/dist/custom-elements.json +8808 -7934
- package/dist/{dialog-triggers-BqXRdHWZ.js → defer-hydration-BwMqeRHq.js} +548 -176
- package/dist/defer-hydration-BwMqeRHq.js.map +1 -0
- package/dist/{glyphs-C8z2oJUg.js → glyphs-2bym5jl5.js} +1 -1
- package/dist/{glyphs-C8z2oJUg.js.map → glyphs-2bym5jl5.js.map} +1 -1
- package/dist/host/aparte-chat-host.d.ts +22 -0
- package/dist/host/aparte-chat-host.d.ts.map +1 -1
- package/dist/icons.js +2 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +282 -56
- package/dist/index.js.map +1 -1
- package/dist/index.node.d.ts +3 -2
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +35 -29
- package/dist/index.node.js.map +1 -1
- package/dist/interop/defer-hydration.d.ts +34 -0
- package/dist/interop/defer-hydration.d.ts.map +1 -0
- package/dist/primitives/icon/aparte-icon.d.ts.map +1 -1
- package/dist/primitives/progress-spinner/aparte-progress-spinner.d.ts.map +1 -1
- package/dist/primitives/select/aparte-optgroup.d.ts.map +1 -1
- package/dist/primitives/select/aparte-option.d.ts.map +1 -1
- package/dist/primitives/select/aparte-select.d.ts.map +1 -1
- package/dist/renderers/index.d.ts +2 -1
- package/dist/renderers/index.d.ts.map +1 -1
- package/dist/renderers/mounted-renderer.d.ts +34 -0
- package/dist/renderers/mounted-renderer.d.ts.map +1 -0
- package/dist/renderers/segment-renderers.d.ts +14 -1
- package/dist/renderers/segment-renderers.d.ts.map +1 -1
- package/dist/renderers/segments/tool-call.d.ts +2 -1
- package/dist/renderers/segments/tool-call.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/segments.d.ts +21 -3
- package/dist/types/segments.d.ts.map +1 -1
- package/dist/types/tools.d.ts +56 -0
- package/dist/types/tools.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/dialog-triggers-BqXRdHWZ.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toolRefusal as toolRefusal$1, unansweredTail, runStreamAgent } from "@aparte/engine";
|
|
2
|
-
import { A as APARTE_ICON_GLYPHS } from "./glyphs-
|
|
2
|
+
import { A as APARTE_ICON_GLYPHS } from "./glyphs-2bym5jl5.js";
|
|
3
3
|
function contentToText(content) {
|
|
4
4
|
if (typeof content === "string") return content;
|
|
5
5
|
return content.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
@@ -950,13 +950,13 @@ function stampSegmentOnInsert(segments, segment, messageId, defaults) {
|
|
|
950
950
|
...timingPatch(base, { startedAt: segmentTiming(segment)?.startedAt ?? Date.now() })
|
|
951
951
|
};
|
|
952
952
|
}
|
|
953
|
-
function adoptSegment(segments, segment, messageId,
|
|
953
|
+
function adoptSegment(segments, segment, messageId, live2 = false) {
|
|
954
954
|
return {
|
|
955
955
|
...segment,
|
|
956
956
|
messageId,
|
|
957
957
|
index: segments.length,
|
|
958
958
|
isStreaming: false,
|
|
959
|
-
...segment.type === "tool_call" && (segment.status === "awaiting-approval" || segment.status === "pending" && !
|
|
959
|
+
...segment.type === "tool_call" && (segment.status === "awaiting-approval" || segment.status === "pending" && !live2) && !segment.deferred?.ticket ? { status: "aborted" } : {}
|
|
960
960
|
};
|
|
961
961
|
}
|
|
962
962
|
const RESERVED = /* @__PURE__ */ new Set(["id", "type", "messageId", "index"]);
|
|
@@ -1030,11 +1030,11 @@ function openSegmentIds(segments) {
|
|
|
1030
1030
|
}
|
|
1031
1031
|
function adoptMessageSegments(message) {
|
|
1032
1032
|
if (!message.segments?.length) return { ...message };
|
|
1033
|
-
const
|
|
1033
|
+
const live2 = message.status === "streaming" || message.status === "pending";
|
|
1034
1034
|
return {
|
|
1035
1035
|
...message,
|
|
1036
1036
|
segments: message.segments.reduce((acc, segment) => {
|
|
1037
|
-
acc.push(adoptSegment(acc, segment, message.id,
|
|
1037
|
+
acc.push(adoptSegment(acc, segment, message.id, live2));
|
|
1038
1038
|
return acc;
|
|
1039
1039
|
}, [])
|
|
1040
1040
|
};
|
|
@@ -1070,8 +1070,8 @@ function detachConfig(el2) {
|
|
|
1070
1070
|
if (previous) notifyConfigChanged(el2, resolveConfig(el2.parentElement), previous);
|
|
1071
1071
|
}
|
|
1072
1072
|
function resolveConfig(el2) {
|
|
1073
|
-
const
|
|
1074
|
-
return
|
|
1073
|
+
const host2 = el2?.closest?.(`[${APARTE_HOST_ATTR}]`);
|
|
1074
|
+
return host2?.[CONFIG_SLOT] ?? aparteGlobalConfig;
|
|
1075
1075
|
}
|
|
1076
1076
|
let _renderConfig = null;
|
|
1077
1077
|
function runWithConfig(config, fn) {
|
|
@@ -1928,6 +1928,33 @@ function renderingVersionOf(cfg) {
|
|
|
1928
1928
|
function bumpRenderingVersion(cfg) {
|
|
1929
1929
|
renderingVersions.set(cfg, renderingVersionOf(cfg) + 1);
|
|
1930
1930
|
}
|
|
1931
|
+
const rendererListeners = /* @__PURE__ */ new Set();
|
|
1932
|
+
const pendingRendererChanges = /* @__PURE__ */ new Set();
|
|
1933
|
+
function onRenderersChange(listener) {
|
|
1934
|
+
rendererListeners.add(listener);
|
|
1935
|
+
return () => {
|
|
1936
|
+
rendererListeners.delete(listener);
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
function notifyRenderersChanged(cfg) {
|
|
1940
|
+
if (pendingRendererChanges.size === 0) {
|
|
1941
|
+
queueMicrotask(() => {
|
|
1942
|
+
const changed = [...pendingRendererChanges];
|
|
1943
|
+
pendingRendererChanges.clear();
|
|
1944
|
+
for (const config of changed) {
|
|
1945
|
+
for (const listener of [...rendererListeners]) {
|
|
1946
|
+
try {
|
|
1947
|
+
listener(config);
|
|
1948
|
+
} catch (err) {
|
|
1949
|
+
console.error("[aparte] a renderer-change listener threw", err);
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1955
|
+
pendingRendererChanges.add(cfg);
|
|
1956
|
+
}
|
|
1957
|
+
const matcherKey = (match) => match instanceof RegExp ? `re:${String(match)}` : `name:${match}`;
|
|
1931
1958
|
const ELEMENT_SHAPING = ["hidden", "open", "details", "quiet"];
|
|
1932
1959
|
function drawingOf(provider, name) {
|
|
1933
1960
|
if (!provider || !(name in provider) || name in Object.prototype) return void 0;
|
|
@@ -2039,6 +2066,11 @@ class AparteConfig {
|
|
|
2039
2066
|
_tools = /* @__PURE__ */ new Map();
|
|
2040
2067
|
// By exact name, pattern or '*' — see `tool-table.ts` for the one resolution rule.
|
|
2041
2068
|
_toolRenderers = new ToolTable();
|
|
2069
|
+
/** {@link overrideToolRenderer}'s stacks: what each matcher held below every override. */
|
|
2070
|
+
/** Per matcher: what it held below every override, then one entry per override — an object of its own, so two overrides of the same renderer are told apart. */
|
|
2071
|
+
_toolRendererOverrides = /* @__PURE__ */ new Map();
|
|
2072
|
+
/** Bumped by `reset()`: a restore function from before it must not undo what came after. */
|
|
2073
|
+
_overrideGeneration = 0;
|
|
2042
2074
|
_toolDisplays = new ToolTable();
|
|
2043
2075
|
/** Tagged blocks the stream parser recognises in the prose — see {@link registerStreamBlock}. */
|
|
2044
2076
|
_streamBlocks = /* @__PURE__ */ new Map();
|
|
@@ -2880,12 +2912,64 @@ class AparteConfig {
|
|
|
2880
2912
|
* // Custom pill for a web-search tool
|
|
2881
2913
|
* aparteGlobalConfig.registerToolRenderer('web_search', { render: (seg) => `<div class="aparte-tool-label">Searching...</div>` });
|
|
2882
2914
|
*
|
|
2915
|
+
* Calls already on screen follow: those this registration now draws are drawn again
|
|
2916
|
+
* by it (the renderer that drew them before gets its `cleanup`), and nothing else on
|
|
2917
|
+
* the page is touched.
|
|
2918
|
+
*
|
|
2883
2919
|
* @example
|
|
2884
2920
|
* // One look for every tool an MCP server brings
|
|
2885
2921
|
* aparteGlobalConfig.registerToolRenderer(/^mcp__/, { render: (seg) => myMcpCard(seg) });
|
|
2886
2922
|
*/
|
|
2887
2923
|
registerToolRenderer(match, renderer) {
|
|
2924
|
+
if (this._toolRenderers.get(match) === renderer) return;
|
|
2888
2925
|
this._toolRenderers.set(match, renderer);
|
|
2926
|
+
notifyRenderersChanged(this);
|
|
2927
|
+
}
|
|
2928
|
+
/**
|
|
2929
|
+
* Put `renderer` over whatever this matcher holds, and get back the function that takes
|
|
2930
|
+
* it off again — the registration a component makes for as long as it is mounted.
|
|
2931
|
+
*
|
|
2932
|
+
* Overrides stack per matcher. The function restores what was there before THIS
|
|
2933
|
+
* override, and taking off an override that is no longer on top changes nothing on
|
|
2934
|
+
* screen: two components declaring the same tool, the newer wins, and unmounting the
|
|
2935
|
+
* older does not take the newer's away. When the last one goes, the matcher holds what
|
|
2936
|
+
* it held before the first — another registration, or nothing. Calls on screen follow
|
|
2937
|
+
* each change, as with {@link registerToolRenderer}. The returned function is safe to
|
|
2938
|
+
* call twice.
|
|
2939
|
+
*
|
|
2940
|
+
* @example
|
|
2941
|
+
* const restore = aparteGlobalConfig.overrideToolRenderer('get_weather', weatherCard);
|
|
2942
|
+
* // …later, when the component that declared it unmounts:
|
|
2943
|
+
* restore();
|
|
2944
|
+
*/
|
|
2945
|
+
overrideToolRenderer(match, renderer) {
|
|
2946
|
+
const key = matcherKey(match);
|
|
2947
|
+
const current = this._toolRenderers.get(match);
|
|
2948
|
+
let stack = this._toolRendererOverrides.get(key);
|
|
2949
|
+
if (!stack) {
|
|
2950
|
+
stack = [{ renderer: current }];
|
|
2951
|
+
this._toolRendererOverrides.set(key, stack);
|
|
2952
|
+
} else if (stack[stack.length - 1].renderer !== current) {
|
|
2953
|
+
stack.splice(0, stack.length, { renderer: current });
|
|
2954
|
+
}
|
|
2955
|
+
const entry = { renderer };
|
|
2956
|
+
stack.push(entry);
|
|
2957
|
+
this.registerToolRenderer(match, renderer);
|
|
2958
|
+
const generation = this._overrideGeneration;
|
|
2959
|
+
let restored = false;
|
|
2960
|
+
return () => {
|
|
2961
|
+
if (restored || generation !== this._overrideGeneration) return;
|
|
2962
|
+
restored = true;
|
|
2963
|
+
const i = stack.indexOf(entry);
|
|
2964
|
+
if (i <= 0) return;
|
|
2965
|
+
const wasTop = i === stack.length - 1;
|
|
2966
|
+
stack.splice(i, 1);
|
|
2967
|
+
if (stack.length === 1 && this._toolRendererOverrides.get(key) === stack) this._toolRendererOverrides.delete(key);
|
|
2968
|
+
if (!wasTop || this._toolRenderers.get(match) !== renderer) return;
|
|
2969
|
+
const top = stack[stack.length - 1].renderer;
|
|
2970
|
+
if (top) this.registerToolRenderer(match, top);
|
|
2971
|
+
else this.unregisterToolRenderer(match);
|
|
2972
|
+
};
|
|
2889
2973
|
}
|
|
2890
2974
|
/**
|
|
2891
2975
|
* Field defaults for a segment TYPE, filled in when a segment enters a message.
|
|
@@ -2925,9 +3009,11 @@ class AparteConfig {
|
|
|
2925
3009
|
clearSegmentDefaults(type) {
|
|
2926
3010
|
this._segmentDefaults.delete(type);
|
|
2927
3011
|
}
|
|
2928
|
-
/** Unregister the renderer registered under this matcher. */
|
|
3012
|
+
/** Unregister the renderer registered under this matcher. Calls on screen it drew go back to core's row. */
|
|
2929
3013
|
unregisterToolRenderer(match) {
|
|
3014
|
+
if (this._toolRenderers.get(match) === void 0) return;
|
|
2930
3015
|
this._toolRenderers.delete(match);
|
|
3016
|
+
notifyRenderersChanged(this);
|
|
2931
3017
|
}
|
|
2932
3018
|
/** The renderer that draws a tool named `toolName` — exact, pattern or `'*'` — or undefined. */
|
|
2933
3019
|
getToolRenderer(toolName) {
|
|
@@ -3278,6 +3364,9 @@ class AparteConfig {
|
|
|
3278
3364
|
this._fetchedModels.clear();
|
|
3279
3365
|
this._tools.clear();
|
|
3280
3366
|
this._toolRenderers.clear();
|
|
3367
|
+
this._toolRendererOverrides.clear();
|
|
3368
|
+
this._overrideGeneration++;
|
|
3369
|
+
notifyRenderersChanged(this);
|
|
3281
3370
|
this._toolDisplays.clear();
|
|
3282
3371
|
this._streamBlocks.clear();
|
|
3283
3372
|
this._modelConfig = {};
|
|
@@ -3329,19 +3418,19 @@ const ONE_SHOT_PROBE = "<i>a</i>";
|
|
|
3329
3418
|
function hasOneShotMarkdownProvider() {
|
|
3330
3419
|
return contextConfig().renderMarkdown(ONE_SHOT_PROBE) !== escapeHtml(ONE_SHOT_PROBE);
|
|
3331
3420
|
}
|
|
3332
|
-
function writeStreamedMarkdown(
|
|
3421
|
+
function writeStreamedMarkdown(host2, contentEl, content, streaming) {
|
|
3333
3422
|
if (streaming) {
|
|
3334
|
-
if (
|
|
3423
|
+
if (host2._aparteSmd === void 0) {
|
|
3335
3424
|
settledFromParser.delete(contentEl);
|
|
3336
3425
|
const renderer = contextConfig().createStreamingMarkdownRenderer(contentEl);
|
|
3337
3426
|
if (renderer) {
|
|
3338
3427
|
contentEl.textContent = "";
|
|
3339
|
-
|
|
3428
|
+
host2._aparteSmd = { renderer, written: 0 };
|
|
3340
3429
|
} else {
|
|
3341
|
-
|
|
3430
|
+
host2._aparteSmd = null;
|
|
3342
3431
|
}
|
|
3343
3432
|
}
|
|
3344
|
-
const smd =
|
|
3433
|
+
const smd = host2._aparteSmd;
|
|
3345
3434
|
if (smd) {
|
|
3346
3435
|
const delta = content.slice(smd.written);
|
|
3347
3436
|
if (delta) {
|
|
@@ -3350,15 +3439,15 @@ function writeStreamedMarkdown(host, contentEl, content, streaming) {
|
|
|
3350
3439
|
}
|
|
3351
3440
|
return;
|
|
3352
3441
|
}
|
|
3353
|
-
} else if (
|
|
3354
|
-
const smd =
|
|
3442
|
+
} else if (host2._aparteSmd) {
|
|
3443
|
+
const smd = host2._aparteSmd;
|
|
3355
3444
|
const tail = content.slice(smd.written);
|
|
3356
3445
|
if (tail) {
|
|
3357
3446
|
smd.renderer.write(tail);
|
|
3358
3447
|
smd.written = content.length;
|
|
3359
3448
|
}
|
|
3360
3449
|
smd.renderer.end();
|
|
3361
|
-
|
|
3450
|
+
host2._aparteSmd = void 0;
|
|
3362
3451
|
if (!hasOneShotMarkdownProvider()) {
|
|
3363
3452
|
contentEl.innerHTML = contextConfig().sanitizeHtml(contentEl.innerHTML);
|
|
3364
3453
|
settledFromParser.set(contentEl, content);
|
|
@@ -3587,16 +3676,16 @@ function streamHighlight(element, paneSelector, content, lang, segId) {
|
|
|
3587
3676
|
if (now - (_lastHighlightAt.get(segId) ?? 0) < HIGHLIGHT_DEBOUNCE_MS) return;
|
|
3588
3677
|
markThrottle(_lastHighlightAt, segId, now);
|
|
3589
3678
|
void contextConfig(element).highlightCode(content.slice(0, cut), lang).then((html) => {
|
|
3590
|
-
const
|
|
3591
|
-
if (!
|
|
3592
|
-
if (cut <= highlightedLen(
|
|
3593
|
-
|
|
3594
|
-
const codeEl =
|
|
3679
|
+
const live2 = element.querySelector(paneSelector);
|
|
3680
|
+
if (!live2) return;
|
|
3681
|
+
if (cut <= highlightedLen(live2)) return;
|
|
3682
|
+
live2.innerHTML = html;
|
|
3683
|
+
const codeEl = live2.querySelector("code") ?? live2;
|
|
3595
3684
|
const span = document.createElement("span");
|
|
3596
3685
|
span.dataset.aparteTail = "";
|
|
3597
3686
|
span.textContent = content.slice(cut);
|
|
3598
3687
|
codeEl.appendChild(span);
|
|
3599
|
-
|
|
3688
|
+
live2.dataset.aparteHlLen = String(cut);
|
|
3600
3689
|
}).catch(() => {
|
|
3601
3690
|
});
|
|
3602
3691
|
}
|
|
@@ -3820,9 +3909,9 @@ function sameShape(a, b) {
|
|
|
3820
3909
|
}
|
|
3821
3910
|
return true;
|
|
3822
3911
|
}
|
|
3823
|
-
function patchChanges(
|
|
3824
|
-
for (let i = 0; i <
|
|
3825
|
-
const l =
|
|
3912
|
+
function patchChanges(live2, prev, next) {
|
|
3913
|
+
for (let i = 0; i < live2.childNodes.length; i++) {
|
|
3914
|
+
const l = live2.childNodes[i];
|
|
3826
3915
|
const p = prev.childNodes[i];
|
|
3827
3916
|
const n = next.childNodes[i];
|
|
3828
3917
|
if (l instanceof Element && p instanceof Element && n instanceof Element) {
|
|
@@ -3989,16 +4078,26 @@ function placeholderMarkup(segment) {
|
|
|
3989
4078
|
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>`;
|
|
3990
4079
|
}
|
|
3991
4080
|
const isPlaceholder = (element) => element.hidden && element.classList.contains("aparte-segment-tool-call") && element.childElementCount === 0;
|
|
3992
|
-
|
|
4081
|
+
const drawnBy = /* @__PURE__ */ new WeakMap();
|
|
4082
|
+
const behind = /* @__PURE__ */ new WeakMap();
|
|
4083
|
+
function toolRendererThatDrew(element) {
|
|
4084
|
+
return behind.get(element) ?? null;
|
|
4085
|
+
}
|
|
4086
|
+
function drawerOf(element, current) {
|
|
4087
|
+
const recorded = drawnBy.get(element);
|
|
4088
|
+
if (recorded) return recorded;
|
|
4089
|
+
return element.classList.contains("aparte-segment-tool-call") ? null : current;
|
|
4090
|
+
}
|
|
4091
|
+
function drawDefault(segment, behind2) {
|
|
3993
4092
|
const name = segment.toolCall?.name ?? "tool";
|
|
3994
4093
|
const status = segment.status ?? "pending";
|
|
3995
4094
|
const toolCallId = segment.toolCall?.id ?? "";
|
|
3996
4095
|
const pill = pillMarkup(segment);
|
|
3997
4096
|
const quiet = isQuiet(segment) ? " data-quiet" : "";
|
|
3998
4097
|
const toggle = contextConfig().getIcon("expand");
|
|
3999
|
-
const input =
|
|
4000
|
-
const outcome =
|
|
4001
|
-
if (
|
|
4098
|
+
const input = behind2.kind === "parts" ? describeInput(segment) : "";
|
|
4099
|
+
const outcome = behind2.kind === "parts" ? outcomeOf(segment) : null;
|
|
4100
|
+
if (behind2.kind === "none" || behind2.kind === "parts" && !input && !outcome) {
|
|
4002
4101
|
return `
|
|
4003
4102
|
<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
4103
|
</div>
|
|
@@ -4007,7 +4106,7 @@ function drawDefault(segment, behind) {
|
|
|
4007
4106
|
const cfg = contextConfig();
|
|
4008
4107
|
const copy = copyButtonMarkup("aparte-tool-copy");
|
|
4009
4108
|
const open = segment.collapsed !== void 0 ? !segment.collapsed : cfg.getToolDisplay(name)?.open === true;
|
|
4010
|
-
if (
|
|
4109
|
+
if (behind2.kind === "body") {
|
|
4011
4110
|
const tpl = document.createElement("template");
|
|
4012
4111
|
tpl.innerHTML = `
|
|
4013
4112
|
<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" : ""}>
|
|
@@ -4015,7 +4114,7 @@ function drawDefault(segment, behind) {
|
|
|
4015
4114
|
<div class="aparte-tool-detail" data-details="app"></div>
|
|
4016
4115
|
</details>`.trim();
|
|
4017
4116
|
const row = tpl.content.firstElementChild;
|
|
4018
|
-
setBody(row,
|
|
4117
|
+
setBody(row, behind2.body);
|
|
4019
4118
|
return row;
|
|
4020
4119
|
}
|
|
4021
4120
|
return `
|
|
@@ -4044,7 +4143,12 @@ const toolCallRenderer = {
|
|
|
4044
4143
|
const customRenderer = contextConfig().getToolRenderer(name);
|
|
4045
4144
|
if (customRenderer) {
|
|
4046
4145
|
injectToolRendererStyles(name, customRenderer);
|
|
4047
|
-
|
|
4146
|
+
const out = customRenderer.render(segment);
|
|
4147
|
+
if (out instanceof HTMLElement) {
|
|
4148
|
+
drawnBy.set(out, customRenderer);
|
|
4149
|
+
behind.set(out, customRenderer);
|
|
4150
|
+
}
|
|
4151
|
+
return out || placeholderMarkup(segment);
|
|
4048
4152
|
}
|
|
4049
4153
|
return drawDefault(segment, behindOf(segment));
|
|
4050
4154
|
},
|
|
@@ -4061,7 +4165,7 @@ const toolCallRenderer = {
|
|
|
4061
4165
|
relabel: (element, segment) => {
|
|
4062
4166
|
if (isPlaceholder(element)) return;
|
|
4063
4167
|
const cfg = contextConfig();
|
|
4064
|
-
const custom = cfg.getToolRenderer(segment.toolCall?.name);
|
|
4168
|
+
const custom = drawerOf(element, cfg.getToolRenderer(segment.toolCall?.name) ?? null);
|
|
4065
4169
|
if (custom) {
|
|
4066
4170
|
custom.relabel?.(element, segment);
|
|
4067
4171
|
return;
|
|
@@ -4081,8 +4185,8 @@ const toolCallRenderer = {
|
|
|
4081
4185
|
for (const button of element.querySelectorAll(".aparte-tool-copy")) relabelCopyButton(button);
|
|
4082
4186
|
const appDetail = appDetailOf(element);
|
|
4083
4187
|
if (appDetail) {
|
|
4084
|
-
const
|
|
4085
|
-
if (
|
|
4188
|
+
const behind2 = behindOf(segment);
|
|
4189
|
+
if (behind2.kind === "body") relabelBody(appDetail, behind2.body);
|
|
4086
4190
|
}
|
|
4087
4191
|
const statusEl = element.querySelector(".aparte-tool-state");
|
|
4088
4192
|
if (statusEl) statusEl.innerHTML = stateBadge(segment);
|
|
@@ -4108,9 +4212,10 @@ const toolCallRenderer = {
|
|
|
4108
4212
|
element.setAttribute("data-status", status);
|
|
4109
4213
|
return;
|
|
4110
4214
|
}
|
|
4111
|
-
const custom = contextConfig().getToolRenderer(segment.toolCall?.name);
|
|
4112
|
-
|
|
4113
|
-
|
|
4215
|
+
const custom = hidden ? null : contextConfig().getToolRenderer(segment.toolCall?.name) ?? null;
|
|
4216
|
+
const drawn = isPlaceholder(element) ? null : drawerOf(element, custom);
|
|
4217
|
+
if (drawn && drawn === custom && drawn.update && !isPlaceholder(element)) {
|
|
4218
|
+
drawn.update(element, segment);
|
|
4114
4219
|
return;
|
|
4115
4220
|
}
|
|
4116
4221
|
const rebuild = (out) => {
|
|
@@ -4119,21 +4224,22 @@ const toolCallRenderer = {
|
|
|
4119
4224
|
const rebuilt = typeof out === "string" ? tpl.content.firstElementChild : out;
|
|
4120
4225
|
if (rebuilt) {
|
|
4121
4226
|
if (!rebuilt.hasAttribute("data-segment-id")) rebuilt.setAttribute("data-segment-id", segment.id);
|
|
4227
|
+
toolCallRenderer.cleanup?.(element, segment);
|
|
4122
4228
|
element.replaceWith(rebuilt);
|
|
4123
4229
|
toolCallRenderer.setup?.(rebuilt, segment);
|
|
4124
4230
|
}
|
|
4125
4231
|
};
|
|
4126
|
-
if (custom || hidden || isPlaceholder(element)) {
|
|
4232
|
+
if (custom || drawn || hidden || isPlaceholder(element)) {
|
|
4127
4233
|
rebuild(toolCallRenderer.render(segment));
|
|
4128
4234
|
return;
|
|
4129
4235
|
}
|
|
4130
|
-
const
|
|
4131
|
-
const input =
|
|
4132
|
-
const outcome =
|
|
4133
|
-
const wantsDetail =
|
|
4236
|
+
const behind2 = behindOf(segment);
|
|
4237
|
+
const input = behind2.kind === "parts" ? describeInput(segment) : "";
|
|
4238
|
+
const outcome = behind2.kind === "parts" ? outcomeOf(segment) : null;
|
|
4239
|
+
const wantsDetail = behind2.kind === "body" || !!input || !!outcome;
|
|
4134
4240
|
const holdsAppDetail = !!appDetailOf(element);
|
|
4135
|
-
if (wantsDetail !== (element.tagName === "DETAILS") || wantsDetail &&
|
|
4136
|
-
rebuild(drawDefault(segment,
|
|
4241
|
+
if (wantsDetail !== (element.tagName === "DETAILS") || wantsDetail && behind2.kind === "body" !== holdsAppDetail) {
|
|
4242
|
+
rebuild(drawDefault(segment, behind2));
|
|
4137
4243
|
return;
|
|
4138
4244
|
}
|
|
4139
4245
|
element.setAttribute("data-status", status);
|
|
@@ -4143,8 +4249,8 @@ const toolCallRenderer = {
|
|
|
4143
4249
|
setName(element, segment);
|
|
4144
4250
|
setTarget(element, segment);
|
|
4145
4251
|
setNote(element, segment);
|
|
4146
|
-
if (
|
|
4147
|
-
setBody(element,
|
|
4252
|
+
if (behind2.kind === "body") {
|
|
4253
|
+
setBody(element, behind2.body);
|
|
4148
4254
|
return;
|
|
4149
4255
|
}
|
|
4150
4256
|
setPart(element, "input", input, "toolInput");
|
|
@@ -4152,12 +4258,31 @@ const toolCallRenderer = {
|
|
|
4152
4258
|
highlightParts(element);
|
|
4153
4259
|
},
|
|
4154
4260
|
setup: (element, segment) => {
|
|
4261
|
+
const hidden = contextConfig().isToolHidden(segment.toolCall?.name ?? "tool");
|
|
4262
|
+
const customRenderer = hidden ? void 0 : contextConfig().getToolRenderer(segment.toolCall?.name);
|
|
4263
|
+
if (customRenderer) behind.set(element, customRenderer);
|
|
4155
4264
|
if (isPlaceholder(element)) return;
|
|
4156
4265
|
wireParts(element);
|
|
4157
4266
|
highlightParts(element);
|
|
4158
|
-
|
|
4267
|
+
if (customRenderer) drawnBy.set(element, customRenderer);
|
|
4159
4268
|
customRenderer?.setup?.(element, segment);
|
|
4160
4269
|
},
|
|
4270
|
+
/**
|
|
4271
|
+
* The row leaves for good: the registered renderer that drew it, if any, cleans up. A
|
|
4272
|
+
* cleanup that throws is reported and goes no further: the row is replaced or removed
|
|
4273
|
+
* all the same, and the stream that caused it is not interrupted.
|
|
4274
|
+
*/
|
|
4275
|
+
cleanup: (element, segment) => {
|
|
4276
|
+
behind.delete(element);
|
|
4277
|
+
const custom = drawnBy.get(element);
|
|
4278
|
+
if (!custom) return;
|
|
4279
|
+
drawnBy.delete(element);
|
|
4280
|
+
try {
|
|
4281
|
+
custom.cleanup?.(element, segment);
|
|
4282
|
+
} catch (err) {
|
|
4283
|
+
console.error("[aparte] a tool renderer's cleanup threw", err);
|
|
4284
|
+
}
|
|
4285
|
+
},
|
|
4161
4286
|
// CSS lives in styles/segment/ — see that folder for why a
|
|
4162
4287
|
// built-in's rules belong there. `getStyles` stays for a CONSUMER's renderer, which
|
|
4163
4288
|
// has no other way onto the page.
|
|
@@ -4181,8 +4306,51 @@ function effectiveRenderers(config) {
|
|
|
4181
4306
|
}
|
|
4182
4307
|
let styleElement = null;
|
|
4183
4308
|
function registerSegmentRenderer(renderer, config = contextConfig()) {
|
|
4184
|
-
registryFor(config)
|
|
4309
|
+
const reg = registryFor(config);
|
|
4310
|
+
if (reg.renderers.get(renderer.type) === renderer) return;
|
|
4311
|
+
reg.renderers.set(renderer.type, renderer);
|
|
4185
4312
|
injectRendererStyles(config);
|
|
4313
|
+
notifyRenderersChanged(config);
|
|
4314
|
+
}
|
|
4315
|
+
const overrideStacks = /* @__PURE__ */ new WeakMap();
|
|
4316
|
+
function overrideSegmentRenderer(renderer, config = contextConfig()) {
|
|
4317
|
+
const type = renderer.type;
|
|
4318
|
+
const reg = registryFor(config);
|
|
4319
|
+
let byType = overrideStacks.get(config);
|
|
4320
|
+
if (!byType) {
|
|
4321
|
+
byType = /* @__PURE__ */ new Map();
|
|
4322
|
+
overrideStacks.set(config, byType);
|
|
4323
|
+
}
|
|
4324
|
+
const current = reg.renderers.get(type);
|
|
4325
|
+
let stack = byType.get(type);
|
|
4326
|
+
if (!stack) {
|
|
4327
|
+
stack = [{ renderer: current }];
|
|
4328
|
+
byType.set(type, stack);
|
|
4329
|
+
} else if (stack[stack.length - 1].renderer !== current) stack.splice(0, stack.length, { renderer: current });
|
|
4330
|
+
const entry = { renderer };
|
|
4331
|
+
stack.push(entry);
|
|
4332
|
+
registerSegmentRenderer(renderer, config);
|
|
4333
|
+
let restored = false;
|
|
4334
|
+
return () => {
|
|
4335
|
+
if (restored) return;
|
|
4336
|
+
restored = true;
|
|
4337
|
+
const i = stack.indexOf(entry);
|
|
4338
|
+
if (i <= 0) return;
|
|
4339
|
+
const wasTop = i === stack.length - 1;
|
|
4340
|
+
stack.splice(i, 1);
|
|
4341
|
+
if (stack.length === 1 && byType.get(type) === stack) byType.delete(type);
|
|
4342
|
+
if (!wasTop || reg.renderers.get(type) !== renderer) return;
|
|
4343
|
+
const top = stack[stack.length - 1].renderer;
|
|
4344
|
+
if (top) {
|
|
4345
|
+
registerSegmentRenderer(top, config);
|
|
4346
|
+
return;
|
|
4347
|
+
}
|
|
4348
|
+
unregisterSegmentRenderer(type, config);
|
|
4349
|
+
if (!effectiveRenderers(config).has(type) && reg.defaultsInstalled && !reg.defaultsDeclined) {
|
|
4350
|
+
const builtIn = DEFAULT_RENDERERS.find((r) => r.type === type);
|
|
4351
|
+
if (builtIn) registerSegmentRenderer(builtIn, config);
|
|
4352
|
+
}
|
|
4353
|
+
};
|
|
4186
4354
|
}
|
|
4187
4355
|
function declineDefaultRenderers(config = contextConfig()) {
|
|
4188
4356
|
registryFor(config).defaultsDeclined = true;
|
|
@@ -4197,7 +4365,10 @@ function installDefaultRenderersOnce(config = contextConfig()) {
|
|
|
4197
4365
|
injectRendererStyles(config);
|
|
4198
4366
|
}
|
|
4199
4367
|
function unregisterSegmentRenderer(type, config = contextConfig()) {
|
|
4200
|
-
registryFor(config)
|
|
4368
|
+
const reg = registryFor(config);
|
|
4369
|
+
if (!reg.renderers.has(type)) return;
|
|
4370
|
+
reg.renderers.delete(type);
|
|
4371
|
+
notifyRenderersChanged(config);
|
|
4201
4372
|
}
|
|
4202
4373
|
function getSegmentRenderer(type, config = contextConfig()) {
|
|
4203
4374
|
return effectiveRenderers(config).get(type);
|
|
@@ -4257,6 +4428,71 @@ const DEFAULT_RENDERERS = [
|
|
|
4257
4428
|
errorRenderer,
|
|
4258
4429
|
toolCallRenderer
|
|
4259
4430
|
];
|
|
4431
|
+
const mountedRenderers = /* @__PURE__ */ new WeakSet();
|
|
4432
|
+
function isMountedRenderer(renderer) {
|
|
4433
|
+
return !!renderer && mountedRenderers.has(renderer);
|
|
4434
|
+
}
|
|
4435
|
+
function toToolCallView(segment) {
|
|
4436
|
+
return {
|
|
4437
|
+
id: segment.toolCall?.id ?? segment.id,
|
|
4438
|
+
name: segment.toolCall?.name ?? "tool",
|
|
4439
|
+
input: segment.toolCall?.input,
|
|
4440
|
+
status: segment.status ?? "pending",
|
|
4441
|
+
result: segment.result,
|
|
4442
|
+
structuredResult: segment.structuredResult,
|
|
4443
|
+
deferred: segment.deferred,
|
|
4444
|
+
refusal: segment.refusal,
|
|
4445
|
+
abortCause: segment.abortCause,
|
|
4446
|
+
segment
|
|
4447
|
+
};
|
|
4448
|
+
}
|
|
4449
|
+
function host(className, segmentId) {
|
|
4450
|
+
const el2 = document.createElement("div");
|
|
4451
|
+
el2.className = className;
|
|
4452
|
+
el2.setAttribute("data-segment-id", segmentId);
|
|
4453
|
+
return el2;
|
|
4454
|
+
}
|
|
4455
|
+
function defineMountedToolRenderer(mount) {
|
|
4456
|
+
const mounted = /* @__PURE__ */ new WeakMap();
|
|
4457
|
+
const renderer = {
|
|
4458
|
+
render: (segment) => host("aparte-tool-ui", segment.id),
|
|
4459
|
+
setup: (el2, segment) => {
|
|
4460
|
+
if (!mounted.has(el2)) mounted.set(el2, mount(el2, toToolCallView(segment)));
|
|
4461
|
+
},
|
|
4462
|
+
update: (el2, segment) => {
|
|
4463
|
+
mounted.get(el2)?.update(toToolCallView(segment));
|
|
4464
|
+
},
|
|
4465
|
+
cleanup: (el2) => {
|
|
4466
|
+
const view = mounted.get(el2);
|
|
4467
|
+
if (!view) return;
|
|
4468
|
+
mounted.delete(el2);
|
|
4469
|
+
view.destroy();
|
|
4470
|
+
}
|
|
4471
|
+
};
|
|
4472
|
+
mountedRenderers.add(renderer);
|
|
4473
|
+
return renderer;
|
|
4474
|
+
}
|
|
4475
|
+
function defineMountedSegmentRenderer(type, mount) {
|
|
4476
|
+
const mounted = /* @__PURE__ */ new WeakMap();
|
|
4477
|
+
const renderer = {
|
|
4478
|
+
type,
|
|
4479
|
+
render: (segment) => host("aparte-segment-ui", segment.id),
|
|
4480
|
+
setup: (el2, segment) => {
|
|
4481
|
+
if (!mounted.has(el2)) mounted.set(el2, mount(el2, segment));
|
|
4482
|
+
},
|
|
4483
|
+
update: (el2, segment) => {
|
|
4484
|
+
mounted.get(el2)?.update(segment);
|
|
4485
|
+
},
|
|
4486
|
+
cleanup: (el2) => {
|
|
4487
|
+
const view = mounted.get(el2);
|
|
4488
|
+
if (!view) return;
|
|
4489
|
+
mounted.delete(el2);
|
|
4490
|
+
view.destroy();
|
|
4491
|
+
}
|
|
4492
|
+
};
|
|
4493
|
+
mountedRenderers.add(renderer);
|
|
4494
|
+
return renderer;
|
|
4495
|
+
}
|
|
4260
4496
|
function populateBubbleFromMessage(bubble, message, siblingInfo) {
|
|
4261
4497
|
if (message.segments && message.segments.length > 0) {
|
|
4262
4498
|
const existing = bubble.getSegments?.() ?? [];
|
|
@@ -4902,7 +5138,7 @@ class AparteConversationController {
|
|
|
4902
5138
|
* Attach event listeners to the binding host. Returns an unbind function.
|
|
4903
5139
|
*/
|
|
4904
5140
|
bind() {
|
|
4905
|
-
const
|
|
5141
|
+
const host2 = this._binding.host;
|
|
4906
5142
|
this._onSendCapture = (e) => {
|
|
4907
5143
|
const evt = e;
|
|
4908
5144
|
const targetId = evt.detail?.targetId;
|
|
@@ -4921,13 +5157,13 @@ class AparteConversationController {
|
|
|
4921
5157
|
evt.detail.echoed = true;
|
|
4922
5158
|
void this._ensureConversationAndPersist(userMsg);
|
|
4923
5159
|
};
|
|
4924
|
-
|
|
5160
|
+
host2.addEventListener("aparte-send", this._onSendCapture, { capture: true });
|
|
4925
5161
|
this._onPathChanged = () => {
|
|
4926
5162
|
if (!this._isLoadingConversation) {
|
|
4927
5163
|
this._persistActive();
|
|
4928
5164
|
}
|
|
4929
5165
|
};
|
|
4930
|
-
|
|
5166
|
+
host2.addEventListener("aparte-path-changed", this._onPathChanged);
|
|
4931
5167
|
this._onMessageStart = (e) => {
|
|
4932
5168
|
this._isStreaming = true;
|
|
4933
5169
|
this._turnMessage = e.detail?.messageId ?? null;
|
|
@@ -4958,12 +5194,12 @@ class AparteConversationController {
|
|
|
4958
5194
|
this._onMessageResumed = (e) => {
|
|
4959
5195
|
if (this._ofThisTurn(e)) this._setTurn("running");
|
|
4960
5196
|
};
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
5197
|
+
host2.addEventListener("aparte-message-start", this._onMessageStart);
|
|
5198
|
+
host2.addEventListener("aparte-message-done", this._onMessageDone);
|
|
5199
|
+
host2.addEventListener("aparte-message-error", this._onMessageError);
|
|
5200
|
+
host2.addEventListener("aparte-message-aborted", this._onMessageAborted);
|
|
5201
|
+
host2.addEventListener("aparte-message-paused", this._onMessagePaused);
|
|
5202
|
+
host2.addEventListener("aparte-message-resumed", this._onMessageResumed);
|
|
4967
5203
|
this._onSelectConversation = (e) => {
|
|
4968
5204
|
const evt = e;
|
|
4969
5205
|
const targetId = evt.detail?.targetId;
|
|
@@ -4995,37 +5231,37 @@ class AparteConversationController {
|
|
|
4995
5231
|
this._turnMessage = null;
|
|
4996
5232
|
this._stopHydrationRetry?.();
|
|
4997
5233
|
this._stopHydrationRetry = null;
|
|
4998
|
-
const
|
|
5234
|
+
const host2 = this._binding.host;
|
|
4999
5235
|
if (this._onSendCapture) {
|
|
5000
|
-
|
|
5236
|
+
host2.removeEventListener("aparte-send", this._onSendCapture, { capture: true });
|
|
5001
5237
|
this._onSendCapture = null;
|
|
5002
5238
|
}
|
|
5003
5239
|
if (this._onPathChanged) {
|
|
5004
|
-
|
|
5240
|
+
host2.removeEventListener("aparte-path-changed", this._onPathChanged);
|
|
5005
5241
|
this._onPathChanged = null;
|
|
5006
5242
|
}
|
|
5007
5243
|
if (this._onMessageStart) {
|
|
5008
|
-
|
|
5244
|
+
host2.removeEventListener("aparte-message-start", this._onMessageStart);
|
|
5009
5245
|
this._onMessageStart = null;
|
|
5010
5246
|
}
|
|
5011
5247
|
if (this._onMessageDone) {
|
|
5012
|
-
|
|
5248
|
+
host2.removeEventListener("aparte-message-done", this._onMessageDone);
|
|
5013
5249
|
this._onMessageDone = null;
|
|
5014
5250
|
}
|
|
5015
5251
|
if (this._onMessageError) {
|
|
5016
|
-
|
|
5252
|
+
host2.removeEventListener("aparte-message-error", this._onMessageError);
|
|
5017
5253
|
this._onMessageError = null;
|
|
5018
5254
|
}
|
|
5019
5255
|
if (this._onMessageAborted) {
|
|
5020
|
-
|
|
5256
|
+
host2.removeEventListener("aparte-message-aborted", this._onMessageAborted);
|
|
5021
5257
|
this._onMessageAborted = null;
|
|
5022
5258
|
}
|
|
5023
5259
|
if (this._onMessagePaused) {
|
|
5024
|
-
|
|
5260
|
+
host2.removeEventListener("aparte-message-paused", this._onMessagePaused);
|
|
5025
5261
|
this._onMessagePaused = null;
|
|
5026
5262
|
}
|
|
5027
5263
|
if (this._onMessageResumed) {
|
|
5028
|
-
|
|
5264
|
+
host2.removeEventListener("aparte-message-resumed", this._onMessageResumed);
|
|
5029
5265
|
this._onMessageResumed = null;
|
|
5030
5266
|
}
|
|
5031
5267
|
if (this._onCompactDone && typeof window !== "undefined") {
|
|
@@ -5302,6 +5538,12 @@ class AparteChatHost {
|
|
|
5302
5538
|
_tokenBuffer = null;
|
|
5303
5539
|
/** Handle of the scheduled coalesced sync, or null when none is pending. */
|
|
5304
5540
|
_flushHandle = null;
|
|
5541
|
+
/**
|
|
5542
|
+
* Lists reported through `onMessagesChange` that the parent has not handed back yet, oldest
|
|
5543
|
+
* first — what {@link takeEcho} recognises. Bounded: a parent that never hands a list back
|
|
5544
|
+
* (an uncontrolled chat) must not make it grow for the life of the page.
|
|
5545
|
+
*/
|
|
5546
|
+
_pendingEchoes = [];
|
|
5305
5547
|
_conversationId = null;
|
|
5306
5548
|
_controller;
|
|
5307
5549
|
_teardown = [];
|
|
@@ -5311,6 +5553,34 @@ class AparteChatHost {
|
|
|
5311
5553
|
this.options = options;
|
|
5312
5554
|
this._conversationId = options.conversationId ?? null;
|
|
5313
5555
|
}
|
|
5556
|
+
/** Every report goes through here, so {@link takeEcho} knows what the parent may hand back. */
|
|
5557
|
+
_report(next) {
|
|
5558
|
+
this._pendingEchoes.push(next);
|
|
5559
|
+
if (this._pendingEchoes.length > 64) this._pendingEchoes.shift();
|
|
5560
|
+
this.binding.onMessagesChange?.(next);
|
|
5561
|
+
}
|
|
5562
|
+
/**
|
|
5563
|
+
* Whether a list the parent hands back is this host's own report coming back — the echo of
|
|
5564
|
+
* `onMessagesChange` through a two-way binding (`bind:messages`, `v-model:messages`,
|
|
5565
|
+
* `[(messages)]`, a controlled React prop). A wrapper asks before applying the list it is
|
|
5566
|
+
* given, because applying an echo rolls back what the host did since without reporting (an
|
|
5567
|
+
* optimistic append).
|
|
5568
|
+
*
|
|
5569
|
+
* True for a list reported and not handed back yet, however late it lands — a parent whose
|
|
5570
|
+
* render comes after the host's next write hands back an EARLIER report — and that list and
|
|
5571
|
+
* every older one are taken. False for any other list, the parent's own word, which clears
|
|
5572
|
+
* them: a list the parent restores later (a reopened conversation, an undo) is applied,
|
|
5573
|
+
* where remembering every list ever reported swallowed it.
|
|
5574
|
+
*/
|
|
5575
|
+
takeEcho(list) {
|
|
5576
|
+
const i = this._pendingEchoes.indexOf(list);
|
|
5577
|
+
if (i < 0) {
|
|
5578
|
+
this._pendingEchoes.length = 0;
|
|
5579
|
+
return false;
|
|
5580
|
+
}
|
|
5581
|
+
this._pendingEchoes.splice(0, i + 1);
|
|
5582
|
+
return true;
|
|
5583
|
+
}
|
|
5314
5584
|
// ── lifecycle ──────────────────────────────────────────────────────────
|
|
5315
5585
|
/**
|
|
5316
5586
|
* Install the host-method surface + event listeners and create the
|
|
@@ -5320,19 +5590,19 @@ class AparteChatHost {
|
|
|
5320
5590
|
bind() {
|
|
5321
5591
|
if (this._bound) return () => this.unbind();
|
|
5322
5592
|
this._bound = true;
|
|
5323
|
-
const
|
|
5324
|
-
if (!
|
|
5593
|
+
const host2 = this.binding.host;
|
|
5594
|
+
if (!host2.id) host2.id = this.binding.hostId;
|
|
5325
5595
|
if (this.options.config) attachConfig(this.binding.host, this.options.config);
|
|
5326
5596
|
const vp = this._vp();
|
|
5327
5597
|
vp?.setFrameworkManagedDOM?.(true);
|
|
5328
5598
|
if (this.options.layoutTransitionMs && this.options.layoutTransitionMs > 0) {
|
|
5329
5599
|
vp?.configure?.({ layoutTransitionMs: this.options.layoutTransitionMs });
|
|
5330
5600
|
}
|
|
5331
|
-
this._installHostMethods(
|
|
5332
|
-
this._installLifecycleListeners(
|
|
5333
|
-
this._teardown.push(gateGlide(
|
|
5601
|
+
this._installHostMethods(host2);
|
|
5602
|
+
this._installLifecycleListeners(host2);
|
|
5603
|
+
this._teardown.push(gateGlide(host2));
|
|
5334
5604
|
this._installViewportListeners();
|
|
5335
|
-
this._createController(
|
|
5605
|
+
this._createController(host2);
|
|
5336
5606
|
return () => this.unbind();
|
|
5337
5607
|
}
|
|
5338
5608
|
unbind() {
|
|
@@ -5378,10 +5648,10 @@ class AparteChatHost {
|
|
|
5378
5648
|
return this._controller?.setConversationId(id) ?? Promise.resolve();
|
|
5379
5649
|
}
|
|
5380
5650
|
_unbindController;
|
|
5381
|
-
_createController(
|
|
5651
|
+
_createController(host2) {
|
|
5382
5652
|
const convBinding = {
|
|
5383
5653
|
hostId: this.binding.hostId,
|
|
5384
|
-
host,
|
|
5654
|
+
host: host2,
|
|
5385
5655
|
// Controller-driven flushes mirror AparteConversationManager state, not
|
|
5386
5656
|
// user intent — deliberately NOT emitted as `messagesChange` to
|
|
5387
5657
|
// avoid a feedback loop with hosts using a two-way `messages` input.
|
|
@@ -5488,7 +5758,7 @@ class AparteChatHost {
|
|
|
5488
5758
|
const merged = { ...next[index], ...updates };
|
|
5489
5759
|
next[index] = merged;
|
|
5490
5760
|
this.binding.setMessages(next);
|
|
5491
|
-
this.
|
|
5761
|
+
this._report(next);
|
|
5492
5762
|
if (updates.status) {
|
|
5493
5763
|
this._bubbleById(messageId)?.updateMessage?.({ status: updates.status });
|
|
5494
5764
|
}
|
|
@@ -5508,7 +5778,7 @@ class AparteChatHost {
|
|
|
5508
5778
|
const newContent = options?.append ? (last.content || "") + content : content;
|
|
5509
5779
|
const next = [...msgs.slice(0, -1), { ...last, content: newContent }];
|
|
5510
5780
|
this.binding.setMessages(next);
|
|
5511
|
-
this.
|
|
5781
|
+
this._report(next);
|
|
5512
5782
|
}
|
|
5513
5783
|
/** Add a segment to the last message (immediate bubble + state sync). */
|
|
5514
5784
|
addSegment(segment) {
|
|
@@ -5533,7 +5803,7 @@ class AparteChatHost {
|
|
|
5533
5803
|
const segments = [...last.segments || [], stamped];
|
|
5534
5804
|
const next = [...msgs.slice(0, -1), { ...last, segments }];
|
|
5535
5805
|
this.binding.setMessages(next);
|
|
5536
|
-
this.
|
|
5806
|
+
this._report(next);
|
|
5537
5807
|
}
|
|
5538
5808
|
/** Update a segment in the last message in place. */
|
|
5539
5809
|
updateSegment(segmentId, updates) {
|
|
@@ -5550,7 +5820,7 @@ class AparteChatHost {
|
|
|
5550
5820
|
);
|
|
5551
5821
|
const next = [...msgs.slice(0, -1), { ...last, segments }];
|
|
5552
5822
|
this.binding.setMessages(next);
|
|
5553
|
-
this.
|
|
5823
|
+
this._report(next);
|
|
5554
5824
|
}
|
|
5555
5825
|
/** Remove a transient segment (a status row the host added itself). */
|
|
5556
5826
|
removeSegment(segmentId) {
|
|
@@ -5564,7 +5834,7 @@ class AparteChatHost {
|
|
|
5564
5834
|
renumberSegments(segments);
|
|
5565
5835
|
const next = [...msgs.slice(0, -1), { ...last, segments }];
|
|
5566
5836
|
this.binding.setMessages(next);
|
|
5567
|
-
this.
|
|
5837
|
+
this._report(next);
|
|
5568
5838
|
}
|
|
5569
5839
|
/**
|
|
5570
5840
|
* Append text to a segment's content in the last message — the streaming path
|
|
@@ -5620,8 +5890,8 @@ class AparteChatHost {
|
|
|
5620
5890
|
this._flushHandle = null;
|
|
5621
5891
|
}
|
|
5622
5892
|
const tokens = this._tokenBuffer;
|
|
5623
|
-
const
|
|
5624
|
-
if (!tokens && !
|
|
5893
|
+
const pending2 = this._segmentBuffer.size > 0 ? new Map(this._segmentBuffer) : null;
|
|
5894
|
+
if (!tokens && !pending2) return;
|
|
5625
5895
|
this._tokenBuffer = null;
|
|
5626
5896
|
this._segmentBuffer.clear();
|
|
5627
5897
|
let msgs = this.binding.getMessages();
|
|
@@ -5635,11 +5905,11 @@ class AparteChatHost {
|
|
|
5635
5905
|
changed = true;
|
|
5636
5906
|
}
|
|
5637
5907
|
}
|
|
5638
|
-
if (
|
|
5908
|
+
if (pending2) {
|
|
5639
5909
|
const last = msgs[msgs.length - 1];
|
|
5640
5910
|
if (last?.segments) {
|
|
5641
5911
|
const segments = last.segments.map((s) => {
|
|
5642
|
-
const buffered =
|
|
5912
|
+
const buffered = pending2.get(s.id);
|
|
5643
5913
|
if (buffered === void 0 || !("content" in s)) return s;
|
|
5644
5914
|
return {
|
|
5645
5915
|
...s,
|
|
@@ -5653,7 +5923,7 @@ class AparteChatHost {
|
|
|
5653
5923
|
}
|
|
5654
5924
|
if (!changed) return;
|
|
5655
5925
|
this.binding.setMessages(msgs);
|
|
5656
|
-
this.
|
|
5926
|
+
this._report(msgs);
|
|
5657
5927
|
}
|
|
5658
5928
|
/** Read the current message list. */
|
|
5659
5929
|
getMessages() {
|
|
@@ -5686,7 +5956,7 @@ class AparteChatHost {
|
|
|
5686
5956
|
const idx = msgs.findIndex((m) => m.id === messageId);
|
|
5687
5957
|
const next = idx >= 0 ? msgs.slice(0, idx) : msgs;
|
|
5688
5958
|
this.binding.setMessages(next);
|
|
5689
|
-
this.
|
|
5959
|
+
this._report(next);
|
|
5690
5960
|
}
|
|
5691
5961
|
/** Keep up to and including a user message, drop later responses (retry). */
|
|
5692
5962
|
truncateResponsesAfter(userMessageId) {
|
|
@@ -5695,7 +5965,7 @@ class AparteChatHost {
|
|
|
5695
5965
|
const idx = msgs.findIndex((m) => m.id === userMessageId);
|
|
5696
5966
|
const next = idx >= 0 ? msgs.slice(0, idx + 1) : msgs;
|
|
5697
5967
|
this.binding.setMessages(next);
|
|
5698
|
-
this.
|
|
5968
|
+
this._report(next);
|
|
5699
5969
|
}
|
|
5700
5970
|
// ── manual token streaming (agnostic core of injectTokenStream) ─────────
|
|
5701
5971
|
/**
|
|
@@ -5723,14 +5993,14 @@ class AparteChatHost {
|
|
|
5723
5993
|
}
|
|
5724
5994
|
ac.signal.addEventListener("abort", () => resolve("aborted"), { once: true });
|
|
5725
5995
|
});
|
|
5726
|
-
const { host, hostId } = this.binding;
|
|
5996
|
+
const { host: host2, hostId } = this.binding;
|
|
5727
5997
|
const onAbort = (e) => {
|
|
5728
5998
|
const target = e.detail?.targetId;
|
|
5729
5999
|
if ((!target || target === hostId) && this._streamAbort === ac) this.stopTokenStream();
|
|
5730
6000
|
};
|
|
5731
6001
|
window.addEventListener("aparte-abort", onAbort);
|
|
5732
6002
|
const replaced = () => this._streamAbort !== void 0 && this._streamAbort !== ac;
|
|
5733
|
-
dispatchLifecycleEvent(
|
|
6003
|
+
dispatchLifecycleEvent(host2, "aparte-message-start", { messageId, role: "assistant" }, hostId);
|
|
5734
6004
|
try {
|
|
5735
6005
|
for (; ; ) {
|
|
5736
6006
|
const res = await Promise.race([iterator.next(), aborted]);
|
|
@@ -5743,7 +6013,7 @@ class AparteChatHost {
|
|
|
5743
6013
|
if (!replaced()) {
|
|
5744
6014
|
this._setStreamingId(null);
|
|
5745
6015
|
dispatchLifecycleEvent(
|
|
5746
|
-
|
|
6016
|
+
host2,
|
|
5747
6017
|
ac.signal.aborted ? "aparte-message-aborted" : "aparte-message-done",
|
|
5748
6018
|
ac.signal.aborted ? { messageId } : { messageId, role: "assistant" },
|
|
5749
6019
|
hostId
|
|
@@ -5753,7 +6023,7 @@ class AparteChatHost {
|
|
|
5753
6023
|
this._flushStreamState();
|
|
5754
6024
|
if (!replaced()) {
|
|
5755
6025
|
this._setStreamingId(null);
|
|
5756
|
-
dispatchLifecycleEvent(
|
|
6026
|
+
dispatchLifecycleEvent(host2, "aparte-message-error", { messageId, error: err }, hostId);
|
|
5757
6027
|
}
|
|
5758
6028
|
throw err;
|
|
5759
6029
|
} finally {
|
|
@@ -5911,22 +6181,22 @@ class AparteChatHost {
|
|
|
5911
6181
|
const all = vp.querySelectorAll("aparte-chat-bubble");
|
|
5912
6182
|
return all.length ? all[all.length - 1] : null;
|
|
5913
6183
|
}
|
|
5914
|
-
_installHostMethods(
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
}
|
|
5929
|
-
_installLifecycleListeners(
|
|
6184
|
+
_installHostMethods(host2) {
|
|
6185
|
+
host2["appendMessage"] = (m) => this.appendMessage(m);
|
|
6186
|
+
host2["updateMessage"] = (id, u) => this.updateMessage(id, u);
|
|
6187
|
+
host2["updateLastMessage"] = (c, o) => this.updateLastMessage(c, o);
|
|
6188
|
+
host2["addSegment"] = (s) => this.addSegment(s);
|
|
6189
|
+
host2["updateSegment"] = (id, u) => this.updateSegment(id, u);
|
|
6190
|
+
host2["removeSegment"] = (id) => this.removeSegment(id);
|
|
6191
|
+
host2["appendToSegment"] = (id, c) => this.appendToSegment(id, c);
|
|
6192
|
+
host2["getMessages"] = () => this.getMessages();
|
|
6193
|
+
host2["addBranch"] = (id) => this.addBranch(id);
|
|
6194
|
+
host2["addSiblingOf"] = (id, m) => this.addSiblingOf(id, m);
|
|
6195
|
+
host2["truncateFrom"] = (id) => this.truncateFrom(id);
|
|
6196
|
+
host2["truncateResponsesAfter"] = (id) => this.truncateResponsesAfter(id);
|
|
6197
|
+
host2["clearAll"] = (options) => this.clearMessages(options);
|
|
6198
|
+
}
|
|
6199
|
+
_installLifecycleListeners(host2) {
|
|
5930
6200
|
const onStart = (e) => {
|
|
5931
6201
|
const d = e?.detail;
|
|
5932
6202
|
if (d?.messageId) this._setStreamingId(d.messageId);
|
|
@@ -5946,7 +6216,7 @@ class AparteChatHost {
|
|
|
5946
6216
|
(m) => m.id === d.messageId ? { ...m, usage: d.usage } : m
|
|
5947
6217
|
);
|
|
5948
6218
|
this.binding.setMessages(next);
|
|
5949
|
-
this.
|
|
6219
|
+
this._report(next);
|
|
5950
6220
|
this._bubbleById(d.messageId)?.setUsage?.(d.usage);
|
|
5951
6221
|
};
|
|
5952
6222
|
const onEnd = (e) => {
|
|
@@ -5954,15 +6224,15 @@ class AparteChatHost {
|
|
|
5954
6224
|
this.binding.onTypingChange?.(false);
|
|
5955
6225
|
this._setStreamingId(null);
|
|
5956
6226
|
};
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
6227
|
+
host2.addEventListener("aparte-message-start", onStart);
|
|
6228
|
+
host2.addEventListener("aparte-message-done", onDone);
|
|
6229
|
+
host2.addEventListener("aparte-message-error", onEnd);
|
|
6230
|
+
host2.addEventListener("aparte-message-aborted", onEnd);
|
|
5961
6231
|
this._teardown.push(() => {
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
6232
|
+
host2.removeEventListener("aparte-message-start", onStart);
|
|
6233
|
+
host2.removeEventListener("aparte-message-done", onDone);
|
|
6234
|
+
host2.removeEventListener("aparte-message-error", onEnd);
|
|
6235
|
+
host2.removeEventListener("aparte-message-aborted", onEnd);
|
|
5966
6236
|
});
|
|
5967
6237
|
}
|
|
5968
6238
|
_installViewportListeners() {
|
|
@@ -5979,7 +6249,7 @@ class AparteChatHost {
|
|
|
5979
6249
|
return old?.usage !== void 0 ? { ...m, usage: old.usage } : m;
|
|
5980
6250
|
});
|
|
5981
6251
|
this.binding.setMessages(merged);
|
|
5982
|
-
this.
|
|
6252
|
+
this._report(merged);
|
|
5983
6253
|
if (evt.detail.siblings.some((s) => s.count > 1)) {
|
|
5984
6254
|
this._pendingSiblings = evt.detail.siblings;
|
|
5985
6255
|
this.binding.afterRender(() => this._applyPendingSiblings());
|
|
@@ -6600,6 +6870,9 @@ function remoteProvider(id) {
|
|
|
6600
6870
|
}
|
|
6601
6871
|
class AparteClient {
|
|
6602
6872
|
_boundHandler = null;
|
|
6873
|
+
/** Between `start()` and `stop()`: the listeners are on `window`. The send handler alone is
|
|
6874
|
+
* not the sign — the constructor prepares it without listening. */
|
|
6875
|
+
_listening = false;
|
|
6603
6876
|
_boundAbortHandler = null;
|
|
6604
6877
|
_boundLoadedHandler = null;
|
|
6605
6878
|
_boundRetryHandler = null;
|
|
@@ -6734,11 +7007,12 @@ class AparteClient {
|
|
|
6734
7007
|
if (!this._boundLoadedHandler) {
|
|
6735
7008
|
this._boundLoadedHandler = (e) => {
|
|
6736
7009
|
if (!this._isForThisInstance(e)) return;
|
|
6737
|
-
const
|
|
6738
|
-
void this.resumeDeferred(
|
|
7010
|
+
const host2 = e.target instanceof HTMLElement ? e.target : void 0;
|
|
7011
|
+
void this.resumeDeferred(host2 ?? e.detail?.targetId);
|
|
6739
7012
|
};
|
|
6740
7013
|
}
|
|
6741
7014
|
window.addEventListener("aparte-conversation-loaded", this._boundLoadedHandler);
|
|
7015
|
+
this._listening = true;
|
|
6742
7016
|
}
|
|
6743
7017
|
/**
|
|
6744
7018
|
* Stop answering: abort the reply in flight, take this client's `keyResolver` off the
|
|
@@ -6748,7 +7022,8 @@ class AparteClient {
|
|
|
6748
7022
|
this.abort();
|
|
6749
7023
|
this._releaseKeyResolver?.();
|
|
6750
7024
|
this._releaseKeyResolver = null;
|
|
6751
|
-
if (!this._boundHandler) return;
|
|
7025
|
+
if (!this._listening || !this._boundHandler) return;
|
|
7026
|
+
this._listening = false;
|
|
6752
7027
|
window.removeEventListener("aparte-send", this._boundHandler);
|
|
6753
7028
|
this._boundHandler = null;
|
|
6754
7029
|
if (this._boundAbortHandler) {
|
|
@@ -7681,15 +7956,15 @@ ${content}
|
|
|
7681
7956
|
* nobody answered — the turn was stopped, or the channel gave up — and there is no
|
|
7682
7957
|
* resume. A channel that CRASHES fails the turn, as it does for a run in the page.
|
|
7683
7958
|
*/
|
|
7684
|
-
async _answerDeferred(targetElement,
|
|
7959
|
+
async _answerDeferred(targetElement, pending2, signal, rowEvents, approvedBefore = /* @__PURE__ */ new Set(), approvedNow = /* @__PURE__ */ new Set()) {
|
|
7685
7960
|
const outcomes = {};
|
|
7686
7961
|
const resolver = this._approvalResolverFor(targetElement, true);
|
|
7687
7962
|
const refuseTheRest = (after) => {
|
|
7688
|
-
for (const rest of
|
|
7963
|
+
for (const rest of pending2.slice(after + 1)) {
|
|
7689
7964
|
outcomes[rest.toolCallId] = { kind: "decision", approved: false, reason: NOT_RUN_AFTER_A_REFUSAL, by: "earlier-refusal" };
|
|
7690
7965
|
}
|
|
7691
7966
|
};
|
|
7692
|
-
for (const [index, p] of
|
|
7967
|
+
for (const [index, p] of pending2.entries()) {
|
|
7693
7968
|
if (signal.aborted) break;
|
|
7694
7969
|
const call = { id: p.toolCallId, name: p.name, input: p.input ?? {} };
|
|
7695
7970
|
if (p.reason === "approval") {
|
|
@@ -7849,8 +8124,8 @@ ${content}
|
|
|
7849
8124
|
* @param target The chat — an element, or its id. Defaults to the one `targetResolver` names, else the first on the page.
|
|
7850
8125
|
*/
|
|
7851
8126
|
async resumeDeferred(target) {
|
|
7852
|
-
const
|
|
7853
|
-
const targetElement =
|
|
8127
|
+
const host2 = typeof target === "string" ? this._byId(target) : target ?? this.options.targetResolver?.() ?? null;
|
|
8128
|
+
const targetElement = host2 ? this._asRenderTarget(host2) : this._scanForTarget();
|
|
7854
8129
|
if (!targetElement) return false;
|
|
7855
8130
|
const messages = targetElement.getMessages?.() ?? [];
|
|
7856
8131
|
const last = [...messages].reverse().find((m) => m.role === "assistant");
|
|
@@ -7869,7 +8144,7 @@ ${content}
|
|
|
7869
8144
|
this._resuming.add(last.id);
|
|
7870
8145
|
try {
|
|
7871
8146
|
const authConfig = provider.id ? await this._resolveAuth(provider.id) : void 0;
|
|
7872
|
-
const
|
|
8147
|
+
const pending2 = open.map((s) => ({
|
|
7873
8148
|
toolCallId: s.toolCall.id,
|
|
7874
8149
|
name: s.toolCall.name,
|
|
7875
8150
|
input: s.toolCall.input,
|
|
@@ -7877,7 +8152,7 @@ ${content}
|
|
|
7877
8152
|
}));
|
|
7878
8153
|
const base = this._resumeBase(messages, messages.indexOf(last));
|
|
7879
8154
|
await this._streamTurn(targetElement, last.id, provider, base, recorded?.modelId ?? config.defaultModel ?? "", authConfig, {
|
|
7880
|
-
resume: { pending, ticket },
|
|
8155
|
+
resume: { pending: pending2, ticket },
|
|
7881
8156
|
...recorded?.temperature !== void 0 ? { temperature: recorded.temperature } : {}
|
|
7882
8157
|
});
|
|
7883
8158
|
} finally {
|
|
@@ -8364,8 +8639,95 @@ function installDialogTriggersOnce(doc = document) {
|
|
|
8364
8639
|
doc.addEventListener("pointerup", onPointerUp, true);
|
|
8365
8640
|
doc.addEventListener("click", onClick);
|
|
8366
8641
|
}
|
|
8642
|
+
const ATTR = "defer-hydration";
|
|
8643
|
+
const waiting = /* @__PURE__ */ new WeakMap();
|
|
8644
|
+
const holderOf = /* @__PURE__ */ new WeakMap();
|
|
8645
|
+
const pending = /* @__PURE__ */ new WeakSet();
|
|
8646
|
+
const live = /* @__PURE__ */ new WeakSet();
|
|
8647
|
+
const observers = /* @__PURE__ */ new WeakMap();
|
|
8648
|
+
const patched = /* @__PURE__ */ new WeakSet();
|
|
8649
|
+
function isHeld(el2) {
|
|
8650
|
+
if (live.has(el2)) return false;
|
|
8651
|
+
if (holderOf.has(el2)) return true;
|
|
8652
|
+
const holder = el2.closest(`[${ATTR}]`);
|
|
8653
|
+
if (!holder) return false;
|
|
8654
|
+
holderOf.set(el2, holder);
|
|
8655
|
+
let list = waiting.get(holder);
|
|
8656
|
+
if (!list) {
|
|
8657
|
+
list = [];
|
|
8658
|
+
waiting.set(holder, list);
|
|
8659
|
+
const observer = new MutationObserver(() => {
|
|
8660
|
+
if (!holder.hasAttribute(ATTR)) release(holder);
|
|
8661
|
+
});
|
|
8662
|
+
observer.observe(holder, { attributes: true, attributeFilter: [ATTR] });
|
|
8663
|
+
observers.set(holder, observer);
|
|
8664
|
+
}
|
|
8665
|
+
list.push(el2);
|
|
8666
|
+
return true;
|
|
8667
|
+
}
|
|
8668
|
+
function release(holder) {
|
|
8669
|
+
observers.get(holder)?.disconnect();
|
|
8670
|
+
observers.delete(holder);
|
|
8671
|
+
const list = waiting.get(holder) ?? [];
|
|
8672
|
+
waiting.delete(holder);
|
|
8673
|
+
for (const el2 of list) {
|
|
8674
|
+
holderOf.delete(el2);
|
|
8675
|
+
if (el2.isConnected && !live.has(el2)) el2.connectedCallback?.();
|
|
8676
|
+
}
|
|
8677
|
+
}
|
|
8678
|
+
function releaseDeferredHydration(root) {
|
|
8679
|
+
if (!root) return;
|
|
8680
|
+
if (root.hasAttribute(ATTR)) root.removeAttribute(ATTR);
|
|
8681
|
+
else if (!waiting.has(root)) return;
|
|
8682
|
+
release(root);
|
|
8683
|
+
}
|
|
8684
|
+
function deferHydrationOf(ctor) {
|
|
8685
|
+
if (patched.has(ctor)) return;
|
|
8686
|
+
patched.add(ctor);
|
|
8687
|
+
const proto = ctor.prototype;
|
|
8688
|
+
const connected = proto.connectedCallback;
|
|
8689
|
+
const changed = proto.attributeChangedCallback;
|
|
8690
|
+
const disconnected = proto.disconnectedCallback;
|
|
8691
|
+
const observed = ctor.observedAttributes ?? [];
|
|
8692
|
+
proto.connectedCallback = function() {
|
|
8693
|
+
if (isHeld(this)) {
|
|
8694
|
+
pending.add(this);
|
|
8695
|
+
return;
|
|
8696
|
+
}
|
|
8697
|
+
if (pending.has(this)) {
|
|
8698
|
+
pending.delete(this);
|
|
8699
|
+
for (const name of observed) {
|
|
8700
|
+
const value = this.getAttribute(name);
|
|
8701
|
+
if (value !== null) changed?.call(this, name, null, value);
|
|
8702
|
+
}
|
|
8703
|
+
}
|
|
8704
|
+
live.add(this);
|
|
8705
|
+
connected?.call(this);
|
|
8706
|
+
};
|
|
8707
|
+
if (changed) {
|
|
8708
|
+
proto.attributeChangedCallback = function(name, oldValue, newValue) {
|
|
8709
|
+
if (isHeld(this)) {
|
|
8710
|
+
pending.add(this);
|
|
8711
|
+
return;
|
|
8712
|
+
}
|
|
8713
|
+
changed.call(this, name, oldValue, newValue);
|
|
8714
|
+
};
|
|
8715
|
+
}
|
|
8716
|
+
proto.disconnectedCallback = function() {
|
|
8717
|
+
const holder = holderOf.get(this);
|
|
8718
|
+
if (holder) {
|
|
8719
|
+
holderOf.delete(this);
|
|
8720
|
+
const list = waiting.get(holder);
|
|
8721
|
+
if (list) list.splice(list.indexOf(this), 1);
|
|
8722
|
+
return;
|
|
8723
|
+
}
|
|
8724
|
+
if (pending.has(this)) return;
|
|
8725
|
+
live.delete(this);
|
|
8726
|
+
disconnected?.call(this);
|
|
8727
|
+
};
|
|
8728
|
+
}
|
|
8367
8729
|
export {
|
|
8368
|
-
|
|
8730
|
+
parseMarkdownToSegments as $,
|
|
8369
8731
|
APARTE_CONFIG_CHANGE as A,
|
|
8370
8732
|
contextConfig as B,
|
|
8371
8733
|
copyText as C,
|
|
@@ -8376,53 +8738,63 @@ export {
|
|
|
8376
8738
|
cssEscape as H,
|
|
8377
8739
|
declineDefaultRenderers as I,
|
|
8378
8740
|
defaultSanitizer as J,
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8741
|
+
deferHydrationOf as K,
|
|
8742
|
+
defineMountedSegmentRenderer as L,
|
|
8743
|
+
defineMountedToolRenderer as M,
|
|
8744
|
+
detachConfig as N,
|
|
8745
|
+
escapeAttr as O,
|
|
8746
|
+
escapeHtml as P,
|
|
8747
|
+
filesToAttachments as Q,
|
|
8748
|
+
getAllRenderers as R,
|
|
8749
|
+
getSegmentRenderer as S,
|
|
8750
|
+
installDefaultRenderersOnce as T,
|
|
8751
|
+
installDialogTriggersOnce as U,
|
|
8752
|
+
isAwaitingReply as V,
|
|
8753
|
+
isFormatAdapter as W,
|
|
8754
|
+
isSafeUrl as X,
|
|
8755
|
+
isSegmentSettled as Y,
|
|
8756
|
+
overrideSegmentRenderer as Z,
|
|
8757
|
+
parseAparteEventStream as _,
|
|
8396
8758
|
APARTE_CONVERSATION_SCHEMA_VERSION as a,
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8759
|
+
populateBubbleFromMessage as a0,
|
|
8760
|
+
readableToAsyncIterable as a1,
|
|
8761
|
+
registerDefaultRenderers as a2,
|
|
8762
|
+
registerSegmentRenderer as a3,
|
|
8763
|
+
releaseDeferredHydration as a4,
|
|
8764
|
+
requestUserInput as a5,
|
|
8765
|
+
resolveConfig as a6,
|
|
8766
|
+
revokeAttachmentUrls as a7,
|
|
8767
|
+
runWithConfig as a8,
|
|
8768
|
+
segmentDuration as a9,
|
|
8769
|
+
conversationStatusOf as aA,
|
|
8770
|
+
chatBoundaryOf as aB,
|
|
8771
|
+
rootOf as aC,
|
|
8772
|
+
segmentTiming as aa,
|
|
8773
|
+
subscribeConfigChange as ab,
|
|
8774
|
+
toToolCallView as ac,
|
|
8775
|
+
toolRefusal as ad,
|
|
8776
|
+
unregisterSegmentRenderer as ae,
|
|
8777
|
+
uuid as af,
|
|
8778
|
+
eventOrigin as ag,
|
|
8779
|
+
activeElementIn as ah,
|
|
8780
|
+
gateGlide as ai,
|
|
8781
|
+
toolCallRenderer as aj,
|
|
8782
|
+
toolRendererThatDrew as ak,
|
|
8783
|
+
isMountedRenderer as al,
|
|
8784
|
+
renderingVersionOf as am,
|
|
8785
|
+
onRenderersChange as an,
|
|
8786
|
+
mergeSegmentUpdate as ao,
|
|
8787
|
+
writeStreamedMarkdown as ap,
|
|
8788
|
+
stampSegmentActivity as aq,
|
|
8789
|
+
stampSegmentOnInsert as ar,
|
|
8790
|
+
stampSegmentOnUpdate as as,
|
|
8791
|
+
renumberSegments as at,
|
|
8792
|
+
openSegmentIds as au,
|
|
8793
|
+
isTerminalStatus as av,
|
|
8794
|
+
adoptMessageSegments as aw,
|
|
8795
|
+
APARTE_DERIVED_SEGMENTS as ax,
|
|
8796
|
+
rememberConversationStatus as ay,
|
|
8797
|
+
tellConversationStatus as az,
|
|
8426
8798
|
APARTE_DEFAULT_BUBBLE_ACTIONS as b,
|
|
8427
8799
|
APARTE_DEFAULT_HOST_HANDLERS as c,
|
|
8428
8800
|
APARTE_DEFAULT_ICON_FALLBACKS as d,
|
|
@@ -8449,4 +8821,4 @@ export {
|
|
|
8449
8821
|
collectRendererStyles as y,
|
|
8450
8822
|
contentToText as z
|
|
8451
8823
|
};
|
|
8452
|
-
//# sourceMappingURL=
|
|
8824
|
+
//# sourceMappingURL=defer-hydration-BwMqeRHq.js.map
|