@autoark-ai/eva-client-sdk-ts 0.0.2-dev
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/GATEWAY_TERMS.md +11 -0
- package/LICENSE +100 -0
- package/README.md +344 -0
- package/THIRD_PARTY_NOTICES.md +116 -0
- package/dist/assets/silero_vad_v6.onnx +0 -0
- package/dist/browser.d.ts +84 -0
- package/dist/browser.js +939 -0
- package/dist/index.d.ts +406 -0
- package/dist/index.js +3 -0
- package/dist/spi.d.ts +130 -0
- package/dist/spi.js +0 -0
- package/package.json +79 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import type { MediaTransportsConfig } from "./spi.js";
|
|
2
|
+
// Generated by dts-bundle-generator v9.5.1
|
|
3
|
+
/** JSON-compatible value accepted at public metadata boundaries. */
|
|
4
|
+
export type JsonValue = null | boolean | number | string | readonly JsonValue[] | JsonObject;
|
|
5
|
+
/** Readonly string-keyed JSON object. */
|
|
6
|
+
export interface JsonObject {
|
|
7
|
+
readonly [key: string]: JsonValue;
|
|
8
|
+
}
|
|
9
|
+
/** A final user or assistant message committed by one agent session. */
|
|
10
|
+
export interface ConversationMessage {
|
|
11
|
+
/** Stable identifier unique within the agent instance. */
|
|
12
|
+
readonly id: string;
|
|
13
|
+
/** Turn identity shared by the corresponding user/assistant messages. */
|
|
14
|
+
readonly turnId: string;
|
|
15
|
+
/** Public alpha message role. */
|
|
16
|
+
readonly role: "user" | "assistant";
|
|
17
|
+
/** Final text content. */
|
|
18
|
+
readonly content: string;
|
|
19
|
+
/** Commit time as Unix epoch milliseconds. */
|
|
20
|
+
readonly createdAt: number;
|
|
21
|
+
/** Recursively isolated caller metadata snapshot. */
|
|
22
|
+
readonly metadata: JsonObject;
|
|
23
|
+
}
|
|
24
|
+
type ErrorSource = "sdk" | "provider" | "gateway" | "media";
|
|
25
|
+
type MediaRole = "audio-input" | "audio-output" | "aec" | "camera";
|
|
26
|
+
type MediaOperation = "start" | "capture" | "stop";
|
|
27
|
+
type MediaErrorReason = "not_configured" | "permission_denied" | "device_unavailable" | "unsupported" | "timeout" | "invalid_data" | "operation_failed";
|
|
28
|
+
/** Sanitized error shape exposed by rejected API calls and `error` events. */
|
|
29
|
+
export interface StructuredError {
|
|
30
|
+
/** Stable, non-sensitive summary suitable for application logs and UI. */
|
|
31
|
+
message: string;
|
|
32
|
+
/** Whether the affected operation/session cannot safely continue without caller action. */
|
|
33
|
+
fatal: boolean;
|
|
34
|
+
/** Subsystem that owns this failure. */
|
|
35
|
+
source: ErrorSource;
|
|
36
|
+
/** Provider identifier when `source` is `provider` or `gateway`. */
|
|
37
|
+
provider?: string;
|
|
38
|
+
/** HTTP status code when a Gateway response supplied one. */
|
|
39
|
+
statusCode?: number;
|
|
40
|
+
/** Media role that failed; present only when `source` is `media`. */
|
|
41
|
+
role?: MediaRole;
|
|
42
|
+
/** Media lifecycle operation that failed; present only when `source` is `media`. */
|
|
43
|
+
operation?: MediaOperation;
|
|
44
|
+
/** Stable media failure reason; present only when `source` is `media`. */
|
|
45
|
+
reason?: MediaErrorReason;
|
|
46
|
+
}
|
|
47
|
+
interface EvaSdkErrorOptions {
|
|
48
|
+
fatal?: boolean;
|
|
49
|
+
cause?: unknown;
|
|
50
|
+
}
|
|
51
|
+
export declare class EvaSdkError extends Error implements StructuredError {
|
|
52
|
+
readonly fatal: boolean;
|
|
53
|
+
readonly source: ErrorSource;
|
|
54
|
+
constructor(message: string, options?: EvaSdkErrorOptions);
|
|
55
|
+
}
|
|
56
|
+
/** Controls whether and how the agent starts a greeting turn. */
|
|
57
|
+
export type GreetingConfig = {
|
|
58
|
+
/** Disables the automatic greeting turn. */
|
|
59
|
+
mode: "disabled";
|
|
60
|
+
} | {
|
|
61
|
+
/** Plays `text` directly as the assistant greeting without calling the LLM. */
|
|
62
|
+
mode: "static";
|
|
63
|
+
/** Non-empty assistant text synthesized for the greeting turn. */
|
|
64
|
+
text: string;
|
|
65
|
+
} | {
|
|
66
|
+
/** Calls the LLM to generate the assistant greeting. */
|
|
67
|
+
mode: "dynamic";
|
|
68
|
+
/** Optional LLM instruction for the greeting; blank or omitted uses the SDK default. */
|
|
69
|
+
prompt?: string;
|
|
70
|
+
};
|
|
71
|
+
/** Bounded conversation history used as context for later LLM turns. */
|
|
72
|
+
export interface HistoryConfig {
|
|
73
|
+
/**
|
|
74
|
+
* Maximum completed user/assistant turn pairs retained as LLM context.
|
|
75
|
+
* @defaultValue 10
|
|
76
|
+
* @remarks Must be a positive integer. History is enabled only when `history` is provided.
|
|
77
|
+
*/
|
|
78
|
+
maxTurns?: number;
|
|
79
|
+
}
|
|
80
|
+
/** Camera capture timing used by the managed dialogue runtime. */
|
|
81
|
+
export interface CameraConfig {
|
|
82
|
+
/**
|
|
83
|
+
* Maximum duration of one still-image capture before the turn falls back to text-only.
|
|
84
|
+
* @defaultValue 1500
|
|
85
|
+
* @remarks Must be a finite positive integer in milliseconds. This is separate from the
|
|
86
|
+
* fixed internal cancellation-settlement deadline.
|
|
87
|
+
*/
|
|
88
|
+
captureTimeoutMs?: number;
|
|
89
|
+
}
|
|
90
|
+
interface RuntimeConfig {
|
|
91
|
+
/**
|
|
92
|
+
* System instruction prepended to each LLM request.
|
|
93
|
+
* @defaultValue An empty string.
|
|
94
|
+
*/
|
|
95
|
+
systemPrompt?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Optional greeting behavior executed when the agent starts.
|
|
98
|
+
* @defaultValue `{ mode: "disabled" }`
|
|
99
|
+
*/
|
|
100
|
+
greeting?: GreetingConfig;
|
|
101
|
+
/**
|
|
102
|
+
* Enables bounded multi-turn LLM context when provided.
|
|
103
|
+
* @remarks Omit this field to keep turns independent.
|
|
104
|
+
*/
|
|
105
|
+
history?: HistoryConfig;
|
|
106
|
+
/**
|
|
107
|
+
* Optional camera capture behavior.
|
|
108
|
+
* @remarks Camera remains disabled by default even when this field and `transports.camera`
|
|
109
|
+
* are present; call `setCameraCaptureEnabled(true)` to acquire the camera session.
|
|
110
|
+
*/
|
|
111
|
+
camera?: CameraConfig;
|
|
112
|
+
/**
|
|
113
|
+
* Complete audio input, output, AEC, and optional camera role set owned by the runtime after construction.
|
|
114
|
+
* @remarks Omit this field for a text-only agent. Do not drive these roles concurrently with the agent.
|
|
115
|
+
*/
|
|
116
|
+
transports?: MediaTransportsConfig;
|
|
117
|
+
/**
|
|
118
|
+
* JSON-compatible metadata attached to agent-produced events and conversation messages.
|
|
119
|
+
* @defaultValue An empty object.
|
|
120
|
+
* @remarks The SDK clones this value at the public boundary.
|
|
121
|
+
*/
|
|
122
|
+
metadata?: JsonObject;
|
|
123
|
+
}
|
|
124
|
+
/** Public managed configuration for one Eva voice-dialogue agent instance. */
|
|
125
|
+
export interface EvaVoiceDialogueAgentConfig extends RuntimeConfig {
|
|
126
|
+
/**
|
|
127
|
+
* Gateway credential shared by the built-in ASR, LLM, and TTS stages.
|
|
128
|
+
* @remarks The SDK does not expose this value through events, metadata, or configuration getters.
|
|
129
|
+
*/
|
|
130
|
+
apiKey: string;
|
|
131
|
+
/** Managed automatic speech recognition configuration. */
|
|
132
|
+
asr: {
|
|
133
|
+
/** Gateway ASR model identifier forwarded as the wire `model` field. */
|
|
134
|
+
model: string;
|
|
135
|
+
/**
|
|
136
|
+
* Target PCM sample rate sent to the configured ASR model, in Hz.
|
|
137
|
+
* @remarks Must be a finite positive integer. The SDK resamples at the ASR boundary and does not infer model compatibility.
|
|
138
|
+
*/
|
|
139
|
+
sampleRate: number;
|
|
140
|
+
};
|
|
141
|
+
/** Managed text-to-speech configuration. */
|
|
142
|
+
tts: {
|
|
143
|
+
/** Gateway TTS model identifier forwarded as the wire `model` field. */
|
|
144
|
+
model: string;
|
|
145
|
+
/** Optional model-specific voice identifier. */
|
|
146
|
+
voice?: string;
|
|
147
|
+
/** Optional speaking speed forwarded as the Gateway `speed` value. */
|
|
148
|
+
speakingRate?: number;
|
|
149
|
+
/** Optional pitch multiplier forwarded as the Gateway `pitch_rate` value. */
|
|
150
|
+
pitch?: number;
|
|
151
|
+
/**
|
|
152
|
+
* Requested TTS PCM sample rate in Hz.
|
|
153
|
+
* @defaultValue 16000
|
|
154
|
+
* @remarks Must be a finite positive integer when provided. This controls synthesis output, not the playback device sample rate.
|
|
155
|
+
*/
|
|
156
|
+
sampleRate?: number;
|
|
157
|
+
};
|
|
158
|
+
/** Managed large-language-model configuration. */
|
|
159
|
+
llm: {
|
|
160
|
+
/** Gateway LLM model identifier forwarded as the wire `model` field. */
|
|
161
|
+
model: string;
|
|
162
|
+
/** Optional sampling temperature forwarded to the selected LLM. */
|
|
163
|
+
temperature?: number;
|
|
164
|
+
/** Optional maximum generated token count forwarded as `max_tokens`. */
|
|
165
|
+
maxTokens?: number;
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Optional local Silero voice-activity-detection tuning.
|
|
169
|
+
* @remarks Required when `transports.input` is configured.
|
|
170
|
+
*/
|
|
171
|
+
vad?: {
|
|
172
|
+
/**
|
|
173
|
+
* Speech probability threshold used to enter the speaking state.
|
|
174
|
+
* @defaultValue 0.5
|
|
175
|
+
* @remarks Must be greater than 0 and less than or equal to 1.
|
|
176
|
+
*/
|
|
177
|
+
sensitivity?: number;
|
|
178
|
+
/**
|
|
179
|
+
* Continuous silence required before speech is considered stopped, in milliseconds.
|
|
180
|
+
* @defaultValue 200
|
|
181
|
+
* @remarks Must be finite and greater than 0. The Silero stage rounds up to 32 ms frames.
|
|
182
|
+
*/
|
|
183
|
+
silenceThresholdMs?: number;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/** The closed alpha event catalog. This is type-only; no runtime enum is exported. */
|
|
187
|
+
export type AgentEventType = "speech.started" | "image.captured" | "speech.stopped" | "transcript.partial" | "transcript.final" | "interruption" | "reply.started" | "reply.partial" | "reply.final" | "playback.started" | "playback.stopped" | "turn.latency" | "error";
|
|
188
|
+
/** Shared envelope fields projected from the language-neutral frame model. */
|
|
189
|
+
export interface AgentEventEnvelope {
|
|
190
|
+
/** Workflow identity such as speech, manual-text, or greeting. */
|
|
191
|
+
readonly streamId: string;
|
|
192
|
+
/** Turn identity; optional only for an error whose turn cannot be determined. */
|
|
193
|
+
readonly turnId?: string;
|
|
194
|
+
/** Monotonic sequence within one stream. */
|
|
195
|
+
readonly sequence?: number;
|
|
196
|
+
/** Whether this event frame is an incremental fragment. */
|
|
197
|
+
readonly partial: boolean;
|
|
198
|
+
/** Whether this event frame is complete. */
|
|
199
|
+
readonly final: boolean;
|
|
200
|
+
/** Optional event time in Unix epoch milliseconds. */
|
|
201
|
+
readonly timestamp?: number;
|
|
202
|
+
/** Sanitized frame metadata; secrets and raw provider payloads are removed. */
|
|
203
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
204
|
+
/** Optional internal-frame correlation identity. */
|
|
205
|
+
readonly frameId?: string;
|
|
206
|
+
}
|
|
207
|
+
interface TurnEventEnvelope extends Omit<AgentEventEnvelope, "turnId" | "partial" | "final"> {
|
|
208
|
+
readonly turnId: string;
|
|
209
|
+
}
|
|
210
|
+
export interface SpeechStartedEvent extends TurnEventEnvelope {
|
|
211
|
+
/** Public event discriminator. */
|
|
212
|
+
readonly type: "speech.started";
|
|
213
|
+
/** Speech start is a discrete event, not a fragment. */
|
|
214
|
+
readonly partial: false;
|
|
215
|
+
/** Speech start is complete when emitted. */
|
|
216
|
+
readonly final: true;
|
|
217
|
+
}
|
|
218
|
+
/** Sanitized local camera snapshot summary. This does not mean the LLM accepted or used the image. */
|
|
219
|
+
export interface ImageCapturedEvent extends TurnEventEnvelope {
|
|
220
|
+
/** Public event discriminator for a locally completed and validated snapshot. */
|
|
221
|
+
readonly type: "image.captured";
|
|
222
|
+
/** Image capture is a discrete event, not an incremental fragment. */
|
|
223
|
+
readonly partial: false;
|
|
224
|
+
/** The local capture result is complete when this event is emitted. */
|
|
225
|
+
readonly final: true;
|
|
226
|
+
/**
|
|
227
|
+
* Non-sensitive snapshot metadata safe for logs and UI.
|
|
228
|
+
* @remarks This object intentionally excludes image bytes, base64 data, device identifiers,
|
|
229
|
+
* and any claim that the Gateway or model accepted or used the image.
|
|
230
|
+
*/
|
|
231
|
+
readonly image: {
|
|
232
|
+
/** Actual MIME type reported by the validated snapshot, for example `image/png`. */
|
|
233
|
+
readonly mimeType: string;
|
|
234
|
+
/** Captured image width in pixels. */
|
|
235
|
+
readonly width: number;
|
|
236
|
+
/** Captured image height in pixels. */
|
|
237
|
+
readonly height: number;
|
|
238
|
+
/** Encoded image payload size in bytes; the payload itself is not exposed by the event. */
|
|
239
|
+
readonly sizeBytes: number;
|
|
240
|
+
/** Local capture duration in milliseconds, measured by the SDK runtime. */
|
|
241
|
+
readonly captureMs: number;
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
export interface SpeechStoppedEvent extends TurnEventEnvelope {
|
|
245
|
+
/** Public event discriminator. */
|
|
246
|
+
readonly type: "speech.stopped";
|
|
247
|
+
/** Speech stop is a discrete event, not a fragment. */
|
|
248
|
+
readonly partial: false;
|
|
249
|
+
/** Speech stop is complete when emitted. */
|
|
250
|
+
readonly final: true;
|
|
251
|
+
}
|
|
252
|
+
export interface TranscriptPartialEvent extends TurnEventEnvelope {
|
|
253
|
+
/** Public event discriminator. */
|
|
254
|
+
readonly type: "transcript.partial";
|
|
255
|
+
/** A partial transcript is an incremental fragment. */
|
|
256
|
+
readonly partial: true;
|
|
257
|
+
/** A partial transcript is not the final transcript. */
|
|
258
|
+
readonly final: false;
|
|
259
|
+
/** Current incremental speech transcript text. */
|
|
260
|
+
readonly text: string;
|
|
261
|
+
/** Partial transcripts are emitted only for captured speech. */
|
|
262
|
+
readonly source: "speech";
|
|
263
|
+
}
|
|
264
|
+
export interface TranscriptFinalEvent extends TurnEventEnvelope {
|
|
265
|
+
/** Public event discriminator. */
|
|
266
|
+
readonly type: "transcript.final";
|
|
267
|
+
/** A final transcript is not an incremental fragment. */
|
|
268
|
+
readonly partial: false;
|
|
269
|
+
/** Marks the complete user transcript for the turn. */
|
|
270
|
+
readonly final: true;
|
|
271
|
+
/** Complete final user transcript text. */
|
|
272
|
+
readonly text: string;
|
|
273
|
+
/** Whether the turn originated from speech or submitText(). */
|
|
274
|
+
readonly source: "speech" | "text";
|
|
275
|
+
}
|
|
276
|
+
export interface InterruptionEvent extends TurnEventEnvelope {
|
|
277
|
+
/** Public event discriminator. */
|
|
278
|
+
readonly type: "interruption";
|
|
279
|
+
/** Interruption is a discrete event, not a fragment. */
|
|
280
|
+
readonly partial: false;
|
|
281
|
+
/** Interruption is complete when emitted. */
|
|
282
|
+
readonly final: true;
|
|
283
|
+
/** User action that superseded the active turn. */
|
|
284
|
+
readonly reason: "user_speech" | "manual_text";
|
|
285
|
+
}
|
|
286
|
+
export interface ReplyStartedEvent extends TurnEventEnvelope {
|
|
287
|
+
/** Public event discriminator. */
|
|
288
|
+
readonly type: "reply.started";
|
|
289
|
+
/** Reply start is a discrete event, not a fragment. */
|
|
290
|
+
readonly partial: false;
|
|
291
|
+
/** Reply start is complete when emitted. */
|
|
292
|
+
readonly final: true;
|
|
293
|
+
}
|
|
294
|
+
export interface ReplyPartialEvent extends TurnEventEnvelope {
|
|
295
|
+
/** Public event discriminator. */
|
|
296
|
+
readonly type: "reply.partial";
|
|
297
|
+
/** A reply delta is an incremental fragment. */
|
|
298
|
+
readonly partial: true;
|
|
299
|
+
/** A reply delta is not the final reply. */
|
|
300
|
+
readonly final: false;
|
|
301
|
+
/** Newly appended reply delta. */
|
|
302
|
+
readonly text: string;
|
|
303
|
+
}
|
|
304
|
+
export interface ReplyFinalEvent extends TurnEventEnvelope {
|
|
305
|
+
/** Public event discriminator. */
|
|
306
|
+
readonly type: "reply.final";
|
|
307
|
+
/** A final reply is not an incremental fragment. */
|
|
308
|
+
readonly partial: false;
|
|
309
|
+
/** Marks the complete assistant reply for the turn. */
|
|
310
|
+
readonly final: true;
|
|
311
|
+
/** Complete final reply for the turn. */
|
|
312
|
+
readonly text: string;
|
|
313
|
+
}
|
|
314
|
+
export interface PlaybackStartedEvent extends TurnEventEnvelope {
|
|
315
|
+
/** Public event discriminator. */
|
|
316
|
+
readonly type: "playback.started";
|
|
317
|
+
/** Playback start is a discrete event, not a fragment. */
|
|
318
|
+
readonly partial: false;
|
|
319
|
+
/** Playback start is complete when emitted. */
|
|
320
|
+
readonly final: true;
|
|
321
|
+
}
|
|
322
|
+
export interface PlaybackStoppedEvent extends TurnEventEnvelope {
|
|
323
|
+
/** Public event discriminator. */
|
|
324
|
+
readonly type: "playback.stopped";
|
|
325
|
+
/** Playback stop is a discrete event, not a fragment. */
|
|
326
|
+
readonly partial: false;
|
|
327
|
+
/** Playback stop is complete when emitted. */
|
|
328
|
+
readonly final: true;
|
|
329
|
+
}
|
|
330
|
+
/** Optional duration measurements for one completed turn. */
|
|
331
|
+
export interface TurnLatencyStages {
|
|
332
|
+
/** Voice activity detection duration in milliseconds. */
|
|
333
|
+
readonly vadMs?: number;
|
|
334
|
+
/** Speech recognition duration in milliseconds. */
|
|
335
|
+
readonly asrMs?: number;
|
|
336
|
+
/** Time to the first LLM token in milliseconds. */
|
|
337
|
+
readonly llmFirstTokenMs?: number;
|
|
338
|
+
/** Time to the first synthesized audio chunk in milliseconds. */
|
|
339
|
+
readonly ttsFirstAudioMs?: number;
|
|
340
|
+
/** Audio playback duration in milliseconds. */
|
|
341
|
+
readonly playbackMs?: number;
|
|
342
|
+
}
|
|
343
|
+
/** Latency summary correlated to one turn. */
|
|
344
|
+
export interface TurnLatencyPayload {
|
|
345
|
+
/** Turn measured by this payload. */
|
|
346
|
+
readonly turnId: string;
|
|
347
|
+
/** Optional end-to-end turn duration in milliseconds. */
|
|
348
|
+
readonly totalMs?: number;
|
|
349
|
+
/** Available per-stage measurements. */
|
|
350
|
+
readonly stages: TurnLatencyStages;
|
|
351
|
+
}
|
|
352
|
+
export interface TurnLatencyEvent extends TurnEventEnvelope {
|
|
353
|
+
/** Public event discriminator. */
|
|
354
|
+
readonly type: "turn.latency";
|
|
355
|
+
/** Latency is a discrete event, not a fragment. */
|
|
356
|
+
readonly partial: false;
|
|
357
|
+
/** Latency is complete when emitted. */
|
|
358
|
+
readonly final: true;
|
|
359
|
+
/** Turn latency measurements. */
|
|
360
|
+
readonly latency: TurnLatencyPayload;
|
|
361
|
+
}
|
|
362
|
+
export interface AgentErrorEvent extends AgentEventEnvelope {
|
|
363
|
+
/** Public event discriminator. */
|
|
364
|
+
readonly type: "error";
|
|
365
|
+
/** Error is a discrete event, not a fragment. */
|
|
366
|
+
readonly partial: false;
|
|
367
|
+
/** Error is complete when emitted. */
|
|
368
|
+
readonly final: true;
|
|
369
|
+
/** Sanitized SDK/provider failure safe for application handling. */
|
|
370
|
+
readonly error: StructuredError;
|
|
371
|
+
}
|
|
372
|
+
/** Discriminated union for every event emitted by the alpha Facade. */
|
|
373
|
+
export type AgentEvent = SpeechStartedEvent | ImageCapturedEvent | SpeechStoppedEvent | TranscriptPartialEvent | TranscriptFinalEvent | InterruptionEvent | ReplyStartedEvent | ReplyPartialEvent | ReplyFinalEvent | PlaybackStartedEvent | PlaybackStoppedEvent | TurnLatencyEvent | AgentErrorEvent;
|
|
374
|
+
/** Synchronous observer invoked for each projected public event. */
|
|
375
|
+
export type AgentEventListener = (event: AgentEvent) => void;
|
|
376
|
+
/** Idempotent function that removes one event listener. */
|
|
377
|
+
export type Unsubscribe = () => void;
|
|
378
|
+
/** Optional identity and caller metadata for one manual-text turn. */
|
|
379
|
+
export interface SubmitTextOptions {
|
|
380
|
+
readonly turnId?: string;
|
|
381
|
+
readonly metadata?: JsonObject;
|
|
382
|
+
}
|
|
383
|
+
/** Minimal public control and observation surface for one dialogue session. */
|
|
384
|
+
export interface EvaVoiceDialogueAgent {
|
|
385
|
+
start(): Promise<void>;
|
|
386
|
+
submitText(text: string, options?: SubmitTextOptions): Promise<void>;
|
|
387
|
+
setAudioInputEnabled(enabled: boolean): Promise<void>;
|
|
388
|
+
/**
|
|
389
|
+
* Enables or disables the optional continuously held camera capture session.
|
|
390
|
+
*
|
|
391
|
+
* @param enabled - `true` acquires the configured camera and keeps its session ready for
|
|
392
|
+
* speech-triggered snapshots; `false` prevents new captures, cancels an in-flight capture,
|
|
393
|
+
* and waits for camera resources to be released.
|
|
394
|
+
* @returns A Promise that resolves after the requested camera state is fully ready or released.
|
|
395
|
+
* Repeated calls with the same value share the same in-flight result.
|
|
396
|
+
* @remarks Camera capture is disabled by default. Enabling rejects when no camera source is
|
|
397
|
+
* configured or acquisition fails. This control does not enable/disable audio input or TTS.
|
|
398
|
+
*/
|
|
399
|
+
setCameraCaptureEnabled(enabled: boolean): Promise<void>;
|
|
400
|
+
setTtsEnabled(enabled: boolean): Promise<void>;
|
|
401
|
+
getMessages(): readonly ConversationMessage[];
|
|
402
|
+
onEvent(listener: AgentEventListener): Unsubscribe;
|
|
403
|
+
stop(): Promise<void>;
|
|
404
|
+
}
|
|
405
|
+
export declare function createEvaVoiceDialogueAgent(config: EvaVoiceDialogueAgentConfig): EvaVoiceDialogueAgent;
|
|
406
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
function C(e){if(!Pe(e))throw new TypeError("Metadata must be a JSON-compatible object");return xe(e,new Set)}function Re(e,t){if(e===null||typeof e=="boolean"||typeof e=="string")return e;if(typeof e=="number"){if(!Number.isFinite(e))throw new TypeError("Metadata numbers must be finite");return e}if(Array.isArray(e))return Ie(e,t,()=>e.map(r=>Re(r,t)));if(Pe(e))return xe(e,t);throw new TypeError("Metadata must contain only JSON-compatible values")}function xe(e,t){return Ie(e,t,()=>{if(Reflect.ownKeys(e).some(n=>typeof n!="string"))throw new TypeError("Metadata object keys must be strings");let r={};for(let[n,a]of Object.entries(e))r[n]=Re(a,t);return r})}function Ie(e,t,r){if(t.has(e))throw new TypeError("Metadata must not contain cycles");t.add(e);try{return r()}finally{t.delete(e)}}function Pe(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}var h=class extends Error{fatal;source="sdk";constructor(t,r={}){super(t,{cause:r.cause}),this.name="EvaSdkError",this.fatal=r.fatal??!0}},N=class extends h{provider;source="provider";constructor(t,r){super(t,r),this.name="StageProviderError",this.provider=r.provider}},W=class extends h{provider;statusCode;source="gateway";constructor(t,r){super(t,r),this.name="GatewayAccessError",this.provider=r.provider,r.statusCode!==void 0&&(this.statusCode=r.statusCode)}},O=class extends h{role;operation;reason;source="media";constructor(t,r){super(t,r),this.name="MediaIoError",this.role=r.role,this.operation=r.operation,this.reason=r.reason}};function w(e,t={}){return e instanceof h?e:new h(t.message??"SDK operation failed",{fatal:t.fatal??!0,cause:e})}function E(e,t){return e instanceof h?e:new N(t.message??"Stage provider failed",{provider:t.provider,fatal:t.fatal??!0,cause:e})}function L(e,t){if(e instanceof h)return e;let r={provider:t.provider,fatal:t.fatal??!0,cause:e};return t.statusCode!==void 0&&(r.statusCode=t.statusCode),new W(t.message??vt(t.statusCode),r)}function vt(e){return e===void 0?"Gateway request failed":`Gateway request failed with status ${e}`}var St=new Set(["pcm_s16le"]);function ie(e,t){if(!St.has(e.format))throw new h("Unsupported audio format",{fatal:!0});return{kind:"audio.input",streamId:t.streamId,...t.turnId!==void 0?{turnId:t.turnId}:{},...t.sequence!==void 0?{sequence:t.sequence}:{},partial:!0,final:!1,...t.timestamp!==void 0?{timestamp:t.timestamp}:{},metadata:t.metadata??{},audio:e.data,sampleRate:e.sampleRate,channels:e.channels}}function oe(e){return{data:e.audio,sampleRate:e.sampleRate,channels:e.channels,format:"pcm_s16le"}}function Fe(){let e,t=()=>{let r=e;if(r!==void 0)return e=void 0,r.controller.abort(),r};return{begin(r){t();let n=new AbortController;return e={...r,controller:n,signal:n.signal},e},current(){return e},cancel:t,complete(r){return e!==r?!1:(e=void 0,!0)},isCurrent(r){return e===r&&!r.signal.aborted},stop:t}}function ke(){let e="";return{push(t){if(t.length===0)return[];e+=t;let r=wt(e);return e=r.rest,r.sentences},flush(){let t=e.trim();return e="",t.length===0?[]:[t]},clear(){e=""}}}var bt=new Set(["\u3002","\uFF01","\uFF1F","!","?","\uFF1B",";","\u2026"]),At=new Set(['"',"'","\u201D","\u2019",")","\uFF09","]","\u3011","}","\u300B","\u300D","\u300F"]),Et=/(?:Mr|Mrs|Ms|Dr|Prof|Sr|Jr|St|vs|etc|e\.g|i\.e)\.$/i;function wt(e){let t=[],r=0,n=0;for(;n<e.length;){if(!Tt(e,n)){n+=1;continue}let a=n+1;for(;a<e.length&&At.has(e[a]);)a+=1;let i=a;for(;i<e.length&&/\s/u.test(e[i]);)i+=1;if(i>=e.length)break;let s=e.slice(r,a).trim();s.length>0&&t.push(s),r=i,n=i}return{sentences:t,rest:e.slice(r)}}function Tt(e,t){let r=e[t];if(bt.has(r))return!(r==="\u2026"&&e[t+1]==="\u2026");if(r!==".")return!1;let n=e[t-1],a=e[t+1];return n!==void 0&&a!==void 0&&/\d/u.test(n)&&/\d/u.test(a)||a==="."?!1:!Et.test(e.slice(0,t+1))}function Me(e){let t=e,r=0,n=()=>{let o,l=new Promise(m=>{o=m});return{id:r,queue:[],invalidated:l,invalidate:o,currentController:void 0,pump:void 0}},a=n(),i=!1,s,u=()=>{let o=a;r+=1,o.queue.length=0,o.currentController?.abort(),o.invalidate(),a=n()},c=()=>{i=!0,u()};t.parentSignal.aborted?c():t.parentSignal.addEventListener("abort",c,{once:!0});let d=o=>{o.pump!==void 0||o.queue.length===0||(o.pump=p(o).catch(l=>{o===a&&(s=l,i=!0,u())}).finally(()=>{o.pump=void 0,o===a&&o.queue.length>0&&d(o)}))};async function p(o){for(;o.queue.length>0&&!t.parentSignal.aborted;){let l=o.queue.shift(),m=new AbortController;o.currentController=m;let v={signal:m.signal,isCurrent:()=>!t.parentSignal.aborted&&!m.signal.aborted&&o===a&&o.id===r};try{await t.process(l,v)}finally{o.currentController===m&&(o.currentController=void 0)}}}return{enqueue(o){i||t.parentSignal.aborted||o.trim().length===0||(a.queue.push(o),d(a))},clearAndAbort:u,async close(){i=!0;let o=a,l=o.pump;if(l!==void 0&&await Promise.race([l,o.invalidated]),t.parentSignal.removeEventListener("abort",c),s!==void 0)throw s}}}function Oe(e){let t=e,r=!1,n;return{start(){r||n!==void 0||(t.onStarted(),r=!0)},async close(){if(!r){n!==void 0&&await n;return}r=!1,n=Promise.resolve(t.onStopped()).finally(()=>{n=void 0}),await n},isActive(){return r}}}function Le(e){let t=e,r=t.now??Rt,n=r(),a,i,s=t.source==="text"||t.source==="greeting"?n:void 0,u,c,d,p=!1,o={},l=()=>{let m=t.source==="text"?0:o.vadMs??j(n,a),v=t.source==="text"?0:o.asrMs??j(i??a,s),f=o.llmFirstTokenMs??j(s,u),g=o.ttsFirstAudioMs??j(u,c),b=o.playbackMs??j(c,d),y={};D(y,"vadMs",m),D(y,"asrMs",v),D(y,"llmFirstTokenMs",f),D(y,"ttsFirstAudioMs",g),D(y,"playbackMs",b),Object.freeze(y);let S=[m,v,f,g],A=S.every(P=>P!==void 0)?S.reduce((P,ae)=>P+ae,0):void 0;return Object.freeze({turnId:t.turnId,...A!==void 0?{totalMs:A}:{},stages:y})};return{markVadStarted(){a??=r()},markAsrStarted(){i??=r()},markAsrFinal(){s??=r()},markLlmFirstToken(){u??=r()},markTtsFirstAudio(){c??=r()},markPlaybackStarted(){d??=r()},recordStageMetadata(m,v){let f=Ct[m],g=v[f];typeof g=="number"&&Number.isFinite(g)&&g>=0&&(o[f]=Math.round(g))},snapshot:l,takeSnapshot(){if(p)return;let m=l();if(Object.keys(m.stages).length!==0)return p=!0,m}}}var Ct={vad:"vadMs",asr:"asrMs",llm:"llmFirstTokenMs",tts:"ttsFirstAudioMs"};function Rt(){return typeof performance>"u"?Date.now():performance.now()}function j(e,t){if(!(e===void 0||t===void 0))return Math.max(0,Math.round(t-e))}function D(e,t,r){r!==void 0&&(e[t]=r)}function De(e,t={}){let r=xt(t.preSpeechMs),n=It(t.maxUtteranceMs),a=[],i=[],s=new Set,u=0,c,d=0,p=0,o=!1,l,m=()=>{for(let f of s)f();s.clear()},v=f=>{l??=new h(f,{fatal:!0}),o=!0,c=void 0,i.length=0,m()};return{async*vadAudio(){try{for await(let f of e){if(l!==void 0)throw l;let g=je(f);for(a.push(f),u+=g;a.length>1;){let b=a[0],y=je(b);if(u-y<r)break;a.shift(),u-=y}if(c!==void 0&&(c.frames.push(f),p+=g,p>n))throw v("VAD utterance exceeded max duration"),l;yield f}}catch(f){throw l??=f,o=!0,m(),f}},start(f,g=d+1){d=g,c={turnId:f,generation:g,frames:[...a]},p=u},stop(){c!==void 0&&c.frames.length>0&&(i.length=0,i.push(c)),c=void 0,p=0,a.length=0,u=0,m()},async*utterances(){for(;;){let f=i.pop();if(i.length=0,f!==void 0){yield{turnId:f.turnId,generation:f.generation,audio:Pt(f.frames)};continue}if(l!==void 0)throw l;if(o)return;await new Promise(g=>s.add(g))}},close(){o||(o=!0,c=void 0,m())}}}function xt(e){return Number.isFinite(e)&&e!==void 0&&e>=0?e:200}function It(e){return Number.isFinite(e)&&e!==void 0&&e>0?e:6e4}function je(e){return e.sampleRate<=0||e.channels<=0?0:e.audio.byteLength/2/e.channels/e.sampleRate*1e3}async function*Pt(e){for(let t of e)yield t}var Ft=1500,V=class extends Error{turnId;generation;constructor(t,r,n){super("Camera capture cancellation failed",{cause:t}),this.name="CameraCaptureSettlementError",this.turnId=r,this.generation=n,Object.defineProperty(this,"mediaError",{value:t,enumerable:!1,configurable:!1,writable:!1})}},q=class{source;now;settlementDeadlineMs;onFault;controlTail=Promise.resolve();acceptedControl=Promise.resolve();stopOperation;running=!1;stopping=!1;acceptedEnabled=!1;acceptedRequestId=0;active=!1;sessionIdentity=0;sessionController;pendingStart;pendingCapture;fault;constructor(t){this.source=t.source,this.now=t.now??Date.now,this.settlementDeadlineMs=t.cancellationSettlementDeadlineMs??Ft,this.onFault=t.onFault}isActive(){return this.active&&!this.stopping&&this.fault===void 0}currentFault(){return this.fault}setEnabled(t){if(this.stopping)return Promise.reject(this.faultedControlError(t?"start":"stop"));if(this.fault!==void 0)return Promise.reject(this.faultedControlError(t?"start":"stop"));if(this.acceptedEnabled===t)return this.acceptedControl;this.acceptedEnabled=t;let r=++this.acceptedRequestId;if(t||this.abortPendingWork(),!this.running)return this.acceptedControl=Promise.resolve(),this.acceptedControl;let n=this.enqueueControl(()=>this.applyEnabled(t,r));return this.acceptedControl=n.catch(a=>{throw this.acceptedRequestId===r&&(this.acceptedEnabled=!1),a}),this.acceptedControl}async startRuntime(){if(!this.running&&(this.running=!0,this.stopping=!1,!!this.acceptedEnabled))try{this.acceptedControl=this.enqueueControl(()=>this.applyEnabled(!0,this.acceptedRequestId)),await this.acceptedControl}catch(t){throw this.acceptedEnabled=!1,t}}async stopRuntime(){if(this.stopping)return this.stopOperation??Promise.resolve();this.stopping=!0,this.running=!1,this.acceptedEnabled=!1,this.abortPendingWork();let t=this.enqueueControl(async()=>{let r=this.source;if(r!==void 0)try{await this.stopSourceAfterCaptureSettlement(r,!0)}catch(n){throw this.markFault("stop","operation_failed",n)}finally{this.active=!1,this.sessionController=void 0}});return this.stopOperation=t,t}async beginCapture(t,r,n){if(await this.cancelPendingCaptureAndWait(),!this.isActive()||this.source===void 0)return;let a=new AbortController,i=Mt(),s=this.now(),u={turnId:t,generation:r},d=Promise.resolve().then(()=>this.source.capture(a.signal)).then(p=>{if(!(a.signal.aborted||i.settled))try{kt(p),k(i,{status:"success",snapshot:p,captureMs:Math.max(0,this.now()-s)})}catch(o){k(i,{status:"failure",error:F("capture","invalid_data",!1,o)})}},p=>{a.signal.aborted||i.settled||k(i,{status:"failure",error:F("capture",Ve(p),!1,p)})}).finally(()=>{u.timeoutHandle!==void 0&&clearTimeout(u.timeoutHandle),this.pendingCapture===u&&(this.pendingCapture=void 0)});return Object.assign(u,{controller:a,result:i,settlement:d}),u.timeoutHandle=setTimeout(()=>{i.settled||(a.abort(),k(i,{status:"failure",error:F("capture","timeout",!1)}),this.watchCaptureSettlement(u))},n),this.pendingCapture=u,{turnId:t,generation:r,result:i.promise}}async cancelPendingCaptureAndWait(){if(this.fault!==void 0)throw this.faultedControlError("capture");let t=this.pendingCapture;if(t!==void 0){t.controller.abort(),k(t.result,{status:"cancelled"});try{await this.settleWithin(t.settlement)}catch(r){let n=this.markFault("capture","operation_failed",r);throw new V(n,t.turnId,t.generation)}}}enqueueControl(t){let r=this.controlTail.then(t,t);return this.controlTail=r.catch(()=>{}),r}async applyEnabled(t,r){if(this.fault!==void 0)throw this.faultedControlError(t?"start":"stop");t?await this.startSession(r):await this.stopSession()}async startSession(t){if(this.active)return;let r=this.source;if(r===void 0)throw F("start","not_configured",!1);let n=++this.sessionIdentity,a=new AbortController;this.sessionController=a;let i=Promise.resolve().then(()=>r.start(a.signal)),s={controller:a,settlement:i.then(()=>{})};this.pendingStart=s;try{if(await Ot(i,a.signal),a.signal.aborted||n!==this.sessionIdentity||this.stopping)throw se();this.active=!0}catch(u){throw this.active=!1,Lt(u)||a.signal.aborted?u:F("start",Ve(u),!1,u)}finally{s.settlement.finally(()=>{this.pendingStart===s&&(this.pendingStart=void 0)}).catch(()=>{})}}async stopSession(){this.active=!1,this.abortPendingWork();let t=this.source;if(t!==void 0)try{await this.stopSourceAfterCaptureSettlement(t,!1),this.sessionController=void 0}catch(r){throw this.markFault("stop","operation_failed",r)}}async stopSourceAfterCaptureSettlement(t,r){let n=this.pendingStart?.settlement??Promise.resolve(),a=this.pendingCapture?.settlement??Promise.resolve();try{await this.settleWithin(a.catch(()=>{}))}catch(i){throw r&&await this.settleWithin(Promise.all([n.catch(()=>{}),Promise.resolve().then(()=>t.stop())])).catch(()=>{}),i}await this.settleWithin(Promise.all([n.catch(()=>{}),Promise.resolve().then(()=>t.stop())]).then(()=>{}))}abortPendingWork(){this.sessionController?.abort(),this.pendingStart?.controller.abort();let t=this.pendingCapture;t!==void 0&&(t.controller.abort(),k(t.result,{status:"cancelled"}))}async watchCaptureSettlement(t){try{await this.settleWithin(t.settlement)}catch(r){let n=this.markFault("capture","operation_failed",r);this.onFault?.(n,t.turnId,t.generation)}}settleWithin(t){return new Promise((r,n)=>{let a=setTimeout(()=>{n(new Error("Camera cancellation settlement deadline exceeded"))},this.settlementDeadlineMs);t.then(()=>{clearTimeout(a),r()},i=>{clearTimeout(a),n(i)})})}markFault(t,r,n){return this.fault===void 0&&(this.fault=F(t,r,!0,n)),this.active=!1,this.fault}faultedControlError(t){return F(t,"operation_failed",!0,this.fault)}};function kt(e){if(!(e.data instanceof Uint8Array)||e.data.byteLength===0)throw new Error("Camera snapshot bytes are empty");if(!/^image\/[a-z0-9.+-]+$/i.test(e.mimeType))throw new Error("Camera snapshot MIME is invalid");if(!Number.isInteger(e.width)||e.width<=0)throw new Error("Camera snapshot width is invalid");if(!Number.isInteger(e.height)||e.height<=0)throw new Error("Camera snapshot height is invalid")}function F(e,t,r,n){return new O("Camera operation failed",{role:"camera",operation:e,reason:t,fatal:r,cause:n})}function Ve(e){let t=e instanceof Error?e.name:"";return t==="NotAllowedError"||t==="SecurityError"?"permission_denied":t==="NotFoundError"||t==="NotReadableError"||t==="OverconstrainedError"?"device_unavailable":t==="NotSupportedError"?"unsupported":"operation_failed"}function Mt(){let e,t;return{promise:new Promise((n,a)=>{e=n,t=a}),resolve(n){e(n)},reject(n){t(n)},settled:!1}}function k(e,t){e.settled||(e.settled=!0,e.resolve(t))}function Ot(e,t){return t.aborted?Promise.reject(se()):new Promise((r,n)=>{let a=()=>n(se());t.addEventListener("abort",a,{once:!0}),e.then(r,n).finally(()=>{t.removeEventListener("abort",a)}).catch(()=>{})})}function se(){return new DOMException("Camera operation aborted","AbortError")}function Lt(e){return e instanceof Error&&e.name==="AbortError"}var _=class{constructor(t){this.config=t;this.agentMetadata=C(t.metadata??{}),this.cameraController=new q({...t.transports?.camera!==void 0?{source:t.transports.camera}:{},...t.now!==void 0?{now:t.now}:{},onFault:(r,n)=>{this.reportCameraFault(r,this.envelope("speech",n,this.agentMetadata))}})}config;listeners=new Set;tasks=new Set;pendingAsrControllers=new Map;turnScopes=Fe();cameraController;cameraCaptures=new Map;cameraFaultReported=!1;admissionTail=Promise.resolve();inputControlTail=Promise.resolve();rootController;started=!1;stopping=!1;inputEnabled=!0;inputSessionCounter=0;inputSession;speechGeneration=0;turnCounter=0;skipTts=!1;activeTtsTurn;committedHistory=[];turnTimings=new Map;messages=[];usedTurnIds=new Set;agentMetadata;messageCounter=0;onEvent(t){return this.listeners.add(t),()=>{this.listeners.delete(t)}}async start(){if(this.started)return;this.started=!0,this.rootController=new AbortController,this.inputEnabled&&this.canRunSpeechInput()&&await this.serializeInputControl(()=>this.reconcileInputSession());try{await this.cameraController.startRuntime()}catch(r){this.emit(x(this.envelope("camera",void 0,this.agentMetadata),w(r,{message:"Camera session failed",fatal:!1})))}let t=this.config.greeting;t!==void 0&&t.mode!=="disabled"&&this.track(this.scheduleGreeting(t))}async stop(){this.stopping=!0,this.inputEnabled=!1;let t=this.turnScopes.current();t!==void 0&&this.emitTurnLatency(t),this.rootController?.abort(),this.speechGeneration+=1,this.abortPendingAsr({emitLatency:!1});let r=this.inputSession===void 0?Promise.resolve():this.releaseInputSession(this.inputSession),n=this.cameraController.stopRuntime();this.turnScopes.stop();let a;try{await r}catch(i){a=i}try{await n}catch(i){a??=i}try{await this.config.transports?.output.stop()}catch(i){a=i}try{await this.config.transports?.aec.release()}catch(i){a??=i}if(a!==void 0)throw w(a,{message:"Dialogue runtime stop failed"})}async drain(){for(;this.tasks.size>0;)await Promise.allSettled([...this.tasks])}getMessages(){return this.messages.map(t=>({...t,metadata:C(t.metadata)}))}scheduleGreeting(t){let r=this.reserveTurnId(),n="greeting",a=this.envelope(n,r,this.agentMetadata);return this.beginTurnTiming(r,"greeting"),this.serializeAdmission(async()=>{if(this.rootController?.signal.aborted===!0)return;let i=this.turnScopes.begin({streamId:n,turnId:r});this.track(this.runAssistantTurn(n,r,t.mode==="dynamic"?t.prompt:t.text,a,i,{commitHistory:!1,...t.mode==="static"?{staticReply:t.text}:{},messageMetadata:this.agentMetadata,recordAssistant:!0}))})}async submitText(t,r={}){if(t.trim().length===0)return;this.started||await this.start();let n=this.reserveTurnId(r.turnId),a="manual-text",i=this.effectiveMetadata(r.metadata),s=this.envelope(a,n,i),u={kind:"text",streamId:a,turnId:n,partial:!1,final:!0,metadata:i,text:t};this.beginTurnTiming(n,"text"),await this.serializeAdmission(async()=>{this.speechGeneration+=1,this.abortPendingAsr(),await this.cancelCameraCaptureWithoutBlocking(s),await this.interruptActiveTurn(s,"manual_text"),this.commitMessage(n,"user",t,i),this.emit(Ge(u,"text"));let c=this.turnScopes.begin({streamId:a,turnId:n});this.track(this.runAssistantTurn(a,n,t,s,c,{messageMetadata:i}))})}async setSkipTts(t){if(this.skipTts===t||(this.skipTts=t,!t))return;let r=this.activeTtsTurn;if(!(r===void 0||!this.turnScopes.isCurrent(r.scope))){r.aggregator.clear(),r.worker.clearAndAbort();try{await this.config.transports?.output.flush(),this.activeTtsTurn===r&&this.turnScopes.isCurrent(r.scope)&&await r.playback.close()}catch(n){if(this.activeTtsTurn===r&&this.turnScopes.isCurrent(r.scope)){let a=E(n,{provider:"runtime"});throw this.emit(x(r.base,a)),a}throw E(n,{provider:"runtime"})}}}async setAudioInputEnabled(t){if(this.stopping)throw new h("Dialogue runtime is stopped",{fatal:!0});if(this.inputEnabled===t)return this.inputControlTail;if(this.inputEnabled=t,t||(this.speechGeneration+=1,this.abortPendingAsr({emitLatency:!1}),await this.cancelCameraCaptureWithoutBlocking(this.envelope("camera",void 0,this.agentMetadata)),this.inputSession!==void 0&&(this.inputSession.controller.abort(),this.releaseInputSession(this.inputSession).catch(()=>{}))),!!this.started)return this.serializeInputControl(()=>this.reconcileInputSession())}async setCameraCaptureEnabled(t){if(this.stopping)throw new h("Dialogue runtime is stopped",{fatal:!0});await this.cameraController.setEnabled(t)}serializeInputControl(t){let r=this.inputControlTail.then(t,t);return this.inputControlTail=r.catch(()=>{}),r}async reconcileInputSession(){let t=this.inputSession;if(!this.started||this.stopping||!this.inputEnabled||!this.canRunSpeechInput()){t!==void 0&&await this.releaseInputSession(t);return}t!==void 0&&!t.controller.signal.aborted||(t!==void 0&&await this.releaseInputSession(t),!(this.stopping||!this.inputEnabled||!this.canRunSpeechInput())&&await this.startInputSession())}async startInputSession(){let t=this.config.transports;if(t===void 0||this.config.providers.vad===void 0)return;let r={identity:++this.inputSessionCounter,controller:new AbortController};this.inputSession=r;let n=t.input;try{if(await n.start(),!this.isCurrentInputSession(r)){await this.releaseInputSession(r);return}let a=n.frames(r.controller.signal),i=this.runSpeechLoop(r.controller.signal,a,r.identity);this.track(i),i.finally(()=>{this.isCurrentInputSession(r)&&!r.controller.signal.aborted&&this.releaseInputSession(r).catch(()=>{})}).catch(()=>{})}catch(a){let i=r.controller.signal.aborted||!this.inputEnabled||this.stopping;if(await this.releaseInputSession(r),i)return;throw this.inputEnabled=!1,w(a,{message:"Audio input session failed"})}}releaseInputSession(t){if(t.releasePromise!==void 0)return t.releasePromise;t.controller.abort();let r=this.inputSession===t,n=this.config.transports?.input;return t.releasePromise=(async()=>{try{r&&await n?.stop()}catch(a){throw w(a,{message:"Audio input release failed"})}finally{this.inputSession===t&&(this.inputSession=void 0)}})(),t.releasePromise}isCurrentInputSession(t){return this.inputSession?.identity===t.identity&&!t.controller.signal.aborted&&this.inputEnabled&&!this.stopping}canRunSpeechInput(){return this.config.transports!==void 0&&this.config.providers.vad!==void 0}async runSpeechLoop(t,r,n){let a=this.config.transports,i=this.config.providers.vad;if(a===void 0||i===void 0)return;let s="speech",u,c,d=new AbortController,p=()=>d.abort();t.aborted?p():t.addEventListener("abort",p,{once:!0});let o=d.signal;try{let l=this.nearEndFrames(r,s,o),m=De(l),v=(async()=>{try{for await(let y of i.run(m.vadAudio(),{signal:o})){if(o.aborted)return;y.state==="started"?await this.serializeAdmission(async()=>{if(o.aborted)return;this.speechGeneration+=1,c=this.speechGeneration,u=this.reserveTurnId();let S=this.beginTurnTiming(u,"speech");S.recordStageMetadata("vad",y.metadata),S.markVadStarted(),this.abortPendingAsr(),m.start(u,c);let A=this.envelope(s,u,this.agentMetadata);if(await this.interruptActiveTurn(A,"user_speech"),o.aborted||c!==this.speechGeneration)return;this.emit(G(A,"speech.started"));let P;try{P=await this.cameraController.beginCapture(u,c,this.config.camera?.captureTimeoutMs??1500)}catch(ae){this.reportCameraFaultFromUnknown(ae,A,"Camera capture failed")}P!==void 0&&this.cameraCaptures.set(u,this.settleCameraCapture(P,A))}):y.state==="stopped"&&u!==void 0&&c!==void 0&&(m.stop(),this.emit(G(this.envelope(s,u,this.agentMetadata),"speech.stopped")),u=void 0,c=void 0)}}catch(y){let S=o.aborted||t.aborted;throw p(),this.abortPendingAsr({emitLatency:!S,inputSessionIdentity:n}),S||this.turnScopes.cancel(),y}finally{m.close()}})(),f=(async()=>{try{for await(let y of m.utterances()){if(o.aborted)return;if(!this.isCurrentSpeechGeneration(y.generation))continue;let S=Ut(o);this.pendingAsrControllers.set(S.controller,{streamId:s,turnId:y.turnId,inputSessionIdentity:n});let A=!1;try{A=await this.runAsr(y.audio,s,y.turnId,this.envelope(s,y.turnId,this.agentMetadata),y.generation,S.controller.signal)}finally{this.pendingAsrControllers.delete(S.controller),S.unlink()}!A&&this.isCurrentSpeechGeneration(y.generation)&&!o.aborted&&this.emitTurnLatency({streamId:s,turnId:y.turnId})}}catch(y){let S=o.aborted||t.aborted;throw p(),this.abortPendingAsr({emitLatency:!S,inputSessionIdentity:n}),S||this.turnScopes.cancel(),m.close(),y}})(),b=(await Promise.allSettled([v,f])).find(y=>y.status==="rejected");if(b!==void 0)throw b.reason}catch(l){!B(l)&&!t.aborted&&this.emit(x(this.envelope(s,u,this.agentMetadata),E(l,{provider:"runtime"})))}finally{this.abortPendingAsr({emitLatency:!1,inputSessionIdentity:n}),t.removeEventListener("abort",p)}}async runAsr(t,r,n,a,i,s){let u=!1,c=!1,d=async()=>{c||s.aborted||!this.isCurrentSpeechGeneration(i)||(c=!0,await this.cancelCameraCaptureWithoutBlocking(a))};try{let p=this.turnTimings.get(n),o=!1;p?.markAsrStarted();for await(let l of this.config.providers.asr.run(t,{signal:s})){if(s.aborted||!this.isCurrentSpeechGeneration(i))return!1;let m={...l,streamId:r,turnId:n};if(p?.recordStageMetadata("asr",l.metadata),l.final){if(o)continue;let v=!1;if(await this.serializeAdmission(async()=>{s.aborted||!this.isCurrentSpeechGeneration(i)||(p?.markAsrFinal(),l.text.trim().length>0&&this.commitMessage(n,"user",l.text,this.agentMetadata),this.emit(Ge(m,"speech")),v=l.text.trim().length>0)}),v){let f=await this.cameraCaptures.get(n);await this.serializeAdmission(async()=>{if(s.aborted||!this.isCurrentSpeechGeneration(i))return;let g=this.turnScopes.begin({streamId:r,turnId:n});this.track(this.runAssistantTurn(r,n,l.text,a,g,{messageMetadata:this.agentMetadata,...f!==void 0?{cameraSnapshot:f}:{}})),u=!0})}else await d();o=!0}else o||this.emit(Dt(m,"speech"))}return u||await d(),u}catch(p){return!B(p)&&!s.aborted&&this.isCurrentSpeechGeneration(i)&&this.emit(x(a,E(p,{provider:"asr"}))),await d(),!1}finally{this.cameraCaptures.delete(n)}}async runAssistantTurn(t,r,n,a,i,s={}){let u=i.signal,c=ke(),d=Oe({onStarted:()=>{this.turnScopes.isCurrent(i)&&this.emit(G(a,"playback.started"))},onStopped:()=>{this.turnScopes.isCurrent(i)&&this.emit(G(a,"playback.stopped"))}}),p=!1,o=Me({parentSignal:u,process:async(m,v)=>{try{for await(let f of this.ttsFrames(m,t,r,v.signal)){if(!v.isCurrent()||!this.turnScopes.isCurrent(i))return;let g=this.turnTimings.get(r);g?.recordStageMetadata("tts",f.metadata),g?.markTtsFirstAudio();let b=this.config.transports;if(b===void 0)continue;let y=oe(f);if(g?.markPlaybackStarted(),d.start(),await b.output.enqueue(y),!v.isCurrent()||!this.turnScopes.isCurrent(i)||(await b.aec.pushFarEnd(y),!v.isCurrent()||!this.turnScopes.isCurrent(i)))return}}catch(f){!B(f)&&v.isCurrent()&&this.turnScopes.isCurrent(i)&&(p=!0,o.clearAndAbort(),this.emit(x(a,E(f,{provider:"tts"}))))}}}),l={scope:i,base:a,aggregator:c,worker:o,playback:d};this.activeTtsTurn=l;try{if(!this.turnScopes.isCurrent(i))return;this.emit(G(a,"reply.started"));let m="",v=!1,f=s.staticReply!==void 0?jt(s.staticReply,t,r):this.config.providers.llm.run({messages:this.llmMessages(n,s.commitHistory!==!1,s.cameraSnapshot),streamId:t,turnId:r,metadata:s.messageMetadata??this.agentMetadata},{signal:u});for await(let g of f){if(u.aborted||!this.turnScopes.isCurrent(i))return;if(g.text.length>0){let b=this.turnTimings.get(r);if(b?.recordStageMetadata("llm",g.metadata),b?.markLlmFirstToken(),m+=g.text,this.emit(_e(a,"reply.partial",g.text)),!p&&!this.skipTts)for(let y of c.push(g.text))o.enqueue(y)}if(g.final){if(v=!0,!p&&!this.skipTts)for(let b of c.flush())o.enqueue(b);s.commitHistory!==!1&&this.commitHistory(n,m),s.recordAssistant!==!1&&this.commitMessage(r,"assistant",m,s.messageMetadata??this.agentMetadata),this.emit(_e(a,"reply.final",m));break}}if(!this.turnScopes.isCurrent(i))return;if(!v){c.clear(),o.clearAndAbort();return}if(await o.close(),!this.turnScopes.isCurrent(i))return;d.isActive()&&(await this.config.transports?.output.drain(),this.turnScopes.isCurrent(i)&&await d.close())}catch(m){!B(m)&&!u.aborted&&this.turnScopes.isCurrent(i)&&this.emit(x(a,E(m,{provider:"llm"})))}finally{this.turnScopes.isCurrent(i)&&this.emitTurnLatency(i),c.clear(),o.clearAndAbort(),this.activeTtsTurn===l&&(this.activeTtsTurn=void 0),this.turnScopes.complete(i)}}llmMessages(t,r,n){return[...this.config.systemPrompt!==void 0&&this.config.systemPrompt.length>0?[{role:"system",content:this.config.systemPrompt}]:[],...r&&this.config.history!==void 0?this.committedHistory.flatMap(({user:a,assistant:i})=>[{role:"user",content:a},{role:"assistant",content:i}]):[],{role:"user",content:n===void 0?t:[{type:"text",text:t},{type:"image",data:n.data,mimeType:n.mimeType}]}]}async settleCameraCapture(t,r){let n=await t.result;if(!(!this.isCurrentSpeechGeneration(t.generation)||this.stopping)&&n.status!=="cancelled"){if(n.status==="failure"){this.emit(x(r,n.error));return}return this.emit(Vt(r,n.snapshot,n.captureMs)),n.snapshot}}async cancelCameraCaptureWithoutBlocking(t){try{await this.cameraController.cancelPendingCaptureAndWait()}catch(r){this.reportCameraFaultFromUnknown(r,t,"Camera cancellation failed")}}reportCameraFaultFromUnknown(t,r,n){if(t instanceof V){this.reportCameraFault(t.mediaError,this.envelope("speech",t.turnId,this.agentMetadata));return}let a=t instanceof h?t:w(t,{message:n,fatal:!0});this.reportCameraFault(a,r)}reportCameraFault(t,r){this.cameraFaultReported||(this.cameraFaultReported=!0,this.emit(x(r,t)))}commitHistory(t,r){let n=this.config.history?.maxTurns;if(n===void 0)return;this.committedHistory.push({user:t,assistant:r});let a=this.committedHistory.length-n;a>0&&this.committedHistory.splice(0,a)}ttsFrames(t,r,n,a){return this.config.providers.tts.run({kind:"text",streamId:r,turnId:n,partial:!1,final:!0,metadata:{},text:t},{signal:a})}async*nearEndFrames(t,r,n){let a=0;for await(let i of t){if(n.aborted)return;let s=await this.config.transports?.aec.processNearEnd(i);s!==void 0&&(yield ie(s,{streamId:r,sequence:a++,metadata:{}}))}}emit(t){for(let r of this.listeners)r(t)}track(t){this.tasks.add(t),t.finally(()=>this.tasks.delete(t)).catch(()=>{})}serializeAdmission(t){let r=this.admissionTail.then(t,t);return this.admissionTail=r.catch(()=>{}),r}async interruptActiveTurn(t,r){let n=this.turnScopes.current();if(!(n===void 0||(this.emitTurnLatency(n),this.turnScopes.cancel()===void 0))){try{await this.config.transports?.output.flush()}catch(i){this.emit(x(this.envelope(t.streamId,t.turnId,t.metadata),E(i,{provider:"runtime"})))}this.emit(Gt(t,r))}}abortPendingAsr(t={}){for(let[r,n]of this.pendingAsrControllers)t.inputSessionIdentity!==void 0&&n.inputSessionIdentity!==t.inputSessionIdentity||(t.emitLatency!==!1?this.emitTurnLatency(n):this.turnTimings.delete(n.turnId),r.abort(),this.pendingAsrControllers.delete(r))}isCurrentSpeechGeneration(t){return t===this.speechGeneration}reserveTurnId(t){let r=t??this.generatedTurnId();if(r.trim().length===0)throw new h("turnId must not be empty",{fatal:!0});if(this.usedTurnIds.has(r))throw new h("turnId must be unique within an agent session",{fatal:!0});return this.usedTurnIds.add(r),r}generatedTurnId(){do this.turnCounter+=1;while(this.usedTurnIds.has(`turn-${this.turnCounter}`));return`turn-${this.turnCounter}`}beginTurnTiming(t,r){let n=Le({turnId:t,source:r,...this.config.now!==void 0?{now:this.config.now}:{}});return this.turnTimings.set(t,n),n}emitTurnLatency(t){let n=this.turnTimings.get(t.turnId)?.takeSnapshot();this.turnTimings.delete(t.turnId),n!==void 0&&this.emit(_t(this.envelope(t.streamId,t.turnId,this.agentMetadata),n))}envelope(t,r,n={}){return{streamId:t,...r!==void 0?{turnId:r}:{},partial:!1,final:!1,metadata:{...n}}}effectiveMetadata(t){try{let r=C(t??{});return C({...this.agentMetadata,...r})}catch(r){throw new h("Turn metadata must be JSON-compatible",{fatal:!0,cause:r})}}commitMessage(t,r,n,a){this.messageCounter+=1,this.messages.push({id:`message-${this.messageCounter}`,turnId:t,role:r,content:n,createdAt:(this.config.now??Date.now)(),metadata:C(a)})}};async function*jt(e,t,r){yield{kind:"llm",streamId:t,turnId:r,partial:!1,final:!0,metadata:{},text:e}}function Ge(e,t){return{...Ue(e),type:"transcript.final",partial:!1,final:!0,text:e.text,source:t}}function Dt(e,t){return{...Ue(e),type:"transcript.partial",partial:!0,final:!1,text:e.text,source:t}}function G(e,t){return{...e,type:t,partial:!1,final:!0}}function Vt(e,t,r){return{...e,type:"image.captured",partial:!1,final:!0,image:{mimeType:t.mimeType,width:t.width,height:t.height,sizeBytes:t.data.byteLength,captureMs:r}}}function _e(e,t,r){return{...e,type:t,partial:t==="reply.partial",final:t==="reply.final",text:r}}function Gt(e,t){return{...e,type:"interruption",partial:!1,final:!0,reason:t}}function _t(e,t){return{...e,type:"turn.latency",partial:!1,final:!0,latency:t}}function x(e,t){return{...e,type:"error",partial:!1,final:!0,error:t}}function Ue(e){return{streamId:e.streamId,...e.turnId!==void 0?{turnId:e.turnId}:{},...e.sequence!==void 0?{sequence:e.sequence}:{},partial:e.partial,final:e.final,...e.timestamp!==void 0?{timestamp:e.timestamp}:{},metadata:e.metadata,...e.frameId!==void 0?{frameId:e.frameId}:{}}}function B(e){return e instanceof Error&&e.name==="AbortError"}function Ut(e){let t=new AbortController,r=()=>t.abort();return e.aborted?(r(),{controller:t,unlink(){}}):(e.addEventListener("abort",r,{once:!0}),{controller:t,unlink(){e.removeEventListener("abort",r)}})}async function H(e,t={}){if(ue(e.channels,"channels"),ue(e.sourceSampleRate,"sourceSampleRate"),ue(e.targetSampleRate,"targetSampleRate"),e.sourceSampleRate===e.targetSampleRate)return new z(e);let r=await(t.load??Nt)(),n=Wt(r),a=await n.create(e.channels,e.sourceSampleRate,e.targetSampleRate,{converterType:n.ConverterType.SRC_SINC_FASTEST});return new z(e,a)}var z=class{constructor(t,r){this.converter=r;this.channels=t.channels,this.sourceSampleRate=t.sourceSampleRate,this.targetSampleRate=t.targetSampleRate}converter;channels;sourceSampleRate;targetSampleRate;destroyed=!1;simple(t){return this.assertUsable(t),this.converter?.simple(t)??t}full(t){return this.assertUsable(t),this.converter?.full(t)??t}destroy(){this.destroyed||(this.destroyed=!0,this.converter?.destroy())}assertUsable(t){if(this.destroyed)throw new Error("Resampler has been destroyed");if(t.length%this.channels!==0)throw new Error("Interleaved audio length must be divisible by channels")}};async function Nt(){return import("@alexanderolsen/libsamplerate-js")}function Wt(e){if(typeof e!="object"||e===null)throw new Error("libsamplerate module did not load as an object");let t=e,r=t.default??t;if(typeof r.create!="function"||typeof r.ConverterType?.SRC_SINC_FASTEST!="number")throw new Error("libsamplerate module has an incompatible API");return r}function ue(e,t){if(!Number.isFinite(e)||!Number.isInteger(e)||e<=0)throw new Error(`${t} must be a finite positive integer`)}var qt="https://eva-gateway-ali.dev.autoarkai.com",J={asr:"/v1/audio/transcriptions",llm:"/llm/v1/chat/completions",tts:"/v1/audio/speech"};function K(e){return`${qt}${e}`}function Bt(){return new DOMException("Operation aborted","AbortError")}function zt(e){if(e?.aborted===!0)throw Bt()}function Ne(e){let t=e.trim();if(t.startsWith("data:"))return t.slice(5).trimStart()}async function*$(e,t={}){let{signal:r,isTerminator:n}=t,a=new TextDecoder,i="",s=!1;for await(let c of e){if(zt(r),s)continue;i+=a.decode(c,{stream:!0});let d=i.indexOf(`
|
|
2
|
+
`);for(;d>=0;){let p=i.slice(0,d);i=i.slice(d+1);let o=Ne(p);if(o!==void 0){if(n?.(o)===!0){s=!0,i="";break}yield o}d=i.indexOf(`
|
|
3
|
+
`)}}if(s)return;i+=a.decode();let u=Ne(i);u!==void 0&&n?.(u)!==!0&&(yield u)}function de(e){return e==="[DONE]"}async function*Y(e){let t=e.getReader(),r=!1;try{for(;;){let{value:n,done:a}=await t.read();if(a===!0){r=!0;break}n!==void 0&&(yield n)}}finally{try{r||await t.cancel().catch(()=>{})}finally{t.releaseLock()}}}function We(e){let t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n+=1)r[n]=t.charCodeAt(n);return r}function le(e){try{return JSON.parse(e)}catch{return}}function Ht(e){try{return We(e)}catch{return}}function ce(e,t,r){return{kind:"asr",streamId:t.streamId,...t.turnId!==void 0?{turnId:t.turnId}:{},partial:!r,final:r,metadata:{},text:e}}function qe(e,t,r){return{kind:"llm",streamId:t.streamId,...t.turnId!==void 0?{turnId:t.turnId}:{},partial:!r,final:r,metadata:{},text:e}}function Be(e,t,r){return{kind:"tts.audio",streamId:t.streamId,...t.turnId!==void 0?{turnId:t.turnId}:{},partial:!r,final:r,metadata:{},audio:e,sampleRate:t.sampleRate,channels:t.channels}}async function*ze(e,t){let r="",n=!1;for await(let a of e){let i=le(a);i!==void 0&&(i.type==="transcript.text.delta"?(r+=i.delta??"",yield ce(r,t,!1)):i.type==="transcript.text.done"&&(yield ce(i.text??r,t,!0),n=!0))}n||(yield ce(r,t,!0))}async function*He(e,t){for await(let r of e){let n=le(r);if(n===void 0)continue;let a=n.choices?.[0]?.delta?.content;typeof a=="string"&&a.length>0&&(yield qe(a,t,!1))}yield qe("",t,!0)}async function*Je(e,t){let r,n=!1;for await(let a of e){if(n)continue;let i=le(a);if(i!==void 0)if(i.type==="speech.audio.delta"&&typeof i.audio=="string"){let s=Ht(i.audio);if(s===void 0)continue;r!==void 0&&(yield Be(r,t,!1)),r=s}else i.type==="speech.audio.done"&&(n=!0)}r!==void 0&&(yield Be(r,t,!0))}function Q(e){return e!==void 0?e:globalThis.fetch.bind(globalThis)}function X(e){return{Authorization:`Bearer ${e}`}}function Jt(e){return e instanceof DOMException&&e.name==="AbortError"}async function Z(e,t,r,n){let a;try{a=await e(t,r)}catch(i){throw Jt(i)?i:L(i,{provider:n})}if(!a.ok){let i;try{i=await a.text()}catch{i=void 0}throw L(i,{provider:n,statusCode:a.status})}return a}function ee(e,t){let r=e.body;if(r===null)throw L("empty response body",{provider:t});return r}var Kt=16e3,re=1;function $t(){return new DOMException("Operation aborted","AbortError")}function pe(e){if(e?.aborted===!0)throw $t()}function Yt(e){let t=e.reduce((a,i)=>a+i.length,0),r=new Uint8Array(t),n=0;for(let a of e)r.set(a,n),n+=a.length;return r}async function Qt(e,t,r){te(t.sampleRate,"ASR target sampleRate"),te(t.channels??re,"ASR fallback channels");let n=t.createResampler??H,a=[],i,s;for await(let d of e){if(pe(r),te(d.sampleRate,"ASR source sampleRate"),te(d.channels,"ASR source channels"),i===void 0)i=d.sampleRate,s=d.channels;else if(d.sampleRate!==i||d.channels!==s)throw new RangeError("ASR source sampleRate and channels must remain stable within an utterance");er(d.audio,d.channels),a.push(d.audio)}pe(r);let u=Yt(a);if(i===void 0||s===void 0)return{bytes:u,sampleRate:t.sampleRate,channels:t.channels??re};if(i===t.sampleRate)return{bytes:u,sampleRate:t.sampleRate,channels:s};let c=await n({channels:s,sourceSampleRate:i,targetSampleRate:t.sampleRate});try{let d=c.simple(Xt(u));if(d.length%s!==0)throw new RangeError("Resampled audio is not aligned to its channel count");return{bytes:Zt(d),sampleRate:t.sampleRate,channels:s}}finally{c.destroy()}}function Xt(e){let t=new Float32Array(e.byteLength/2),r=new DataView(e.buffer,e.byteOffset,e.byteLength);for(let n=0;n<t.length;n+=1)t[n]=r.getInt16(n*2,!0)/32768;return t}function Zt(e){let t=new Uint8Array(e.length*2),r=new DataView(t.buffer);for(let n=0;n<e.length;n+=1){let a=Math.max(-1,Math.min(1,e[n])),i=a<0?Math.round(a*32768):Math.round(a*32767);r.setInt16(n*2,i,!0)}return t}function er(e,t){if(e.byteLength%2!==0)throw new RangeError("ASR PCM16 frame must contain an even number of bytes");if(e.byteLength/2%t!==0)throw new RangeError("ASR PCM16 frame must align to its channel count")}function te(e,t){if(!Number.isFinite(e)||!Number.isInteger(e)||e<=0)throw new RangeError(`${t} must be a finite positive integer`)}function tr(e){return Symbol.asyncIterator in Object(e)}async function rr(e,t){if(tr(e)){let r="",n="tts",a;for await(let i of e)pe(t),r+=i.text,n=i.streamId,a=i.turnId;return a!==void 0?{text:r,streamId:n,turnId:a}:{text:r,streamId:n}}return e.turnId!==void 0?{text:e.text,streamId:e.streamId,turnId:e.turnId}:{text:e.text,streamId:e.streamId}}function nr(e){return e.map(t=>{if(Array.isArray(t.content)&&t.content.length===0)throw new h("Gateway LLM content parts must not be empty",{fatal:!0});let r=typeof t.content=="string"?t.content:t.content.map(a=>{if(a.type==="text")return{type:"text",text:a.text};if(a.data.byteLength===0||!/^image\/[a-z0-9.+-]+$/i.test(a.mimeType))throw new h("Gateway LLM image content is invalid",{fatal:!0});return{type:"image_url",image_url:{url:`data:${a.mimeType};base64,${ar(a.data)}`}}}),n={role:t.role,content:r};return t.name!==void 0&&(n.name=t.name),t.toolCallId!==void 0&&(n.tool_call_id=t.toolCallId),n})}function ar(e){let r="";for(let n=0;n<e.length;n+=32768)r+=String.fromCharCode(...e.subarray(n,n+32768));return btoa(r)}function me(e){let t=Q(e.fetch),r=X(e.apiKey);return{run(n,a){return(async function*(){let s=a?.signal,u;try{u=await Qt(n,e,s)}catch(f){throw f instanceof DOMException&&f.name==="AbortError"?f:E(f,{provider:"gateway-asr",message:"Gateway ASR audio preprocessing failed"})}let{bytes:c,sampleRate:d,channels:p}=u,o=new FormData;o.append("model",e.model),o.append("stream","true"),o.append("audio_format","pcm"),o.append("sample_rate",String(d)),o.append("channels",String(p)),e.hotwords!==void 0&&o.append("hotwords",e.hotwords),o.append("file",new Blob([c],{type:"application/octet-stream"}),"audio.pcm");let l={method:"POST",headers:r,body:o};s!==void 0&&(l.signal=s);let m=await Z(t,K(J.asr),l,"asr"),v=$(Y(ee(m,"asr")),{...s!==void 0?{signal:s}:{},isTerminator:de});yield*ze(v,{streamId:"speech"})})()}}}function fe(e){let t=Q(e.fetch),n={...X(e.apiKey),"Content-Type":"application/json"};return{run(a,i){return(async function*(){let u=i?.signal,c={model:e.model,stream:!0,messages:nr(a.messages)};e.temperature!==void 0&&(c.temperature=e.temperature),e.maxTokens!==void 0&&(c.max_tokens=e.maxTokens),e.topP!==void 0&&(c.top_p=e.topP);let d={method:"POST",headers:n,body:JSON.stringify(c)};u!==void 0&&(d.signal=u);let p=await Z(t,K(J.llm),d,"llm"),o=$(Y(ee(p,"llm")),{...u!==void 0?{signal:u}:{},isTerminator:de}),l=a.turnId!==void 0?{streamId:a.streamId,turnId:a.turnId}:{streamId:a.streamId};yield*He(o,l)})()}}}function he(e){let t=Q(e.fetch),n={...X(e.apiKey),"Content-Type":"application/json"};return{run(a,i){return(async function*(){let u=i?.signal,{text:c,streamId:d,turnId:p}=await rr(a,u),o=e.sampleRate??Kt,l={model:e.model,input:c,response_format:"pcm",stream_format:"sse",sample_rate:o};e.voice!==void 0&&(l.voice=e.voice),e.speed!==void 0&&(l.speed=e.speed),e.pitchRate!==void 0&&(l.pitch_rate=e.pitchRate);let m={method:"POST",headers:n,body:JSON.stringify(l)};u!==void 0&&(m.signal=u);let v=await Z(t,K(J.tts),m,"tts"),f=$(Y(ee(v,"tts")),{...u!==void 0?{signal:u}:{}});yield*Je(f,p!==void 0?{streamId:d,turnId:p,sampleRate:o,channels:re}:{streamId:d,sampleRate:o,channels:re})})()}}}import*as M from"onnxruntime-web";var ir=new URL("./assets/silero_vad_v6.onnx",import.meta.url).href;async function Ke(e={},t){let r=e.modelUrl??ir,n=await(e.modelFetcher??or)(r,t),a=await M.InferenceSession.create(n);return{async run(i){let s=await a.run({input:new M.Tensor("float32",i.input,[1,i.input.length]),state:new M.Tensor("float32",i.state,[2,1,128]),sr:new M.Tensor("int64",BigInt64Array.from([BigInt(i.sampleRate)]),[])}),u=s.output,c=s.stateN;if(u===void 0||c===void 0||u.type!=="float32"||c.type!=="float32"||!(u.data instanceof Float32Array)||!(c.data instanceof Float32Array)||u.data.length!==1||!sr(c.dims,[2,1,128]))throw new Error("Silero VAD v6 returned an invalid result");return ge({speechProbability:u.data[0],state:Float32Array.from(c.data)})}}}function ge(e){if(!Number.isFinite(e.speechProbability)||e.speechProbability<0||e.speechProbability>1||e.state.length!==256||!e.state.every(Number.isFinite))throw new Error("Silero VAD v6 returned an invalid result");return e}async function or(e,t){let r=await fetch(e,t!==void 0?{signal:t}:{});if(!r.ok)throw new Error("Silero VAD model fetch failed");return r.arrayBuffer()}function sr(e,t){return e.length===t.length&&e.every((r,n)=>r===t[n])}var $e=16e3,ye=512,ne=64;function be(e={}){return new Se(e)}var Se=class{constructor(t){this.options=t}options;run(t,r){return this.runFrames(t,r)}async*runFrames(t,r){let n=r?.signal,a=this.options.positiveSpeechThreshold??.5,i=this.options.negativeSpeechThreshold??.35,s=Math.max(1,Math.ceil((this.options.silenceThresholdMs??200)/32)),u=!1,c=0,d=new Float32Array(256),p=new Float32Array(ne),o,l,m,v=[];try{if(U(n))return;let f=await Ye(this.options.createSession!==void 0?this.options.createSession():Ke(this.options,n),n);for await(let g of t){if(U(n))return;if(o=g,l!==void 0&&g.sampleRate!==l)throw new RangeError("VAD source sampleRate cannot change within a run");l??=g.sampleRate,m??=await H({channels:1,sourceSampleRate:l,targetSampleRate:$e});let b=ur(g);for(v.push(...m.full(b));v.length>=ye;){let y=Float32Array.from(v.splice(0,ye)),S=new Float32Array(ne+ye);S.set(p),S.set(y,ne);let A=ge(await Ye(f.run({input:S,state:d,sampleRate:$e}),n));if(U(n))return;d=Float32Array.from(A.state),p=S.slice(S.length-ne),A.speechProbability>=a?(c=0,u||(u=!0,yield ve(g,"started",A.speechProbability))):u&&A.speechProbability<i?(c+=1,c>=s&&(u=!1,c=0,yield ve(g,"stopped",A.speechProbability))):u&&(c=0)}}u&&!U(n)&&o!==void 0&&(yield ve(o,"stopped"))}catch(f){if(U(n))return;throw E(f,{provider:"silero-vad"})}finally{m?.destroy()}}};function U(e){return e?.aborted===!0}function Ye(e,t){return t===void 0?e:t.aborted?Promise.reject(Qe()):new Promise((r,n)=>{let a=()=>{t.removeEventListener("abort",a),n(Qe())};t.addEventListener("abort",a,{once:!0}),e.then(i=>{t.removeEventListener("abort",a),r(i)},i=>{t.removeEventListener("abort",a),n(i)})})}function Qe(){let e=new Error("Operation aborted");return e.name="AbortError",e}function ur(e){if(!Number.isInteger(e.channels)||e.channels<=0)throw new RangeError("Audio frame channels must be positive");let t=e.channels*2;if(e.audio.byteLength%t!==0)throw new RangeError("Audio frame PCM must align to its channel count");let r=e.audio.byteLength/t,n=new Float32Array(r),a=new DataView(e.audio.buffer,e.audio.byteOffset,e.audio.byteLength);for(let i=0;i<r;i+=1){let s=0;for(let u=0;u<e.channels;u+=1)s+=a.getInt16((i*e.channels+u)*2,!0)/32768;n[i]=s/e.channels}return n}function ve(e,t,r){return{kind:"vad",streamId:e.streamId,...e.turnId!==void 0?{turnId:e.turnId}:{},partial:t==="started",final:t==="stopped",metadata:e.metadata,state:t,...r!==void 0?{confidence:r}:{}}}function Ae(e){return e.fetch!==void 0?{fetch:e.fetch}:{}}function Xe(e,t){return me({apiKey:t.apiKey,model:e.model,sampleRate:e.sampleRate,...Ae(t)})}function Ze(e,t){return fe({apiKey:t.apiKey,model:e.model,...e.temperature!==void 0?{temperature:e.temperature}:{},...e.maxTokens!==void 0?{maxTokens:e.maxTokens}:{},...Ae(t)})}function et(e,t){return he({apiKey:t.apiKey,model:e.model,...e.voice!==void 0?{voice:e.voice}:{},...e.speakingRate!==void 0?{speed:e.speakingRate}:{},...e.sampleRate!==void 0?{sampleRate:e.sampleRate}:{},...e.pitch!==void 0?{pitchRate:e.pitch}:{},...Ae(t)})}function tt(e,t){if(e===void 0)return;if(e.sensitivity!==void 0&&!(e.sensitivity>0&&e.sensitivity<=1))throw new h("VAD sensitivity must be within (0, 1]",{fatal:!0});if(e.silenceThresholdMs!==void 0&&(!Number.isFinite(e.silenceThresholdMs)||e.silenceThresholdMs<=0))throw new h("VAD silenceThresholdMs must be finite and greater than 0",{fatal:!0});let r=e.sensitivity??.5;return be({positiveSpeechThreshold:r,negativeSpeechThreshold:Math.max(0,r-.15),...e.silenceThresholdMs!==void 0?{silenceThresholdMs:e.silenceThresholdMs}:{},...t.createSileroSession!==void 0?{createSession:t.createSileroSession}:{}})}var dr=10,cr=1500,lr="\u8BF7\u7528\u4E00\u53E5\u7B80\u77ED\u3001\u81EA\u7136\u7684\u8BDD\u5411\u7528\u6237\u6253\u62DB\u547C\u3002";function Ee(e={}){return{create(t){let r={apiKey:t.apiKey,...e.fetch!==void 0?{fetch:e.fetch}:{},...e.createSileroSession!==void 0?{createSileroSession:e.createSileroSession}:{}},n=tt(t.vad,r);return{asr:Xe(t.asr,r),llm:Ze(t.llm,r),tts:et(t.tts,r),...n!==void 0?{vad:n}:{}}}}}function we(e,t){rt(e.asr.sampleRate,"ASR sampleRate"),e.tts.sampleRate!==void 0&&rt(e.tts.sampleRate,"TTS sampleRate");let r=pr(e.camera?.captureTimeoutMs),n=e.transports?.input!==void 0,a={apiKey:e.apiKey,asr:e.asr,tts:e.tts,llm:e.llm};e.vad!==void 0&&(a.vad=e.vad);let i=t.create(a);if(n&&i.vad===void 0)throw new h("Audio input requires a VAD provider",{fatal:!0});let s={systemPrompt:e.systemPrompt??"",greeting:fr(e.greeting),metadata:mr(e.metadata),camera:{captureTimeoutMs:r},providers:i};return e.history!==void 0&&(s.history={maxTurns:hr(e.history.maxTurns)}),e.transports!==void 0&&(s.transports=e.transports),s}function pr(e){let t=e??cr;if(!Number.isFinite(t)||!Number.isInteger(t)||t<=0)throw new h("Camera captureTimeoutMs must be a finite positive integer",{fatal:!0});return t}function mr(e){try{return C(e??{})}catch(t){throw new h("Agent metadata must be JSON-compatible",{fatal:!0,cause:t})}}function fr(e){if(e===void 0||e.mode==="disabled")return{mode:"disabled"};if(e.mode==="static"){if(e.text.trim().length===0)throw new h("Static greeting text must not be empty",{fatal:!0});return{mode:"static",text:e.text}}return{mode:"dynamic",prompt:e.prompt===void 0||e.prompt.trim().length===0?lr:e.prompt}}function hr(e){let t=e??dr;if(!Number.isInteger(t)||t<=0)throw new h("History maxTurns must be a positive integer",{fatal:!0});return t}function rt(e,t){if(!Number.isFinite(e)||!Number.isInteger(e)||e<=0)throw new h(`${t} must be a finite positive integer`,{fatal:!0})}function nt(e,t,r){return{...T(e),type:"transcript.final",final:!0,partial:!1,text:t,source:r}}function at(e,t){return{...T(e),type:"transcript.partial",final:!1,partial:!0,text:t,source:"speech"}}function it(e){return{...T(e),type:"speech.started",partial:!1,final:!0}}function ot(e,t){return{...T(e),type:"image.captured",partial:!1,final:!0,image:{...t}}}function st(e){return{...T(e),type:"speech.stopped",partial:!1,final:!0}}function ut(e,t){return{...T(e),type:"interruption",partial:!1,final:!0,reason:t}}function dt(e){return{...T(e),type:"reply.started",partial:!1,final:!0}}function ct(e,t){return{...T(e),type:"reply.partial",partial:!0,final:!1,text:t}}function lt(e,t){return{...T(e),type:"reply.final",partial:!1,final:!0,text:t}}function pt(e){return{...T(e),type:"playback.started",partial:!1,final:!0}}function mt(e){return{...T(e),type:"playback.stopped",partial:!1,final:!0}}function ft(e,t){return{...T(e),type:"turn.latency",partial:!1,final:!0,latency:t}}function ht(e,t){return{...e,type:"error",partial:!1,final:!0,error:gr(t)}}function T(e){if(e.turnId===void 0)throw new h("Runtime event is missing turn identity",{fatal:!0});return{...e,turnId:e.turnId}}function gr(e){return{message:e.message,fatal:e.fatal,source:e.source,...e.provider!==void 0?{provider:e.provider}:{},...e.statusCode!==void 0?{statusCode:e.statusCode}:{},...e.role!==void 0?{role:e.role}:{},...e.operation!==void 0?{operation:e.operation}:{},...e.reason!==void 0?{reason:e.reason}:{}}}function Ce(e){let t=new Set,r=new Map,n=e.onEvent(a=>{let i=vr(a,yr(r,a.streamId));if(i!==void 0)for(let s of t)s(i)});return{onEvent(a){return t.add(a),()=>{t.delete(a)}},close(){n(),t.clear()}}}function yr(e,t){let r=e.get(t)??0;return e.set(t,r+1),r}function vr(e,t){let r=Sr(e,t);switch(e.type){case"speech.started":return it(r);case"image.captured":return ot(r,e.image);case"speech.stopped":return st(r);case"transcript.partial":return at(r,e.text);case"transcript.final":return nt(r,e.text,e.source);case"interruption":return ut(r,e.reason);case"reply.started":return dt(r);case"reply.partial":return ct(r,e.text);case"reply.final":return lt(r,e.text);case"playback.started":return pt(r);case"playback.stopped":return mt(r);case"turn.latency":return ft(r,e.latency);case"error":return ht(r,e.error);default:return}}function Sr(e,t){return{streamId:e.streamId,...e.turnId!==void 0?{turnId:e.turnId}:{},sequence:t,partial:e.partial,final:e.final,...e.timestamp!==void 0?{timestamp:e.timestamp}:{},metadata:br(e.metadata),...e.frameId!==void 0?{frameId:e.frameId}:{}}}var gt=/(api.?key|authorization|headers?|raw|body|sse|pcm|provider.?object|secret|token|credential|password|cookies?)/i,I=Symbol("unsafe-metadata");function br(e){let t={};for(let[r,n]of Object.entries(e)){if(gt.test(r))continue;let a=Te(n,new Set);a!==I&&(t[r]=a)}return t}function Te(e,t){if(e===null||typeof e=="string"||typeof e=="boolean")return e;if(typeof e=="number")return Number.isFinite(e)?e:I;if(typeof e!="object"||t.has(e))return I;t.add(e);try{if(Array.isArray(e)){let n=[];for(let a of e){let i=Te(a,t);if(i===I)return I;n.push(i)}return n}if(Object.getPrototypeOf(e)!==Object.prototype&&Object.getPrototypeOf(e)!==null)return I;let r={};for(let[n,a]of Object.entries(e)){if(gt.test(n))continue;let i=Te(a,t);if(i===I)return I;r[n]=i}return r}finally{t.delete(e)}}function yt(e){return Ar(e,Ee())}function Ar(e,t){let r=we(e,t);return Er(new _(r))}function Er(e){let t=Ce(e),r="created",n=!1,a,i,s=new Set,u=(d,p,o=!0)=>{let l;return l=(async()=>{try{if(await d(),n)throw R("Agent media control was cancelled by stop")}catch(m){throw n?R("Agent media control was cancelled by stop"):o&&m instanceof h?m:new h(p,{cause:m})}finally{s.delete(l)}})(),s.add(l),l};return{start(){if(n||r==="stopped")return Promise.reject(R("Agent is stopped"));if(a!==void 0)return a;let d=(async()=>{try{if(await e.start(),n)throw R("Agent start was cancelled by stop");r="running"}catch(p){if(n)throw R("Agent start was cancelled by stop");try{await e.stop()}catch{}throw r="created",a=void 0,p instanceof h?p:w(p,{message:"Agent start failed"})}})();return a=d,d},submitText(d,p){if(n||r!=="running")return Promise.reject(R(r==="created"?"Agent has not started":"Agent is stopped"));let o;try{o=p===void 0?void 0:wr(p)}catch(l){return Promise.reject(w(l,{message:"Turn metadata must be JSON-compatible"}))}return e.submitText(d,o).catch(l=>{throw w(l,{message:"Agent text submission failed"})})},setAudioInputEnabled(d){return n||r==="stopped"?Promise.reject(R("Agent is stopped")):u(()=>e.setAudioInputEnabled(d),"Agent audio input update failed",!1)},setCameraCaptureEnabled(d){return n||r==="stopped"?Promise.reject(R("Agent is stopped")):u(()=>e.setCameraCaptureEnabled(d),"Agent camera capture update failed")},setTtsEnabled(d){return n||r==="stopped"?Promise.reject(R("Agent is stopped")):u(()=>e.setSkipTts(!d),"Agent TTS update failed")},getMessages(){return e.getMessages()},onEvent(d){if(n||r==="stopped")throw R(r==="stopped"?"Agent is stopped":"Agent is stopping");let p=t.onEvent(d),o=!0;return()=>{o&&(o=!1,p())}},stop(){if(i!==void 0)return i;n=!0;let d=a,p=[...s],o=(async()=>{let l;try{try{await e.stop()}catch(m){l=m}if(await Promise.allSettled([...d===void 0?[]:[d],...p]),l!==void 0)throw w(l,{message:"Agent stop failed"})}finally{t.close(),r="stopped"}})();return i=o,o}}}function wr(e){return{...e.turnId!==void 0?{turnId:e.turnId}:{},...e.metadata!==void 0?{metadata:C(e.metadata)}:{}}}function R(e){return new h(e,{fatal:!0})}export{h as EvaSdkError,yt as createEvaVoiceDialogueAgent};
|