@alexkroman1/aai 0.10.3 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/_internal-types.d.ts +8 -1
  2. package/dist/_run-code.d.ts +16 -12
  3. package/dist/_runtime-conformance.d.ts +55 -0
  4. package/dist/_test-utils.d.ts +73 -0
  5. package/dist/_utils.d.ts +0 -19
  6. package/dist/_utils.js +28 -2
  7. package/dist/builtin-tools.d.ts +1 -5
  8. package/dist/constants-CwotjpJR.js +45 -0
  9. package/dist/constants.d.ts +42 -0
  10. package/dist/direct-executor-DAGCZOAN.js +1530 -0
  11. package/dist/direct-executor.d.ts +90 -31
  12. package/dist/hooks.d.ts +44 -0
  13. package/dist/hooks.js +58 -0
  14. package/dist/index.d.ts +1 -2
  15. package/dist/index.js +2 -2
  16. package/dist/internal.d.ts +19 -0
  17. package/dist/internal.js +164 -0
  18. package/dist/kv.d.ts +1 -1
  19. package/dist/kv.js +32 -1
  20. package/dist/matchers.js +1 -1
  21. package/dist/protocol.d.ts +3 -29
  22. package/dist/protocol.js +140 -2
  23. package/dist/server.d.ts +27 -40
  24. package/dist/server.js +117 -145
  25. package/dist/session.d.ts +65 -44
  26. package/dist/{testing-BbitshLb.js → testing-Dmx-dudh.js} +39 -43
  27. package/dist/testing.d.ts +9 -14
  28. package/dist/testing.js +2 -2
  29. package/dist/types.d.ts +24 -226
  30. package/dist/types.js +176 -2
  31. package/dist/types.test-d.d.ts +7 -0
  32. package/dist/vite-plugin.d.ts +15 -0
  33. package/dist/vite-plugin.js +82 -0
  34. package/dist/ws-handler.d.ts +1 -2
  35. package/package.json +34 -95
  36. package/dist/_embeddings.d.ts +0 -31
  37. package/dist/_internal-types-IfPcaJd5.js +0 -61
  38. package/dist/_internal-types.js +0 -2
  39. package/dist/_session-ctx.d.ts +0 -73
  40. package/dist/_session-otel.d.ts +0 -43
  41. package/dist/_session-persist.d.ts +0 -30
  42. package/dist/_ssrf-DCp_27V4.js +0 -123
  43. package/dist/_ssrf.d.ts +0 -30
  44. package/dist/_ssrf.js +0 -2
  45. package/dist/_utils-DgzpOMSV.js +0 -61
  46. package/dist/direct-executor-B-5mq3cu.js +0 -570
  47. package/dist/kv-iXtikQmR.js +0 -32
  48. package/dist/middleware-core-BwyBIPed.js +0 -107
  49. package/dist/middleware-core.d.ts +0 -47
  50. package/dist/middleware-core.js +0 -2
  51. package/dist/middleware.d.ts +0 -37
  52. package/dist/protocol-B-H2Q4ox.js +0 -162
  53. package/dist/runtime-CxcwaK68.js +0 -58
  54. package/dist/runtime.js +0 -2
  55. package/dist/s2s-M7JqtgFw.js +0 -272
  56. package/dist/s2s.js +0 -2
  57. package/dist/session-BYlwcrya.js +0 -683
  58. package/dist/session.js +0 -2
  59. package/dist/telemetry-CJlaDFNc.js +0 -95
  60. package/dist/telemetry.d.ts +0 -49
  61. package/dist/telemetry.js +0 -2
  62. package/dist/types-D8ZBxTL_.js +0 -192
  63. package/dist/unstorage-kv-CDgP-frt.js +0 -64
  64. package/dist/unstorage-kv.js +0 -2
  65. package/dist/unstorage-vector-Cj5llNhg.js +0 -172
  66. package/dist/unstorage-vector.d.ts +0 -47
  67. package/dist/unstorage-vector.js +0 -2
  68. package/dist/vector.d.ts +0 -86
  69. package/dist/vector.js +0 -49
  70. package/dist/worker-entry-2jaiqIj0.js +0 -70
  71. package/dist/worker-entry.d.ts +0 -47
  72. package/dist/worker-entry.js +0 -2
  73. package/dist/ws-handler-C0Q6eSay.js +0 -207
  74. package/dist/ws-handler.js +0 -2
