@pagelines/sdk 1.0.767 → 1.0.769
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/AgentWrap.js +66 -39
- package/dist/AgentWrap.js.map +1 -1
- package/dist/agent/ui/ElCreateAgent.vue.d.ts +2 -2
- package/dist/agent/ui/VoiceMode.vue.d.ts +3 -0
- package/dist/agent/voice/provider.d.ts +7 -0
- package/dist/agent/voice/providers/elevenlabs/provider.d.ts +2 -0
- package/dist/agent/voice/voice-session-client.d.ts +3 -0
- package/dist/agent.js +7 -0
- package/dist/agent.js.map +1 -1
- package/dist/contract.js +37 -19
- package/dist/contract.js.map +1 -1
- package/dist/demo/index.d.ts +1 -1
- package/dist/provider.js.map +1 -1
- package/dist/provider2.js +3 -0
- package/dist/provider2.js.map +1 -1
- package/dist/sdkClient.d.ts +3 -3
- package/dist/widget/composables/useWidgetState.d.ts +3 -3
- package/dist/widget.js +1 -1
- package/package.json +1 -1
|
@@ -69,7 +69,7 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {
|
|
|
69
69
|
}[] | null | undefined;
|
|
70
70
|
model?: string | null | undefined;
|
|
71
71
|
gender?: "woman" | "man" | undefined;
|
|
72
|
-
voiceKey?: "
|
|
72
|
+
voiceKey?: "lauren" | "amy" | "eve" | "korina" | "tamsin" | "jessica" | "jude" | "adam" | "evan" | "jon" | "joe" | "julius" | "chuck" | null | undefined;
|
|
73
73
|
billingTier?: "essential" | "professional" | "business" | undefined;
|
|
74
74
|
lastActiveAt?: string | null | undefined;
|
|
75
75
|
lastMessageAt?: string | null | undefined;
|
|
@@ -207,7 +207,7 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {
|
|
|
207
207
|
}[] | null | undefined;
|
|
208
208
|
model?: string | null | undefined;
|
|
209
209
|
gender?: "woman" | "man" | undefined;
|
|
210
|
-
voiceKey?: "
|
|
210
|
+
voiceKey?: "lauren" | "amy" | "eve" | "korina" | "tamsin" | "jessica" | "jude" | "adam" | "evan" | "jon" | "joe" | "julius" | "chuck" | null | undefined;
|
|
211
211
|
billingTier?: "essential" | "professional" | "business" | undefined;
|
|
212
212
|
lastActiveAt?: string | null | undefined;
|
|
213
213
|
lastMessageAt?: string | null | undefined;
|
|
@@ -7,8 +7,11 @@ type __VLS_Props = {
|
|
|
7
7
|
};
|
|
8
8
|
/** Await provider teardown before the host reloads the persisted transcript. */
|
|
9
9
|
declare function end(): Promise<void>;
|
|
10
|
+
/** Typed text during a live call, delivered as if the caller had said it. */
|
|
11
|
+
declare function sendUserMessage(text: string): boolean;
|
|
10
12
|
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {
|
|
11
13
|
end: typeof end;
|
|
14
|
+
sendUserMessage: typeof sendUserMessage;
|
|
12
15
|
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
13
16
|
end: () => any;
|
|
14
17
|
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
@@ -17,6 +17,13 @@ export interface VoiceProviderClient {
|
|
|
17
17
|
}) => Promise<void>;
|
|
18
18
|
disconnect: () => Promise<void>;
|
|
19
19
|
sampleLevel: () => VoiceLevelEvent | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Hand the provider text the caller typed during a live call, as though
|
|
22
|
+
* they had said it — the assistant answers aloud and the turn lands in the
|
|
23
|
+
* transcript through the normal provider path. Optional: a provider that
|
|
24
|
+
* cannot inject text simply omits it and the surface hides the affordance.
|
|
25
|
+
*/
|
|
26
|
+
sendUserMessage?: (text: string) => void;
|
|
20
27
|
}
|
|
21
28
|
export type CreateVoiceProviderClient = (mint: VoiceSessionMint) => Promise<VoiceProviderClient>;
|
|
22
29
|
/** Provider selection is a closed union; each SDK remains in its lazy chunk. */
|
|
@@ -5,6 +5,7 @@ type ElevenLabsMint = Extract<VoiceSessionMint, {
|
|
|
5
5
|
}>;
|
|
6
6
|
interface ElevenLabsConversation {
|
|
7
7
|
endSession: () => Promise<void>;
|
|
8
|
+
sendUserMessage: (text: string) => void;
|
|
8
9
|
getInputVolume: () => number;
|
|
9
10
|
getOutputVolume: () => number;
|
|
10
11
|
getInputByteFrequencyData: () => Uint8Array;
|
|
@@ -36,6 +37,7 @@ export declare class ElevenLabsVoiceProvider implements VoiceProviderClient {
|
|
|
36
37
|
private handlers?;
|
|
37
38
|
constructor(mint: ElevenLabsMint, startSession?: StartSession);
|
|
38
39
|
connect(handlers: Parameters<VoiceProviderClient['connect']>[0]): Promise<void>;
|
|
40
|
+
sendUserMessage(text: string): void;
|
|
39
41
|
disconnect(): Promise<void>;
|
|
40
42
|
sampleLevel(): ReturnType<VoiceProviderClient['sampleLevel']>;
|
|
41
43
|
}
|
|
@@ -50,6 +50,9 @@ export declare class VoiceSessionClient extends SettingsObject<VoiceSessionClien
|
|
|
50
50
|
start(): Promise<void>;
|
|
51
51
|
end(): Promise<void>;
|
|
52
52
|
private connect;
|
|
53
|
+
/** True while a live provider can accept typed text as a spoken turn. */
|
|
54
|
+
get canSendUserMessage(): boolean;
|
|
55
|
+
sendUserMessage(text: string): boolean;
|
|
53
56
|
private emitMetric;
|
|
54
57
|
private setState;
|
|
55
58
|
private fail;
|
package/dist/agent.js
CHANGED
|
@@ -181,6 +181,13 @@ var B = .08, V = .12, VoiceSessionClient = class extends f {
|
|
|
181
181
|
}
|
|
182
182
|
n !== this.generation || this.provider !== r || (this.startLevelTimer(r, n), this.liveAtMs = Date.now(), this.setState("live"), this.emitMetric("voice.ready", this.liveAtMs - this.startAtMs), this.chime("start"));
|
|
183
183
|
}
|
|
184
|
+
get canSendUserMessage() {
|
|
185
|
+
return this.state.value === "live" && !!this.provider?.sendUserMessage;
|
|
186
|
+
}
|
|
187
|
+
sendUserMessage(e) {
|
|
188
|
+
let t = e.trim();
|
|
189
|
+
return !t || !this.canSendUserMessage ? !1 : (this.provider.sendUserMessage(t), !0);
|
|
190
|
+
}
|
|
184
191
|
emitMetric(e, t) {
|
|
185
192
|
this.settings.onMetric?.({
|
|
186
193
|
name: e,
|
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' | 'engaged' | 'end'\n\n/** Client-owned latency phases — speech-end-to-first-text is measured on the handler. */\nexport type VoiceMetricName = 'voice.ready' | 'voice.first_playback'\n\nexport interface VoiceMetric {\n name: VoiceMetricName\n durationMs: number\n}\n\nexport interface VoiceClientHandlers {\n onStateChange?: (state: VoiceSessionClientState) => void\n onLevel?: (event: VoiceLevelEvent) => void\n onError?: (error: VoiceSessionError) => void\n /** Fire-and-forget latency phases for product observability. */\n onMetric?: (metric: VoiceMetric) => 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 // The conversation has actually begun: we heard the caller for the first\n // time. Connecting alone proves nothing about their mic, so this is the\n // first moment the surface can honestly say it is listening to them.\n engaged: '/audio/engaged-call.mp3',\n end: '/audio/end-call.mp3',\n}\nconst CHIME_VOLUME = 0.7\nconst LEVEL_INTERVAL_MS = 50\nconst CONNECT_TIMEOUT_MS = 15_000\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(Object.entries(CHIME_PATHS).map(([kind, path]) => {\n const audio = new Audio(`${apiBase}${path}`)\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\n/** Playback above this is treated as audible first audio, not room tone. */\nconst FIRST_PLAYBACK_LEVEL = 0.08\n\n/** Mic above this is the caller speaking, not a quiet room. */\nconst FIRST_SPEECH_LEVEL = 0.12\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 private startAtMs = 0\n private liveAtMs = 0\n private firstPlaybackEmitted = false\n private engagedChimed = false\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.startAtMs = Date.now()\n this.liveAtMs = 0\n this.firstPlaybackEmitted = false\n this.engagedChimed = false\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 async end(): Promise<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 await 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 const connectPromise = 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 let timeoutId: ReturnType<typeof setTimeout> | undefined\n try {\n await Promise.race([\n connectPromise,\n new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(Object.assign(new Error('Voice connection timed out.'), { code: 'VOICE_CONNECT_TIMEOUT' })), CONNECT_TIMEOUT_MS)\n }),\n ])\n } catch (error) {\n void connectPromise.then(() => provider.disconnect()).catch(() => {})\n if (generation !== this.generation || this.provider !== provider)\n return\n this.fail(this.toSessionError(error, 'VOICE_CONNECT_FAILED'))\n return\n } finally {\n if (timeoutId)\n clearTimeout(timeoutId)\n }\n if (generation !== this.generation || this.provider !== provider)\n return\n\n this.startLevelTimer(provider, generation)\n this.liveAtMs = Date.now()\n this.setState('live')\n this.emitMetric('voice.ready', this.liveAtMs - this.startAtMs)\n this.chime('start')\n }\n\n private emitMetric(name: VoiceMetricName, durationMs: number): void {\n this.settings.onMetric?.({ name, durationMs: Math.max(0, Math.round(durationMs)) })\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 void this.teardown()\n }\n\n private async teardown(): Promise<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 this.settings.onLevel?.({ source: 'playback', level: 0 })\n if (provider)\n await provider.disconnect().catch(() => {})\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 return\n this.settings.onLevel?.(level)\n if (\n !this.engagedChimed\n && level.source === 'mic'\n && level.level >= FIRST_SPEECH_LEVEL\n && this.liveAtMs > 0\n ) {\n this.engagedChimed = true\n this.chime('engaged')\n }\n if (\n !this.firstPlaybackEmitted\n && level.source === 'playback'\n && level.level >= FIRST_PLAYBACK_LEVEL\n && this.liveAtMs > 0\n ) {\n this.firstPlaybackEmitted = true\n this.emitMetric('voice.first_playback', Date.now() - this.liveAtMs)\n }\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' | 'engaged' | 'end'\n\n/** Client-owned latency phases — speech-end-to-first-text is measured on the handler. */\nexport type VoiceMetricName = 'voice.ready' | 'voice.first_playback'\n\nexport interface VoiceMetric {\n name: VoiceMetricName\n durationMs: number\n}\n\nexport interface VoiceClientHandlers {\n onStateChange?: (state: VoiceSessionClientState) => void\n onLevel?: (event: VoiceLevelEvent) => void\n onError?: (error: VoiceSessionError) => void\n /** Fire-and-forget latency phases for product observability. */\n onMetric?: (metric: VoiceMetric) => 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 // The conversation has actually begun: we heard the caller for the first\n // time. Connecting alone proves nothing about their mic, so this is the\n // first moment the surface can honestly say it is listening to them.\n engaged: '/audio/engaged-call.mp3',\n end: '/audio/end-call.mp3',\n}\nconst CHIME_VOLUME = 0.7\nconst LEVEL_INTERVAL_MS = 50\nconst CONNECT_TIMEOUT_MS = 15_000\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(Object.entries(CHIME_PATHS).map(([kind, path]) => {\n const audio = new Audio(`${apiBase}${path}`)\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\n/** Playback above this is treated as audible first audio, not room tone. */\nconst FIRST_PLAYBACK_LEVEL = 0.08\n\n/** Mic above this is the caller speaking, not a quiet room. */\nconst FIRST_SPEECH_LEVEL = 0.12\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 private startAtMs = 0\n private liveAtMs = 0\n private firstPlaybackEmitted = false\n private engagedChimed = false\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.startAtMs = Date.now()\n this.liveAtMs = 0\n this.firstPlaybackEmitted = false\n this.engagedChimed = false\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 async end(): Promise<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 await 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 const connectPromise = 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 let timeoutId: ReturnType<typeof setTimeout> | undefined\n try {\n await Promise.race([\n connectPromise,\n new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(Object.assign(new Error('Voice connection timed out.'), { code: 'VOICE_CONNECT_TIMEOUT' })), CONNECT_TIMEOUT_MS)\n }),\n ])\n } catch (error) {\n void connectPromise.then(() => provider.disconnect()).catch(() => {})\n if (generation !== this.generation || this.provider !== provider)\n return\n this.fail(this.toSessionError(error, 'VOICE_CONNECT_FAILED'))\n return\n } finally {\n if (timeoutId)\n clearTimeout(timeoutId)\n }\n if (generation !== this.generation || this.provider !== provider)\n return\n\n this.startLevelTimer(provider, generation)\n this.liveAtMs = Date.now()\n this.setState('live')\n this.emitMetric('voice.ready', this.liveAtMs - this.startAtMs)\n this.chime('start')\n }\n\n /** True while a live provider can accept typed text as a spoken turn. */\n get canSendUserMessage(): boolean {\n return this.state.value === 'live' && !!this.provider?.sendUserMessage\n }\n\n sendUserMessage(text: string): boolean {\n const body = text.trim()\n if (!body || !this.canSendUserMessage)\n return false\n this.provider!.sendUserMessage!(body)\n return true\n }\n\n private emitMetric(name: VoiceMetricName, durationMs: number): void {\n this.settings.onMetric?.({ name, durationMs: Math.max(0, Math.round(durationMs)) })\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 void this.teardown()\n }\n\n private async teardown(): Promise<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 this.settings.onLevel?.({ source: 'playback', level: 0 })\n if (provider)\n await provider.disconnect().catch(() => {})\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 return\n this.settings.onLevel?.(level)\n if (\n !this.engagedChimed\n && level.source === 'mic'\n && level.level >= FIRST_SPEECH_LEVEL\n && this.liveAtMs > 0\n ) {\n this.engagedChimed = true\n this.chime('engaged')\n }\n if (\n !this.firstPlaybackEmitted\n && level.source === 'playback'\n && level.level >= FIRST_PLAYBACK_LEVEL\n && this.liveAtMs > 0\n ) {\n this.firstPlaybackEmitted = true\n this.emitMetric('voice.first_playback', Date.now() - this.liveAtMs)\n }\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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"}
|
package/dist/contract.js
CHANGED
|
@@ -4424,71 +4424,89 @@ function isAgentReady(e) {
|
|
|
4424
4424
|
//#region ../core/dist/wire/voice-session.js
|
|
4425
4425
|
var U = _enum(["woman", "man"]), W = [
|
|
4426
4426
|
{
|
|
4427
|
-
key: "
|
|
4427
|
+
key: "lauren",
|
|
4428
4428
|
gender: "woman",
|
|
4429
4429
|
accent: "American",
|
|
4430
4430
|
character: "Friendly, comforting and soft"
|
|
4431
4431
|
},
|
|
4432
4432
|
{
|
|
4433
|
-
key: "
|
|
4433
|
+
key: "amy",
|
|
4434
4434
|
gender: "woman",
|
|
4435
4435
|
accent: "American",
|
|
4436
4436
|
character: "Natural and sweet"
|
|
4437
4437
|
},
|
|
4438
4438
|
{
|
|
4439
|
-
key: "
|
|
4439
|
+
key: "eve",
|
|
4440
4440
|
gender: "woman",
|
|
4441
4441
|
accent: "American",
|
|
4442
4442
|
character: "Authentic, energetic and happy"
|
|
4443
4443
|
},
|
|
4444
4444
|
{
|
|
4445
|
-
key: "
|
|
4445
|
+
key: "korina",
|
|
4446
4446
|
gender: "woman",
|
|
4447
4447
|
accent: "American",
|
|
4448
4448
|
character: "Calm and friendly"
|
|
4449
4449
|
},
|
|
4450
4450
|
{
|
|
4451
|
-
key: "
|
|
4451
|
+
key: "tamsin",
|
|
4452
|
+
gender: "woman",
|
|
4453
|
+
accent: "British",
|
|
4454
|
+
character: "Engaging and emotionally resonant",
|
|
4455
|
+
isDefault: !0
|
|
4456
|
+
},
|
|
4457
|
+
{
|
|
4458
|
+
key: "jessica",
|
|
4459
|
+
gender: "woman",
|
|
4460
|
+
accent: "British",
|
|
4461
|
+
character: "Smooth, articulate and warm"
|
|
4462
|
+
},
|
|
4463
|
+
{
|
|
4464
|
+
key: "jude",
|
|
4465
|
+
gender: "man",
|
|
4466
|
+
accent: "British",
|
|
4467
|
+
character: "Engaging and naturally conversational",
|
|
4468
|
+
isDefault: !0
|
|
4469
|
+
},
|
|
4470
|
+
{
|
|
4471
|
+
key: "adam",
|
|
4472
|
+
gender: "man",
|
|
4473
|
+
accent: "British",
|
|
4474
|
+
character: "Steady, rich and low"
|
|
4475
|
+
},
|
|
4476
|
+
{
|
|
4477
|
+
key: "evan",
|
|
4452
4478
|
gender: "man",
|
|
4453
4479
|
accent: "American",
|
|
4454
4480
|
character: "Calm, grounded and reflective"
|
|
4455
4481
|
},
|
|
4456
4482
|
{
|
|
4457
|
-
key: "
|
|
4483
|
+
key: "jon",
|
|
4458
4484
|
gender: "man",
|
|
4459
4485
|
accent: "American",
|
|
4460
4486
|
character: "Relaxed, deep and approachable"
|
|
4461
4487
|
},
|
|
4462
4488
|
{
|
|
4463
|
-
key: "
|
|
4489
|
+
key: "joe",
|
|
4464
4490
|
gender: "man",
|
|
4465
4491
|
accent: "British",
|
|
4466
4492
|
character: "Reflective and thoughtful"
|
|
4467
4493
|
},
|
|
4468
4494
|
{
|
|
4469
|
-
key: "
|
|
4495
|
+
key: "julius",
|
|
4470
4496
|
gender: "man",
|
|
4471
4497
|
accent: "German",
|
|
4472
4498
|
character: "Deep, articulate and professional"
|
|
4473
4499
|
},
|
|
4474
4500
|
{
|
|
4475
|
-
key: "
|
|
4501
|
+
key: "chuck",
|
|
4476
4502
|
gender: "man",
|
|
4477
4503
|
accent: "American",
|
|
4478
4504
|
character: "Easygoing and plain-spoken"
|
|
4479
4505
|
}
|
|
4480
|
-
], G = _enum(W.map((e) => e.key)), Xr = {
|
|
4481
|
-
gender: "man",
|
|
4482
|
-
voiceKeyByGender: {
|
|
4483
|
-
woman: "warm",
|
|
4484
|
-
man: "grounded"
|
|
4485
|
-
}
|
|
4486
|
-
};
|
|
4506
|
+
], G = _enum(W.map((e) => e.key)), Xr = { gender: "man" };
|
|
4487
4507
|
function resolveVoice(e) {
|
|
4488
4508
|
let t = W.find((t) => t.key === e.voiceKey);
|
|
4489
|
-
|
|
4490
|
-
let n = Xr.voiceKeyByGender[e.gender];
|
|
4491
|
-
return W.find((e) => e.key === n);
|
|
4509
|
+
return t?.gender === e.gender ? t : W.find((t) => t.gender === e.gender && "isDefault" in t);
|
|
4492
4510
|
}
|
|
4493
4511
|
var Zr = object({ conversationId: string().min(1) }).strict(), Qr = object({
|
|
4494
4512
|
conversationId: string().min(1),
|