@pagelines/sdk 1.0.759 → 1.0.761
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/AgentProvider.js +18 -4
- package/dist/AgentProvider.js.map +1 -1
- package/dist/AgentWrap.js +2 -2
- package/dist/AgentWrap.js.map +1 -1
- package/dist/agent/AgentController.d.ts +2 -0
- package/dist/agent/ui/AgentChat.vue.d.ts +4 -0
- package/dist/agent/ui/AgentProvider.vue.d.ts +4 -0
- package/dist/agent/ui/ElCreateAgent.vue.d.ts +6 -0
- package/dist/agent/voice/voice-session-client.d.ts +6 -1
- package/dist/agent.js +9 -14
- package/dist/agent.js.map +1 -1
- package/dist/contract.js +1698 -1680
- package/dist/contract.js.map +1 -1
- package/dist/demo/index.d.ts +3 -0
- package/dist/sdkClient.d.ts +9 -0
- package/dist/widget/composables/useWidgetState.d.ts +9 -0
- package/package.json +1 -1
|
@@ -86,6 +86,8 @@ export type AgentChatControllerSettings = {
|
|
|
86
86
|
}) => VoiceSessionClient;
|
|
87
87
|
/** Reload the bound transcript after an out-of-band voice session writes turns. */
|
|
88
88
|
refreshMessagesFn?: () => Promise<void>;
|
|
89
|
+
onTurnStarted?: () => void;
|
|
90
|
+
onTurnCompleted?: (conversationId: string) => void;
|
|
89
91
|
};
|
|
90
92
|
export declare class AgentChatController extends SettingsObject<AgentChatControllerSettings> {
|
|
91
93
|
private isTextMode;
|
|
@@ -32,9 +32,13 @@ type __VLS_Slots = {
|
|
|
32
32
|
declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
33
33
|
error: (message: string) => any;
|
|
34
34
|
close: (value: string) => any;
|
|
35
|
+
turnStarted: () => any;
|
|
36
|
+
turnCompleted: (conversationId: string) => any;
|
|
35
37
|
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
36
38
|
onError?: ((message: string) => any) | undefined;
|
|
37
39
|
onClose?: ((value: string) => any) | undefined;
|
|
40
|
+
onTurnStarted?: (() => any) | undefined;
|
|
41
|
+
onTurnCompleted?: ((conversationId: string) => any) | undefined;
|
|
38
42
|
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
39
43
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
40
44
|
declare const _default: typeof __VLS_export;
|
|
@@ -27,9 +27,13 @@ type __VLS_Slots = {
|
|
|
27
27
|
declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
28
28
|
error: (message: string) => any;
|
|
29
29
|
close: (value: string) => any;
|
|
30
|
+
turnStarted: () => any;
|
|
31
|
+
turnCompleted: (conversationId: string) => any;
|
|
30
32
|
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
31
33
|
onError?: ((message: string) => any) | undefined;
|
|
32
34
|
onClose?: ((value: string) => any) | undefined;
|
|
35
|
+
onTurnStarted?: (() => any) | undefined;
|
|
36
|
+
onTurnCompleted?: ((conversationId: string) => any) | undefined;
|
|
33
37
|
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
34
38
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
35
39
|
declare const _default: typeof __VLS_export;
|
|
@@ -77,6 +77,9 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {
|
|
|
77
77
|
desiredStatus?: "active" | "stopped" | null | undefined;
|
|
78
78
|
automationPrimaryChannel?: string | undefined;
|
|
79
79
|
heartbeatEnabled?: boolean | undefined;
|
|
80
|
+
heartbeatBriefingTime?: string | undefined;
|
|
81
|
+
heartbeatCheckinTime?: string | undefined;
|
|
82
|
+
heartbeatCloseoutTime?: string | undefined;
|
|
80
83
|
onboardedAt?: string | null | undefined;
|
|
81
84
|
org?: {
|
|
82
85
|
orgId: string;
|
|
@@ -211,6 +214,9 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {
|
|
|
211
214
|
desiredStatus?: "active" | "stopped" | null | undefined;
|
|
212
215
|
automationPrimaryChannel?: string | undefined;
|
|
213
216
|
heartbeatEnabled?: boolean | undefined;
|
|
217
|
+
heartbeatBriefingTime?: string | undefined;
|
|
218
|
+
heartbeatCheckinTime?: string | undefined;
|
|
219
|
+
heartbeatCloseoutTime?: string | undefined;
|
|
214
220
|
onboardedAt?: string | null | undefined;
|
|
215
221
|
org?: {
|
|
216
222
|
orgId: string;
|
|
@@ -22,7 +22,12 @@ export interface VoiceSessionClientSettings extends VoiceClientHandlers, Record<
|
|
|
22
22
|
createProvider?: CreateVoiceProviderClient;
|
|
23
23
|
playChime?: (kind: VoiceChimeKind) => void;
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* The readiness cue is the only signal an eyes-off user gets, so it is served
|
|
27
|
+
* from the API origin rather than the embedding page — a relative path would
|
|
28
|
+
* silently 404 wherever the SDK is not hosted by the app itself.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createBrowserVoiceChimePlayer(apiBase: string): (kind: VoiceChimeKind) => void;
|
|
26
31
|
export declare class VoiceSessionClient extends SettingsObject<VoiceSessionClientSettings> {
|
|
27
32
|
readonly state: Ref<VoiceSessionClientState>;
|
|
28
33
|
private provider?;
|
package/dist/agent.js
CHANGED
|
@@ -115,23 +115,18 @@ var k = {
|
|
|
115
115
|
start: "/audio/start-call.mp3",
|
|
116
116
|
end: "/audio/end-call.mp3"
|
|
117
117
|
}, L = .7, R = 50;
|
|
118
|
-
function createBrowserVoiceChimePlayer() {
|
|
119
|
-
let
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
let n = e[t];
|
|
127
|
-
if (!n) return;
|
|
128
|
-
n.currentTime = 0, n.play().catch(() => {});
|
|
129
|
-
} catch {}
|
|
118
|
+
function createBrowserVoiceChimePlayer(e) {
|
|
119
|
+
let t = Object.fromEntries(["start", "end"].map((t) => {
|
|
120
|
+
let n = new Audio(`${e}${I[t]}`);
|
|
121
|
+
return n.preload = "auto", n.volume = L, [t, n];
|
|
122
|
+
}));
|
|
123
|
+
return (e) => {
|
|
124
|
+
t[e].currentTime = 0, t[e].play().catch(() => {});
|
|
130
125
|
};
|
|
131
126
|
}
|
|
132
127
|
var VoiceSessionClient = class extends f {
|
|
133
|
-
constructor(
|
|
134
|
-
super("VoiceSessionClient",
|
|
128
|
+
constructor(n) {
|
|
129
|
+
super("VoiceSessionClient", n), t(this, "state", T("idle")), t(this, "provider", void 0), t(this, "chime", void 0), t(this, "generation", 0), t(this, "levelTimer", void 0), this.chime = n.playChime ?? createBrowserVoiceChimePlayer(e(n.apiBase, n.isDev));
|
|
135
130
|
}
|
|
136
131
|
async start() {
|
|
137
132
|
if (this.state.value !== "idle") return;
|
package/dist/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","names":[],"sources":["../agent/ui/AgentWidget.vue","../agent/ui/AgentWidget.vue","../agent/ui/ElAgentChatPreview.vue","../agent/ui/ElAgentChatPreview.vue","../agent/voice/voice-session-client.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport { nextTick, ref, watch } from 'vue'\nimport AgentChat from './AgentChat.vue'\nimport AgentWrap from './AgentWrap.vue'\n\ninterface Props {\n sdk?: PageLinesSDK\n handle: string\n context?: string\n firstMessage?: string\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'\n}\n\nconst props = defineProps<Props>()\nconst isOpen = ref(false)\nconst isAgentActive = ref(false)\n\nfunction toggle() {\n isOpen.value = !isOpen.value\n}\n\n// Watch isOpen to delay agent activation for smooth transition\nwatch(isOpen, async (newValue) => {\n if (newValue) {\n // When opening, delay agent activation until transition starts\n await nextTick()\n setTimeout(() => {\n isAgentActive.value = true\n }, 400) // Delay to let container expand first\n } else {\n // When closing, immediately deactivate agent\n isAgentActive.value = false\n }\n})\n\nfunction open() {\n isOpen.value = true\n}\n\nfunction close() {\n isOpen.value = false\n}\n\nfunction handleClose() {\n close()\n}\n\ndefineExpose({\n toggle,\n open,\n close,\n})\n</script>\n\n<template>\n <AgentWrap\n v-slot=\"{ agent, sdk: resolvedSdk }\"\n :sdk=\"sdk\"\n :handle=\"handle\"\n :context=\"context\"\n :first-message=\"firstMessage\"\n >\n <!-- Fixed Widget Wrapper -->\n <div\n v-if=\"agent\"\n class=\"fixed z-[999999] pointer-events-auto\"\n :class=\"[\n props.position === 'bottom-left' ? 'bottom-6 left-6'\n : props.position === 'top-right' ? 'top-6 right-6'\n : props.position === 'top-left' ? 'top-6 left-6'\n : 'bottom-6 right-6',\n ]\"\n >\n <!-- Widget Content with Transition -->\n <div\n class=\"transition-all duration-500 ease-[cubic-bezier(0.25,1,0.33,1)] transform-gpu\"\n :class=\"[\n isOpen\n ? 'widget-expanded w-96 h-[600px] max-w-[calc(100vw-48px)] max-h-[calc(100vh-48px)] rounded-3xl opacity-100 scale-100'\n : 'widget-button w-[80px] h-[80px] opacity-100 scale-100 flex items-center justify-center cursor-pointer',\n ]\"\n :style=\"{\n 'transform-origin':\n props.position === 'bottom-left' ? 'bottom left'\n : props.position === 'top-right' ? 'top right'\n : props.position === 'top-left' ? 'top left'\n : 'bottom right',\n }\"\n @click=\"!isOpen ? toggle() : undefined\"\n >\n <!-- Button Content (visible when closed) -->\n <div v-if=\"!isOpen\" class=\"relative h-full w-full\">\n <div class=\"group relative h-full w-full rounded-3xl overflow-hidden shadow-lg transition-all duration-300 ease-[cubic-bezier(0.25,1,0.33,1)] hover:shadow-2xl hover:translate-y-[-1px] hover:brightness-110 active:scale-[1.06] active:-translate-y-0.5 active:duration-100\">\n <img\n :src=\"agent.avatarUrl.value\"\n :alt=\"`${agent.displayName.value} assistant`\"\n class=\"h-full w-full object-cover pointer-events-none\"\n width=\"80\"\n height=\"80\"\n />\n <!-- Gradient overlay for contrast -->\n <div class=\"absolute inset-0 pointer-events-none bg-gradient-to-br from-transparent via-black/10 to-black/40 opacity-60 transition-opacity duration-300 group-hover:opacity-40\" />\n </div>\n <!-- Online indicator -->\n <div v-if=\"agent.state.value.lifecycle === 'running'\" class=\"absolute top-0.5 right-0.5\">\n <div class=\"size-3 bg-green-500 rounded-full ring-2 ring-white absolute animate-ping\" style=\"animation-duration: 3s;\" />\n <div class=\"size-3 bg-green-500 rounded-full ring-2 ring-white\" />\n </div>\n </div>\n\n <!-- Chat Content (visible when open) -->\n <AgentChat\n v-if=\"isOpen && agent\"\n class=\"rounded-3xl shadow-2xl border border-white/10\"\n :sdk=\"resolvedSdk\"\n :agent=\"agent\"\n :context=\"context\"\n :first-message=\"firstMessage\"\n :has-close=\"true\"\n :is-active=\"isAgentActive\"\n @close=\"handleClose\"\n />\n </div>\n </div>\n </AgentWrap>\n</template>\n","<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport { nextTick, ref, watch } from 'vue'\nimport AgentChat from './AgentChat.vue'\nimport AgentWrap from './AgentWrap.vue'\n\ninterface Props {\n sdk?: PageLinesSDK\n handle: string\n context?: string\n firstMessage?: string\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'\n}\n\nconst props = defineProps<Props>()\nconst isOpen = ref(false)\nconst isAgentActive = ref(false)\n\nfunction toggle() {\n isOpen.value = !isOpen.value\n}\n\n// Watch isOpen to delay agent activation for smooth transition\nwatch(isOpen, async (newValue) => {\n if (newValue) {\n // When opening, delay agent activation until transition starts\n await nextTick()\n setTimeout(() => {\n isAgentActive.value = true\n }, 400) // Delay to let container expand first\n } else {\n // When closing, immediately deactivate agent\n isAgentActive.value = false\n }\n})\n\nfunction open() {\n isOpen.value = true\n}\n\nfunction close() {\n isOpen.value = false\n}\n\nfunction handleClose() {\n close()\n}\n\ndefineExpose({\n toggle,\n open,\n close,\n})\n</script>\n\n<template>\n <AgentWrap\n v-slot=\"{ agent, sdk: resolvedSdk }\"\n :sdk=\"sdk\"\n :handle=\"handle\"\n :context=\"context\"\n :first-message=\"firstMessage\"\n >\n <!-- Fixed Widget Wrapper -->\n <div\n v-if=\"agent\"\n class=\"fixed z-[999999] pointer-events-auto\"\n :class=\"[\n props.position === 'bottom-left' ? 'bottom-6 left-6'\n : props.position === 'top-right' ? 'top-6 right-6'\n : props.position === 'top-left' ? 'top-6 left-6'\n : 'bottom-6 right-6',\n ]\"\n >\n <!-- Widget Content with Transition -->\n <div\n class=\"transition-all duration-500 ease-[cubic-bezier(0.25,1,0.33,1)] transform-gpu\"\n :class=\"[\n isOpen\n ? 'widget-expanded w-96 h-[600px] max-w-[calc(100vw-48px)] max-h-[calc(100vh-48px)] rounded-3xl opacity-100 scale-100'\n : 'widget-button w-[80px] h-[80px] opacity-100 scale-100 flex items-center justify-center cursor-pointer',\n ]\"\n :style=\"{\n 'transform-origin':\n props.position === 'bottom-left' ? 'bottom left'\n : props.position === 'top-right' ? 'top right'\n : props.position === 'top-left' ? 'top left'\n : 'bottom right',\n }\"\n @click=\"!isOpen ? toggle() : undefined\"\n >\n <!-- Button Content (visible when closed) -->\n <div v-if=\"!isOpen\" class=\"relative h-full w-full\">\n <div class=\"group relative h-full w-full rounded-3xl overflow-hidden shadow-lg transition-all duration-300 ease-[cubic-bezier(0.25,1,0.33,1)] hover:shadow-2xl hover:translate-y-[-1px] hover:brightness-110 active:scale-[1.06] active:-translate-y-0.5 active:duration-100\">\n <img\n :src=\"agent.avatarUrl.value\"\n :alt=\"`${agent.displayName.value} assistant`\"\n class=\"h-full w-full object-cover pointer-events-none\"\n width=\"80\"\n height=\"80\"\n />\n <!-- Gradient overlay for contrast -->\n <div class=\"absolute inset-0 pointer-events-none bg-gradient-to-br from-transparent via-black/10 to-black/40 opacity-60 transition-opacity duration-300 group-hover:opacity-40\" />\n </div>\n <!-- Online indicator -->\n <div v-if=\"agent.state.value.lifecycle === 'running'\" class=\"absolute top-0.5 right-0.5\">\n <div class=\"size-3 bg-green-500 rounded-full ring-2 ring-white absolute animate-ping\" style=\"animation-duration: 3s;\" />\n <div class=\"size-3 bg-green-500 rounded-full ring-2 ring-white\" />\n </div>\n </div>\n\n <!-- Chat Content (visible when open) -->\n <AgentChat\n v-if=\"isOpen && agent\"\n class=\"rounded-3xl shadow-2xl border border-white/10\"\n :sdk=\"resolvedSdk\"\n :agent=\"agent\"\n :context=\"context\"\n :first-message=\"firstMessage\"\n :has-close=\"true\"\n :is-active=\"isAgentActive\"\n @close=\"handleClose\"\n />\n </div>\n </div>\n </AgentWrap>\n</template>\n","<script setup lang=\"ts\">\nimport ChatRichText from './ChatRichText.vue'\n\nexport type ChatPreviewMessage = {\n sender: 'user' | 'agent'\n text: string\n}\n\ndefineProps<{\n messages: ChatPreviewMessage[]\n variant?: 'light' | 'dark'\n}>()\n</script>\n\n<template>\n <div\n class=\"@container/chat-preview flex flex-col gap-3\"\n :class=\"variant === 'dark' ? 'text-white' : 'text-slate-950'\"\n data-test=\"agent-chat-preview\"\n >\n <div\n v-for=\"(message, index) in messages\"\n :key=\"`${message.sender}-${index}`\"\n class=\"flex\"\n :class=\"message.sender === 'user' ? 'justify-end' : 'justify-start'\"\n data-test=\"agent-chat-preview-message\"\n :data-sender=\"message.sender\"\n >\n <div\n class=\"max-w-[88%] rounded-2xl px-4 py-3 text-sm shadow-sm @sm/chat-preview:max-w-[78%]\"\n :class=\"message.sender === 'user'\n ? 'bg-slate-950 text-white'\n : variant === 'dark'\n ? 'border border-white/10 bg-white/10 text-white'\n : 'border border-slate-200 bg-white text-slate-950'\"\n >\n <ChatRichText\n :text=\"message.text\"\n :inverted=\"message.sender === 'user' || variant === 'dark'\"\n />\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ChatRichText from './ChatRichText.vue'\n\nexport type ChatPreviewMessage = {\n sender: 'user' | 'agent'\n text: string\n}\n\ndefineProps<{\n messages: ChatPreviewMessage[]\n variant?: 'light' | 'dark'\n}>()\n</script>\n\n<template>\n <div\n class=\"@container/chat-preview flex flex-col gap-3\"\n :class=\"variant === 'dark' ? 'text-white' : 'text-slate-950'\"\n data-test=\"agent-chat-preview\"\n >\n <div\n v-for=\"(message, index) in messages\"\n :key=\"`${message.sender}-${index}`\"\n class=\"flex\"\n :class=\"message.sender === 'user' ? 'justify-end' : 'justify-start'\"\n data-test=\"agent-chat-preview-message\"\n :data-sender=\"message.sender\"\n >\n <div\n class=\"max-w-[88%] rounded-2xl px-4 py-3 text-sm shadow-sm @sm/chat-preview:max-w-[78%]\"\n :class=\"message.sender === 'user'\n ? 'bg-slate-950 text-white'\n : variant === 'dark'\n ? 'border border-white/10 bg-white/10 text-white'\n : 'border border-slate-200 bg-white text-slate-950'\"\n >\n <ChatRichText\n :text=\"message.text\"\n :inverted=\"message.sender === 'user' || variant === 'dark'\"\n />\n </div>\n </div>\n </div>\n</template>\n","/** Provider-neutral voice session state machine for web clients. */\nimport type { ApiResponse, VoiceSessionMint } from '@pagelines/core'\nimport type { Ref } from 'vue'\nimport type {\n CreateVoiceProviderClient,\n VoiceLevelEvent,\n VoiceProviderClient,\n VoiceSessionError,\n} from './provider'\nimport { SettingsObject, zVoiceSessionMint } from '@pagelines/core'\nimport { ref } from 'vue'\nimport { resolveApiBase } from '../../api'\nimport { createVoiceProviderClient } from './provider'\n\nexport type { VoiceLevelEvent, VoiceSessionError } from './provider'\nexport { VOICE_SPECTRUM_BANDS, voiceSpectrum } from './provider'\n\nexport type VoiceSessionClientState = 'idle' | 'minting' | 'connecting' | 'live' | 'ended'\nexport type VoiceChimeKind = 'start' | 'end'\n\nexport interface VoiceClientHandlers {\n onStateChange?: (state: VoiceSessionClientState) => void\n onLevel?: (event: VoiceLevelEvent) => void\n onError?: (error: VoiceSessionError) => void\n}\n\nexport interface VoiceSessionClientSettings extends VoiceClientHandlers, Record<string, unknown> {\n agentId: string\n orgId: string\n conversationId?: string\n apiBase?: string\n isDev?: boolean\n token?: string\n fetchFn?: typeof fetch\n /** Provider composition seam; the default dynamically loads the minted provider. */\n createProvider?: CreateVoiceProviderClient\n playChime?: (kind: VoiceChimeKind) => void\n}\n\nconst CHIME_SOURCES: Record<VoiceChimeKind, string> = {\n start: '/audio/start-call.mp3',\n end: '/audio/end-call.mp3',\n}\nconst CHIME_VOLUME = 0.7\nconst LEVEL_INTERVAL_MS = 50\n\nexport function createBrowserVoiceChimePlayer(): (kind: VoiceChimeKind) => void {\n const players: Partial<Record<VoiceChimeKind, HTMLAudioElement>> = {}\n for (const kind of ['start', 'end'] as const) {\n try {\n const audio = new Audio(CHIME_SOURCES[kind])\n audio.preload = 'auto'\n audio.volume = CHIME_VOLUME\n players[kind] = audio\n } catch {}\n }\n return (kind) => {\n try {\n const audio = players[kind]\n if (!audio)\n return\n audio.currentTime = 0\n void audio.play().catch(() => {})\n } catch {}\n }\n}\n\nexport class VoiceSessionClient extends SettingsObject<VoiceSessionClientSettings> {\n readonly state: Ref<VoiceSessionClientState> = ref('idle')\n\n private provider?: VoiceProviderClient\n private readonly chime: (kind: VoiceChimeKind) => void\n private generation = 0\n private levelTimer: ReturnType<typeof setInterval> | undefined\n\n constructor(settings: VoiceSessionClientSettings) {\n super('VoiceSessionClient', settings)\n this.chime = settings.playChime ?? createBrowserVoiceChimePlayer()\n }\n\n async start(): Promise<void> {\n if (this.state.value !== 'idle')\n return\n const generation = ++this.generation\n this.setState('minting')\n try {\n const mint = await this.mintSession(generation)\n if (!mint || generation !== this.generation)\n return\n this.setState('connecting')\n await this.connect({ mint, generation })\n } catch (error) {\n if (generation !== this.generation)\n return\n this.fail(this.toSessionError(error, 'VOICE_MINT_FAILED'))\n }\n }\n\n end(): void {\n if (this.state.value === 'idle' || this.state.value === 'ended')\n return\n const shouldChime = this.state.value === 'live'\n this.generation++\n if (shouldChime)\n this.chime('end')\n this.setState('ended')\n this.teardown()\n }\n\n private async connect(args: { mint: VoiceSessionMint, generation: number }): Promise<void> {\n const { mint, generation } = args\n const provider = await (this.settings.createProvider ?? createVoiceProviderClient)(mint)\n if (generation !== this.generation) {\n await provider.disconnect().catch(() => {})\n return\n }\n this.provider = provider\n\n try {\n await provider.connect({\n onDisconnected: () => {\n if (generation !== this.generation || this.provider !== provider)\n return\n this.fail({\n code: this.state.value === 'live' ? 'VOICE_CONNECTION_LOST' : 'VOICE_CONNECT_FAILED',\n message: this.state.value === 'live'\n ? 'The voice connection dropped.'\n : 'Could not open the voice connection.',\n })\n },\n onError: error => {\n if (generation === this.generation && this.provider === provider)\n this.fail(error)\n },\n })\n } catch (error) {\n if (generation !== this.generation || this.provider !== provider)\n return\n this.fail(this.toSessionError(error, 'VOICE_CONNECT_FAILED'))\n return\n }\n if (generation !== this.generation || this.provider !== provider)\n return\n\n this.startLevelTimer(provider, generation)\n this.setState('live')\n this.chime('start')\n }\n\n private setState(state: VoiceSessionClientState): void {\n if (this.state.value === state)\n return\n this.state.value = state\n this.settings.onStateChange?.(state)\n }\n\n private fail(error: VoiceSessionError): void {\n this.generation++\n this.settings.onError?.(error)\n this.setState('ended')\n this.teardown()\n }\n\n private teardown(): void {\n if (this.levelTimer !== undefined) {\n clearInterval(this.levelTimer)\n this.levelTimer = undefined\n }\n const provider = this.provider\n this.provider = undefined\n if (provider)\n void provider.disconnect().catch(() => {})\n this.settings.onLevel?.({ source: 'playback', level: 0 })\n }\n\n private startLevelTimer(provider: VoiceProviderClient, generation: number): void {\n if (this.levelTimer !== undefined)\n return\n this.levelTimer = setInterval(() => {\n if (generation !== this.generation || this.provider !== provider)\n return\n const level = provider.sampleLevel()\n if (level)\n this.settings.onLevel?.(level)\n }, LEVEL_INTERVAL_MS)\n }\n\n private authHeaders(): Record<string, string> {\n return this.settings.token ? { Authorization: `Bearer ${this.settings.token}` } : {}\n }\n\n private async post<T>(args: { path: string, body: unknown }): Promise<T> {\n const apiBase = resolveApiBase(this.settings.apiBase, this.settings.isDev)\n const fetchFn = this.settings.fetchFn ?? fetch\n const res = await fetchFn(`${apiBase}${args.path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...this.authHeaders() },\n credentials: 'include',\n body: JSON.stringify(args.body),\n })\n const result = await res.json() as ApiResponse<T>\n if (!res.ok || !result.ok) {\n const message = !result.ok ? result.error : `HTTP ${res.status}`\n const code = !result.ok && result.code ? result.code : 'VOICE_MINT_FAILED'\n throw Object.assign(new Error(message || 'Voice request failed.'), { code })\n }\n return result.data\n }\n\n private async mintSession(generation: number): Promise<VoiceSessionMint | null> {\n let conversationId = this.settings.conversationId\n if (!conversationId) {\n conversationId = (await this.post<{ conversationId: string }>({\n path: '/api/conversations',\n body: {\n orgId: this.settings.orgId,\n participants: [{ type: 'agent', id: this.settings.agentId }],\n },\n })).conversationId\n if (generation !== this.generation)\n return null\n }\n\n const data = await this.post<unknown>({ path: '/api/voice/sessions', body: { conversationId } })\n if (generation !== this.generation)\n return null\n const parsed = zVoiceSessionMint.safeParse(data)\n if (!parsed.success)\n throw Object.assign(new Error('Voice session mint returned an unexpected shape.'), { code: 'VOICE_MINT_INVALID' })\n return parsed.data\n }\n\n private toSessionError(error: unknown, fallbackCode: string): VoiceSessionError {\n return error instanceof Error\n ? {\n code: 'code' in error ? String((error as Error & { code: unknown }).code) : fallbackCode,\n message: error.message,\n }\n : { code: fallbackCode, message: 'Voice session failed to start.' }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent.js","names":[],"sources":["../agent/ui/AgentWidget.vue","../agent/ui/AgentWidget.vue","../agent/ui/ElAgentChatPreview.vue","../agent/ui/ElAgentChatPreview.vue","../agent/voice/voice-session-client.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport { nextTick, ref, watch } from 'vue'\nimport AgentChat from './AgentChat.vue'\nimport AgentWrap from './AgentWrap.vue'\n\ninterface Props {\n sdk?: PageLinesSDK\n handle: string\n context?: string\n firstMessage?: string\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'\n}\n\nconst props = defineProps<Props>()\nconst isOpen = ref(false)\nconst isAgentActive = ref(false)\n\nfunction toggle() {\n isOpen.value = !isOpen.value\n}\n\n// Watch isOpen to delay agent activation for smooth transition\nwatch(isOpen, async (newValue) => {\n if (newValue) {\n // When opening, delay agent activation until transition starts\n await nextTick()\n setTimeout(() => {\n isAgentActive.value = true\n }, 400) // Delay to let container expand first\n } else {\n // When closing, immediately deactivate agent\n isAgentActive.value = false\n }\n})\n\nfunction open() {\n isOpen.value = true\n}\n\nfunction close() {\n isOpen.value = false\n}\n\nfunction handleClose() {\n close()\n}\n\ndefineExpose({\n toggle,\n open,\n close,\n})\n</script>\n\n<template>\n <AgentWrap\n v-slot=\"{ agent, sdk: resolvedSdk }\"\n :sdk=\"sdk\"\n :handle=\"handle\"\n :context=\"context\"\n :first-message=\"firstMessage\"\n >\n <!-- Fixed Widget Wrapper -->\n <div\n v-if=\"agent\"\n class=\"fixed z-[999999] pointer-events-auto\"\n :class=\"[\n props.position === 'bottom-left' ? 'bottom-6 left-6'\n : props.position === 'top-right' ? 'top-6 right-6'\n : props.position === 'top-left' ? 'top-6 left-6'\n : 'bottom-6 right-6',\n ]\"\n >\n <!-- Widget Content with Transition -->\n <div\n class=\"transition-all duration-500 ease-[cubic-bezier(0.25,1,0.33,1)] transform-gpu\"\n :class=\"[\n isOpen\n ? 'widget-expanded w-96 h-[600px] max-w-[calc(100vw-48px)] max-h-[calc(100vh-48px)] rounded-3xl opacity-100 scale-100'\n : 'widget-button w-[80px] h-[80px] opacity-100 scale-100 flex items-center justify-center cursor-pointer',\n ]\"\n :style=\"{\n 'transform-origin':\n props.position === 'bottom-left' ? 'bottom left'\n : props.position === 'top-right' ? 'top right'\n : props.position === 'top-left' ? 'top left'\n : 'bottom right',\n }\"\n @click=\"!isOpen ? toggle() : undefined\"\n >\n <!-- Button Content (visible when closed) -->\n <div v-if=\"!isOpen\" class=\"relative h-full w-full\">\n <div class=\"group relative h-full w-full rounded-3xl overflow-hidden shadow-lg transition-all duration-300 ease-[cubic-bezier(0.25,1,0.33,1)] hover:shadow-2xl hover:translate-y-[-1px] hover:brightness-110 active:scale-[1.06] active:-translate-y-0.5 active:duration-100\">\n <img\n :src=\"agent.avatarUrl.value\"\n :alt=\"`${agent.displayName.value} assistant`\"\n class=\"h-full w-full object-cover pointer-events-none\"\n width=\"80\"\n height=\"80\"\n />\n <!-- Gradient overlay for contrast -->\n <div class=\"absolute inset-0 pointer-events-none bg-gradient-to-br from-transparent via-black/10 to-black/40 opacity-60 transition-opacity duration-300 group-hover:opacity-40\" />\n </div>\n <!-- Online indicator -->\n <div v-if=\"agent.state.value.lifecycle === 'running'\" class=\"absolute top-0.5 right-0.5\">\n <div class=\"size-3 bg-green-500 rounded-full ring-2 ring-white absolute animate-ping\" style=\"animation-duration: 3s;\" />\n <div class=\"size-3 bg-green-500 rounded-full ring-2 ring-white\" />\n </div>\n </div>\n\n <!-- Chat Content (visible when open) -->\n <AgentChat\n v-if=\"isOpen && agent\"\n class=\"rounded-3xl shadow-2xl border border-white/10\"\n :sdk=\"resolvedSdk\"\n :agent=\"agent\"\n :context=\"context\"\n :first-message=\"firstMessage\"\n :has-close=\"true\"\n :is-active=\"isAgentActive\"\n @close=\"handleClose\"\n />\n </div>\n </div>\n </AgentWrap>\n</template>\n","<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport { nextTick, ref, watch } from 'vue'\nimport AgentChat from './AgentChat.vue'\nimport AgentWrap from './AgentWrap.vue'\n\ninterface Props {\n sdk?: PageLinesSDK\n handle: string\n context?: string\n firstMessage?: string\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'\n}\n\nconst props = defineProps<Props>()\nconst isOpen = ref(false)\nconst isAgentActive = ref(false)\n\nfunction toggle() {\n isOpen.value = !isOpen.value\n}\n\n// Watch isOpen to delay agent activation for smooth transition\nwatch(isOpen, async (newValue) => {\n if (newValue) {\n // When opening, delay agent activation until transition starts\n await nextTick()\n setTimeout(() => {\n isAgentActive.value = true\n }, 400) // Delay to let container expand first\n } else {\n // When closing, immediately deactivate agent\n isAgentActive.value = false\n }\n})\n\nfunction open() {\n isOpen.value = true\n}\n\nfunction close() {\n isOpen.value = false\n}\n\nfunction handleClose() {\n close()\n}\n\ndefineExpose({\n toggle,\n open,\n close,\n})\n</script>\n\n<template>\n <AgentWrap\n v-slot=\"{ agent, sdk: resolvedSdk }\"\n :sdk=\"sdk\"\n :handle=\"handle\"\n :context=\"context\"\n :first-message=\"firstMessage\"\n >\n <!-- Fixed Widget Wrapper -->\n <div\n v-if=\"agent\"\n class=\"fixed z-[999999] pointer-events-auto\"\n :class=\"[\n props.position === 'bottom-left' ? 'bottom-6 left-6'\n : props.position === 'top-right' ? 'top-6 right-6'\n : props.position === 'top-left' ? 'top-6 left-6'\n : 'bottom-6 right-6',\n ]\"\n >\n <!-- Widget Content with Transition -->\n <div\n class=\"transition-all duration-500 ease-[cubic-bezier(0.25,1,0.33,1)] transform-gpu\"\n :class=\"[\n isOpen\n ? 'widget-expanded w-96 h-[600px] max-w-[calc(100vw-48px)] max-h-[calc(100vh-48px)] rounded-3xl opacity-100 scale-100'\n : 'widget-button w-[80px] h-[80px] opacity-100 scale-100 flex items-center justify-center cursor-pointer',\n ]\"\n :style=\"{\n 'transform-origin':\n props.position === 'bottom-left' ? 'bottom left'\n : props.position === 'top-right' ? 'top right'\n : props.position === 'top-left' ? 'top left'\n : 'bottom right',\n }\"\n @click=\"!isOpen ? toggle() : undefined\"\n >\n <!-- Button Content (visible when closed) -->\n <div v-if=\"!isOpen\" class=\"relative h-full w-full\">\n <div class=\"group relative h-full w-full rounded-3xl overflow-hidden shadow-lg transition-all duration-300 ease-[cubic-bezier(0.25,1,0.33,1)] hover:shadow-2xl hover:translate-y-[-1px] hover:brightness-110 active:scale-[1.06] active:-translate-y-0.5 active:duration-100\">\n <img\n :src=\"agent.avatarUrl.value\"\n :alt=\"`${agent.displayName.value} assistant`\"\n class=\"h-full w-full object-cover pointer-events-none\"\n width=\"80\"\n height=\"80\"\n />\n <!-- Gradient overlay for contrast -->\n <div class=\"absolute inset-0 pointer-events-none bg-gradient-to-br from-transparent via-black/10 to-black/40 opacity-60 transition-opacity duration-300 group-hover:opacity-40\" />\n </div>\n <!-- Online indicator -->\n <div v-if=\"agent.state.value.lifecycle === 'running'\" class=\"absolute top-0.5 right-0.5\">\n <div class=\"size-3 bg-green-500 rounded-full ring-2 ring-white absolute animate-ping\" style=\"animation-duration: 3s;\" />\n <div class=\"size-3 bg-green-500 rounded-full ring-2 ring-white\" />\n </div>\n </div>\n\n <!-- Chat Content (visible when open) -->\n <AgentChat\n v-if=\"isOpen && agent\"\n class=\"rounded-3xl shadow-2xl border border-white/10\"\n :sdk=\"resolvedSdk\"\n :agent=\"agent\"\n :context=\"context\"\n :first-message=\"firstMessage\"\n :has-close=\"true\"\n :is-active=\"isAgentActive\"\n @close=\"handleClose\"\n />\n </div>\n </div>\n </AgentWrap>\n</template>\n","<script setup lang=\"ts\">\nimport ChatRichText from './ChatRichText.vue'\n\nexport type ChatPreviewMessage = {\n sender: 'user' | 'agent'\n text: string\n}\n\ndefineProps<{\n messages: ChatPreviewMessage[]\n variant?: 'light' | 'dark'\n}>()\n</script>\n\n<template>\n <div\n class=\"@container/chat-preview flex flex-col gap-3\"\n :class=\"variant === 'dark' ? 'text-white' : 'text-slate-950'\"\n data-test=\"agent-chat-preview\"\n >\n <div\n v-for=\"(message, index) in messages\"\n :key=\"`${message.sender}-${index}`\"\n class=\"flex\"\n :class=\"message.sender === 'user' ? 'justify-end' : 'justify-start'\"\n data-test=\"agent-chat-preview-message\"\n :data-sender=\"message.sender\"\n >\n <div\n class=\"max-w-[88%] rounded-2xl px-4 py-3 text-sm shadow-sm @sm/chat-preview:max-w-[78%]\"\n :class=\"message.sender === 'user'\n ? 'bg-slate-950 text-white'\n : variant === 'dark'\n ? 'border border-white/10 bg-white/10 text-white'\n : 'border border-slate-200 bg-white text-slate-950'\"\n >\n <ChatRichText\n :text=\"message.text\"\n :inverted=\"message.sender === 'user' || variant === 'dark'\"\n />\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ChatRichText from './ChatRichText.vue'\n\nexport type ChatPreviewMessage = {\n sender: 'user' | 'agent'\n text: string\n}\n\ndefineProps<{\n messages: ChatPreviewMessage[]\n variant?: 'light' | 'dark'\n}>()\n</script>\n\n<template>\n <div\n class=\"@container/chat-preview flex flex-col gap-3\"\n :class=\"variant === 'dark' ? 'text-white' : 'text-slate-950'\"\n data-test=\"agent-chat-preview\"\n >\n <div\n v-for=\"(message, index) in messages\"\n :key=\"`${message.sender}-${index}`\"\n class=\"flex\"\n :class=\"message.sender === 'user' ? 'justify-end' : 'justify-start'\"\n data-test=\"agent-chat-preview-message\"\n :data-sender=\"message.sender\"\n >\n <div\n class=\"max-w-[88%] rounded-2xl px-4 py-3 text-sm shadow-sm @sm/chat-preview:max-w-[78%]\"\n :class=\"message.sender === 'user'\n ? 'bg-slate-950 text-white'\n : variant === 'dark'\n ? 'border border-white/10 bg-white/10 text-white'\n : 'border border-slate-200 bg-white text-slate-950'\"\n >\n <ChatRichText\n :text=\"message.text\"\n :inverted=\"message.sender === 'user' || variant === 'dark'\"\n />\n </div>\n </div>\n </div>\n</template>\n","/** Provider-neutral voice session state machine for web clients. */\nimport type { ApiResponse, VoiceSessionMint } from '@pagelines/core'\nimport type { Ref } from 'vue'\nimport type {\n CreateVoiceProviderClient,\n VoiceLevelEvent,\n VoiceProviderClient,\n VoiceSessionError,\n} from './provider'\nimport { SettingsObject, zVoiceSessionMint } from '@pagelines/core'\nimport { ref } from 'vue'\nimport { resolveApiBase } from '../../api'\nimport { createVoiceProviderClient } from './provider'\n\nexport type { VoiceLevelEvent, VoiceSessionError } from './provider'\nexport { VOICE_SPECTRUM_BANDS, voiceSpectrum } from './provider'\n\nexport type VoiceSessionClientState = 'idle' | 'minting' | 'connecting' | 'live' | 'ended'\nexport type VoiceChimeKind = 'start' | 'end'\n\nexport interface VoiceClientHandlers {\n onStateChange?: (state: VoiceSessionClientState) => void\n onLevel?: (event: VoiceLevelEvent) => void\n onError?: (error: VoiceSessionError) => void\n}\n\nexport interface VoiceSessionClientSettings extends VoiceClientHandlers, Record<string, unknown> {\n agentId: string\n orgId: string\n conversationId?: string\n apiBase?: string\n isDev?: boolean\n token?: string\n fetchFn?: typeof fetch\n /** Provider composition seam; the default dynamically loads the minted provider. */\n createProvider?: CreateVoiceProviderClient\n playChime?: (kind: VoiceChimeKind) => void\n}\n\nconst CHIME_PATHS: Record<VoiceChimeKind, string> = {\n start: '/audio/start-call.mp3',\n end: '/audio/end-call.mp3',\n}\nconst CHIME_VOLUME = 0.7\nconst LEVEL_INTERVAL_MS = 50\n\n/**\n * The readiness cue is the only signal an eyes-off user gets, so it is served\n * from the API origin rather than the embedding page — a relative path would\n * silently 404 wherever the SDK is not hosted by the app itself.\n */\nexport function createBrowserVoiceChimePlayer(apiBase: string): (kind: VoiceChimeKind) => void {\n const players = Object.fromEntries((['start', 'end'] as const).map((kind) => {\n const audio = new Audio(`${apiBase}${CHIME_PATHS[kind]}`)\n audio.preload = 'auto'\n audio.volume = CHIME_VOLUME\n return [kind, audio]\n })) as Record<VoiceChimeKind, HTMLAudioElement>\n return (kind) => {\n players[kind].currentTime = 0\n // Autoplay policy rejects until the surface has a user gesture; a missing\n // cue must never take the call down with it.\n void players[kind].play().catch(() => {})\n }\n}\n\nexport class VoiceSessionClient extends SettingsObject<VoiceSessionClientSettings> {\n readonly state: Ref<VoiceSessionClientState> = ref('idle')\n\n private provider?: VoiceProviderClient\n private readonly chime: (kind: VoiceChimeKind) => void\n private generation = 0\n private levelTimer: ReturnType<typeof setInterval> | undefined\n\n constructor(settings: VoiceSessionClientSettings) {\n super('VoiceSessionClient', settings)\n this.chime = settings.playChime\n ?? createBrowserVoiceChimePlayer(resolveApiBase(settings.apiBase, settings.isDev))\n }\n\n async start(): Promise<void> {\n if (this.state.value !== 'idle')\n return\n const generation = ++this.generation\n this.setState('minting')\n try {\n const mint = await this.mintSession(generation)\n if (!mint || generation !== this.generation)\n return\n this.setState('connecting')\n await this.connect({ mint, generation })\n } catch (error) {\n if (generation !== this.generation)\n return\n this.fail(this.toSessionError(error, 'VOICE_MINT_FAILED'))\n }\n }\n\n end(): void {\n if (this.state.value === 'idle' || this.state.value === 'ended')\n return\n const shouldChime = this.state.value === 'live'\n this.generation++\n if (shouldChime)\n this.chime('end')\n this.setState('ended')\n this.teardown()\n }\n\n private async connect(args: { mint: VoiceSessionMint, generation: number }): Promise<void> {\n const { mint, generation } = args\n const provider = await (this.settings.createProvider ?? createVoiceProviderClient)(mint)\n if (generation !== this.generation) {\n await provider.disconnect().catch(() => {})\n return\n }\n this.provider = provider\n\n try {\n await provider.connect({\n onDisconnected: () => {\n if (generation !== this.generation || this.provider !== provider)\n return\n this.fail({\n code: this.state.value === 'live' ? 'VOICE_CONNECTION_LOST' : 'VOICE_CONNECT_FAILED',\n message: this.state.value === 'live'\n ? 'The voice connection dropped.'\n : 'Could not open the voice connection.',\n })\n },\n onError: error => {\n if (generation === this.generation && this.provider === provider)\n this.fail(error)\n },\n })\n } catch (error) {\n if (generation !== this.generation || this.provider !== provider)\n return\n this.fail(this.toSessionError(error, 'VOICE_CONNECT_FAILED'))\n return\n }\n if (generation !== this.generation || this.provider !== provider)\n return\n\n this.startLevelTimer(provider, generation)\n this.setState('live')\n this.chime('start')\n }\n\n private setState(state: VoiceSessionClientState): void {\n if (this.state.value === state)\n return\n this.state.value = state\n this.settings.onStateChange?.(state)\n }\n\n private fail(error: VoiceSessionError): void {\n this.generation++\n this.settings.onError?.(error)\n this.setState('ended')\n this.teardown()\n }\n\n private teardown(): void {\n if (this.levelTimer !== undefined) {\n clearInterval(this.levelTimer)\n this.levelTimer = undefined\n }\n const provider = this.provider\n this.provider = undefined\n if (provider)\n void provider.disconnect().catch(() => {})\n this.settings.onLevel?.({ source: 'playback', level: 0 })\n }\n\n private startLevelTimer(provider: VoiceProviderClient, generation: number): void {\n if (this.levelTimer !== undefined)\n return\n this.levelTimer = setInterval(() => {\n if (generation !== this.generation || this.provider !== provider)\n return\n const level = provider.sampleLevel()\n if (level)\n this.settings.onLevel?.(level)\n }, LEVEL_INTERVAL_MS)\n }\n\n private authHeaders(): Record<string, string> {\n return this.settings.token ? { Authorization: `Bearer ${this.settings.token}` } : {}\n }\n\n private async post<T>(args: { path: string, body: unknown }): Promise<T> {\n const apiBase = resolveApiBase(this.settings.apiBase, this.settings.isDev)\n const fetchFn = this.settings.fetchFn ?? fetch\n const res = await fetchFn(`${apiBase}${args.path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...this.authHeaders() },\n credentials: 'include',\n body: JSON.stringify(args.body),\n })\n const result = await res.json() as ApiResponse<T>\n if (!res.ok || !result.ok) {\n const message = !result.ok ? result.error : `HTTP ${res.status}`\n const code = !result.ok && result.code ? result.code : 'VOICE_MINT_FAILED'\n throw Object.assign(new Error(message || 'Voice request failed.'), { code })\n }\n return result.data\n }\n\n private async mintSession(generation: number): Promise<VoiceSessionMint | null> {\n let conversationId = this.settings.conversationId\n if (!conversationId) {\n conversationId = (await this.post<{ conversationId: string }>({\n path: '/api/conversations',\n body: {\n orgId: this.settings.orgId,\n participants: [{ type: 'agent', id: this.settings.agentId }],\n },\n })).conversationId\n if (generation !== this.generation)\n return null\n }\n\n const data = await this.post<unknown>({ path: '/api/voice/sessions', body: { conversationId } })\n if (generation !== this.generation)\n return null\n const parsed = zVoiceSessionMint.safeParse(data)\n if (!parsed.success)\n throw Object.assign(new Error('Voice session mint returned an unexpected shape.'), { code: 'VOICE_MINT_INVALID' })\n return parsed.data\n }\n\n private toSessionError(error: unknown, fallbackCode: string): VoiceSessionError {\n return error instanceof Error\n ? {\n code: 'code' in error ? String((error as Error & { code: unknown }).code) : fallbackCode,\n message: error.message,\n }\n : { code: fallbackCode, message: 'Voice session failed to start.' }\n }\n}\n"],"mappings":"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"}
|