@helpai/elements 0.50.8 → 0.51.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/elements-web-component.esm.js +19 -19
- package/elements-web-component.esm.js.map +3 -3
- package/elements.cjs.js +19 -19
- package/elements.cjs.js.map +3 -3
- package/elements.esm.js +19 -19
- package/elements.esm.js.map +3 -3
- package/elements.js +19 -19
- package/elements.js.map +3 -3
- package/index.d.ts +1 -1
- package/index.mjs +98 -14
- package/package.json +1 -1
- package/schema.d.ts +26 -26
- package/web-component.mjs +98 -14
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, H as HandshakeResponse, L as Link, S as ServerConfig, b as SiteConfig, W as WidgetConfig, c as WidgetConfigPartial, d as WidgetSettings, e as WidgetSettingsPartial } from './deployment-
|
|
1
|
+
export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, H as HandshakeResponse, L as Link, S as ServerConfig, b as SiteConfig, W as WidgetConfig, c as WidgetConfigPartial, d as WidgetSettings, e as WidgetSettingsPartial } from './deployment-oSJ2nv2G.js';
|
|
2
2
|
import 'zod';
|
|
3
3
|
|
|
4
4
|
/**
|
package/index.mjs
CHANGED
|
@@ -29,7 +29,7 @@ var BRAND = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
// src/core/version.ts
|
|
32
|
-
var ELEMENTS_VERSION = true ? "0.
|
|
32
|
+
var ELEMENTS_VERSION = true ? "0.51.0" : "0.0.0-dev";
|
|
33
33
|
var ELEMENTS_VERSION_PARAM = "_ev";
|
|
34
34
|
|
|
35
35
|
// src/i18n/strings.ts
|
|
@@ -2112,6 +2112,13 @@ var AgentTransport = class {
|
|
|
2112
2112
|
// (visitor, conversation) pair.
|
|
2113
2113
|
__publicField(this, "visitorId");
|
|
2114
2114
|
__publicField(this, "conversationId");
|
|
2115
|
+
/**
|
|
2116
|
+
* Outcome of the most recent `resumeStream()` once it found NO replayable SSE — drives the App's
|
|
2117
|
+
* dangling-turn recovery. `live` = a stream was replayed; otherwise the server's JSON recovery status.
|
|
2118
|
+
* `needs-generation` means a durable user turn has no reply (e.g. a fast send→refresh aborted the
|
|
2119
|
+
* deferred LLM run) → the App re-sends to generate it. Reset at the start of each `resumeStream()`.
|
|
2120
|
+
*/
|
|
2121
|
+
__publicField(this, "resumeStatus");
|
|
2115
2122
|
// Host-asserted context (sanitised `userContext` / `pageContext`), refreshed via
|
|
2116
2123
|
// `setContext` and carried as the envelope's optional `context` so the backend
|
|
2117
2124
|
// always sees the visitor's latest context as they navigate.
|
|
@@ -2468,6 +2475,7 @@ var AgentTransport = class {
|
|
|
2468
2475
|
resumeStream() {
|
|
2469
2476
|
const ctrl = new AbortController();
|
|
2470
2477
|
const seenIds = /* @__PURE__ */ new Set();
|
|
2478
|
+
this.resumeStatus = void 0;
|
|
2471
2479
|
const iter = this.resumeStreamGen(ctrl, seenIds, true);
|
|
2472
2480
|
return { iter, cancel: () => ctrl.abort() };
|
|
2473
2481
|
}
|
|
@@ -2522,6 +2530,15 @@ var AgentTransport = class {
|
|
|
2522
2530
|
log6.debug("resume \u2192 no in-flight stream", { status: res.status });
|
|
2523
2531
|
return;
|
|
2524
2532
|
}
|
|
2533
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
2534
|
+
if (!contentType.includes("text/event-stream")) {
|
|
2535
|
+
const status = await res.json().then((body) => body.status).catch(() => void 0);
|
|
2536
|
+
log6.debug("resume \u2192 no live stream (status response)", { status, attempt });
|
|
2537
|
+
if (status === "pending" && attempt < MAX_RESUME_ATTEMPTS) continue;
|
|
2538
|
+
this.resumeStatus = status === "needs-generation" ? "needs-generation" : "completed";
|
|
2539
|
+
return;
|
|
2540
|
+
}
|
|
2541
|
+
this.resumeStatus = "live";
|
|
2525
2542
|
const before = seenIds.size;
|
|
2526
2543
|
if (yield* this.drain(parseChatStream(res, ctrl.signal), seenIds, ctrl)) return;
|
|
2527
2544
|
if (seenIds.size === before) {
|
|
@@ -2741,6 +2758,7 @@ function toReactive(m) {
|
|
|
2741
2758
|
role: m.role,
|
|
2742
2759
|
createdAt: m.createdAt,
|
|
2743
2760
|
status: m.status,
|
|
2761
|
+
canceled: m.canceled,
|
|
2744
2762
|
errorText: m.errorText,
|
|
2745
2763
|
finishReason: m.finishReason,
|
|
2746
2764
|
serverMessageId: m.serverMessageId,
|
|
@@ -2804,7 +2822,11 @@ function fromWireMessage(w) {
|
|
|
2804
2822
|
// Real send time when the backend provides it; otherwise fall back to now
|
|
2805
2823
|
// (older backends) so the timestamp + day divider still render.
|
|
2806
2824
|
createdAt: parseWireDate(w.createdAt) ?? Date.now(),
|
|
2807
|
-
status:
|
|
2825
|
+
// Map the persisted terminal status onto the bubble's render state: `failed` → an error bubble;
|
|
2826
|
+
// `canceled` → `complete` + the `canceled` flag (an empty canceled turn is hidden on render — see
|
|
2827
|
+
// `message-bubble`); everything else is a normal completed turn.
|
|
2828
|
+
status: w.status === "failed" ? "error" : "complete",
|
|
2829
|
+
canceled: w.status === "canceled",
|
|
2808
2830
|
partsSig: signal(parts)
|
|
2809
2831
|
};
|
|
2810
2832
|
}
|
|
@@ -2814,6 +2836,7 @@ function fromReactive(m) {
|
|
|
2814
2836
|
role: m.role,
|
|
2815
2837
|
createdAt: m.createdAt,
|
|
2816
2838
|
status: m.status,
|
|
2839
|
+
canceled: m.canceled,
|
|
2817
2840
|
errorText: m.errorText,
|
|
2818
2841
|
finishReason: m.finishReason,
|
|
2819
2842
|
serverMessageId: m.serverMessageId,
|
|
@@ -2836,6 +2859,9 @@ function hasNoVisibleAnswer(m) {
|
|
|
2836
2859
|
function isEmptyAssistantReply(m) {
|
|
2837
2860
|
return m.role === "assistant" && m.status !== "streaming" && hasNoVisibleAnswer(m);
|
|
2838
2861
|
}
|
|
2862
|
+
function isHiddenCanceledTurn(m) {
|
|
2863
|
+
return m.canceled === true && isEmptyAssistantReply(m);
|
|
2864
|
+
}
|
|
2839
2865
|
function partToReactive(p36) {
|
|
2840
2866
|
if (p36.kind === "text" || p36.kind === "reasoning") {
|
|
2841
2867
|
return { kind: p36.kind, id: p36.id, textSig: signal(p36.text), doneSig: signal(p36.done) };
|
|
@@ -2995,6 +3021,8 @@ var StreamReducer = class {
|
|
|
2995
3021
|
return;
|
|
2996
3022
|
case "data-notification":
|
|
2997
3023
|
return;
|
|
3024
|
+
case "data-conversation-rebind":
|
|
3025
|
+
return;
|
|
2998
3026
|
default: {
|
|
2999
3027
|
const _exhaustive = chunk;
|
|
3000
3028
|
void _exhaustive;
|
|
@@ -5707,6 +5735,7 @@ function MessageBubble({
|
|
|
5707
5735
|
const parts = useComputed5(() => message.partsSig.value);
|
|
5708
5736
|
const partList = parts.value;
|
|
5709
5737
|
const emptyReply = useComputed5(() => isEmptyAssistantReply(message));
|
|
5738
|
+
const hideCanceledHusk = useComputed5(() => isHiddenCanceledTurn(message));
|
|
5710
5739
|
const hasAnswerText = useComputed5(
|
|
5711
5740
|
() => message.partsSig.value.some((part) => part.kind === "text" && part.textSig.value.length > 0)
|
|
5712
5741
|
);
|
|
@@ -5717,6 +5746,7 @@ function MessageBubble({
|
|
|
5717
5746
|
const bufferedHold = responseMode === "buffered" && streaming;
|
|
5718
5747
|
const working = streaming && !hasAnswerText.value;
|
|
5719
5748
|
const showStreamDots = streaming && !bufferedHold && !(reasoningVisible.value && working);
|
|
5749
|
+
if (hideCanceledHusk.value) return null;
|
|
5720
5750
|
const stamp = formatStamp(message.createdAt);
|
|
5721
5751
|
return /* @__PURE__ */ jsx18("div", { class: `${p17}-bubble-row`, "data-role": message.role, "data-testid": tid(TID.messageBubble, message.id), children: /* @__PURE__ */ jsxs15("div", { class: `${p17}-bubble-col`, children: [
|
|
5722
5752
|
/* @__PURE__ */ jsxs15("div", { class: `${p17}-bubble`, children: [
|
|
@@ -7662,6 +7692,8 @@ function App({ options, hostElement, bus }) {
|
|
|
7662
7692
|
const homeNavSeeded = useRef9(false);
|
|
7663
7693
|
const resumeActiveRef = useRef9(false);
|
|
7664
7694
|
const resumeBubbleRef = useRef9(null);
|
|
7695
|
+
const regenerateDanglingRef = useRef9(null);
|
|
7696
|
+
const regenInFlightRef = useRef9(false);
|
|
7665
7697
|
useEffect16(() => {
|
|
7666
7698
|
if (!conversationReady || homeNavSeeded.current) return;
|
|
7667
7699
|
homeNavSeeded.current = true;
|
|
@@ -7731,6 +7763,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7731
7763
|
} else {
|
|
7732
7764
|
messagesSig.value = withWelcomeRows([], markers);
|
|
7733
7765
|
}
|
|
7766
|
+
if (transport.resumeStatus === "needs-generation") regenerateDanglingRef.current?.();
|
|
7734
7767
|
} catch (err) {
|
|
7735
7768
|
if (isStale()) return;
|
|
7736
7769
|
log17.warn("loadThread failed; resetting conversationId", { err, conversationId });
|
|
@@ -7860,11 +7893,28 @@ function App({ options, hostElement, bus }) {
|
|
|
7860
7893
|
useEffect16(() => {
|
|
7861
7894
|
if (effectiveLocale !== activeLocale) setActiveLocale(effectiveLocale);
|
|
7862
7895
|
}, [effectiveLocale, activeLocale]);
|
|
7896
|
+
const adoptConversationRebind = useCallback6(
|
|
7897
|
+
(chunk) => {
|
|
7898
|
+
if (chunk.type !== "data-conversation-rebind") return false;
|
|
7899
|
+
const next = chunk.data?.conversationId;
|
|
7900
|
+
if (next && next !== conversationIdSig.value) {
|
|
7901
|
+
const previous = conversationIdSig.value;
|
|
7902
|
+
conversationIdSig.value = next;
|
|
7903
|
+
persistence.saveConversationId(next);
|
|
7904
|
+
transport.primeIdentity(void 0, next);
|
|
7905
|
+
log17.info("conversation rebound (in-stream)", { previous, current: next });
|
|
7906
|
+
if (previous) bus.emit("conversationRebound", { previous, current: next, reason: next });
|
|
7907
|
+
}
|
|
7908
|
+
return true;
|
|
7909
|
+
},
|
|
7910
|
+
[conversationIdSig, persistence, transport, bus]
|
|
7911
|
+
);
|
|
7863
7912
|
const runResume = useCallback6(
|
|
7864
7913
|
async (handle) => {
|
|
7865
7914
|
let bubble = null;
|
|
7866
7915
|
try {
|
|
7867
7916
|
for await (const evt of handle.iter) {
|
|
7917
|
+
if (adoptConversationRebind(evt.chunk)) continue;
|
|
7868
7918
|
if (!bubble) {
|
|
7869
7919
|
bubble = makeAssistantMessage();
|
|
7870
7920
|
resumeBubbleRef.current = bubble;
|
|
@@ -7908,7 +7958,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7908
7958
|
}
|
|
7909
7959
|
}
|
|
7910
7960
|
},
|
|
7911
|
-
[reducer, messagesSig, feedback, bus, options, homeNav]
|
|
7961
|
+
[reducer, messagesSig, feedback, bus, options, homeNav, adoptConversationRebind]
|
|
7912
7962
|
);
|
|
7913
7963
|
const resumeHandleRef = useRef9(null);
|
|
7914
7964
|
useEffect16(() => {
|
|
@@ -7933,16 +7983,22 @@ function App({ options, hostElement, bus }) {
|
|
|
7933
7983
|
setFormsReady(true);
|
|
7934
7984
|
}
|
|
7935
7985
|
})();
|
|
7936
|
-
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7986
|
+
void (async () => {
|
|
7987
|
+
const tasks = [];
|
|
7988
|
+
if (pendingThreadRef.current) {
|
|
7989
|
+
pendingThreadRef.current = false;
|
|
7990
|
+
const persisted = conversationIdSig.value;
|
|
7991
|
+
if (persisted) tasks.push(loadThread(persisted));
|
|
7992
|
+
}
|
|
7993
|
+
if (conversationIdSig.value) {
|
|
7994
|
+
const handle = transport.resumeStream();
|
|
7995
|
+
resumeHandleRef.current = handle;
|
|
7996
|
+
tasks.push(runResume(handle));
|
|
7997
|
+
}
|
|
7998
|
+
if (tasks.length === 0) return;
|
|
7999
|
+
await Promise.allSettled(tasks);
|
|
8000
|
+
if (transport.resumeStatus === "needs-generation") regenerateDanglingRef.current?.();
|
|
8001
|
+
})();
|
|
7946
8002
|
}, [activated]);
|
|
7947
8003
|
const formsLocaleRef = useRef9(null);
|
|
7948
8004
|
useEffect16(() => {
|
|
@@ -8015,6 +8071,7 @@ function App({ options, hostElement, bus }) {
|
|
|
8015
8071
|
setActiveCancel(() => handle.cancel);
|
|
8016
8072
|
try {
|
|
8017
8073
|
for await (const evt of handle.iter) {
|
|
8074
|
+
if (adoptConversationRebind(evt.chunk)) continue;
|
|
8018
8075
|
reducer.apply(evt.chunk);
|
|
8019
8076
|
if (evt.chunk.type === "finish" && evt.chunk.canContinue === false) {
|
|
8020
8077
|
setCanSend(false);
|
|
@@ -8055,8 +8112,35 @@ function App({ options, hostElement, bus }) {
|
|
|
8055
8112
|
messagesSig.value = [...messagesSig.value];
|
|
8056
8113
|
}
|
|
8057
8114
|
},
|
|
8058
|
-
[
|
|
8115
|
+
[
|
|
8116
|
+
transport,
|
|
8117
|
+
reducer,
|
|
8118
|
+
messagesSig,
|
|
8119
|
+
conversationIdSig,
|
|
8120
|
+
options,
|
|
8121
|
+
bus,
|
|
8122
|
+
feedback,
|
|
8123
|
+
persistence,
|
|
8124
|
+
visitorId,
|
|
8125
|
+
adoptConversationRebind
|
|
8126
|
+
]
|
|
8059
8127
|
);
|
|
8128
|
+
const regenerateDanglingTurn = useCallback6(() => {
|
|
8129
|
+
if (streaming || regenInFlightRef.current || resumeBubbleRef.current) return;
|
|
8130
|
+
const last = messagesSig.value.filter((m) => !m.ephemeral).at(-1);
|
|
8131
|
+
if (last?.role !== "user") return;
|
|
8132
|
+
regenInFlightRef.current = true;
|
|
8133
|
+
log17.info("regenerating dangling user turn (needs-generation)");
|
|
8134
|
+
const assistantMsg = makeAssistantMessage();
|
|
8135
|
+
messagesSig.value = [...messagesSig.value, assistantMsg];
|
|
8136
|
+
reducer.attach(assistantMsg);
|
|
8137
|
+
void streamAssistant(assistantMsg, { continueExisting: false }).finally(() => {
|
|
8138
|
+
regenInFlightRef.current = false;
|
|
8139
|
+
});
|
|
8140
|
+
}, [streaming, messagesSig, reducer, streamAssistant]);
|
|
8141
|
+
useEffect16(() => {
|
|
8142
|
+
regenerateDanglingRef.current = regenerateDanglingTurn;
|
|
8143
|
+
}, [regenerateDanglingTurn]);
|
|
8060
8144
|
const decideTool = useCallback6(
|
|
8061
8145
|
(toolCallId, mutate) => {
|
|
8062
8146
|
if (streaming) return;
|
package/package.json
CHANGED
package/schema.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, E as Endpoints, H as HandshakeResponse, L as Link, P as PAGE_AREA_SUGGESTIONS, f as PageContext, S as ServerConfig, b as SiteConfig, U as UserContext, W as WidgetConfig, c as WidgetConfigPartial, d as WidgetSettings, e as WidgetSettingsPartial, g as assetSchema, h as blocksConfigSchema, i as connectionConfigPartialSchema, j as connectionConfigSchema, k as cssColorSchema, l as cssLengthSchema, m as endpointsSchema, n as handshakeResponseSchema, o as linkSchema, p as localeSchema, q as pageContextSchema, s as serverConfigSchema, r as siteConfigSchema, u as userContextSchema, t as uuid7Schema, w as widgetConfigPartialSchema, v as widgetConfigSchema, x as widgetSettingsPartialSchema, y as widgetSettingsSchema } from './deployment-
|
|
1
|
+
export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, E as Endpoints, H as HandshakeResponse, L as Link, P as PAGE_AREA_SUGGESTIONS, f as PageContext, S as ServerConfig, b as SiteConfig, U as UserContext, W as WidgetConfig, c as WidgetConfigPartial, d as WidgetSettings, e as WidgetSettingsPartial, g as assetSchema, h as blocksConfigSchema, i as connectionConfigPartialSchema, j as connectionConfigSchema, k as cssColorSchema, l as cssLengthSchema, m as endpointsSchema, n as handshakeResponseSchema, o as linkSchema, p as localeSchema, q as pageContextSchema, s as serverConfigSchema, r as siteConfigSchema, u as userContextSchema, t as uuid7Schema, w as widgetConfigPartialSchema, v as widgetConfigSchema, x as widgetSettingsPartialSchema, y as widgetSettingsSchema } from './deployment-oSJ2nv2G.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -56,9 +56,9 @@ declare const presentationSchema: z.ZodObject<{
|
|
|
56
56
|
inset: z.ZodOptional<z.ZodString>;
|
|
57
57
|
initialSize: z.ZodDefault<z.ZodEnum<{
|
|
58
58
|
fullscreen: "fullscreen";
|
|
59
|
+
normal: "normal";
|
|
59
60
|
expanded: "expanded";
|
|
60
61
|
auto: "auto";
|
|
61
|
-
normal: "normal";
|
|
62
62
|
}>>;
|
|
63
63
|
autoSizeBreakpoint: z.ZodDefault<z.ZodNumber>;
|
|
64
64
|
}, z.core.$loose>>;
|
|
@@ -240,9 +240,9 @@ type LauncherOptions = z.infer<typeof launcherOptionsSchema>;
|
|
|
240
240
|
|
|
241
241
|
declare const initialSizeSchema: z.ZodEnum<{
|
|
242
242
|
fullscreen: "fullscreen";
|
|
243
|
+
normal: "normal";
|
|
243
244
|
expanded: "expanded";
|
|
244
245
|
auto: "auto";
|
|
245
|
-
normal: "normal";
|
|
246
246
|
}>;
|
|
247
247
|
declare const resizeOptionsSchema: z.ZodObject<{
|
|
248
248
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -269,9 +269,9 @@ declare const sizeOptionsSchema: z.ZodObject<{
|
|
|
269
269
|
inset: z.ZodOptional<z.ZodString>;
|
|
270
270
|
initialSize: z.ZodDefault<z.ZodEnum<{
|
|
271
271
|
fullscreen: "fullscreen";
|
|
272
|
+
normal: "normal";
|
|
272
273
|
expanded: "expanded";
|
|
273
274
|
auto: "auto";
|
|
274
|
-
normal: "normal";
|
|
275
275
|
}>>;
|
|
276
276
|
autoSizeBreakpoint: z.ZodDefault<z.ZodNumber>;
|
|
277
277
|
}, z.core.$loose>;
|
|
@@ -323,40 +323,40 @@ type FeatureFlags = z.infer<typeof featureFlagsSchema>;
|
|
|
323
323
|
*/
|
|
324
324
|
|
|
325
325
|
declare const actionNameSchema: z.ZodEnum<{
|
|
326
|
-
close: "close";
|
|
327
326
|
expand: "expand";
|
|
328
327
|
fullscreen: "fullscreen";
|
|
329
|
-
|
|
330
|
-
theme: "theme";
|
|
328
|
+
close: "close";
|
|
331
329
|
language: "language";
|
|
330
|
+
theme: "theme";
|
|
332
331
|
textSize: "textSize";
|
|
333
332
|
history: "history";
|
|
333
|
+
clear: "clear";
|
|
334
334
|
sound: "sound";
|
|
335
335
|
}>;
|
|
336
336
|
type ActionName = z.infer<typeof actionNameSchema>;
|
|
337
337
|
declare const headerActionsSchema: z.ZodArray<z.ZodEnum<{
|
|
338
|
-
close: "close";
|
|
339
338
|
expand: "expand";
|
|
340
339
|
fullscreen: "fullscreen";
|
|
341
|
-
|
|
342
|
-
theme: "theme";
|
|
340
|
+
close: "close";
|
|
343
341
|
language: "language";
|
|
342
|
+
theme: "theme";
|
|
344
343
|
textSize: "textSize";
|
|
345
344
|
history: "history";
|
|
345
|
+
clear: "clear";
|
|
346
346
|
sound: "sound";
|
|
347
347
|
}>>;
|
|
348
348
|
type HeaderActions = z.infer<typeof headerActionsSchema>;
|
|
349
349
|
/** Section wrapper — `actions` list wrapped under `header` in the dashboard form. */
|
|
350
350
|
declare const headerSchema: z.ZodObject<{
|
|
351
351
|
actions: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
352
|
-
close: "close";
|
|
353
352
|
expand: "expand";
|
|
354
353
|
fullscreen: "fullscreen";
|
|
355
|
-
|
|
356
|
-
theme: "theme";
|
|
354
|
+
close: "close";
|
|
357
355
|
language: "language";
|
|
356
|
+
theme: "theme";
|
|
358
357
|
textSize: "textSize";
|
|
359
358
|
history: "history";
|
|
359
|
+
clear: "clear";
|
|
360
360
|
sound: "sound";
|
|
361
361
|
}>>>;
|
|
362
362
|
}, z.core.$loose>;
|
|
@@ -372,33 +372,33 @@ type HeaderOptions = z.infer<typeof headerSchema>;
|
|
|
372
372
|
*/
|
|
373
373
|
|
|
374
374
|
declare const feedbackEventSchema: z.ZodEnum<{
|
|
375
|
-
voiceStart: "voiceStart";
|
|
376
|
-
voiceStop: "voiceStop";
|
|
377
375
|
error: "error";
|
|
378
376
|
messageReceived: "messageReceived";
|
|
379
377
|
messageSent: "messageSent";
|
|
378
|
+
voiceStart: "voiceStart";
|
|
379
|
+
voiceStop: "voiceStop";
|
|
380
380
|
}>;
|
|
381
381
|
type FeedbackEvent = z.infer<typeof feedbackEventSchema>;
|
|
382
382
|
declare const soundOptionsSchema: z.ZodObject<{
|
|
383
383
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
384
384
|
volume: z.ZodDefault<z.ZodNumber>;
|
|
385
385
|
events: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
386
|
-
voiceStart: "voiceStart";
|
|
387
|
-
voiceStop: "voiceStop";
|
|
388
386
|
error: "error";
|
|
389
387
|
messageReceived: "messageReceived";
|
|
390
388
|
messageSent: "messageSent";
|
|
389
|
+
voiceStart: "voiceStart";
|
|
390
|
+
voiceStop: "voiceStop";
|
|
391
391
|
}> & z.core.$partial, z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>>;
|
|
392
392
|
}, z.core.$loose>;
|
|
393
393
|
type SoundOptions = z.infer<typeof soundOptionsSchema>;
|
|
394
394
|
declare const hapticsOptionsSchema: z.ZodObject<{
|
|
395
395
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
396
396
|
events: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
397
|
-
voiceStart: "voiceStart";
|
|
398
|
-
voiceStop: "voiceStop";
|
|
399
397
|
error: "error";
|
|
400
398
|
messageReceived: "messageReceived";
|
|
401
399
|
messageSent: "messageSent";
|
|
400
|
+
voiceStart: "voiceStart";
|
|
401
|
+
voiceStop: "voiceStop";
|
|
402
402
|
}> & z.core.$partial, z.ZodUnion<readonly [z.ZodBoolean, z.ZodNumber, z.ZodArray<z.ZodNumber>]>>>;
|
|
403
403
|
}, z.core.$loose>;
|
|
404
404
|
type HapticsOptions = z.infer<typeof hapticsOptionsSchema>;
|
|
@@ -407,21 +407,21 @@ declare const feedbackSchema: z.ZodObject<{
|
|
|
407
407
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
408
408
|
volume: z.ZodDefault<z.ZodNumber>;
|
|
409
409
|
events: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
410
|
-
voiceStart: "voiceStart";
|
|
411
|
-
voiceStop: "voiceStop";
|
|
412
410
|
error: "error";
|
|
413
411
|
messageReceived: "messageReceived";
|
|
414
412
|
messageSent: "messageSent";
|
|
413
|
+
voiceStart: "voiceStart";
|
|
414
|
+
voiceStop: "voiceStop";
|
|
415
415
|
}> & z.core.$partial, z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>>;
|
|
416
416
|
}, z.core.$loose>>;
|
|
417
417
|
haptics: z.ZodOptional<z.ZodObject<{
|
|
418
418
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
419
419
|
events: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
420
|
-
voiceStart: "voiceStart";
|
|
421
|
-
voiceStop: "voiceStop";
|
|
422
420
|
error: "error";
|
|
423
421
|
messageReceived: "messageReceived";
|
|
424
422
|
messageSent: "messageSent";
|
|
423
|
+
voiceStart: "voiceStart";
|
|
424
|
+
voiceStop: "voiceStop";
|
|
425
425
|
}> & z.core.$partial, z.ZodUnion<readonly [z.ZodBoolean, z.ZodNumber, z.ZodArray<z.ZodNumber>]>>>;
|
|
426
426
|
}, z.core.$loose>>;
|
|
427
427
|
}, z.core.$loose>;
|
|
@@ -856,18 +856,18 @@ type I18nOptions = z.infer<typeof i18nSchema>;
|
|
|
856
856
|
*/
|
|
857
857
|
|
|
858
858
|
declare const moduleLayoutSchema: z.ZodEnum<{
|
|
859
|
-
home: "home";
|
|
860
859
|
chat: "chat";
|
|
861
860
|
help: "help";
|
|
861
|
+
home: "home";
|
|
862
862
|
news: "news";
|
|
863
863
|
}>;
|
|
864
864
|
type ModuleLayout = z.infer<typeof moduleLayoutSchema>;
|
|
865
865
|
declare const moduleSchema: z.ZodObject<{
|
|
866
866
|
label: z.ZodString;
|
|
867
867
|
layout: z.ZodEnum<{
|
|
868
|
-
home: "home";
|
|
869
868
|
chat: "chat";
|
|
870
869
|
help: "help";
|
|
870
|
+
home: "home";
|
|
871
871
|
news: "news";
|
|
872
872
|
}>;
|
|
873
873
|
contentTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -893,9 +893,9 @@ type ModuleOptions = z.infer<typeof moduleSchema>;
|
|
|
893
893
|
declare const modulesSchema: z.ZodArray<z.ZodObject<{
|
|
894
894
|
label: z.ZodString;
|
|
895
895
|
layout: z.ZodEnum<{
|
|
896
|
-
home: "home";
|
|
897
896
|
chat: "chat";
|
|
898
897
|
help: "help";
|
|
898
|
+
home: "home";
|
|
899
899
|
news: "news";
|
|
900
900
|
}>;
|
|
901
901
|
contentTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
package/web-component.mjs
CHANGED
|
@@ -1794,7 +1794,7 @@ function createAuth(opts) {
|
|
|
1794
1794
|
}
|
|
1795
1795
|
|
|
1796
1796
|
// src/core/version.ts
|
|
1797
|
-
var ELEMENTS_VERSION = true ? "0.
|
|
1797
|
+
var ELEMENTS_VERSION = true ? "0.51.0" : "0.0.0-dev";
|
|
1798
1798
|
var ELEMENTS_VERSION_PARAM = "_ev";
|
|
1799
1799
|
|
|
1800
1800
|
// src/stream/types.ts
|
|
@@ -2071,6 +2071,13 @@ var AgentTransport = class {
|
|
|
2071
2071
|
// (visitor, conversation) pair.
|
|
2072
2072
|
__publicField(this, "visitorId");
|
|
2073
2073
|
__publicField(this, "conversationId");
|
|
2074
|
+
/**
|
|
2075
|
+
* Outcome of the most recent `resumeStream()` once it found NO replayable SSE — drives the App's
|
|
2076
|
+
* dangling-turn recovery. `live` = a stream was replayed; otherwise the server's JSON recovery status.
|
|
2077
|
+
* `needs-generation` means a durable user turn has no reply (e.g. a fast send→refresh aborted the
|
|
2078
|
+
* deferred LLM run) → the App re-sends to generate it. Reset at the start of each `resumeStream()`.
|
|
2079
|
+
*/
|
|
2080
|
+
__publicField(this, "resumeStatus");
|
|
2074
2081
|
// Host-asserted context (sanitised `userContext` / `pageContext`), refreshed via
|
|
2075
2082
|
// `setContext` and carried as the envelope's optional `context` so the backend
|
|
2076
2083
|
// always sees the visitor's latest context as they navigate.
|
|
@@ -2427,6 +2434,7 @@ var AgentTransport = class {
|
|
|
2427
2434
|
resumeStream() {
|
|
2428
2435
|
const ctrl = new AbortController();
|
|
2429
2436
|
const seenIds = /* @__PURE__ */ new Set();
|
|
2437
|
+
this.resumeStatus = void 0;
|
|
2430
2438
|
const iter = this.resumeStreamGen(ctrl, seenIds, true);
|
|
2431
2439
|
return { iter, cancel: () => ctrl.abort() };
|
|
2432
2440
|
}
|
|
@@ -2481,6 +2489,15 @@ var AgentTransport = class {
|
|
|
2481
2489
|
log5.debug("resume \u2192 no in-flight stream", { status: res.status });
|
|
2482
2490
|
return;
|
|
2483
2491
|
}
|
|
2492
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
2493
|
+
if (!contentType.includes("text/event-stream")) {
|
|
2494
|
+
const status = await res.json().then((body) => body.status).catch(() => void 0);
|
|
2495
|
+
log5.debug("resume \u2192 no live stream (status response)", { status, attempt });
|
|
2496
|
+
if (status === "pending" && attempt < MAX_RESUME_ATTEMPTS) continue;
|
|
2497
|
+
this.resumeStatus = status === "needs-generation" ? "needs-generation" : "completed";
|
|
2498
|
+
return;
|
|
2499
|
+
}
|
|
2500
|
+
this.resumeStatus = "live";
|
|
2484
2501
|
const before = seenIds.size;
|
|
2485
2502
|
if (yield* this.drain(parseChatStream(res, ctrl.signal), seenIds, ctrl)) return;
|
|
2486
2503
|
if (seenIds.size === before) {
|
|
@@ -2700,6 +2717,7 @@ function toReactive(m) {
|
|
|
2700
2717
|
role: m.role,
|
|
2701
2718
|
createdAt: m.createdAt,
|
|
2702
2719
|
status: m.status,
|
|
2720
|
+
canceled: m.canceled,
|
|
2703
2721
|
errorText: m.errorText,
|
|
2704
2722
|
finishReason: m.finishReason,
|
|
2705
2723
|
serverMessageId: m.serverMessageId,
|
|
@@ -2763,7 +2781,11 @@ function fromWireMessage(w) {
|
|
|
2763
2781
|
// Real send time when the backend provides it; otherwise fall back to now
|
|
2764
2782
|
// (older backends) so the timestamp + day divider still render.
|
|
2765
2783
|
createdAt: parseWireDate(w.createdAt) ?? Date.now(),
|
|
2766
|
-
status:
|
|
2784
|
+
// Map the persisted terminal status onto the bubble's render state: `failed` → an error bubble;
|
|
2785
|
+
// `canceled` → `complete` + the `canceled` flag (an empty canceled turn is hidden on render — see
|
|
2786
|
+
// `message-bubble`); everything else is a normal completed turn.
|
|
2787
|
+
status: w.status === "failed" ? "error" : "complete",
|
|
2788
|
+
canceled: w.status === "canceled",
|
|
2767
2789
|
partsSig: signal(parts)
|
|
2768
2790
|
};
|
|
2769
2791
|
}
|
|
@@ -2773,6 +2795,7 @@ function fromReactive(m) {
|
|
|
2773
2795
|
role: m.role,
|
|
2774
2796
|
createdAt: m.createdAt,
|
|
2775
2797
|
status: m.status,
|
|
2798
|
+
canceled: m.canceled,
|
|
2776
2799
|
errorText: m.errorText,
|
|
2777
2800
|
finishReason: m.finishReason,
|
|
2778
2801
|
serverMessageId: m.serverMessageId,
|
|
@@ -2795,6 +2818,9 @@ function hasNoVisibleAnswer(m) {
|
|
|
2795
2818
|
function isEmptyAssistantReply(m) {
|
|
2796
2819
|
return m.role === "assistant" && m.status !== "streaming" && hasNoVisibleAnswer(m);
|
|
2797
2820
|
}
|
|
2821
|
+
function isHiddenCanceledTurn(m) {
|
|
2822
|
+
return m.canceled === true && isEmptyAssistantReply(m);
|
|
2823
|
+
}
|
|
2798
2824
|
function partToReactive(p36) {
|
|
2799
2825
|
if (p36.kind === "text" || p36.kind === "reasoning") {
|
|
2800
2826
|
return { kind: p36.kind, id: p36.id, textSig: signal(p36.text), doneSig: signal(p36.done) };
|
|
@@ -2954,6 +2980,8 @@ var StreamReducer = class {
|
|
|
2954
2980
|
return;
|
|
2955
2981
|
case "data-notification":
|
|
2956
2982
|
return;
|
|
2983
|
+
case "data-conversation-rebind":
|
|
2984
|
+
return;
|
|
2957
2985
|
default: {
|
|
2958
2986
|
const _exhaustive = chunk;
|
|
2959
2987
|
void _exhaustive;
|
|
@@ -5666,6 +5694,7 @@ function MessageBubble({
|
|
|
5666
5694
|
const parts = useComputed5(() => message.partsSig.value);
|
|
5667
5695
|
const partList = parts.value;
|
|
5668
5696
|
const emptyReply = useComputed5(() => isEmptyAssistantReply(message));
|
|
5697
|
+
const hideCanceledHusk = useComputed5(() => isHiddenCanceledTurn(message));
|
|
5669
5698
|
const hasAnswerText = useComputed5(
|
|
5670
5699
|
() => message.partsSig.value.some((part) => part.kind === "text" && part.textSig.value.length > 0)
|
|
5671
5700
|
);
|
|
@@ -5676,6 +5705,7 @@ function MessageBubble({
|
|
|
5676
5705
|
const bufferedHold = responseMode === "buffered" && streaming;
|
|
5677
5706
|
const working = streaming && !hasAnswerText.value;
|
|
5678
5707
|
const showStreamDots = streaming && !bufferedHold && !(reasoningVisible.value && working);
|
|
5708
|
+
if (hideCanceledHusk.value) return null;
|
|
5679
5709
|
const stamp = formatStamp(message.createdAt);
|
|
5680
5710
|
return /* @__PURE__ */ jsx18("div", { class: `${p17}-bubble-row`, "data-role": message.role, "data-testid": tid(TID.messageBubble, message.id), children: /* @__PURE__ */ jsxs15("div", { class: `${p17}-bubble-col`, children: [
|
|
5681
5711
|
/* @__PURE__ */ jsxs15("div", { class: `${p17}-bubble`, children: [
|
|
@@ -7621,6 +7651,8 @@ function App({ options, hostElement, bus }) {
|
|
|
7621
7651
|
const homeNavSeeded = useRef9(false);
|
|
7622
7652
|
const resumeActiveRef = useRef9(false);
|
|
7623
7653
|
const resumeBubbleRef = useRef9(null);
|
|
7654
|
+
const regenerateDanglingRef = useRef9(null);
|
|
7655
|
+
const regenInFlightRef = useRef9(false);
|
|
7624
7656
|
useEffect16(() => {
|
|
7625
7657
|
if (!conversationReady || homeNavSeeded.current) return;
|
|
7626
7658
|
homeNavSeeded.current = true;
|
|
@@ -7690,6 +7722,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7690
7722
|
} else {
|
|
7691
7723
|
messagesSig.value = withWelcomeRows([], markers);
|
|
7692
7724
|
}
|
|
7725
|
+
if (transport.resumeStatus === "needs-generation") regenerateDanglingRef.current?.();
|
|
7693
7726
|
} catch (err) {
|
|
7694
7727
|
if (isStale()) return;
|
|
7695
7728
|
log16.warn("loadThread failed; resetting conversationId", { err, conversationId });
|
|
@@ -7819,11 +7852,28 @@ function App({ options, hostElement, bus }) {
|
|
|
7819
7852
|
useEffect16(() => {
|
|
7820
7853
|
if (effectiveLocale !== activeLocale) setActiveLocale(effectiveLocale);
|
|
7821
7854
|
}, [effectiveLocale, activeLocale]);
|
|
7855
|
+
const adoptConversationRebind = useCallback6(
|
|
7856
|
+
(chunk) => {
|
|
7857
|
+
if (chunk.type !== "data-conversation-rebind") return false;
|
|
7858
|
+
const next = chunk.data?.conversationId;
|
|
7859
|
+
if (next && next !== conversationIdSig.value) {
|
|
7860
|
+
const previous = conversationIdSig.value;
|
|
7861
|
+
conversationIdSig.value = next;
|
|
7862
|
+
persistence.saveConversationId(next);
|
|
7863
|
+
transport.primeIdentity(void 0, next);
|
|
7864
|
+
log16.info("conversation rebound (in-stream)", { previous, current: next });
|
|
7865
|
+
if (previous) bus.emit("conversationRebound", { previous, current: next, reason: next });
|
|
7866
|
+
}
|
|
7867
|
+
return true;
|
|
7868
|
+
},
|
|
7869
|
+
[conversationIdSig, persistence, transport, bus]
|
|
7870
|
+
);
|
|
7822
7871
|
const runResume = useCallback6(
|
|
7823
7872
|
async (handle) => {
|
|
7824
7873
|
let bubble = null;
|
|
7825
7874
|
try {
|
|
7826
7875
|
for await (const evt of handle.iter) {
|
|
7876
|
+
if (adoptConversationRebind(evt.chunk)) continue;
|
|
7827
7877
|
if (!bubble) {
|
|
7828
7878
|
bubble = makeAssistantMessage();
|
|
7829
7879
|
resumeBubbleRef.current = bubble;
|
|
@@ -7867,7 +7917,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7867
7917
|
}
|
|
7868
7918
|
}
|
|
7869
7919
|
},
|
|
7870
|
-
[reducer, messagesSig, feedback, bus, options, homeNav]
|
|
7920
|
+
[reducer, messagesSig, feedback, bus, options, homeNav, adoptConversationRebind]
|
|
7871
7921
|
);
|
|
7872
7922
|
const resumeHandleRef = useRef9(null);
|
|
7873
7923
|
useEffect16(() => {
|
|
@@ -7892,16 +7942,22 @@ function App({ options, hostElement, bus }) {
|
|
|
7892
7942
|
setFormsReady(true);
|
|
7893
7943
|
}
|
|
7894
7944
|
})();
|
|
7895
|
-
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7945
|
+
void (async () => {
|
|
7946
|
+
const tasks = [];
|
|
7947
|
+
if (pendingThreadRef.current) {
|
|
7948
|
+
pendingThreadRef.current = false;
|
|
7949
|
+
const persisted = conversationIdSig.value;
|
|
7950
|
+
if (persisted) tasks.push(loadThread(persisted));
|
|
7951
|
+
}
|
|
7952
|
+
if (conversationIdSig.value) {
|
|
7953
|
+
const handle = transport.resumeStream();
|
|
7954
|
+
resumeHandleRef.current = handle;
|
|
7955
|
+
tasks.push(runResume(handle));
|
|
7956
|
+
}
|
|
7957
|
+
if (tasks.length === 0) return;
|
|
7958
|
+
await Promise.allSettled(tasks);
|
|
7959
|
+
if (transport.resumeStatus === "needs-generation") regenerateDanglingRef.current?.();
|
|
7960
|
+
})();
|
|
7905
7961
|
}, [activated]);
|
|
7906
7962
|
const formsLocaleRef = useRef9(null);
|
|
7907
7963
|
useEffect16(() => {
|
|
@@ -7974,6 +8030,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7974
8030
|
setActiveCancel(() => handle.cancel);
|
|
7975
8031
|
try {
|
|
7976
8032
|
for await (const evt of handle.iter) {
|
|
8033
|
+
if (adoptConversationRebind(evt.chunk)) continue;
|
|
7977
8034
|
reducer.apply(evt.chunk);
|
|
7978
8035
|
if (evt.chunk.type === "finish" && evt.chunk.canContinue === false) {
|
|
7979
8036
|
setCanSend(false);
|
|
@@ -8014,8 +8071,35 @@ function App({ options, hostElement, bus }) {
|
|
|
8014
8071
|
messagesSig.value = [...messagesSig.value];
|
|
8015
8072
|
}
|
|
8016
8073
|
},
|
|
8017
|
-
[
|
|
8074
|
+
[
|
|
8075
|
+
transport,
|
|
8076
|
+
reducer,
|
|
8077
|
+
messagesSig,
|
|
8078
|
+
conversationIdSig,
|
|
8079
|
+
options,
|
|
8080
|
+
bus,
|
|
8081
|
+
feedback,
|
|
8082
|
+
persistence,
|
|
8083
|
+
visitorId,
|
|
8084
|
+
adoptConversationRebind
|
|
8085
|
+
]
|
|
8018
8086
|
);
|
|
8087
|
+
const regenerateDanglingTurn = useCallback6(() => {
|
|
8088
|
+
if (streaming || regenInFlightRef.current || resumeBubbleRef.current) return;
|
|
8089
|
+
const last = messagesSig.value.filter((m) => !m.ephemeral).at(-1);
|
|
8090
|
+
if (last?.role !== "user") return;
|
|
8091
|
+
regenInFlightRef.current = true;
|
|
8092
|
+
log16.info("regenerating dangling user turn (needs-generation)");
|
|
8093
|
+
const assistantMsg = makeAssistantMessage();
|
|
8094
|
+
messagesSig.value = [...messagesSig.value, assistantMsg];
|
|
8095
|
+
reducer.attach(assistantMsg);
|
|
8096
|
+
void streamAssistant(assistantMsg, { continueExisting: false }).finally(() => {
|
|
8097
|
+
regenInFlightRef.current = false;
|
|
8098
|
+
});
|
|
8099
|
+
}, [streaming, messagesSig, reducer, streamAssistant]);
|
|
8100
|
+
useEffect16(() => {
|
|
8101
|
+
regenerateDanglingRef.current = regenerateDanglingTurn;
|
|
8102
|
+
}, [regenerateDanglingTurn]);
|
|
8019
8103
|
const decideTool = useCallback6(
|
|
8020
8104
|
(toolCallId, mutate) => {
|
|
8021
8105
|
if (streaming) return;
|