@pagelines/sdk 1.0.820 → 1.0.822
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 +271 -243
- package/dist/AgentWrap.js.map +1 -1
- package/dist/agent/ui/VoiceMode.vue.d.ts +7 -0
- package/dist/agent/voice/provider.d.ts +3 -1
- package/dist/agent/voice/providers/elevenlabs/provider.d.ts +3 -1
- package/dist/agent/voice/voice-session-client.d.ts +18 -2
- package/dist/agent/voice/voice-work-state.d.ts +9 -0
- package/dist/agent.js +142 -50
- package/dist/agent.js.map +1 -1
- package/dist/contract.js +327 -328
- package/dist/contract.js.map +1 -1
- package/dist/provider.js.map +1 -1
- package/dist/provider2.js +3 -2
- package/dist/provider2.js.map +1 -1
- package/dist/provider3.js +865 -860
- package/dist/provider3.js.map +1 -1
- package/dist/sdk.css +1 -1
- package/dist/widget.js +1 -1
- package/dist/widget.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,6 +4,13 @@ type __VLS_Props = {
|
|
|
4
4
|
agent: Agent;
|
|
5
5
|
chatController?: AgentChatController;
|
|
6
6
|
isLight?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* The avatar to fill the background with, already decoded by the host
|
|
9
|
+
* (`resolveVoiceBackdrop`). The whole surface enters as one root, so the
|
|
10
|
+
* backdrop is decided before presentation: absent means the dark fallback
|
|
11
|
+
* for this call, never an image that pops in over the slide-up.
|
|
12
|
+
*/
|
|
13
|
+
backdropSrc?: string;
|
|
7
14
|
};
|
|
8
15
|
/** Await provider teardown before the host reloads the persisted transcript. */
|
|
9
16
|
declare function end(): Promise<void>;
|
|
@@ -10,10 +10,12 @@ export interface VoiceSessionError {
|
|
|
10
10
|
code: string;
|
|
11
11
|
message: string;
|
|
12
12
|
}
|
|
13
|
+
export type VoiceDisconnectCause = 'agent' | 'error' | 'network' | 'unknown';
|
|
13
14
|
export interface VoiceProviderClient {
|
|
14
15
|
connect: (handlers: {
|
|
15
|
-
onDisconnected: () => void;
|
|
16
|
+
onDisconnected: (cause: VoiceDisconnectCause) => void;
|
|
16
17
|
onError: (error: VoiceSessionError) => void;
|
|
18
|
+
onThinkingChange?: (thinking: boolean) => void;
|
|
17
19
|
}) => Promise<void>;
|
|
18
20
|
disconnect: () => Promise<void>;
|
|
19
21
|
sampleLevel: () => VoiceLevelEvent | undefined;
|
|
@@ -27,7 +27,9 @@ type StartSession = (options: {
|
|
|
27
27
|
voiceId?: string;
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
|
-
onDisconnect: (
|
|
30
|
+
onDisconnect: (details: {
|
|
31
|
+
reason: 'agent' | 'error' | 'user';
|
|
32
|
+
}) => void;
|
|
31
33
|
onError: (message: string) => void;
|
|
32
34
|
}) => Promise<ElevenLabsConversation>;
|
|
33
35
|
export declare class ElevenLabsVoiceProvider implements VoiceProviderClient {
|
|
@@ -4,7 +4,11 @@ import { SettingsObject } from '@pagelines/core';
|
|
|
4
4
|
export type { VoiceLevelEvent, VoiceSessionError } from './provider';
|
|
5
5
|
export { VOICE_SPECTRUM_BANDS, voiceSpectrum } from './provider';
|
|
6
6
|
export type VoiceSessionClientState = 'idle' | 'minting' | 'connecting' | 'live' | 'ended';
|
|
7
|
-
export type VoiceChimeKind = 'start' | '
|
|
7
|
+
export type VoiceChimeKind = 'start' | 'end';
|
|
8
|
+
export interface VoiceWorkStatus {
|
|
9
|
+
active: boolean;
|
|
10
|
+
description?: string;
|
|
11
|
+
}
|
|
8
12
|
/** Client-owned latency phases — speech-end-to-first-text is measured on the handler. */
|
|
9
13
|
export type VoiceMetricName = 'voice.ready' | 'voice.first_playback';
|
|
10
14
|
export interface VoiceMetric {
|
|
@@ -15,8 +19,10 @@ export interface VoiceClientHandlers {
|
|
|
15
19
|
onStateChange?: (state: VoiceSessionClientState) => void;
|
|
16
20
|
onLevel?: (event: VoiceLevelEvent) => void;
|
|
17
21
|
onError?: (error: VoiceSessionError) => void;
|
|
22
|
+
onThinkingChange?: (thinking: boolean) => void;
|
|
18
23
|
/** Fire-and-forget latency phases for product observability. */
|
|
19
24
|
onMetric?: (metric: VoiceMetric) => void;
|
|
25
|
+
onWorkChange?: (work: VoiceWorkStatus) => void;
|
|
20
26
|
}
|
|
21
27
|
export interface VoiceSessionClientSettings extends VoiceClientHandlers, Record<string, unknown> {
|
|
22
28
|
agentId: string;
|
|
@@ -29,6 +35,8 @@ export interface VoiceSessionClientSettings extends VoiceClientHandlers, Record<
|
|
|
29
35
|
/** Provider composition seam; the default dynamically loads the minted provider. */
|
|
30
36
|
createProvider?: CreateVoiceProviderClient;
|
|
31
37
|
playChime?: (kind: VoiceChimeKind) => void;
|
|
38
|
+
/** Test seam; production uses the quiet looping work asset. */
|
|
39
|
+
setWorkCue?: (active: boolean) => void;
|
|
32
40
|
}
|
|
33
41
|
/**
|
|
34
42
|
* The readiness cue is the only signal an eyes-off user gets, so it is served
|
|
@@ -41,13 +49,18 @@ export declare class VoiceSessionClient extends SettingsObject<VoiceSessionClien
|
|
|
41
49
|
readonly isMuted: Ref<boolean>;
|
|
42
50
|
private provider?;
|
|
43
51
|
private readonly chime;
|
|
52
|
+
private readonly workCue;
|
|
44
53
|
private generation;
|
|
45
54
|
private levelTimer;
|
|
46
55
|
private startAtMs;
|
|
47
56
|
private liveAtMs;
|
|
48
57
|
private firstPlaybackEmitted;
|
|
49
|
-
private engagedChimed;
|
|
50
58
|
private mutePending;
|
|
59
|
+
private conversationId?;
|
|
60
|
+
private workAbort?;
|
|
61
|
+
private workState;
|
|
62
|
+
private workCuePlaying;
|
|
63
|
+
private audible;
|
|
51
64
|
constructor(settings: VoiceSessionClientSettings);
|
|
52
65
|
start(): Promise<void>;
|
|
53
66
|
end(): Promise<void>;
|
|
@@ -63,6 +76,9 @@ export declare class VoiceSessionClient extends SettingsObject<VoiceSessionClien
|
|
|
63
76
|
private teardown;
|
|
64
77
|
private startLevelTimer;
|
|
65
78
|
private authHeaders;
|
|
79
|
+
private startWorkStream;
|
|
80
|
+
private updateWorkCue;
|
|
81
|
+
private setWorkCue;
|
|
66
82
|
private post;
|
|
67
83
|
private mintSession;
|
|
68
84
|
private toSessionError;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ChatEvent } from '@pagelines/core';
|
|
2
|
+
export interface VoiceWorkState {
|
|
3
|
+
turnIds: ReadonlySet<string>;
|
|
4
|
+
activeTurnId?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function createVoiceWorkState(): VoiceWorkState;
|
|
8
|
+
/** Project canonical conversation events onto the one active voice work line. */
|
|
9
|
+
export declare function reduceVoiceWorkEvent(state: VoiceWorkState, event: ChatEvent): VoiceWorkState;
|
package/dist/agent.js
CHANGED
|
@@ -3,16 +3,16 @@ import { c as e, s as t } from "./sdkClient.js";
|
|
|
3
3
|
import { a as n, h as r, m as i, n as a, p as o, r as s, t as c } from "./AgentWrap.js";
|
|
4
4
|
import { n as l, t as u } from "./AgentProvider.js";
|
|
5
5
|
import { t as d } from "./provider.js";
|
|
6
|
-
import { SettingsObject as f,
|
|
7
|
-
import { Fragment as
|
|
6
|
+
import { SettingsObject as f, readChatEventStream as p, zVoiceSessionMint as m } from "@pagelines/core";
|
|
7
|
+
import { Fragment as h, createBlock as g, createCommentVNode as _, createElementBlock as v, createElementVNode as y, createVNode as b, defineComponent as x, nextTick as S, normalizeClass as C, normalizeStyle as w, openBlock as T, ref as E, renderList as D, watch as O, withCtx as k } from "vue";
|
|
8
8
|
//#region agent/ui/AgentWidget.vue?vue&type=script&setup=true&lang.ts
|
|
9
|
-
var
|
|
9
|
+
var A = {
|
|
10
10
|
key: 0,
|
|
11
11
|
class: "relative h-full w-full"
|
|
12
|
-
},
|
|
12
|
+
}, j = { 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" }, M = ["src", "alt"], N = {
|
|
13
13
|
key: 0,
|
|
14
14
|
class: "absolute top-0.5 right-0.5"
|
|
15
|
-
},
|
|
15
|
+
}, P = /* @__PURE__ */ x({
|
|
16
16
|
__name: "AgentWidget",
|
|
17
17
|
props: {
|
|
18
18
|
sdk: {},
|
|
@@ -22,12 +22,12 @@ var k = {
|
|
|
22
22
|
position: {}
|
|
23
23
|
},
|
|
24
24
|
setup(e, { expose: t }) {
|
|
25
|
-
let n = e, r =
|
|
25
|
+
let n = e, r = E(!1), i = E(!1);
|
|
26
26
|
function toggle() {
|
|
27
27
|
r.value = !r.value;
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
e ? (await
|
|
29
|
+
O(r, async (e) => {
|
|
30
|
+
e ? (await S(), setTimeout(() => {
|
|
31
31
|
i.value = !0;
|
|
32
32
|
}, 400)) : i.value = !1;
|
|
33
33
|
});
|
|
@@ -44,29 +44,29 @@ var k = {
|
|
|
44
44
|
toggle,
|
|
45
45
|
open,
|
|
46
46
|
close
|
|
47
|
-
}), (t, a) => (
|
|
47
|
+
}), (t, a) => (T(), g(c, {
|
|
48
48
|
sdk: e.sdk,
|
|
49
49
|
handle: e.handle,
|
|
50
50
|
context: e.context,
|
|
51
51
|
"first-message": e.firstMessage
|
|
52
52
|
}, {
|
|
53
|
-
default:
|
|
53
|
+
default: k(({ agent: t, sdk: o }) => [t ? (T(), v("div", {
|
|
54
54
|
key: 0,
|
|
55
|
-
class:
|
|
56
|
-
}, [
|
|
57
|
-
class:
|
|
58
|
-
style:
|
|
55
|
+
class: C(["fixed z-[999999] pointer-events-auto", [n.position === "bottom-left" ? "bottom-6 left-6" : n.position === "top-right" ? "top-6 right-6" : n.position === "top-left" ? "top-6 left-6" : "bottom-6 right-6"]])
|
|
56
|
+
}, [y("div", {
|
|
57
|
+
class: C(["transition-all duration-500 ease-[cubic-bezier(0.25,1,0.33,1)] transform-gpu", [r.value ? "widget-expanded w-96 h-[600px] max-w-[calc(100vw-48px)] max-h-[calc(100vh-48px)] rounded-3xl opacity-100 scale-100" : "widget-button w-[80px] h-[80px] opacity-100 scale-100 flex items-center justify-center cursor-pointer"]]),
|
|
58
|
+
style: w({ "transform-origin": n.position === "bottom-left" ? "bottom left" : n.position === "top-right" ? "top right" : n.position === "top-left" ? "top left" : "bottom right" }),
|
|
59
59
|
onClick: a[0] || (a[0] = (e) => r.value ? void 0 : toggle())
|
|
60
|
-
}, [r.value ?
|
|
60
|
+
}, [r.value ? _("", !0) : (T(), v("div", A, [y("div", j, [y("img", {
|
|
61
61
|
src: t.avatarUrl.value,
|
|
62
62
|
alt: `${t.displayName.value} assistant`,
|
|
63
63
|
class: "h-full w-full object-cover pointer-events-none",
|
|
64
64
|
width: "80",
|
|
65
65
|
height: "80"
|
|
66
|
-
}, null, 8,
|
|
66
|
+
}, null, 8, M), a[1] || (a[1] = y("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" }, null, -1))]), t.state.value.lifecycle === "running" ? (T(), v("div", N, [...a[2] || (a[2] = [y("div", {
|
|
67
67
|
class: "size-3 bg-green-500 rounded-full ring-2 ring-white absolute animate-ping",
|
|
68
68
|
style: { "animation-duration": "3s" }
|
|
69
|
-
}, null, -1),
|
|
69
|
+
}, null, -1), y("div", { class: "size-3 bg-green-500 rounded-full ring-2 ring-white" }, null, -1)])])) : _("", !0)])), r.value && t ? (T(), g(l, {
|
|
70
70
|
key: 1,
|
|
71
71
|
class: "rounded-3xl shadow-2xl border border-white/10",
|
|
72
72
|
sdk: o,
|
|
@@ -82,7 +82,7 @@ var k = {
|
|
|
82
82
|
"context",
|
|
83
83
|
"first-message",
|
|
84
84
|
"is-active"
|
|
85
|
-
])) :
|
|
85
|
+
])) : _("", !0)], 6)], 2)) : _("", !0)]),
|
|
86
86
|
_: 1
|
|
87
87
|
}, 8, [
|
|
88
88
|
"sdk",
|
|
@@ -91,52 +91,101 @@ var k = {
|
|
|
91
91
|
"first-message"
|
|
92
92
|
]));
|
|
93
93
|
}
|
|
94
|
-
}),
|
|
94
|
+
}), F = ["data-sender"], I = /* @__PURE__ */ x({
|
|
95
95
|
__name: "ElAgentChatPreview",
|
|
96
96
|
props: {
|
|
97
97
|
messages: {},
|
|
98
98
|
variant: {}
|
|
99
99
|
},
|
|
100
100
|
setup(e) {
|
|
101
|
-
return (t, r) => (
|
|
102
|
-
class:
|
|
101
|
+
return (t, r) => (T(), v("div", {
|
|
102
|
+
class: C(["@container/chat-preview flex flex-col gap-3", e.variant === "dark" ? "text-white" : "text-slate-950"]),
|
|
103
103
|
"data-test": "agent-chat-preview"
|
|
104
|
-
}, [(
|
|
104
|
+
}, [(T(!0), v(h, null, D(e.messages, (t, r) => (T(), v("div", {
|
|
105
105
|
key: `${t.sender}-${r}`,
|
|
106
|
-
class:
|
|
106
|
+
class: C(["flex", t.sender === "user" ? "justify-end" : "justify-start"]),
|
|
107
107
|
"data-test": "agent-chat-preview-message",
|
|
108
108
|
"data-sender": t.sender
|
|
109
|
-
}, [
|
|
109
|
+
}, [y("div", { class: C(["max-w-[88%] rounded-2xl px-4 py-3 text-sm shadow-sm @sm/chat-preview:max-w-[78%]", t.sender === "user" ? "bg-slate-950 text-white" : e.variant === "dark" ? "border border-white/10 bg-white/10 text-white" : "border border-slate-200 bg-white text-slate-950"]) }, [b(n, {
|
|
110
110
|
text: t.text,
|
|
111
111
|
inverted: t.sender === "user" || e.variant === "dark"
|
|
112
|
-
}, null, 8, ["text", "inverted"])], 2)], 10,
|
|
112
|
+
}, null, 8, ["text", "inverted"])], 2)], 10, F))), 128))], 2));
|
|
113
113
|
}
|
|
114
|
-
})
|
|
114
|
+
});
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region agent/voice/voice-work-state.ts
|
|
117
|
+
function createVoiceWorkState() {
|
|
118
|
+
return { turnIds: /* @__PURE__ */ new Set() };
|
|
119
|
+
}
|
|
120
|
+
function reduceVoiceWorkEvent(e, t) {
|
|
121
|
+
if (t.event === "message") {
|
|
122
|
+
let n = t.data.message;
|
|
123
|
+
if (n.role === "user" && n.metadata?.clientContext === "voice") return {
|
|
124
|
+
...e,
|
|
125
|
+
turnIds: new Set(e.turnIds).add(n.messageId)
|
|
126
|
+
};
|
|
127
|
+
let r = typeof n.metadata?.turnId == "string" ? n.metadata.turnId : void 0;
|
|
128
|
+
if (r && e.turnIds.has(r)) {
|
|
129
|
+
let t = new Set(e.turnIds);
|
|
130
|
+
return t.delete(r), e.activeTurnId === r ? { turnIds: t } : {
|
|
131
|
+
...e,
|
|
132
|
+
turnIds: t
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return e;
|
|
136
|
+
}
|
|
137
|
+
let n = "turnId" in t.data && typeof t.data.turnId == "string" ? t.data.turnId : void 0;
|
|
138
|
+
return !n || !e.turnIds.has(n) ? e : t.event === "working_state" ? {
|
|
139
|
+
...e,
|
|
140
|
+
activeTurnId: n,
|
|
141
|
+
description: t.data.description.trim() || "Working on it"
|
|
142
|
+
} : t.event === "tool_activity" && t.data.status === "started" ? {
|
|
143
|
+
...e,
|
|
144
|
+
activeTurnId: n,
|
|
145
|
+
description: e.activeTurnId === n && e.description ? e.description : t.data.label
|
|
146
|
+
} : t.event === "working_end" || t.event === "stream_end" ? {
|
|
147
|
+
...e,
|
|
148
|
+
activeTurnId: void 0,
|
|
149
|
+
description: void 0
|
|
150
|
+
} : e;
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region agent/voice/voice-session-client.ts
|
|
154
|
+
var L = {
|
|
115
155
|
start: "/audio/start-call.mp3",
|
|
116
|
-
engaged: "/audio/engaged-call.mp3",
|
|
117
156
|
end: "/audio/end-call.mp3"
|
|
118
|
-
},
|
|
157
|
+
}, R = .7, z = 50, B = 15e3;
|
|
119
158
|
function createBrowserVoiceChimePlayer(e) {
|
|
120
|
-
let t = Object.fromEntries(Object.entries(
|
|
159
|
+
let t = Object.fromEntries(Object.entries(L).map(([t, n]) => {
|
|
121
160
|
let r = new Audio(`${e}${n}`);
|
|
122
|
-
return r.preload = "auto", r.volume =
|
|
161
|
+
return r.preload = "auto", r.volume = R, [t, r];
|
|
123
162
|
}));
|
|
124
163
|
return (e) => {
|
|
125
164
|
t[e].currentTime = 0, t[e].play().catch(() => {});
|
|
126
165
|
};
|
|
127
166
|
}
|
|
128
|
-
|
|
167
|
+
function createBrowserVoiceWorkCue(e) {
|
|
168
|
+
let t = new Audio(`${e}/audio/thinking.mp3`);
|
|
169
|
+
return t.preload = "auto", t.loop = !0, t.volume = .16, (e) => {
|
|
170
|
+
if (e) {
|
|
171
|
+
t.play().catch(() => {});
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
t.pause(), t.currentTime = 0;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
var V = .08, H = .08, VoiceSessionClient = class extends f {
|
|
129
178
|
constructor(n) {
|
|
130
|
-
super("VoiceSessionClient", n), t(this, "state",
|
|
179
|
+
super("VoiceSessionClient", n), t(this, "state", E("idle")), t(this, "isMuted", E(!1)), t(this, "provider", void 0), t(this, "chime", void 0), t(this, "workCue", void 0), t(this, "generation", 0), t(this, "levelTimer", void 0), t(this, "startAtMs", 0), t(this, "liveAtMs", 0), t(this, "firstPlaybackEmitted", !1), t(this, "mutePending", !1), t(this, "conversationId", void 0), t(this, "workAbort", void 0), t(this, "workState", createVoiceWorkState()), t(this, "workCuePlaying", !1), t(this, "audible", !1), this.chime = n.playChime ?? createBrowserVoiceChimePlayer(e(n.apiBase, n.isDev)), this.workCue = n.setWorkCue ?? (n.onWorkChange ? createBrowserVoiceWorkCue(e(n.apiBase, n.isDev)) : () => {});
|
|
131
180
|
}
|
|
132
181
|
async start() {
|
|
133
182
|
if (this.state.value !== "idle") return;
|
|
134
183
|
let e = ++this.generation;
|
|
135
|
-
this.startAtMs = Date.now(), this.liveAtMs = 0, this.firstPlaybackEmitted = !1, this.
|
|
184
|
+
this.startAtMs = Date.now(), this.liveAtMs = 0, this.firstPlaybackEmitted = !1, this.workState = createVoiceWorkState(), this.setState("minting");
|
|
136
185
|
try {
|
|
137
186
|
let t = await this.mintSession(e);
|
|
138
187
|
if (!t || e !== this.generation) return;
|
|
139
|
-
this.setState("connecting"), await this.connect({
|
|
188
|
+
this.conversationId && this.startWorkStream(this.conversationId, e), this.setState("connecting"), await this.connect({
|
|
140
189
|
mint: t,
|
|
141
190
|
generation: e
|
|
142
191
|
});
|
|
@@ -158,19 +207,28 @@ var B = .08, V = .12, VoiceSessionClient = class extends f {
|
|
|
158
207
|
}
|
|
159
208
|
this.provider = r;
|
|
160
209
|
let i = r.connect({
|
|
161
|
-
onDisconnected: () => {
|
|
162
|
-
n !== this.generation || this.provider !== r
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
210
|
+
onDisconnected: (e) => {
|
|
211
|
+
if (!(n !== this.generation || this.provider !== r)) {
|
|
212
|
+
if (this.state.value === "live" && e === "agent") {
|
|
213
|
+
this.generation++, this.chime("end"), this.setState("ended"), this.teardown();
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this.fail({
|
|
217
|
+
code: this.state.value === "live" ? "VOICE_CONNECTION_LOST" : "VOICE_CONNECT_FAILED",
|
|
218
|
+
message: this.state.value === "live" ? "The voice connection dropped." : "Could not open the voice connection."
|
|
219
|
+
});
|
|
220
|
+
}
|
|
166
221
|
},
|
|
167
222
|
onError: (e) => {
|
|
168
223
|
n === this.generation && this.provider === r && this.fail(e);
|
|
224
|
+
},
|
|
225
|
+
onThinkingChange: (e) => {
|
|
226
|
+
n === this.generation && this.provider === r && this.settings.onThinkingChange?.(e);
|
|
169
227
|
}
|
|
170
228
|
}), a;
|
|
171
229
|
try {
|
|
172
230
|
await Promise.race([i, new Promise((e, t) => {
|
|
173
|
-
a = setTimeout(() => t(Object.assign(/* @__PURE__ */ Error("Voice connection timed out."), { code: "VOICE_CONNECT_TIMEOUT" })),
|
|
231
|
+
a = setTimeout(() => t(Object.assign(/* @__PURE__ */ Error("Voice connection timed out."), { code: "VOICE_CONNECT_TIMEOUT" })), B);
|
|
174
232
|
})]);
|
|
175
233
|
} catch (e) {
|
|
176
234
|
if (i.then(() => r.disconnect()).catch(() => {}), n !== this.generation || this.provider !== r) return;
|
|
@@ -179,7 +237,7 @@ var B = .08, V = .12, VoiceSessionClient = class extends f {
|
|
|
179
237
|
} finally {
|
|
180
238
|
a && clearTimeout(a);
|
|
181
239
|
}
|
|
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"));
|
|
240
|
+
n !== this.generation || this.provider !== r || (this.startLevelTimer(r, n), this.liveAtMs = Date.now(), this.setState("live"), this.updateWorkCue(), this.emitMetric("voice.ready", this.liveAtMs - this.startAtMs), this.chime("start"));
|
|
183
241
|
}
|
|
184
242
|
get canSendUserMessage() {
|
|
185
243
|
return this.state.value === "live" && !!this.provider?.sendUserMessage;
|
|
@@ -211,26 +269,60 @@ var B = .08, V = .12, VoiceSessionClient = class extends f {
|
|
|
211
269
|
this.state.value !== e && (this.state.value = e, this.settings.onStateChange?.(e));
|
|
212
270
|
}
|
|
213
271
|
fail(e) {
|
|
214
|
-
|
|
272
|
+
let t = this.state.value === "live";
|
|
273
|
+
this.generation++, t && this.chime("end"), this.settings.onError?.(e), this.setState("ended"), this.teardown();
|
|
215
274
|
}
|
|
216
275
|
async teardown() {
|
|
217
|
-
this.
|
|
218
|
-
let e = this.
|
|
276
|
+
this.workAbort?.abort(), this.workAbort = void 0;
|
|
277
|
+
let e = !!this.workState.activeTurnId;
|
|
278
|
+
this.workState = createVoiceWorkState(), e && this.settings.onWorkChange?.({ active: !1 }), this.audible = !1, this.settings.onThinkingChange?.(!1), this.setWorkCue(!1), this.levelTimer !== void 0 && (clearInterval(this.levelTimer), this.levelTimer = void 0);
|
|
279
|
+
let t = this.provider;
|
|
219
280
|
this.provider = void 0, this.isMuted.value = !1, this.settings.onLevel?.({
|
|
220
281
|
source: "playback",
|
|
221
282
|
level: 0
|
|
222
|
-
}),
|
|
283
|
+
}), t && await t.disconnect().catch(() => {});
|
|
223
284
|
}
|
|
224
285
|
startLevelTimer(e, t) {
|
|
225
286
|
this.levelTimer === void 0 && (this.levelTimer = setInterval(() => {
|
|
226
287
|
if (t !== this.generation || this.provider !== e) return;
|
|
227
288
|
let n = e.sampleLevel();
|
|
228
|
-
n && (this.settings.onLevel?.(n),
|
|
229
|
-
},
|
|
289
|
+
n && (this.settings.onLevel?.(n), this.audible = n.level >= H, this.updateWorkCue(), !this.firstPlaybackEmitted && n.source === "playback" && n.level >= V && this.liveAtMs > 0 && (this.firstPlaybackEmitted = !0, this.emitMetric("voice.first_playback", Date.now() - this.liveAtMs)));
|
|
290
|
+
}, z));
|
|
230
291
|
}
|
|
231
292
|
authHeaders() {
|
|
232
293
|
return this.settings.token ? { Authorization: `Bearer ${this.settings.token}` } : {};
|
|
233
294
|
}
|
|
295
|
+
startWorkStream(t, n) {
|
|
296
|
+
if (!this.settings.onWorkChange) return;
|
|
297
|
+
this.workAbort?.abort();
|
|
298
|
+
let r = new AbortController();
|
|
299
|
+
this.workAbort = r;
|
|
300
|
+
let i = e(this.settings.apiBase, this.settings.isDev), a = this.settings.fetchFn ?? fetch;
|
|
301
|
+
(async () => {
|
|
302
|
+
let e = await a(`${i}/api/conversations/${encodeURIComponent(t)}/stream`, {
|
|
303
|
+
headers: {
|
|
304
|
+
Accept: "text/event-stream",
|
|
305
|
+
...this.authHeaders()
|
|
306
|
+
},
|
|
307
|
+
credentials: "include",
|
|
308
|
+
signal: r.signal
|
|
309
|
+
});
|
|
310
|
+
if (!(!e.ok || !e.body)) for await (let t of p(e.body.getReader())) {
|
|
311
|
+
if (r.signal.aborted || n !== this.generation) return;
|
|
312
|
+
let e = this.workState, i = reduceVoiceWorkEvent(e, t);
|
|
313
|
+
i !== e && (this.workState = i, (i.activeTurnId !== e.activeTurnId || i.description !== e.description) && (this.settings.onWorkChange?.({
|
|
314
|
+
active: !!i.activeTurnId,
|
|
315
|
+
...i.description ? { description: i.description } : {}
|
|
316
|
+
}), this.updateWorkCue()));
|
|
317
|
+
}
|
|
318
|
+
})().catch(() => {});
|
|
319
|
+
}
|
|
320
|
+
updateWorkCue() {
|
|
321
|
+
this.setWorkCue(this.state.value === "live" && !!this.workState.activeTurnId && !this.audible);
|
|
322
|
+
}
|
|
323
|
+
setWorkCue(e) {
|
|
324
|
+
this.workCuePlaying !== e && (this.workCuePlaying = e, this.workCue(e));
|
|
325
|
+
}
|
|
234
326
|
async post(t) {
|
|
235
327
|
let n = e(this.settings.apiBase, this.settings.isDev), r = await (this.settings.fetchFn ?? fetch)(`${n}${t.path}`, {
|
|
236
328
|
method: "POST",
|
|
@@ -264,9 +356,9 @@ var B = .08, V = .12, VoiceSessionClient = class extends f {
|
|
|
264
356
|
body: { conversationId: t }
|
|
265
357
|
});
|
|
266
358
|
if (e !== this.generation) return null;
|
|
267
|
-
let r =
|
|
359
|
+
let r = m.safeParse(n);
|
|
268
360
|
if (!r.success) throw Object.assign(/* @__PURE__ */ Error("Voice session mint returned an unexpected shape."), { code: "VOICE_MINT_INVALID" });
|
|
269
|
-
return r.data;
|
|
361
|
+
return this.conversationId = t, r.data;
|
|
270
362
|
}
|
|
271
363
|
toSessionError(e, t) {
|
|
272
364
|
return e instanceof Error ? {
|
|
@@ -279,6 +371,6 @@ var B = .08, V = .12, VoiceSessionClient = class extends f {
|
|
|
279
371
|
}
|
|
280
372
|
};
|
|
281
373
|
//#endregion
|
|
282
|
-
export { i as AGENT_MODES, r as Agent, l as AgentChat, o as AgentChatController, o as AgentController, u as AgentProvider,
|
|
374
|
+
export { i as AGENT_MODES, r as Agent, l as AgentChat, o as AgentChatController, o as AgentController, u as AgentProvider, P as AgentWidget, c as AgentWrap, a as ElAgentChat, I as ElAgentChatPreview, s as VoiceMode, VoiceSessionClient };
|
|
283
375
|
|
|
284
376
|
//# sourceMappingURL=agent.js.map
|