@voicethere/agent 0.3.0 → 0.5.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.
package/README.md CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  VoiceThere **customer agent SDK** — TypeScript types and runtime helpers for sandboxed child bundles running inside the **VoiceThere agent runner** (session worker).
4
4
 
5
+ **Website:** [voicethere.io](https://voicethere.io)
5
6
  **npm:** `@voicethere/agent`
6
7
  **Repo:** [`voicethere/agent`](https://github.com/voicethere/agent)
7
8
 
8
9
  ## Role
9
10
 
10
- | Layer | Package | Runs in |
11
- | --------- | ----------------------------------------------------------- | ------------------------------------ |
12
- | Parent | VoiceThere agent runner | Trusted Node + WebRTC + speech stack |
13
- | **Child** | **`@voicethere/agent`** | Sandboxed customer `agent.js` bundle |
11
+ | Layer | Package | Runs in |
12
+ | --------- | ----------------------- | ------------------------------------ |
13
+ | Parent | VoiceThere agent runner | Trusted Node + WebRTC + speech stack |
14
+ | **Child** | **`@voicethere/agent`** | Sandboxed customer `agent.js` bundle |
14
15
 
15
16
  The child receives speech lifecycle events over IPC (same shapes as `@node-webrtc-rust/sdk/voice`) and calls `speak()` to request TTS from the parent.
16
17
 
@@ -41,12 +42,12 @@ npx @voicethere/agent verify-start --no-build --bundle ./dist/agent.js
41
42
 
42
43
  `verify-start` launches the bundle in the sandboxed child with restricted Node flags (`--permission` + fs-read allowlist), sends `session_start`, and requires `session_start_ack`.
43
44
 
44
- | Command | When to use |
45
- | ------- | ----------- |
46
- | `npx @voicethere/agent verify` | **Default** — build `agent.ts` → `dist/agent.js`, then run all static checks |
47
- | `npx @voicethere/agent verify --no-build` | Re-run checks on an existing bundle |
48
- | `npx @voicethere/agent verify --no-build --bundle ./dist/agent.js` | Verify a specific bundle path |
49
- | `npx @voicethere/agent verify-start --no-build --bundle ./dist/agent.js` | Verify sandbox startup + restricted Node flags on a specific bundle |
45
+ | Command | When to use |
46
+ | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
47
+ | `npx @voicethere/agent verify` | **Default** — build `agent.ts` → `dist/agent.js`, then run all static checks |
48
+ | `npx @voicethere/agent verify --no-build` | Re-run checks on an existing bundle |
49
+ | `npx @voicethere/agent verify --no-build --bundle ./dist/agent.js` | Verify a specific bundle path |
50
+ | `npx @voicethere/agent verify-start --no-build --bundle ./dist/agent.js` | Verify sandbox startup + restricted Node flags on a specific bundle |
50
51
 
51
52
  Optional flags: `--entry` / `-e`, `--outfile` / `-o` (same as `build`).
52
53
 
@@ -146,45 +147,48 @@ import {
146
147
  defineAgent,
147
148
  speak,
148
149
  type SpeechEvent,
149
- } from '@voicethere/agent'
150
- import { SPEECH_EVENT_TYPE } from '@node-webrtc-rust/sdk/voice'
150
+ } from "@voicethere/agent";
151
+ import { SPEECH_EVENT_TYPE } from "@node-webrtc-rust/sdk/voice";
151
152
 
152
153
  defineAgent({
153
154
  async onAgentStart({ env }) {
154
155
  // When project Redis is enabled, VoiceThere injects AGENT_REDIS_URL.
155
156
  // Depend on `ioredis` in your agent package and connect here (once per child).
156
- const redisUrl = env.AGENT_REDIS_URL // or process.env.AGENT_REDIS_URL
157
+ const redisUrl = env.AGENT_REDIS_URL; // or process.env.AGENT_REDIS_URL
157
158
  if (redisUrl) {
158
159
  // const Redis = (await import('ioredis')).default
159
160
  // globalThis.redis = new Redis(redisUrl)
160
161
  }
161
162
  },
162
163
  onSessionStart({ sessionId }) {
163
- speak(sessionId, 'Hello!')
164
+ speak(sessionId, "Hello!");
164
165
  },
165
166
  onUserSpeechFinal({ sessionId, text }) {
166
- speak(sessionId, `You said: ${text}`)
167
+ speak(sessionId, `You said: ${text}`);
167
168
  },
168
169
  onSpeechEvent({ sessionId }, speech: SpeechEvent) {
169
170
  if (speech.type === SPEECH_EVENT_TYPE.bargeIn) {
170
- agentLog('info', `User interrupted on ${sessionId}`)
171
+ agentLog("info", `User interrupted on ${sessionId}`);
171
172
  }
172
173
  },
173
- })
174
+ });
174
175
  ```
175
176
 
176
177
  ### Shared Redis (project-scoped)
177
178
 
178
179
  On plans that include project Redis, the runner injects **`AGENT_REDIS_URL`** into the child environment and grants scoped `--allow-net` for that host. Add **`ioredis`** as a dependency of your agent, bundle it with the CLI, and open the client in **`onAgentStart`** so it is ready before any `onSessionStart` / session IPC.
179
180
 
180
- | Export | Purpose |
181
- | ----------------------------------------------- | ------------------------------------------------------------------------------------- |
182
- | `defineAgent` | Register `onAgentStart`, `onSessionStart`, `onSpeechEvent`, `onUserSpeechFinal`, `onSessionEnd` |
183
- | `SpeechEvent`, `SpeechEventType` | Re-exported **types** from `@node-webrtc-rust/sdk/voice` |
184
- | `SPEECH_EVENT_TYPE` | Import from `@node-webrtc-rust/sdk/voice` (runtime constants; not bundled into child) |
185
- | `speak` | Request parent TTS |
186
- | `agentLog` | Forward structured logs to parent |
187
- | `ParentToChildMessage` / `ChildToParentMessage` | IPC contract shared with the VoiceThere agent runner |
181
+ For inbound HTTP webhooks, configure **`AGENT_WEBHOOK_SIGNING_SECRET`** in project settings. The runner forwards the exact request bytes on process-wide **`onWebhook`** IPC (not session-queued). Verify HMAC on `ctx.body` before `JSON.parse` — VoiceThere does not verify signatures in the SDK. See [`templates/webhooks.ts`](./templates/webhooks.ts).
182
+
183
+ | Export | Purpose |
184
+ | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
185
+ | `defineAgent` | Register `onAgentStart`, `onWebhook`, `onSessionStart`, `onSpeechEvent`, `onUserSpeechFinal`, `onSessionEnd` |
186
+ | `SpeechEvent`, `SpeechEventType` | Re-exported **types** from `@node-webrtc-rust/sdk/voice` |
187
+ | `SPEECH_EVENT_TYPE` | Import from `@node-webrtc-rust/sdk/voice` (runtime constants; not bundled into child) |
188
+ | `speak` | Request parent TTS |
189
+ | `startRecording` / `pauseRecording` / `resumeRecording` / `stopRecording` | Request parent conversation recording control |
190
+ | `agentLog` | Forward structured logs to parent |
191
+ | `ParentToChildMessage` / `ChildToParentMessage` | IPC contract shared with the VoiceThere agent runner |
188
192
 
189
193
  ### Runner runtime subpath (minimal shared sandbox API)
190
194
 
@@ -277,12 +281,12 @@ Customer code runs in a **forked child process**, separate from the trusted agen
277
281
 
278
282
  ### Layer 1 — Process isolation
279
283
 
280
- | Mechanism | What it means for your bundle |
281
- | --------- | ----------------------------- |
282
- | **Separate process** | Crash or `process.exit` in your bundle does not take down the parent voice stack |
283
- | **IPC only for media** | WebRTC, mic, STT, and TTS go through the parent — use `defineAgent`, `speak`, and speech events |
284
+ | Mechanism | What it means for your bundle |
285
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
286
+ | **Separate process** | Crash or `process.exit` in your bundle does not take down the parent voice stack |
287
+ | **IPC only for media** | WebRTC, mic, STT, and TTS go through the parent — use `defineAgent`, `speak`, and speech events |
284
288
  | **Stripped `process.env`** | Child receives only `NODE_ENV`, internal loader path, and allowlisted keys (`SESSION_ID`, `PROJECT_ID`, `BUILD_ID`) — not parent secrets |
285
- | **Console redirection** | `console.log` / `warn` / `error` → IPC logs |
289
+ | **Console redirection** | `console.log` / `warn` / `error` → IPC logs |
286
290
 
287
291
  ### Layer 2 — Node `--permission` (runtime-enforced)
288
292
 
@@ -290,24 +294,24 @@ The parent starts the child with Node’s [Permission Model](https://nodejs.org/
290
294
 
291
295
  **Granted today** (via `execArgv` on `fork()`):
292
296
 
293
- | Flag | Effect |
294
- | ---- | ------ |
295
- | `--permission` | Enables restriction mode |
296
- | `--allow-fs-read=<loaderDir>` | Read files under the child loader directory |
297
- | `--allow-fs-read=<bundleParentDir>` | Read files under the **directory containing your `agent.js`** (see below) |
298
- | `--allow-net` | Outbound network (HTTPS/fetch, TCP) for customer LLM and tool APIs (Node **26+**) |
299
- | `--allow-net=<host>` | Reserved for project Redis host entries when Node supports host-scoped net ACLs |
297
+ | Flag | Effect |
298
+ | ----------------------------------- | --------------------------------------------------------------------------------- |
299
+ | `--permission` | Enables restriction mode |
300
+ | `--allow-fs-read=<loaderDir>` | Read files under the child loader directory |
301
+ | `--allow-fs-read=<bundleParentDir>` | Read files under the **directory containing your `agent.js`** (see below) |
302
+ | `--allow-net` | Outbound network (HTTPS/fetch, TCP) for customer LLM and tool APIs (Node **26+**) |
303
+ | `--allow-net=<host>` | Reserved for project Redis host entries when Node supports host-scoped net ACLs |
300
304
 
301
305
  **Not granted → blocked at runtime:**
302
306
 
303
- | Missing flag | What fails |
304
- | ------------ | ---------- |
305
- | No `--allow-child-process` | `child_process`, `exec`, `spawn`, `fork` |
306
- | No `--allow-fs-write` | Any file write (`writeFile`, logs to disk, etc.) |
307
+ | Missing flag | What fails |
308
+ | -------------------------------- | ------------------------------------------------------------ |
309
+ | No `--allow-child-process` | `child_process`, `exec`, `spawn`, `fork` |
310
+ | No `--allow-fs-write` | Any file write (`writeFile`, logs to disk, etc.) |
307
311
  | No extra `--allow-fs-read` paths | Reading `/etc/passwd`, parent files, etc. outside bundle dir |
308
- | No `--allow-addons` | Native `.node` addons (`bcrypt`, `sharp`, …) |
309
- | No `--allow-worker-threads` | `worker_threads` |
310
- | No `--allow-wasi` | WASI modules |
312
+ | No `--allow-addons` | Native `.node` addons (`bcrypt`, `sharp`, …) |
313
+ | No `--allow-worker-threads` | `worker_threads` |
314
+ | No `--allow-wasi` | WASI modules |
311
315
 
312
316
  This is **not** an import allowlist — Node gates **capability classes**, not package names. Using `node:fs` inside the allowed read tree can work; using it on `/etc/passwd` does not.
313
317
 
@@ -325,23 +329,23 @@ This is **not** an import allowlist — Node gates **capability classes**, not p
325
329
  node_modules/ ← JS-only deps may resolve; native addons still blocked
326
330
  ```