@@ -1,107 +0,0 @@
1
- //#region middleware-core.ts
2
- /**
3
- * Run all `beforeInput` middleware in order, piping the text through each.
4
- * Symmetric to {@link runOutputFilters} but for user input.
5
- */
6
- async function runInputFilters(middleware, text, ctx) {
7
- let filtered = text;
8
- for (const mw of middleware) {
9
- if (!mw.beforeInput) continue;
10
- try {
11
- filtered = await mw.beforeInput(filtered, ctx);
12
- } catch (err) {
13
- console.warn("Middleware beforeInput failed:", err);
14
- }
15
- }
16
- return filtered;
17
- }
18
- /**
19
- * Run all `beforeTurn` middleware in order. Returns a block result if any
20
- * middleware blocks the turn, or `undefined` to proceed.
21
- */
22
- async function runBeforeTurnMiddleware(middleware, text, ctx) {
23
- for (const mw of middleware) {
24
- if (!mw.beforeTurn) continue;
25
- try {
26
- const result = await mw.beforeTurn(text, ctx);
27
- if (result && "block" in result && result.block) return result;
28
- } catch (err) {
29
- console.warn("Middleware beforeTurn failed:", err);
30
- }
31
- }
32
- }
33
- /**
34
- * Run all `afterTurn` middleware in reverse order.
35
- */
36
- async function runAfterTurnMiddleware(middleware, text, ctx) {
37
- for (let i = middleware.length - 1; i >= 0; i--) {
38
- const mw = middleware[i];
39
- if (!mw?.afterTurn) continue;
40
- try {
41
- await mw.afterTurn(text, ctx);
42
- } catch (err) {
43
- console.warn("Middleware afterTurn failed:", err);
44
- }
45
- }
46
- }
47
- /**
48
- * Run all `beforeToolCall` middleware in order. Returns a result that
49
- * may block execution, provide a cached result, or transform args.
50
- * Returns `undefined` to proceed with normal execution.
51
- */
52
- async function runToolCallInterceptors(middleware, toolName, args, ctx) {
53
- let currentArgs = args;
54
- for (const mw of middleware) {
55
- if (!mw.beforeToolCall) continue;
56
- try {
57
- const result = await mw.beforeToolCall(toolName, currentArgs, ctx);
58
- if (!result) continue;
59
- if ("block" in result && result.block) return {
60
- type: "block",
61
- reason: result.reason
62
- };
63
- if ("result" in result) return {
64
- type: "result",
65
- result: result.result
66
- };
67
- if ("args" in result) currentArgs = result.args;
68
- } catch (err) {
69
- console.warn("Middleware beforeToolCall failed:", err);
70
- }
71
- }
72
- if (currentArgs !== args) return {
73
- type: "args",
74
- args: currentArgs
75
- };
76
- }
77
- /**
78
- * Run all `afterToolCall` middleware in reverse order.
79
- */
80
- async function runAfterToolCallMiddleware(middleware, toolName, args, result, ctx) {
81
- for (let i = middleware.length - 1; i >= 0; i--) {
82
- const mw = middleware[i];
83
- if (!mw?.afterToolCall) continue;
84
- try {
85
- await mw.afterToolCall(toolName, args, result, ctx);
86
- } catch (err) {
87
- console.warn("Middleware afterToolCall failed:", err);
88
- }
89
- }
90
- }
91
- /**
92
- * Run all `beforeOutput` middleware in order, piping the text through each.
93
- */
94
- async function runOutputFilters(middleware, text, ctx) {
95
- let filtered = text;
96
- for (const mw of middleware) {
97
- if (!mw.beforeOutput) continue;
98
- try {
99
- filtered = await mw.beforeOutput(filtered, ctx);
100
- } catch (err) {
101
- console.warn("Middleware beforeOutput failed:", err);
102
- }
103
- }
104
- return filtered;
105
- }
106
- //#endregion
107
- export { runOutputFilters as a, runInputFilters as i, runAfterTurnMiddleware as n, runToolCallInterceptors as o, runBeforeTurnMiddleware as r, runAfterToolCallMiddleware as t };
@@ -1,47 +0,0 @@
1
- /**
2
- * Pure middleware runner functions — zero runtime dependencies.
3
- *
4
- * This module is intentionally dependency-free so it can be bundled into
5
- * the secure-exec isolate harness (which has no access to node_modules).
6
- * Only `import type` statements are allowed here.
7
- */
8
- import type { HookContext, Middleware, MiddlewareBlockResult } from "./types.ts";
9
- /** Result from a middleware tool call interceptor. */
10
- export type ToolInterceptResult = {
11
- type: "block";
12
- reason: string;
13
- } | {
14
- type: "result";
15
- result: string;
16
- } | {
17
- type: "args";
18
- args: Record<string, unknown>;
19
- } | undefined;
20
- /**
21
- * Run all `beforeInput` middleware in order, piping the text through each.
22
- * Symmetric to {@link runOutputFilters} but for user input.
23
- */
24
- export declare function runInputFilters(middleware: readonly Middleware[], text: string, ctx: HookContext): Promise<string>;
25
- /**
26
- * Run all `beforeTurn` middleware in order. Returns a block result if any
27
- * middleware blocks the turn, or `undefined` to proceed.
28
- */
29
- export declare function runBeforeTurnMiddleware(middleware: readonly Middleware[], text: string, ctx: HookContext): Promise<MiddlewareBlockResult | undefined>;
30
- /**
31
- * Run all `afterTurn` middleware in reverse order.
32
- */
33
- export declare function runAfterTurnMiddleware(middleware: readonly Middleware[], text: string, ctx: HookContext): Promise<void>;
34
- /**
35
- * Run all `beforeToolCall` middleware in order. Returns a result that
36
- * may block execution, provide a cached result, or transform args.
37
- * Returns `undefined` to proceed with normal execution.
38
- */
39
- export declare function runToolCallInterceptors(middleware: readonly Middleware[], toolName: string, args: Readonly<Record<string, unknown>>, ctx: HookContext): Promise<ToolInterceptResult>;
40
- /**
41
- * Run all `afterToolCall` middleware in reverse order.
42
- */
43
- export declare function runAfterToolCallMiddleware(middleware: readonly Middleware[], toolName: string, args: Readonly<Record<string, unknown>>, result: string, ctx: HookContext): Promise<void>;
44
- /**
45
- * Run all `beforeOutput` middleware in order, piping the text through each.
46
- */
47
- export declare function runOutputFilters(middleware: readonly Middleware[], text: string, ctx: HookContext): Promise<string>;
@@ -1,2 +0,0 @@
1
- import { a as runOutputFilters, i as runInputFilters, n as runAfterTurnMiddleware, o as runToolCallInterceptors, r as runBeforeTurnMiddleware, t as runAfterToolCallMiddleware } from "./middleware-core-BwyBIPed.js";
2
- export { runAfterToolCallMiddleware, runAfterTurnMiddleware, runBeforeTurnMiddleware, runInputFilters, runOutputFilters, runToolCallInterceptors };
@@ -1,37 +0,0 @@
1
- /**
2
- * Middleware runner — executes middleware chains for turns, tool calls,
3
- * and output filtering.
4
- *
5
- * Pure runner logic lives in middleware-core.ts (isolate-safe, zero deps).
6
- * This module re-exports it and adds the HookInvoker interface.
7
- */
8
- import type { StepInfo } from "./types.ts";
9
- export { runAfterToolCallMiddleware, runAfterTurnMiddleware, runBeforeTurnMiddleware, runInputFilters, runOutputFilters, runToolCallInterceptors, type ToolInterceptResult, } from "./middleware-core.ts";
10
- /** Generic interface for invoking agent lifecycle hooks, including middleware. */
11
- export type HookInvoker = {
12
- onConnect(sessionId: string, timeoutMs?: number): Promise<void>;
13
- onDisconnect(sessionId: string, timeoutMs?: number): Promise<void>;
14
- onTurn(sessionId: string, text: string, timeoutMs?: number): Promise<void>;
15
- onError(sessionId: string, error: {
16
- message: string;
17
- }, timeoutMs?: number): Promise<void>;
18
- onStep(sessionId: string, step: StepInfo, timeoutMs?: number): Promise<void>;
19
- resolveTurnConfig(sid: string, ms?: number): Promise<{
20
- maxSteps?: number;
21
- } | null>;
22
- filterInput?(sid: string, text: string, ms?: number): Promise<string>;
23
- beforeTurn?(sid: string, text: string, ms?: number): Promise<string | undefined>;
24
- afterTurn?(sid: string, text: string, ms?: number): Promise<void>;
25
- interceptToolCall?(sid: string, tool: string, args: Readonly<Record<string, unknown>>, ms?: number): Promise<{
26
- type: "block";
27
- reason: string;
28
- } | {
29
- type: "result";
30
- result: string;
31
- } | {
32
- type: "args";
33
- args: Record<string, unknown>;
34
- } | undefined>;
35
- afterToolCall?(sid: string, tool: string, args: Readonly<Record<string, unknown>>, result: string, ms?: number): Promise<void>;
36
- filterOutput?(sid: string, text: string, ms?: number): Promise<string>;
37
- };
@@ -1,162 +0,0 @@
1
- import { z } from "zod";
2
- //#region protocol.ts
3
- /**
4
- * WebSocket wire-format types shared by server and client.
5
- *
6
- * Note: this module is for internal use only and should not be used directly.
7
- */
8
- /**
9
- * Default sample rate for speech-to-text audio in Hz.
10
- *
11
- * This is the sample rate expected by the STT provider (AssemblyAI).
12
- */
13
- const DEFAULT_STT_SAMPLE_RATE = 16e3;
14
- /**
15
- * Default sample rate for text-to-speech audio in Hz.
16
- *
17
- * This is the sample rate produced by the TTS provider.
18
- */
19
- const DEFAULT_TTS_SAMPLE_RATE = 24e3;
20
- /**
21
- * Audio codec identifier used in the wire protocol.
22
- *
23
- * All audio frames are 16-bit signed PCM, little-endian, mono.
24
- */
25
- const AUDIO_FORMAT = "pcm16";
26
- /** Zod schema for KV operation requests from the worker to the host. */
27
- const KvRequestSchema = z.discriminatedUnion("op", [
28
- z.object({
29
- op: z.literal("get"),
30
- key: z.string().min(1)
31
- }),
32
- z.object({
33
- op: z.literal("set"),
34
- key: z.string().min(1),
35
- value: z.string(),
36
- expireIn: z.number().int().positive().optional()
37
- }),
38
- z.object({
39
- op: z.literal("del"),
40
- key: z.string().min(1)
41
- }),
42
- z.object({
43
- op: z.literal("list"),
44
- prefix: z.string(),
45
- limit: z.number().int().positive().optional(),
46
- reverse: z.boolean().optional()
47
- }),
48
- z.object({
49
- op: z.literal("keys"),
50
- pattern: z.string().optional()
51
- })
52
- ]);
53
- /** Default timeout for agent lifecycle hooks (onConnect, onTurn, etc). */
54
- const HOOK_TIMEOUT_MS = 5e3;
55
- /** Default timeout for tool execution in the worker. */
56
- const TOOL_EXECUTION_TIMEOUT_MS = 3e4;
57
- /** Maximum length for tool result strings sent to clients. */
58
- const MAX_TOOL_RESULT_CHARS = 4e3;
59
- /**
60
- * Zod schema for session error codes.
61
- * @public
62
- */
63
- const SessionErrorCodeSchema = z.enum([
64
- "stt",
65
- "llm",
66
- "tts",
67
- "tool",
68
- "protocol",
69
- "connection",
70
- "audio",
71
- "internal"
72
- ]);
73
- /** Helper: simple event with only a type field. */
74
- const ev = (t) => z.object({ type: z.literal(t) });
75
- /** Helper: event with type + text. */
76
- const textEv = (t) => z.object({
77
- type: z.literal(t),
78
- text: z.string()
79
- });
80
- const turnOrder = z.number().int().nonnegative().optional();
81
- /** Zod schema for {@link ClientEvent}. */
82
- const ClientEventSchema = z.discriminatedUnion("type", [
83
- ev("speech_started"),
84
- ev("speech_stopped"),
85
- z.object({
86
- type: z.literal("transcript"),
87
- text: z.string(),
88
- isFinal: z.boolean(),
89
- turnOrder
90
- }),
91
- textEv("turn").extend({ turnOrder }),
92
- textEv("chat"),
93
- textEv("chat_delta"),
94
- z.object({
95
- type: z.literal("tool_call_start"),
96
- toolCallId: z.string(),
97
- toolName: z.string(),
98
- args: z.record(z.string(), z.unknown())
99
- }),
100
- z.object({
101
- type: z.literal("tool_call_update"),
102
- toolCallId: z.string(),
103
- data: z.string().max(MAX_TOOL_RESULT_CHARS)
104
- }),
105
- z.object({
106
- type: z.literal("tool_call_done"),
107
- toolCallId: z.string(),
108
- result: z.string().max(MAX_TOOL_RESULT_CHARS)
109
- }),
110
- ev("tts_done"),
111
- ev("cancelled"),
112
- ev("reset"),
113
- ev("idle_timeout"),
114
- z.object({
115
- type: z.literal("error"),
116
- code: SessionErrorCodeSchema,
117
- message: z.string()
118
- })
119
- ]);
120
- /** Zod schema for {@link ReadyConfig}. */
121
- const ReadyConfigSchema = z.object({
122
- audioFormat: z.enum(["pcm16"]),
123
- sampleRate: z.number().int().positive(),
124
- ttsSampleRate: z.number().int().positive()
125
- });
126
- /** Zod schema for server→client text messages. */
127
- const ServerMessageSchema = z.discriminatedUnion("type", [
128
- z.object({
129
- type: z.literal("config"),
130
- audioFormat: z.string(),
131
- sampleRate: z.number(),
132
- ttsSampleRate: z.number(),
133
- sessionId: z.string().optional()
134
- }),
135
- ev("audio_done"),
136
- ...ClientEventSchema.options
137
- ]);
138
- /** Zod schema for client→server text messages. */
139
- const ClientMessageSchema = z.discriminatedUnion("type", [
140
- ev("audio_ready"),
141
- ev("cancel"),
142
- ev("reset"),
143
- z.object({
144
- type: z.literal("history"),
145
- messages: z.array(z.object({
146
- role: z.enum(["user", "assistant"]),
147
- content: z.string().max(1e5)
148
- })).max(200)
149
- })
150
- ]);
151
- /** Build the protocol-level session config from S2S sample rates. */
152
- function buildReadyConfig(s2sConfig) {
153
- return {
154
- audioFormat: AUDIO_FORMAT,
155
- sampleRate: s2sConfig.inputSampleRate,
156
- ttsSampleRate: s2sConfig.outputSampleRate
157
- };
158
- }
159
- /** Zod schema for {@link TurnConfig}. */
160
- const TurnConfigSchema = z.object({ maxSteps: z.number().int().positive().optional() });
161
- //#endregion
162
- export { DEFAULT_TTS_SAMPLE_RATE as a, MAX_TOOL_RESULT_CHARS as c, SessionErrorCodeSchema as d, TOOL_EXECUTION_TIMEOUT_MS as f, DEFAULT_STT_SAMPLE_RATE as i, ReadyConfigSchema as l, buildReadyConfig as m, ClientEventSchema as n, HOOK_TIMEOUT_MS as o, TurnConfigSchema as p, ClientMessageSchema as r, KvRequestSchema as s, AUDIO_FORMAT as t, ServerMessageSchema as u };
@@ -1,58 +0,0 @@
1
- import { a as DEFAULT_TTS_SAMPLE_RATE, i as DEFAULT_STT_SAMPLE_RATE } from "./protocol-B-H2Q4ox.js";
2
- //#region runtime.ts
3
- /**
4
- * Runtime dependencies injected into the session pipeline.
5
- *
6
- * Defines the {@link Logger} interface, a default {@link consoleLogger},
7
- * and the {@link S2SConfig} for Speech-to-Speech endpoint configuration.
8
- */
9
- let _otel;
10
- try {
11
- _otel = await import("@opentelemetry/api");
12
- } catch {}
13
- /** Default console-backed logger. */
14
- const consoleLogger = {
15
- info: (msg, ctx) => ctx ? console.log(msg, ctx) : console.log(msg),
16
- warn: (msg, ctx) => ctx ? console.warn(msg, ctx) : console.warn(msg),
17
- error: (msg, ctx) => ctx ? console.error(msg, ctx) : console.error(msg),
18
- debug: (msg, ctx) => ctx ? console.debug(msg, ctx) : console.debug(msg)
19
- };
20
- /**
21
- * Structured JSON logger for production diagnostics. Each log entry is a
22
- * single-line JSON object with `timestamp`, `level`, `msg`, and any
23
- * caller-provided context fields. When an active OpenTelemetry span exists,
24
- * `trace_id` and `span_id` are included automatically.
25
- */
26
- function jsonLog(level) {
27
- return (msg, ctx) => {
28
- const entry = {
29
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
30
- level,
31
- msg
32
- };
33
- if (_otel) {
34
- const span = _otel.trace.getSpan(_otel.context.active());
35
- if (span) {
36
- const sc = span.spanContext();
37
- entry.trace_id = sc.traceId;
38
- entry.span_id = sc.spanId;
39
- }
40
- }
41
- if (ctx) Object.assign(entry, ctx);
42
- (level === "error" || level === "warn" ? process.stderr : process.stdout).write(`${JSON.stringify(entry)}\n`);
43
- };
44
- }
45
- const jsonLogger = {
46
- info: jsonLog("info"),
47
- warn: jsonLog("warn"),
48
- error: jsonLog("error"),
49
- debug: jsonLog("debug")
50
- };
51
- /** Default S2S endpoint configuration. */
52
- const DEFAULT_S2S_CONFIG = {
53
- wssUrl: "wss://speech-to-speech.us.assemblyai.com/v1/realtime",
54
- inputSampleRate: DEFAULT_STT_SAMPLE_RATE,
55
- outputSampleRate: DEFAULT_TTS_SAMPLE_RATE
56
- };
57
- //#endregion
58
- export { consoleLogger as n, jsonLogger as r, DEFAULT_S2S_CONFIG as t };
package/dist/runtime.js DELETED
@@ -1,2 +0,0 @@
1
- import { n as consoleLogger, r as jsonLogger, t as DEFAULT_S2S_CONFIG } from "./runtime-CxcwaK68.js";
2
- export { DEFAULT_S2S_CONFIG, consoleLogger, jsonLogger };
@@ -1,272 +0,0 @@
1
- import { n as consoleLogger } from "./runtime-CxcwaK68.js";
2
- import { c as s2sConnectionDuration, h as tracer, l as s2sErrorCounter } from "./telemetry-CJlaDFNc.js";
3
- import { createNanoEvents } from "nanoevents";
4
- import { WebSocket } from "ws";
5
- //#region s2s.ts
6
- const uint8ToBase64 = (bytes) => Buffer.from(bytes).toString("base64");
7
- const base64ToUint8 = (base64) => new Uint8Array(Buffer.from(base64, "base64"));
8
- const WS_OPEN = 1;
9
- const defaultCreateS2sWebSocket = (url, opts) => new WebSocket(url, { headers: opts.headers });
10
- function hasStringFields(obj, ...keys) {
11
- for (const k of keys) if (typeof obj[k] !== "string") return false;
12
- return true;
13
- }
14
- function parseAgentTranscript(obj) {
15
- if (typeof obj.text !== "string") return;
16
- return {
17
- type: "transcript.agent",
18
- text: obj.text,
19
- reply_id: typeof obj.reply_id === "string" ? obj.reply_id : "",
20
- item_id: typeof obj.item_id === "string" ? obj.item_id : "",
21
- interrupted: obj.interrupted === true
22
- };
23
- }
24
- function parseToolCall(obj) {
25
- if (typeof obj.call_id !== "string" || typeof obj.name !== "string") return;
26
- const args = obj.args != null && typeof obj.args === "object" && !Array.isArray(obj.args) ? obj.args : {};
27
- return {
28
- type: "tool.call",
29
- call_id: obj.call_id,
30
- name: obj.name,
31
- args
32
- };
33
- }
34
- function passthrough(obj) {
35
- return obj;
36
- }
37
- function requireFields(...keys) {
38
- return (obj) => hasStringFields(obj, ...keys) ? obj : void 0;
39
- }
40
- const MESSAGE_VALIDATORS = new Map([
41
- ["session.ready", requireFields("session_id")],
42
- ["session.updated", passthrough],
43
- ["input.speech.started", passthrough],
44
- ["input.speech.stopped", passthrough],
45
- ["reply.content_part.started", passthrough],
46
- ["reply.content_part.done", passthrough],
47
- ["transcript.user.delta", requireFields("text")],
48
- ["transcript.user", requireFields("item_id", "text")],
49
- ["reply.started", requireFields("reply_id")],
50
- ["transcript.agent.delta", requireFields("delta")],
51
- ["transcript.agent", parseAgentTranscript],
52
- ["tool.call", parseToolCall],
53
- ["reply.done", (obj) => ({
54
- type: "reply.done",
55
- ...typeof obj.status === "string" ? { status: obj.status } : {}
56
- })],
57
- ["session.error", requireFields("code", "message")],
58
- ["error", requireFields("message")]
59
- ]);
60
- function parseS2sMessage(obj) {
61
- const type = obj.type;
62
- if (typeof type !== "string") return;
63
- return MESSAGE_VALIDATORS.get(type)?.(obj);
64
- }
65
- function dispatchS2sMessage(emitter, msg) {
66
- switch (msg.type) {
67
- case "session.ready":
68
- emitter.emit("ready", { sessionId: msg.session_id });
69
- break;
70
- case "session.updated":
71
- emitter.emit("sessionUpdated", msg);
72
- break;
73
- case "input.speech.started":
74
- emitter.emit("speechStarted");
75
- break;
76
- case "input.speech.stopped":
77
- emitter.emit("speechStopped");
78
- break;
79
- case "transcript.user.delta":
80
- emitter.emit("userTranscriptDelta", { text: msg.text });
81
- break;
82
- case "transcript.user":
83
- emitter.emit("userTranscript", {
84
- itemId: msg.item_id,
85
- text: msg.text
86
- });
87
- break;
88
- case "reply.started":
89
- emitter.emit("replyStarted", { replyId: msg.reply_id });
90
- break;
91
- case "transcript.agent.delta":
92
- emitter.emit("agentTranscriptDelta", { text: msg.delta });
93
- break;
94
- case "transcript.agent":
95
- emitter.emit("agentTranscript", {
96
- text: msg.text,
97
- replyId: msg.reply_id,
98
- itemId: msg.item_id,
99
- interrupted: msg.interrupted
100
- });
101
- break;
102
- case "tool.call":
103
- emitter.emit("toolCall", {
104
- callId: msg.call_id,
105
- name: msg.name,
106
- args: msg.args
107
- });
108
- break;
109
- case "reply.done":
110
- emitter.emit("replyDone", msg.status ? { status: msg.status } : {});
111
- break;
112
- case "session.error":
113
- if (msg.code === "session_not_found" || msg.code === "session_forbidden") emitter.emit("sessionExpired", {
114
- code: msg.code,
115
- message: msg.message
116
- });
117
- else emitter.emit("error", {
118
- code: msg.code,
119
- message: msg.message
120
- });
121
- break;
122
- case "error":
123
- emitter.emit("error", {
124
- code: "connection",
125
- message: msg.message
126
- });
127
- break;
128
- case "reply.content_part.started":
129
- case "reply.content_part.done": break;
130
- default: break;
131
- }
132
- }
133
- function connectS2s(opts) {
134
- const { apiKey, config, createWebSocket, logger: log = consoleLogger } = opts;
135
- return new Promise((resolve, reject) => {
136
- log.info("S2S connecting", { url: config.wssUrl });
137
- const connectionSpan = tracer.startSpan("s2s.connection", { attributes: { "aai.s2s.url": config.wssUrl } });
138
- const connectStart = performance.now();
139
- const ws = createWebSocket(config.wssUrl, { headers: { Authorization: `Bearer ${apiKey}` } });
140
- const emitter = createNanoEvents();
141
- let opened = false;
142
- function send(msg) {
143
- if (ws.readyState !== WS_OPEN) {
144
- log.debug("S2S send dropped: socket not open", { type: msg.type });
145
- return;
146
- }
147
- const json = JSON.stringify(msg);
148
- if (msg.type !== "input.audio") log.info(`S2S >> ${msg.type}`, msg.type === "session.update" ? { payload: json } : void 0);
149
- ws.send(json);
150
- }
151
- const handle = {
152
- on: emitter.on.bind(emitter),
153
- sendAudio(audio) {
154
- if (ws.readyState !== WS_OPEN) {
155
- log.debug("S2S sendAudio dropped: socket not open");
156
- return;
157
- }
158
- ws.send(`{"type":"input.audio","audio":"${uint8ToBase64(audio)}"}`);
159
- },
160
- sendToolResult(callId, result) {
161
- const msg = {
162
- type: "tool.result",
163
- call_id: callId,
164
- result
165
- };
166
- log.info("S2S >> tool.result", {
167
- call_id: callId,
168
- resultLength: result.length
169
- });
170
- send(msg);
171
- },
172
- updateSession(sessionConfig) {
173
- const { systemPrompt, ...rest } = sessionConfig;
174
- send({
175
- type: "session.update",
176
- session: {
177
- system_prompt: systemPrompt,
178
- ...rest
179
- }
180
- });
181
- },
182
- resumeSession(sessionId) {
183
- send({
184
- type: "session.resume",
185
- session_id: sessionId
186
- });
187
- },
188
- close() {
189
- log.info("S2S closing");
190
- ws.close();
191
- }
192
- };
193
- ws.addEventListener("open", () => {
194
- opened = true;
195
- log.info("S2S WebSocket open");
196
- connectionSpan.addEvent("ws.open");
197
- resolve(handle);
198
- });
199
- function tryParseJson(data) {
200
- try {
201
- return JSON.parse(String(data));
202
- } catch {
203
- log.warn("S2S << invalid JSON", { data: String(data).slice(0, 200) });
204
- }
205
- }
206
- function handleAudioFastPath(obj) {
207
- if (obj.type === "reply.audio" && typeof obj.data === "string") {
208
- const audioBytes = base64ToUint8(obj.data);
209
- emitter.emit("audio", { audio: audioBytes });
210
- return true;
211
- }
212
- return false;
213
- }
214
- function logIncoming(obj) {
215
- if (obj.type === "reply.audio" || obj.type === "input.audio") return;
216
- log.info(`S2S << ${obj.type}`, obj.type === "transcript.agent.delta" ? { delta: obj.delta } : void 0);
217
- }
218
- function handleS2sMessage(ev) {
219
- const raw = tryParseJson(ev.data);
220
- if (raw === void 0) return;
221
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
222
- log.warn("S2S << non-object JSON message", { type: typeof raw });
223
- return;
224
- }
225
- const obj = raw;
226
- logIncoming(obj);
227
- if (handleAudioFastPath(obj)) return;
228
- const parsed = parseS2sMessage(obj);
229
- if (!parsed) {
230
- log.warn(`S2S << unrecognised message type: ${obj.type ?? JSON.stringify(raw).slice(0, 200)}`);
231
- return;
232
- }
233
- dispatchS2sMessage(emitter, parsed);
234
- }
235
- ws.addEventListener("message", handleS2sMessage);
236
- ws.addEventListener("close", (ev) => {
237
- log.info("S2S WebSocket closed", {
238
- code: ev.code ?? 0,
239
- reason: ev.reason ?? ""
240
- });
241
- const elapsed = (performance.now() - connectStart) / 1e3;
242
- s2sConnectionDuration.record(elapsed);
243
- connectionSpan.addEvent("ws.closed", {
244
- "ws.close.code": ev.code ?? 0,
245
- "ws.close.reason": ev.reason ?? ""
246
- });
247
- connectionSpan.end();
248
- if (!opened) reject(/* @__PURE__ */ new Error(`WebSocket closed before open (code: ${ev.code ?? 0})`));
249
- emitter.emit("close");
250
- });
251
- ws.addEventListener("error", (ev) => {
252
- const message = typeof ev.message === "string" ? ev.message : "WebSocket error";
253
- const errObj = new Error(message);
254
- log.error("S2S WebSocket error", { error: errObj.message });
255
- s2sErrorCounter.add(1);
256
- connectionSpan.setStatus({
257
- code: 2,
258
- message: errObj.message
259
- });
260
- connectionSpan.recordException(errObj);
261
- if (!opened) {
262
- connectionSpan.end();
263
- reject(errObj);
264
- } else emitter.emit("error", {
265
- code: "ws_error",
266
- message: errObj.message
267
- });
268
- });
269
- });
270
- }
271
- //#endregion
272
- export { defaultCreateS2sWebSocket as n, connectS2s as t };
package/dist/s2s.js DELETED
@@ -1,2 +0,0 @@
1
- import { n as defaultCreateS2sWebSocket, t as connectS2s } from "./s2s-M7JqtgFw.js";
2
- export { connectS2s, defaultCreateS2sWebSocket };