327
331
 
328
- | Artifact in bundle dir | Works? |
329
- | ---------------------- | ------ |
330
- | Single bundled `agent.js` (recommended) | Yes |
331
- | Extra pure `.js` / `.json` siblings | Usually yes (same allowed tree) |
332
+ | Artifact in bundle dir | Works? |
333
+ | ------------------------------------------------- | ------------------------------------------------------------ |
334
+ | Single bundled `agent.js` (recommended) | Yes |
335
+ | Extra pure `.js` / `.json` siblings | Usually yes (same allowed tree) |
332
336
  | `node_modules/` with **JavaScript-only** packages | Often yes (Node resolves imports by reading under that tree) |
333
- | **Native** npm packages (`.node` binaries) | **No** — requires `--allow-addons` (not enabled) |
334
- | Packages that **spawn subprocesses** | **No** — no `--allow-child-process` |
337
+ | **Native** npm packages (`.node` binaries) | **No** — requires `--allow-addons` (not enabled) |
338
+ | Packages that **spawn subprocesses** | **No** — no `--allow-child-process` |
335
339
 
336
340
  Prefer **one esbuild bundle** so production behavior matches `npm run verify:local`.
337
341
 
338
342
  ### Layer 3 — Platform policy
339
343
 
340
- | Capability | Behavior |
341
- | ---------- | -------- |
344
+ | Capability | Behavior |
345
+ | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
342
346
  | **Outbound network** (`fetch`, `http`, `https`) | **Public internet:** allowed — typical for LLM/tool calls from your agent code. **Internal platform / private network:** blocked on hosted sessions. |
343
- | **`process.exit`** | Not blocked — kills your agent leg; parent may play crash TTS |
344
- | **Direct WebRTC / mic / STT / TTS** | Parent only — use `speak()` and speech event handlers |
347
+ | **`process.exit`** | Not blocked — kills your agent leg; parent may play crash TTS |
348
+ | **Direct WebRTC / mic / STT / TTS** | Parent only — use `speak()` and speech event handlers |
345
349
 
346
350
  ### What you should use in agent code
347
351
 
@@ -372,9 +376,9 @@ For iterative work: `npx @voicethere/agent build` then `npx @voicethere/agent ve
372
376
 
373
377
  ## Build outputs
374
378
 
375
- | Path | Purpose |
376
- | --------------- | ----------------------------------------------------------- |
377
- | `dist/index.js` | Published npm library entry |
379
+ | Path | Purpose |
380
+ | --------------- | -------------------------------------------------------------- |
381
+ | `dist/index.js` | Published npm library entry |
378
382
  | `dist/agent.js` | Example bundle (`examples/agent.ts`) for local runner / verify |
379
383
 
380
384
  ## Scripts
package/dist/agent.js CHANGED
@@ -3,6 +3,7 @@ const require = createRequire(import.meta.url);
3
3
 
4
4
 
5
5
  // src/runtime.ts
6
+ import { randomUUID } from "node:crypto";
6
7
  import { AsyncLocalStorage } from "node:async_hooks";
7
8
 
8
9
  // src/session-serial-queue.ts
@@ -129,10 +130,51 @@ var SessionSerialQueue = class {
129
130
  var SESSION_START_INIT_DELAY_ENABLED_ENV = "AGENT_SESSION_START_INIT_DELAY_ENABLED";
130
131
  var SESSION_START_INIT_DELAY_MS_ENV = "AGENT_SESSION_START_INIT_DELAY_MS";
131
132
  var DEFAULT_SESSION_START_INIT_DELAY_MS = 500;
133
+ function isRecordingControlAckMessage(value) {
134
+ if (!value || typeof value !== "object") return false;
135
+ const msg = value;
136
+ return msg.type === "recording_control_ack" && typeof msg.requestId === "string";
137
+ }
138
+ function isWebhookMessage(value) {
139
+ if (!value || typeof value !== "object") return false;
140
+ const msg = value;
141
+ return msg.type === "webhook" && typeof msg.eventId === "string" && typeof msg.projectId === "string";
142
+ }
143
+ function coerceInboundBinary(value) {
144
+ if (!value) return null;
145
+ if (Buffer.isBuffer(value)) return value;
146
+ if (value instanceof Uint8Array) {
147
+ return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
148
+ }
149
+ if (value instanceof ArrayBuffer) return Buffer.from(value);
150
+ if (ArrayBuffer.isView(value)) {
151
+ return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
152
+ }
153
+ if (typeof value === "object") {
154
+ const maybeBufferLike = value;
155
+ if (maybeBufferLike.type === "Buffer" && Array.isArray(maybeBufferLike.data)) {
156
+ return Buffer.from(maybeBufferLike.data);
157
+ }
158
+ }
159
+ return null;
160
+ }
161
+ function normalizeWebhookHeaders(value) {
162
+ if (!value || typeof value !== "object") return {};
163
+ const out = {};
164
+ for (const [key, raw] of Object.entries(value)) {
165
+ if (typeof raw === "string") {
166
+ out[key] = raw;
167
+ }
168
+ }
169
+ return out;
170
+ }
132
171
  function isParentMessage(value) {
133
172
  if (!value || typeof value !== "object") return false;
134
173
  const msg = value;
135
- return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout";
174
+ return msg.type === "session_start" || msg.type === "speech_event" || msg.type === "session_end" || msg.type === "data_channel_message" || msg.type === "data_channel_binary" || msg.type === "idle_timeout" || msg.type === "recording_control_ack" || msg.type === "webhook";
175
+ }
176
+ function isSessionScopedParentMessage(value) {
177
+ return isParentMessage(value) && !isWebhookMessage(value);
136
178
  }
137
179
  function parseDataChannelPayload(raw) {
138
180
  try {
@@ -143,6 +185,26 @@ function parseDataChannelPayload(raw) {
143
185
  }
144
186
  var peerEnvBySessionId = /* @__PURE__ */ new Map();
145
187
  var endedSessionIds = /* @__PURE__ */ new Set();
188
+ var pendingRecordingAcks = /* @__PURE__ */ new Map();
189
+ function handleRecordingControlAck(message) {
190
+ const pending = pendingRecordingAcks.get(message.requestId);
191
+ if (!pending) return;
192
+ clearTimeout(pending.timer);
193
+ pendingRecordingAcks.delete(message.requestId);
194
+ pending.resolve({
195
+ ok: message.ok,
196
+ reason: message.reason,
197
+ requestId: message.requestId
198
+ });
199
+ }
200
+ function clearPendingRecordingAcksForSession(sessionId, reason) {
201
+ for (const [requestId, pending] of pendingRecordingAcks) {
202
+ if (pending.sessionId !== sessionId) continue;
203
+ clearTimeout(pending.timer);
204
+ pendingRecordingAcks.delete(requestId);
205
+ pending.resolve({ ok: false, reason, requestId });
206
+ }
207
+ }
146
208
  var sessionExecutionContext = new AsyncLocalStorage();
147
209
  var agentLogSessionContext = new AsyncLocalStorage();
148
210
  var inboundQueueAuthority = null;
@@ -219,6 +281,48 @@ function resolveSessionStartInitDelayMs() {
219
281
  DEFAULT_SESSION_START_INIT_DELAY_MS
220
282
  );
221
283
  }
284
+ async function handleWebhookMessage(message, handlers) {
285
+ if (!handlers.onWebhook) return;
286
+ const body = coerceInboundBinary(message.body);
287
+ if (!body) {
288
+ agentLog("warn", "webhook ipc dropped: body is not binary");
289
+ return;
290
+ }
291
+ const ctx = {
292
+ eventId: message.eventId,
293
+ projectId: message.projectId,
294
+ method: typeof message.method === "string" ? message.method : "POST",
295
+ path: typeof message.path === "string" ? message.path : "",
296
+ headers: normalizeWebhookHeaders(message.headers),
297
+ body,
298
+ contentType: typeof message.contentType === "string" ? message.contentType : null,
299
+ receivedAt: typeof message.receivedAt === "string" ? message.receivedAt : ""
300
+ };
301
+ try {
302
+ const started = Date.now();
303
+ await handlers.onWebhook(ctx);
304
+ sendParentMessage({
305
+ type: "webhook_handled",
306
+ projectId: message.projectId,
307
+ eventId: message.eventId,
308
+ durationMs: Date.now() - started
309
+ });
310
+ } catch (error) {
311
+ const err = error instanceof Error ? error : new Error(String(error));
312
+ await runErrorHook(handlers, {
313
+ sessionId: "",
314
+ projectId: message.projectId,
315
+ env: process.env,
316
+ error: err
317
+ });
318
+ sendParentMessage({
319
+ type: "agent_error",
320
+ sessionId: "",
321
+ message: err.message,
322
+ stack: err.stack
323
+ });
324
+ }
325
+ }
222
326
  async function handleParentMessage(message, handlers) {
223
327
  switch (message.type) {
224
328
  case "session_start":
@@ -232,7 +336,8 @@ async function handleParentMessage(message, handlers) {
232
336
  }
233
337
  await (handlers.onClientJoin ?? handlers.onSessionStart)?.({
234
338
  sessionId: message.sessionId,
235
- env: message.env
339
+ env: message.env,
340
+ recordingAvailable: message.recordingAvailable ?? false
236
341
  });
237
342
  sendParentMessage({
238
343
  type: "session_start_ack",
@@ -270,6 +375,7 @@ async function handleParentMessage(message, handlers) {
270
375
  });
271
376
  break;
272
377
  case "session_end":
378
+ clearPendingRecordingAcksForSession(message.sessionId, "session_ended");
273
379
  peerEnvBySessionId.delete(message.sessionId);
274
380
  await (handlers.onClientLeave ?? handlers.onSessionEnd)?.({
275
381
  sessionId: message.sessionId
@@ -286,9 +392,18 @@ function defineAgent(handlers) {
286
392
  inboundQueueAuthority = inboundBySession;
287
393
  const agentStartReady = runAgentStartHook(handlers);
288
394
  process.on("message", (message) => {
289
- if (!isParentMessage(message)) return;
395
+ if (isRecordingControlAckMessage(message)) {
396
+ handleRecordingControlAck(message);
397
+ return;
398
+ }
399
+ if (isWebhookMessage(message)) {
400
+ void agentStartReady.then(() => handleWebhookMessage(message, handlers));
401
+ return;
402
+ }
403
+ if (!isSessionScopedParentMessage(message)) return;
290
404
  if (message.type === "session_end") {
291
405
  endedSessionIds.add(message.sessionId);
406
+ clearPendingRecordingAcksForSession(message.sessionId, "session_ended");
292
407
  inboundBySession.clear(message.sessionId);
293
408
  }
294
409
  if (message.type === "session_start") {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export type { SpeechEvent, SpeechEventListener, SpeechEventName, SpeechEventType, } from "@node-webrtc-rust/sdk/voice";
2
- export { ALLOWED_CHILD_ENV_KEYS, type AgentErrorMessage, type AgentLogLevel, type AgentLogMessage, type AllowedChildEnvKey, type ChildToParentMessage, type ParentToChildMessage, type SessionEndMessage, type SessionStartMessage, type SendToClientMessage, type DataChannelMessageMessage, type DataChannelBinaryMessage, type DataChannelKind, type DisconnectClientMessage, type IdleTimeoutDoneMessage, type IdleTimeoutMessage, type SendBinaryToClientMessage, type SpeakMessage, type SpeechEventMessage, } from "./protocol.js";
3
- export { agentLog, defineAgent, disconnectClient, parseChatText, sendToClient, sendBinaryToClient, speak, broadcastToClients, type AgentHandlers, type AgentErrorContext, type AgentStartContext, type DataChannelContext, type IdleTimeoutContext, type SessionContext, type SpeechContext, type SpeechEventContext, } from "./runtime.js";
2
+ export { ALLOWED_CHILD_ENV_KEYS, type AgentErrorMessage, type AgentLogLevel, type AgentLogMessage, type AllowedChildEnvKey, type ChildToParentMessage, type ParentToChildMessage, type SessionEndMessage, type SessionStartMessage, type SendToClientMessage, type DataChannelMessageMessage, type DataChannelBinaryMessage, type DataChannelKind, type DisconnectClientMessage, type IdleTimeoutDoneMessage, type IdleTimeoutMessage, type RecordingControlMessage, type RecordingControlAckMessage, type RecordingControlAction, type RecordingControlResult, type SendBinaryToClientMessage, type SpeakMessage, type SpeechEventMessage, type WebhookMessage, } from "./protocol.js";
3
+ export { agentLog, defineAgent, disconnectClient, parseChatText, pauseRecording, resumeRecording, sendToClient, sendBinaryToClient, speak, startRecording, stopRecording, isRecordingAvailable, broadcastToClients, type AgentHandlers, type AgentErrorContext, type AgentStartContext, type DataChannelContext, type IdleTimeoutContext, type SessionContext, type SpeechContext, type SpeechEventContext, type WebhookContext, } from "./runtime.js";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,eAAe,GAChB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EACjB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,KAAK,EACL,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,eAAe,GAChB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,KAAK,EACL,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { ALLOWED_CHILD_ENV_KEYS, } from "./protocol.js";
2
- export { agentLog, defineAgent, disconnectClient, parseChatText, sendToClient, sendBinaryToClient, speak, broadcastToClients, } from "./runtime.js";
2
+ export { agentLog, defineAgent, disconnectClient, parseChatText, pauseRecording, resumeRecording, sendToClient, sendBinaryToClient, speak, startRecording, stopRecording, isRecordingAvailable, broadcastToClients, } from "./runtime.js";
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,sBAAsB,GAmBvB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,KAAK,EACL,kBAAkB,GASnB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,sBAAsB,GAwBvB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,KAAK,EACL,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,kBAAkB,GAUnB,MAAM,cAAc,CAAC"}
@@ -16,13 +16,13 @@ export type { SpeechEvent } from "@node-webrtc-rust/sdk/voice";
16
16
  * Register handlers via {@link defineAgent} in `@voicethere/agent` — do not read
17
17
  * `process.on('message')` directly in customer bundles.
18
18
  */
19
- export type ParentToChildMessage = SessionStartMessage | SpeechEventMessage | SessionEndMessage | DataChannelMessageMessage | DataChannelBinaryMessage | IdleTimeoutMessage;
19
+ export type ParentToChildMessage = SessionStartMessage | SpeechEventMessage | SessionEndMessage | DataChannelMessageMessage | DataChannelBinaryMessage | IdleTimeoutMessage | RecordingControlAckMessage | WebhookMessage;
20
20
  /**
21
21
  * Messages the customer child may send back to the runner parent.
22
22
  *
23
- * Prefer {@link speak}, {@link sendToClient}, {@link sendBinaryToClient}, and {@link agentLog} helpers over raw `process.send`.
23
+ * Prefer {@link speak}, {@link startRecording}, {@link sendToClient}, {@link sendBinaryToClient}, and {@link agentLog} helpers over raw `process.send`.
24
24
  */
25
- export type ChildToParentMessage = SessionStartAckMessage | SpeakMessage | AgentLogMessage | AgentErrorMessage | SendToClientMessage | SendBinaryToClientMessage | IdleTimeoutDoneMessage | DisconnectClientMessage;
25
+ export type ChildToParentMessage = SessionStartAckMessage | SpeakMessage | RecordingControlMessage | AgentLogMessage | AgentErrorMessage | SendToClientMessage | SendBinaryToClientMessage | IdleTimeoutDoneMessage | DisconnectClientMessage | WebhookHandledMessage;
26
26
  /** Which WebRTC data channel carried a binary IPC payload. */
27
27
  export type DataChannelKind = "control" | "sync";
28
28
  /**
@@ -40,6 +40,11 @@ export interface SessionStartMessage {
40
40
  * Keys are a subset of {@link ALLOWED_CHILD_ENV_KEYS}.
41
41
  */
42
42
  env: Record<string, string>;
43
+ /**
44
+ * When `true`, the runner has conversation recording enabled for this project.
45
+ * Absent on older runners — treat as `false`.
46
+ */
47
+ recordingAvailable?: boolean;
43
48
  }
44
49
  /**
45
50
  * Forwards one speech lifecycle event from the parent Sherpa/VAD/STT/TTS pipeline.
@@ -109,6 +114,36 @@ export interface SpeakMessage {
109
114
  /** UTF-8 text passed to the parent TTS vendor. */
110
115
  text: string;
111
116
  }
117
+ /**
118
+ * Ask the parent to start, pause, resume, or stop conversation recording for a session.
119
+ *
120
+ * Recording runs in the runner parent — use {@link startRecording}, {@link pauseRecording},
121
+ * {@link resumeRecording}, and {@link stopRecording} instead of raw `process.send`.
122
+ */
123
+ export type RecordingControlAction = "start" | "pause" | "resume" | "stop";
124
+ export interface RecordingControlMessage {
125
+ type: "recording_control";
126
+ /** Target peer/session id (must match a prior {@link SessionStartMessage}). */
127
+ sessionId: string;
128
+ action: RecordingControlAction;
129
+ /** Correlates with {@link RecordingControlAckMessage.requestId}. */
130
+ requestId: string;
131
+ }
132
+ /** Runner acknowledgement for a {@link RecordingControlMessage}. */
133
+ export interface RecordingControlAckMessage {
134
+ type: "recording_control_ack";
135
+ sessionId: string;
136
+ action: RecordingControlAction;
137
+ requestId: string;
138
+ ok: boolean;
139
+ reason?: "applied" | "disabled" | "unsupported" | "stopped" | "local_mock" | "timeout" | string;
140
+ }
141
+ /** Result returned by {@link startRecording} and related helpers. */
142
+ export type RecordingControlResult = {
143
+ ok: boolean;
144
+ reason?: string;
145
+ requestId: string;
146
+ };
112
147
  /** Log severity forwarded to the runner parent process. */
113
148
  export type AgentLogLevel = "debug" | "info" | "warn" | "error";
114
149
  /**
@@ -157,6 +192,34 @@ export interface SendBinaryToClientMessage {
157
192
  data: Buffer;
158
193
  channel?: DataChannelKind;
159
194
  }
195
+ /**
196
+ * Inbound HTTP webhook forwarded from the edge — process-wide, not tied to a session.
197
+ *
198
+ * Delivered to {@link AgentHandlers.onWebhook} on every child in the runner process
199
+ * (not session-queued). {@link WebhookMessage.body} is the exact inbound bytes — verify
200
+ * HMAC/signatures on `body` before `JSON.parse` in customer code.
201
+ */
202
+ export interface WebhookMessage {
203
+ type: "webhook";
204
+ /** Edge-generated id for idempotency. */
205
+ eventId: string;
206
+ projectId: string;
207
+ method: string;
208
+ path: string;
209
+ /** All inbound request headers (string values). */
210
+ headers: Record<string, string>;
211
+ /** Exact inbound body bytes — do not parse in the SDK before the customer handler. */
212
+ body: Buffer;
213
+ contentType: string | null;
214
+ receivedAt: string;
215
+ }
216
+ /** Child reports onWebhook completion latency (process-wide, not session-scoped). */
217
+ export interface WebhookHandledMessage {
218
+ type: "webhook_handled";
219
+ projectId: string;
220
+ eventId: string;
221
+ durationMs: number;
222
+ }
160
223
  /**
161
224
  * Idle timeout fired — run {@link AgentHandlers.onIdleTimeout} before disconnect.
162
225
  */
@@ -189,8 +252,9 @@ export interface DisconnectClientMessage {
189
252
  * The runner may add more project-specific keys over time; customer bundles must
190
253
  * not read `process.env` for session fields — only the `env` object on session start.
191
254
  *
192
- * Process-wide secrets such as `AGENT_REDIS_URL` (when project Redis is enabled) are
193
- * still available on `process.env` inside `onAgentStart`.
255
+ * Process-wide secrets such as `AGENT_REDIS_URL` (when project Redis is enabled) and
256
+ * `AGENT_WEBHOOK_SIGNING_SECRET` (for inbound webhook HMAC verification) are still
257
+ * available on `process.env` inside `onAgentStart` / `onWebhook`.
194
258
  * Keys prefixed with `AGENT_` may also be forwarded into the child environment.
195
259
  */
196
260
  export declare const ALLOWED_CHILD_ENV_KEYS: readonly ["SESSION_ID", "PROJECT_ID", "BUILD_ID", "IDLE_TIMEOUT_SEC", "AGENT_CUSTOMER_CONTEXT"];
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
package/dist/protocol.js CHANGED
@@ -14,8 +14,9 @@
14
14
  * The runner may add more project-specific keys over time; customer bundles must
15
15
  * not read `process.env` for session fields — only the `env` object on session start.
16
16
  *
17
- * Process-wide secrets such as `AGENT_REDIS_URL` (when project Redis is enabled) are
18
- * still available on `process.env` inside `onAgentStart`.
17
+ * Process-wide secrets such as `AGENT_REDIS_URL` (when project Redis is enabled) and
18
+ * `AGENT_WEBHOOK_SIGNING_SECRET` (for inbound webhook HMAC verification) are still
19
+ * available on `process.env` inside `onAgentStart` / `onWebhook`.
19
20
  * Keys prefixed with `AGENT_` may also be forwarded into the child environment.
20
21
  */
21
22
  export const ALLOWED_CHILD_ENV_KEYS = [
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAkNH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,YAAY;IACZ,YAAY;IACZ,UAAU;IACV,kBAAkB;IAClB,wEAAwE;IACxE,wBAAwB;CAChB,CAAC"}
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAkSH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,YAAY;IACZ,YAAY;IACZ,UAAU;IACV,kBAAkB;IAClB,wEAAwE;IACxE,wBAAwB;CAChB,CAAC"}
package/dist/runtime.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import type { SpeechEvent } from "@node-webrtc-rust/sdk/voice";
2
- import type { AgentLogLevel, DataChannelKind } from "./protocol.js";
2
+ import type { AgentLogLevel, DataChannelKind, RecordingControlResult } from "./protocol.js";
3
3
  export declare const SESSION_START_INIT_DELAY_ENABLED_ENV = "AGENT_SESSION_START_INIT_DELAY_ENABLED";
4
4
  export declare const SESSION_START_INIT_DELAY_MS_ENV = "AGENT_SESSION_START_INIT_DELAY_MS";
5
5
  export interface SessionContext {
6
6
  sessionId: string;
7
7
  env: Record<string, string>;
8
+ /** `true` when the runner advertises conversation recording for this project. */
9
+ recordingAvailable: boolean;
8
10
  }
9
11
  export interface SpeechContext {
10
12
  sessionId: string;
@@ -26,6 +28,18 @@ export interface AgentStartContext {
26
28
  /** Snapshot of `process.env` at child start (includes `AGENT_REDIS_URL` when set). */
27
29
  env: Record<string, string>;
28
30
  }
31
+ /** Context for process-wide inbound webhook IPC (`type: "webhook"`). */
32
+ export interface WebhookContext {
33
+ eventId: string;
34
+ projectId: string;
35
+ method: string;
36
+ path: string;
37
+ headers: Record<string, string>;
38
+ /** Exact inbound bytes — verify HMAC on this, then `JSON.parse`. */
39
+ body: Buffer;
40
+ contentType: string | null;
41
+ receivedAt: string;
42
+ }
29
43
  export interface AgentHandlers {
30
44
  /**
31
45
  * Runs once when the child registers handlers — before any session IPC is handled.
@@ -33,6 +47,12 @@ export interface AgentHandlers {
33
47
  * Errors are logged and reported; session IPC is still accepted afterward so the child does not hang.
34
48
  */
35
49
  onAgentStart?: (ctx: AgentStartContext) => void | Promise<void>;
50
+ /**
51
+ * Process-wide inbound HTTP webhook from the edge (not session-queued).
52
+ * VoiceThere does not verify signatures — use `AGENT_WEBHOOK_SIGNING_SECRET` in
53
+ * `process.env` and verify HMAC on {@link WebhookContext.body} before parsing JSON.
54
+ */
55
+ onWebhook?: (ctx: WebhookContext) => void | Promise<void>;
36
56
  /** Alias for {@link AgentHandlers.onSessionStart}. */
37
57
  onClientJoin?: (ctx: SessionContext) => void | Promise<void>;
38
58
  onSessionStart?: (ctx: SessionContext) => void | Promise<void>;
@@ -105,6 +125,16 @@ export declare function defineAgent(handlers: AgentHandlers): void;
105
125
  export declare function resetAgentIpcStateForTests(): void;
106
126
  /** Ask the runner parent to synthesize speech for the session. */
107
127
  export declare function speak(sessionId: string, text: string): void;
128
+ /** True when {@link SessionStartMessage.recordingAvailable} was set for the session. */
129
+ export declare function isRecordingAvailable(ctx: SessionContext): boolean;
130
+ /** Ask the runner parent to start conversation recording for the session. */
131
+ export declare function startRecording(sessionId: string): Promise<RecordingControlResult>;
132
+ /** Ask the runner parent to pause an in-progress recording for the session. */
133
+ export declare function pauseRecording(sessionId: string): Promise<RecordingControlResult>;
134
+ /** Ask the runner parent to resume a paused recording for the session. */
135
+ export declare function resumeRecording(sessionId: string): Promise<RecordingControlResult>;
136
+ /** Ask the runner parent to stop conversation recording for the session. */
137
+ export declare function stopRecording(sessionId: string): Promise<RecordingControlResult>;
108
138
  /** Send a JSON payload to the browser peer via the runner parent. */
109
139
  export declare function sendToClient(sessionId: string, payload: unknown): void;
110
140
  /** Send raw bytes to the browser peer via the runner parent. */