@happyrobot-ai/sdk 0.1.11 → 0.1.12

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
@@ -44,10 +44,11 @@ const { run_id } = await client.workflows.triggerRun("my-workflow", {
44
44
 
45
45
  ```ts
46
46
  const client = new HappyRobotClient({
47
- apiKey: "sk_live_...", // Required. API key (sk_live_... or sk_test_...)
48
- timeout: 30_000, // Optional. Request timeout in ms. Defaults to 30000
49
- maxRetries: 2, // Optional. Retries on 429/5xx with exponential backoff. Defaults to 2
50
- fetch: customFetch, // Optional. Custom fetch implementation
47
+ apiKey: "sk_live_...", // Required. API key (sk_live_... or sk_test_...)
48
+ cluster: "eu", // Optional. "us" (default) or "eu"
49
+ timeout: 30_000, // Optional. Request timeout in ms. Defaults to 30000
50
+ maxRetries: 2, // Optional. Retries on 429/5xx with exponential backoff. Defaults to 2
51
+ fetch: customFetch, // Optional. Custom fetch implementation
51
52
  });
52
53
  ```
53
54
 
@@ -65,9 +66,9 @@ import { triggerAndWait } from "@happyrobot-ai/sdk/helpers";
65
66
  const { run, sessions } = await triggerAndWait(client, {
66
67
  workflowId: "my-workflow",
67
68
  payload: { phone: "+1234567890" },
68
- timeoutMs: 300_000, // Optional. Defaults to 5 minutes
69
- pollIntervalMs: 2_000, // Optional. Defaults to 2 seconds
70
- fetchSessions: true, // Optional. Fetch sessions on completion. Defaults to true
69
+ timeoutMs: 300_000, // Optional. Defaults to 5 minutes
70
+ pollIntervalMs: 2_000, // Optional. Defaults to 2 seconds
71
+ fetchSessions: true, // Optional. Fetch sessions on completion. Defaults to true
71
72
  environment: "production", // Optional. Defaults to "production"
72
73
  });
73
74
 
@@ -83,12 +84,12 @@ import { createVoiceAgent } from "@happyrobot-ai/sdk/helpers";
83
84
 
84
85
  const { workflow, publishResult } = await createVoiceAgent(client, {
85
86
  name: "Sales Agent",
86
- template: "voice-agent", // "voice-agent" (outbound) or "inbound-voice-agent"
87
+ template: "voice-agent", // "voice-agent" (outbound) or "inbound-voice-agent"
87
88
  prompt: "You are a helpful sales assistant...",
88
89
  initialMessage: "Hi, how can I help you today?",
89
90
  publish: true,
90
91
  environment: "production",
91
- folderId: "folder-id", // Optional
92
+ folderId: "folder-id", // Optional
92
93
  });
93
94
  ```
94
95
 
@@ -109,33 +110,33 @@ const { workflow } = await createFromTemplate(client, {
109
110
 
110
111
  ## Resources
111
112
 
112
- | Property | Class | Description |
113
- |---|---|---|
114
- | `client.workflows` | `WorkflowsResource` | Workflow CRUD, publishing, runs, and templates |
115
- | `client.versions` | `VersionsResource` | Version management (fork, publish, lock, test) |
116
- | `client.nodes` | `NodesResource` | Node CRUD, config schema, and available variables |
117
- | `client.runs` | `RunsResource` | Run details, cancellation, and annotations |
118
- | `client.sessions` | `SessionsResource` | Session details, messages, and SSE streaming |
119
- | `client.messages` | `MessagesResource` | Message quality flags |
120
- | `client.variables` | `VariablesResource` | Workflow-scoped variables |
121
- | `client.phoneNumbers` | `PhoneNumbersResource` | Phone number management |
122
- | `client.sipTrunks` | `SipTrunksResource` | SIP trunk management |
123
- | `client.integrations` | `IntegrationsResource` | Integration and event discovery |
124
- | `client.contacts` | `ContactsResource` | Contact lookup and history |
125
- | `client.knowledgeBases` | `KnowledgeBasesResource` | Knowledge base document management |
126
- | `client.workflowFolders` | `WorkflowFoldersResource` | Workflow folder organization |
127
- | `client.mcp` | `MCPResource` | MCP server management |
128
- | `client.billing` | `BillingResource` | Billing usage details and totals |
129
- | `client.apiKey` | `ApiKeyResource` | API key introspection |
130
- | `client.artifacts` | `ArtifactsResource` | Resolve fresh artifact URLs |
131
- | `client.adversarialSuites` | `AdversarialSuitesResource` | Adversarial suite management and execution |
132
- | `client.adversarialTests` | `AdversarialTestsResource` | Adversarial test management and execution |
133
- | `client.northstars` | `NorthstarsResource` | Northstar quality criteria management |
134
- | `client.customEvals` | `CustomEvalsResource` | Custom eval management and execution |
135
- | `client.issues` | `IssuesResource` | Quality issue (flag) status management |
136
- | `client.auditRemarks` | `AuditRemarksResource` | Audit remark feedback management |
137
- | `client.chat` | `ChatResource` | Chat session management, messaging, and file uploads |
138
- | `client.voice` | `VoiceResource` | Voice call token creation |
113
+ | Property | Class | Description |
114
+ | -------------------------- | --------------------------- | ---------------------------------------------------- |
115
+ | `client.workflows` | `WorkflowsResource` | Workflow CRUD, publishing, runs, and templates |
116
+ | `client.versions` | `VersionsResource` | Version management (fork, publish, lock, test) |
117
+ | `client.nodes` | `NodesResource` | Node CRUD, config schema, and available variables |
118
+ | `client.runs` | `RunsResource` | Run details, cancellation, and annotations |
119
+ | `client.sessions` | `SessionsResource` | Session details, messages, and SSE streaming |
120
+ | `client.messages` | `MessagesResource` | Message quality flags |
121
+ | `client.variables` | `VariablesResource` | Workflow-scoped variables |
122
+ | `client.phoneNumbers` | `PhoneNumbersResource` | Phone number management |
123
+ | `client.sipTrunks` | `SipTrunksResource` | SIP trunk management |
124
+ | `client.integrations` | `IntegrationsResource` | Integration and event discovery |
125
+ | `client.contacts` | `ContactsResource` | Contact lookup and history |
126
+ | `client.knowledgeBases` | `KnowledgeBasesResource` | Knowledge base document management |
127
+ | `client.workflowFolders` | `WorkflowFoldersResource` | Workflow folder organization |
128
+ | `client.mcp` | `MCPResource` | MCP server management |
129
+ | `client.billing` | `BillingResource` | Billing usage details and totals |
130
+ | `client.apiKey` | `ApiKeyResource` | API key introspection |
131
+ | `client.artifacts` | `ArtifactsResource` | Resolve fresh artifact URLs |
132
+ | `client.adversarialSuites` | `AdversarialSuitesResource` | Adversarial suite management and execution |
133
+ | `client.adversarialTests` | `AdversarialTestsResource` | Adversarial test management and execution |
134
+ | `client.northstars` | `NorthstarsResource` | Northstar quality criteria management |
135
+ | `client.customEvals` | `CustomEvalsResource` | Custom eval management and execution |
136
+ | `client.issues` | `IssuesResource` | Quality issue (flag) status management |
137
+ | `client.auditRemarks` | `AuditRemarksResource` | Audit remark feedback management |
138
+ | `client.chat` | `ChatResource` | Chat session management, messaging, and file uploads |
139
+ | `client.voice` | `VoiceResource` | Voice call token creation |
139
140
 
140
141
  ---
141
142
 
@@ -183,22 +184,22 @@ const { data } = await client.workflows.listRuns("my-workflow");
183
184
  const { run_id } = await client.workflows.triggerRun("my-workflow", { payload: { phone: "+1..." } });
184
185
  ```
185
186
 
186
- | Method | HTTP | Path | Description |
187
- |---|---|---|---|
188
- | `list(query?)` | GET | `/workflows` | List workflows, paginated |
189
- | `listAll(query?)` | GET | `/workflows` | Async generator over all pages |
190
- | `create(body)` | POST | `/workflows` | Create a new workflow |
191
- | `get(workflowId)` | GET | `/workflows/:id` | Get workflow by ID or slug |
192
- | `update(workflowId, body)` | PATCH | `/workflows/:id` | Update name, description, etc. |
193
- | `delete(workflowId)` | DELETE | `/workflows/:id` | Delete a workflow |
194
- | `duplicate(workflowId, body?)` | POST | `/workflows/:id/duplicate` | Duplicate a workflow |
195
- | `publish(workflowId, body?)` | POST | `/workflows/:id/publish` | Publish the latest version |
196
- | `unpublish(workflowId)` | POST | `/workflows/:id/unpublish` | Unpublish a workflow |
197
- | `cancelRuns(workflowId)` | POST | `/workflows/:id/cancel-runs` | Cancel all active runs |
198
- | `listTemplates(query?)` | GET | `/workflows/templates` | List workflow templates |
199
- | `listVersions(workflowId, query?)` | GET | `/workflows/:id/versions` | List versions for a workflow |
200
- | `listRuns(workflowId, query?)` | GET | `/workflows/:id/runs` | List runs for a workflow |
201
- | `triggerRun(workflowId, body?)` | POST | `/workflows/:id/runs` | Trigger a new run |
187
+ | Method | HTTP | Path | Description |
188
+ | ---------------------------------- | ------ | ---------------------------- | ------------------------------ |
189
+ | `list(query?)` | GET | `/workflows` | List workflows, paginated |
190
+ | `listAll(query?)` | GET | `/workflows` | Async generator over all pages |
191
+ | `create(body)` | POST | `/workflows` | Create a new workflow |
192
+ | `get(workflowId)` | GET | `/workflows/:id` | Get workflow by ID or slug |
193
+ | `update(workflowId, body)` | PATCH | `/workflows/:id` | Update name, description, etc. |
194
+ | `delete(workflowId)` | DELETE | `/workflows/:id` | Delete a workflow |
195
+ | `duplicate(workflowId, body?)` | POST | `/workflows/:id/duplicate` | Duplicate a workflow |
196
+ | `publish(workflowId, body?)` | POST | `/workflows/:id/publish` | Publish the latest version |
197
+ | `unpublish(workflowId)` | POST | `/workflows/:id/unpublish` | Unpublish a workflow |
198
+ | `cancelRuns(workflowId)` | POST | `/workflows/:id/cancel-runs` | Cancel all active runs |
199
+ | `listTemplates(query?)` | GET | `/workflows/templates` | List workflow templates |
200
+ | `listVersions(workflowId, query?)` | GET | `/workflows/:id/versions` | List versions for a workflow |
201
+ | `listRuns(workflowId, query?)` | GET | `/workflows/:id/runs` | List runs for a workflow |
202
+ | `triggerRun(workflowId, body?)` | POST | `/workflows/:id/runs` | Trigger a new run |
202
203
 
203
204
  ---
204
205
 
@@ -216,17 +217,17 @@ await client.versions.testAll("version-id");
216
217
  const issues = await client.versions.getPromptIssues("version-id");
217
218
  ```
218
219
 
219
- | Method | HTTP | Path | Description |
220
- |---|---|---|---|
221
- | `get(versionId)` | GET | `/versions/:id` | Get version with node summary and changelog |
222
- | `update(versionId, body)` | PATCH | `/versions/:id` | Update name or description |
223
- | `fork(versionId)` | POST | `/versions/:id/fork` | Clone a version |
224
- | `publish(versionId, body?)` | POST | `/versions/:id/publish` | Publish a version |
225
- | `unpublish(versionId)` | POST | `/versions/:id/unpublish` | Unpublish a version |
226
- | `lock(versionId)` | POST | `/versions/:id/lock` | Lock a version (prevent edits) |
227
- | `unlock(versionId)` | POST | `/versions/:id/unlock` | Unlock a version |
228
- | `testAll(versionId)` | POST | `/versions/:id/test-all` | Run test-all validation |
229
- | `getPromptIssues(versionId)` | GET | `/versions/:id/prompt-issues` | Get prompt quality issues for all prompt nodes |
220
+ | Method | HTTP | Path | Description |
221
+ | ---------------------------- | ----- | ----------------------------- | ---------------------------------------------- |
222
+ | `get(versionId)` | GET | `/versions/:id` | Get version with node summary and changelog |
223
+ | `update(versionId, body)` | PATCH | `/versions/:id` | Update name or description |
224
+ | `fork(versionId)` | POST | `/versions/:id/fork` | Clone a version |
225
+ | `publish(versionId, body?)` | POST | `/versions/:id/publish` | Publish a version |
226
+ | `unpublish(versionId)` | POST | `/versions/:id/unpublish` | Unpublish a version |
227
+ | `lock(versionId)` | POST | `/versions/:id/lock` | Lock a version (prevent edits) |
228
+ | `unlock(versionId)` | POST | `/versions/:id/unlock` | Unlock a version |
229
+ | `testAll(versionId)` | POST | `/versions/:id/test-all` | Run test-all validation |
230
+ | `getPromptIssues(versionId)` | GET | `/versions/:id/prompt-issues` | Get prompt quality issues for all prompt nodes |
230
231
 
231
232
  ---
232
233
 
@@ -245,16 +246,16 @@ const vars = await client.nodes.getAvailableVars("version-id", "node-id");
245
246
  const result = await client.nodes.test("version-id", "node-id");
246
247
  ```
247
248
 
248
- | Method | HTTP | Path | Description |
249
- |---|---|---|---|
250
- | `list(versionId)` | GET | `/versions/:vId/nodes` | List all nodes in a version |
251
- | `addBatch(versionId, body)` | POST | `/versions/:vId/nodes` | Add nodes in batch (1–50) |
252
- | `get(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId` | Get a single node |
253
- | `update(versionId, nodeId, body)` | PUT | `/versions/:vId/nodes/:nId` | Update a node |
254
- | `delete(versionId, nodeId)` | DELETE | `/versions/:vId/nodes/:nId` | Delete a node |
255
- | `getConfigSchema(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId/config-schema` | Get field types and requirements |
256
- | `getAvailableVars(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId/available-vars` | Get upstream variables available to this node |
257
- | `test(versionId, nodeId, body?)` | POST | `/versions/:vId/nodes/:nId/test` | Test a single node (version must not be published) |
249
+ | Method | HTTP | Path | Description |
250
+ | ------------------------------------- | ------ | ------------------------------------------ | -------------------------------------------------- |
251
+ | `list(versionId)` | GET | `/versions/:vId/nodes` | List all nodes in a version |
252
+ | `addBatch(versionId, body)` | POST | `/versions/:vId/nodes` | Add nodes in batch (1–50) |
253
+ | `get(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId` | Get a single node |
254
+ | `update(versionId, nodeId, body)` | PUT | `/versions/:vId/nodes/:nId` | Update a node |
255
+ | `delete(versionId, nodeId)` | DELETE | `/versions/:vId/nodes/:nId` | Delete a node |
256
+ | `getConfigSchema(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId/config-schema` | Get field types and requirements |
257
+ | `getAvailableVars(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId/available-vars` | Get upstream variables available to this node |
258
+ | `test(versionId, nodeId, body?)` | POST | `/versions/:vId/nodes/:nId/test` | Test a single node (version must not be published) |
258
259
 
259
260
  ---
260
261
 
@@ -269,14 +270,14 @@ await client.runs.cancel("run-id");
269
270
  await client.runs.mark("run-id", { annotation: "correct" });
270
271
  ```
271
272
 
272
- | Method | HTTP | Path | Description |
273
- |---|---|---|---|
274
- | `get(runId)` | GET | `/runs/:id` | Get run details |
275
- | `getSessions(runId, query?)` | GET | `/runs/:id/sessions` | Get sessions for a run |
276
- | `getRecordings(runId)` | GET | `/runs/:id/recordings` | Get recordings for a run |
277
- | `getFlags(runId, query?)` | GET | `/runs/:id/flags` | Get quality flags for a run |
278
- | `cancel(runId)` | POST | `/runs/:id/cancel` | Cancel a run |
279
- | `mark(runId, body)` | POST | `/runs/:id/mark` | Annotate a run (correct / incorrect / critical) |
273
+ | Method | HTTP | Path | Description |
274
+ | ---------------------------- | ---- | ---------------------- | ----------------------------------------------- |
275
+ | `get(runId)` | GET | `/runs/:id` | Get run details |
276
+ | `getSessions(runId, query?)` | GET | `/runs/:id/sessions` | Get sessions for a run |
277
+ | `getRecordings(runId)` | GET | `/runs/:id/recordings` | Get recordings for a run |
278
+ | `getFlags(runId, query?)` | GET | `/runs/:id/flags` | Get quality flags for a run |
279
+ | `cancel(runId)` | POST | `/runs/:id/cancel` | Cancel a run |
280
+ | `mark(runId, body)` | POST | `/runs/:id/mark` | Annotate a run (correct / incorrect / critical) |
280
281
 
281
282
  ---
282
283
 
@@ -288,16 +289,17 @@ const { data } = await client.sessions.getMessages("session-id");
288
289
 
289
290
  // SSE streaming
290
291
  for await (const event of await client.sessions.stream("session-id")) {
291
- if (event.event === "message") console.log(event.data.role, event.data.content);
292
+ if (event.event === "message")
293
+ console.log(event.data.role, event.data.content);
292
294
  if (event.event === "session_ended") break;
293
295
  }
294
296
  ```
295
297
 
296
- | Method | HTTP | Path | Description |
297
- |---|---|---|---|
298
- | `get(sessionId)` | GET | `/sessions/:id` | Get session details |
299
- | `getMessages(sessionId, query?)` | GET | `/sessions/:id/messages` | Get paginated messages for a session |
300
- | `stream(sessionId, query?)` | GET | `/sessions/:id/stream` | Open SSE stream of session messages |
298
+ | Method | HTTP | Path | Description |
299
+ | -------------------------------- | ---- | ------------------------ | ------------------------------------ |
300
+ | `get(sessionId)` | GET | `/sessions/:id` | Get session details |
301
+ | `getMessages(sessionId, query?)` | GET | `/sessions/:id/messages` | Get paginated messages for a session |
302
+ | `stream(sessionId, query?)` | GET | `/sessions/:id/stream` | Open SSE stream of session messages |
301
303
 
302
304
  ---
303
305
 
@@ -305,13 +307,16 @@ for await (const event of await client.sessions.stream("session-id")) {
305
307
 
306
308
  ```ts
307
309
  const { data } = await client.messages.listFlags("message-id");
308
- await client.messages.createFlag("message-id", { type: "incorrect", note: "..." });
310
+ await client.messages.createFlag("message-id", {
311
+ type: "incorrect",
312
+ note: "...",
313
+ });
309
314
  ```
310
315
 
311
- | Method | HTTP | Path | Description |
312
- |---|---|---|---|
313
- | `listFlags(messageId, query?)` | GET | `/messages/:id/flags` | List quality flags for a message |
314
- | `createFlag(messageId, body)` | POST | `/messages/:id/flags` | Create a quality flag on a message |
316
+ | Method | HTTP | Path | Description |
317
+ | ------------------------------ | ---- | --------------------- | ---------------------------------- |
318
+ | `listFlags(messageId, query?)` | GET | `/messages/:id/flags` | List quality flags for a message |
319
+ | `createFlag(messageId, body)` | POST | `/messages/:id/flags` | Create a quality flag on a message |
315
320
 
316
321
  ---
317
322
 
@@ -323,8 +328,8 @@ const resolved = await client.artifacts.resolve({
323
328
  });
324
329
  ```
325
330
 
326
- | Method | HTTP | Path | Description |
327
- |---|---|---|---|
331
+ | Method | HTTP | Path | Description |
332
+ | --------------- | ---- | -------------------- | ------------------------------------------ |
328
333
  | `resolve(body)` | POST | `/artifacts/resolve` | Resolve fresh presigned URLs for artifacts |
329
334
 
330
335
  ---
@@ -335,17 +340,20 @@ Variables are scoped to a workflow.
335
340
 
336
341
  ```ts
337
342
  const { data } = await client.variables.list("workflow-id");
338
- await client.variables.create("workflow-id", { name: "MY_VAR", value: "hello" });
343
+ await client.variables.create("workflow-id", {
344
+ name: "MY_VAR",
345
+ value: "hello",
346
+ });
339
347
  await client.variables.update("workflow-id", "variable-id", { value: "world" });
340
348
  await client.variables.delete("workflow-id", "variable-id");
341
349
  ```
342
350
 
343
- | Method | HTTP | Path | Description |
344
- |---|---|---|---|
345
- | `list(workflowId, query?)` | GET | `/workflows/:wId/variables` | List variables for a workflow |
346
- | `create(workflowId, body)` | POST | `/workflows/:wId/variables` | Create a variable |
347
- | `update(workflowId, variableId, body)` | PATCH | `/workflows/:wId/variables/:vId` | Update a variable |
348
- | `delete(workflowId, variableId)` | DELETE | `/workflows/:wId/variables/:vId` | Delete a variable |
351
+ | Method | HTTP | Path | Description |
352
+ | -------------------------------------- | ------ | -------------------------------- | ----------------------------- |
353
+ | `list(workflowId, query?)` | GET | `/workflows/:wId/variables` | List variables for a workflow |
354
+ | `create(workflowId, body)` | POST | `/workflows/:wId/variables` | Create a variable |
355
+ | `update(workflowId, variableId, body)` | PATCH | `/workflows/:wId/variables/:vId` | Update a variable |
356
+ | `delete(workflowId, variableId)` | DELETE | `/workflows/:wId/variables/:vId` | Delete a variable |
349
357
 
350
358
  ---
351
359
 
@@ -366,20 +374,20 @@ await client.phoneNumbers.createSipTrunk("id");
366
374
  await client.phoneNumbers.validateTollFreeNumbers({ phone_numbers: [...] });
367
375
  ```
368
376
 
369
- | Method | HTTP | Path | Description |
370
- |---|---|---|---|
371
- | `list(query?)` | GET | `/phone-numbers` | List all phone numbers |
372
- | `buy(body)` | POST | `/phone-numbers` | Purchase a new phone number |
373
- | `update(id, body)` | PUT | `/phone-numbers/:id` | Update name or caller ID |
374
- | `getUsage(id)` | GET | `/phone-numbers/:id/usage` | Get usage info |
375
- | `getTollFreeVerification(id)` | GET | `/phone-numbers/:id/tollfree-verification` | Get toll-free verification status |
376
- | `createTollFreeVerification(id, body)` | POST | `/phone-numbers/:id/tollfree-verification` | Start toll-free verification |
377
- | `deleteTollFreeVerification(verificationSid)` | DELETE | `/phone-numbers/tollfree-verification/:sid` | Delete a toll-free verification |
378
- | `createSipTrunk(id)` | POST | `/phone-numbers/:id/sip-trunk` | Create a SIP trunk for a number |
379
- | `freeUp(id)` | POST | `/phone-numbers/:id/free-up-number` | Release a number from workflows |
380
- | `delete(id)` | POST | `/phone-numbers/:id/delete-number` | Permanently delete a number |
381
- | `removeFromWorkflow(id, body)` | POST | `/phone-numbers/:id/remove-from-workflow` | Remove from a specific workflow |
382
- | `validateTollFreeNumbers(body)` | POST | `/phone-numbers/validate-toll-free-numbers` | Check for conflicts |
377
+ | Method | HTTP | Path | Description |
378
+ | --------------------------------------------- | ------ | ------------------------------------------- | --------------------------------- |
379
+ | `list(query?)` | GET | `/phone-numbers` | List all phone numbers |
380
+ | `buy(body)` | POST | `/phone-numbers` | Purchase a new phone number |
381
+ | `update(id, body)` | PUT | `/phone-numbers/:id` | Update name or caller ID |
382
+ | `getUsage(id)` | GET | `/phone-numbers/:id/usage` | Get usage info |
383
+ | `getTollFreeVerification(id)` | GET | `/phone-numbers/:id/tollfree-verification` | Get toll-free verification status |
384
+ | `createTollFreeVerification(id, body)` | POST | `/phone-numbers/:id/tollfree-verification` | Start toll-free verification |
385
+ | `deleteTollFreeVerification(verificationSid)` | DELETE | `/phone-numbers/tollfree-verification/:sid` | Delete a toll-free verification |
386
+ | `createSipTrunk(id)` | POST | `/phone-numbers/:id/sip-trunk` | Create a SIP trunk for a number |
387
+ | `freeUp(id)` | POST | `/phone-numbers/:id/free-up-number` | Release a number from workflows |
388
+ | `delete(id)` | POST | `/phone-numbers/:id/delete-number` | Permanently delete a number |
389
+ | `removeFromWorkflow(id, body)` | POST | `/phone-numbers/:id/remove-from-workflow` | Remove from a specific workflow |
390
+ | `validateTollFreeNumbers(body)` | POST | `/phone-numbers/validate-toll-free-numbers` | Check for conflicts |
383
391
 
384
392
  ---
385
393
 
@@ -395,15 +403,15 @@ await client.sipTrunks.update("trunk-id", { name: "Updated" });
395
403
  await client.sipTrunks.delete("trunk-id");
396
404
  ```
397
405
 
398
- | Method | HTTP | Path | Description |
399
- |---|---|---|---|
400
- | `list()` | GET | `/sip-trunks` | List all SIP trunks |
401
- | `listOptions()` | GET | `/sip-trunks/options` | Lightweight list of trunk options |
402
- | `create(body)` | POST | `/sip-trunks` | Create a SIP trunk |
403
- | `createBulk(body)` | POST | `/sip-trunks/bulk` | Create multiple SIP trunks |
404
- | `get(trunkId)` | GET | `/sip-trunks/:id` | Get a SIP trunk |
405
- | `update(trunkId, body)` | PUT | `/sip-trunks/:id` | Update a SIP trunk |
406
- | `delete(trunkId)` | DELETE | `/sip-trunks/:id` | Delete a SIP trunk |
406
+ | Method | HTTP | Path | Description |
407
+ | ----------------------- | ------ | --------------------- | --------------------------------- |
408
+ | `list()` | GET | `/sip-trunks` | List all SIP trunks |
409
+ | `listOptions()` | GET | `/sip-trunks/options` | Lightweight list of trunk options |
410
+ | `create(body)` | POST | `/sip-trunks` | Create a SIP trunk |
411
+ | `createBulk(body)` | POST | `/sip-trunks/bulk` | Create multiple SIP trunks |
412
+ | `get(trunkId)` | GET | `/sip-trunks/:id` | Get a SIP trunk |
413
+ | `update(trunkId, body)` | PUT | `/sip-trunks/:id` | Update a SIP trunk |
414
+ | `delete(trunkId)` | DELETE | `/sip-trunks/:id` | Delete a SIP trunk |
407
415
 
408
416
  ---
409
417
 
@@ -435,25 +443,25 @@ await client.integrations.whatsApp.phoneNumbers({ credential_id: "...", business
435
443
  await client.integrations.whatsApp.messageTemplates({ credential_id: "...", business_account_id: "..." });
436
444
  ```
437
445
 
438
- | Method | HTTP | Path | Description |
439
- |---|---|---|---|
440
- | `list(query?)` | GET | `/integrations` | List all integrations |
441
- | `get(id)` | GET | `/integrations/:id` | Get integration and its events |
442
- | `createCredential(id, body)` | POST | `/integrations/:id/create-credential` | Create a credential for a form-based integration |
443
- | `googleSheets.spreadsheets(query?)` | GET | `/integrations/google-sheets/spreadsheets` | List spreadsheets |
444
- | `googleSheets.worksheets(query)` | GET | `/integrations/google-sheets/worksheets` | List worksheets in a spreadsheet |
445
- | `googleSheets.columns(query)` | GET | `/integrations/google-sheets/columns` | List columns in a worksheet |
446
- | `googleSheets.rows(query)` | GET | `/integrations/google-sheets/rows` | List rows in a worksheet |
447
- | `slack.channels(query?)` | GET | `/integrations/slack/channels` | List Slack channels |
448
- | `slack.users(query?)` | GET | `/integrations/slack/users` | List Slack users |
449
- | `teams.teams(query?)` | GET | `/integrations/teams/teams` | List Microsoft Teams teams |
450
- | `teams.channels(query?)` | GET | `/integrations/teams/channels` | List Microsoft Teams channels |
451
- | `teams.users(query?)` | GET | `/integrations/teams/users` | List Microsoft Teams users |
452
- | `twilioSms.phoneNumbers(query?)` | GET | `/integrations/twilio-sms/phone-numbers` | List Twilio SMS numbers |
453
- | `whatsApp.businesses(query)` | GET | `/integrations/whatsapp/businesses` | List WhatsApp businesses |
454
- | `whatsApp.businessAccounts(query)` | GET | `/integrations/whatsapp/business-accounts` | List WhatsApp business accounts |
455
- | `whatsApp.phoneNumbers(query)` | GET | `/integrations/whatsapp/phone-numbers` | List WhatsApp phone numbers |
456
- | `whatsApp.messageTemplates(query)` | GET | `/integrations/whatsapp/message-templates` | List WhatsApp message templates |
446
+ | Method | HTTP | Path | Description |
447
+ | ----------------------------------- | ---- | ------------------------------------------ | ------------------------------------------------ |
448
+ | `list(query?)` | GET | `/integrations` | List all integrations |
449
+ | `get(id)` | GET | `/integrations/:id` | Get integration and its events |
450
+ | `createCredential(id, body)` | POST | `/integrations/:id/create-credential` | Create a credential for a form-based integration |
451
+ | `googleSheets.spreadsheets(query?)` | GET | `/integrations/google-sheets/spreadsheets` | List spreadsheets |
452
+ | `googleSheets.worksheets(query)` | GET | `/integrations/google-sheets/worksheets` | List worksheets in a spreadsheet |
453
+ | `googleSheets.columns(query)` | GET | `/integrations/google-sheets/columns` | List columns in a worksheet |
454
+ | `googleSheets.rows(query)` | GET | `/integrations/google-sheets/rows` | List rows in a worksheet |
455
+ | `slack.channels(query?)` | GET | `/integrations/slack/channels` | List Slack channels |
456
+ | `slack.users(query?)` | GET | `/integrations/slack/users` | List Slack users |
457
+ | `teams.teams(query?)` | GET | `/integrations/teams/teams` | List Microsoft Teams teams |
458
+ | `teams.channels(query?)` | GET | `/integrations/teams/channels` | List Microsoft Teams channels |
459
+ | `teams.users(query?)` | GET | `/integrations/teams/users` | List Microsoft Teams users |
460
+ | `twilioSms.phoneNumbers(query?)` | GET | `/integrations/twilio-sms/phone-numbers` | List Twilio SMS numbers |
461
+ | `whatsApp.businesses(query)` | GET | `/integrations/whatsapp/businesses` | List WhatsApp businesses |
462
+ | `whatsApp.businessAccounts(query)` | GET | `/integrations/whatsapp/business-accounts` | List WhatsApp business accounts |
463
+ | `whatsApp.phoneNumbers(query)` | GET | `/integrations/whatsapp/phone-numbers` | List WhatsApp phone numbers |
464
+ | `whatsApp.messageTemplates(query)` | GET | `/integrations/whatsapp/message-templates` | List WhatsApp message templates |
457
465
 
458
466
  ---
459
467
 
@@ -467,13 +475,13 @@ const interactions = await client.contacts.getInteractions("contact-id");
467
475
  const memories = await client.contacts.getMemories("contact-id");
468
476
  ```
469
477
 
470
- | Method | HTTP | Path | Description |
471
- |---|---|---|---|
472
- | `list(query?)` | GET | `/contacts` | List contacts (cursor-paginated) |
473
- | `resolve(query)` | GET | `/contacts/resolve` | Look up a contact by phone number or email |
474
- | `get(contactId)` | GET | `/contacts/:id` | Get contact by ID |
475
- | `getInteractions(contactId)` | GET | `/contacts/:id/interactions` | Get call/message history for a contact |
476
- | `getMemories(contactId)` | GET | `/contacts/:id/memories` | Get AI memories for a contact |
478
+ | Method | HTTP | Path | Description |
479
+ | ---------------------------- | ---- | ---------------------------- | ------------------------------------------ |
480
+ | `list(query?)` | GET | `/contacts` | List contacts (cursor-paginated) |
481
+ | `resolve(query)` | GET | `/contacts/resolve` | Look up a contact by phone number or email |
482
+ | `get(contactId)` | GET | `/contacts/:id` | Get contact by ID |
483
+ | `getInteractions(contactId)` | GET | `/contacts/:id/interactions` | Get call/message history for a contact |
484
+ | `getMemories(contactId)` | GET | `/contacts/:id/memories` | Get AI memories for a contact |
477
485
 
478
486
  ---
479
487
 
@@ -482,20 +490,22 @@ const memories = await client.contacts.getMemories("contact-id");
482
490
  ```ts
483
491
  const kbs = await client.knowledgeBases.list();
484
492
  const files = await client.knowledgeBases.listFiles("kb-id");
485
- const urls = await client.knowledgeBases.getUploadUrls("kb-id", { files: [{ name: "doc.pdf", content_type: "application/pdf" }] });
493
+ const urls = await client.knowledgeBases.getUploadUrls("kb-id", {
494
+ files: [{ name: "doc.pdf", content_type: "application/pdf" }],
495
+ });
486
496
  await client.knowledgeBases.triggerChunking("kb-id");
487
497
  await client.knowledgeBases.deleteFile("kb-id", "file-id");
488
498
  await client.knowledgeBases.delete("kb-id");
489
499
  ```
490
500
 
491
- | Method | HTTP | Path | Description |
492
- |---|---|---|---|
493
- | `list()` | GET | `/knowledge-bases` | List all knowledge bases |
494
- | `listFiles(kbId)` | GET | `/knowledge-bases/:id/files` | List documents in a knowledge base |
495
- | `getUploadUrls(kbId, body)` | POST | `/knowledge-bases/:id/upload-urls` | Get pre-signed S3 upload URLs |
496
- | `triggerChunking(kbId)` | POST | `/knowledge-bases/:id/trigger-chunking` | Start document processing/chunking |
497
- | `deleteFile(kbId, fileId)` | DELETE | `/knowledge-bases/:id/files/:fileId` | Delete a file from a knowledge base |
498
- | `delete(kbId)` | DELETE | `/knowledge-bases/:id` | Delete a knowledge base |
501
+ | Method | HTTP | Path | Description |
502
+ | --------------------------- | ------ | --------------------------------------- | ----------------------------------- |
503
+ | `list()` | GET | `/knowledge-bases` | List all knowledge bases |
504
+ | `listFiles(kbId)` | GET | `/knowledge-bases/:id/files` | List documents in a knowledge base |
505
+ | `getUploadUrls(kbId, body)` | POST | `/knowledge-bases/:id/upload-urls` | Get pre-signed S3 upload URLs |
506
+ | `triggerChunking(kbId)` | POST | `/knowledge-bases/:id/trigger-chunking` | Start document processing/chunking |
507
+ | `deleteFile(kbId, fileId)` | DELETE | `/knowledge-bases/:id/files/:fileId` | Delete a file from a knowledge base |
508
+ | `delete(kbId)` | DELETE | `/knowledge-bases/:id` | Delete a knowledge base |
499
509
 
500
510
  ---
501
511
 
@@ -509,13 +519,13 @@ await client.workflowFolders.update("folder-id", { name: "Updated" });
509
519
  await client.workflowFolders.delete("folder-id");
510
520
  ```
511
521
 
512
- | Method | HTTP | Path | Description |
513
- |---|---|---|---|
514
- | `list(query?)` | GET | `/workflow-folders` | List folders (paginated) |
515
- | `create(body)` | POST | `/workflow-folders` | Create a folder |
516
- | `get(folderId)` | GET | `/workflow-folders/:id` | Get a folder |
517
- | `update(folderId, body)` | PUT | `/workflow-folders/:id` | Update a folder |
518
- | `delete(folderId)` | DELETE | `/workflow-folders/:id` | Delete a folder |
522
+ | Method | HTTP | Path | Description |
523
+ | ------------------------ | ------ | ----------------------- | ------------------------ |
524
+ | `list(query?)` | GET | `/workflow-folders` | List folders (paginated) |
525
+ | `create(body)` | POST | `/workflow-folders` | Create a folder |
526
+ | `get(folderId)` | GET | `/workflow-folders/:id` | Get a folder |
527
+ | `update(folderId, body)` | PUT | `/workflow-folders/:id` | Update a folder |
528
+ | `delete(folderId)` | DELETE | `/workflow-folders/:id` | Delete a folder |
519
529
 
520
530
  ---
521
531
 
@@ -527,10 +537,10 @@ await client.mcp.create({ name: "My MCP", url: "https://..." });
527
537
  await client.mcp.refresh("mcp-id");
528
538
  ```
529
539
 
530
- | Method | HTTP | Path | Description |
531
- |---|---|---|---|
532
- | `list(query?)` | GET | `/mcp` | List MCP servers (paginated) |
533
- | `create(body)` | POST | `/mcp` | Register a new MCP server |
540
+ | Method | HTTP | Path | Description |
541
+ | ---------------- | ---- | ------------------ | ----------------------------------- |
542
+ | `list(query?)` | GET | `/mcp` | List MCP servers (paginated) |
543
+ | `create(body)` | POST | `/mcp` | Register a new MCP server |
534
544
  | `refresh(mcpId)` | POST | `/mcp/:id/refresh` | Re-discover tools for an MCP server |
535
545
 
536
546
  ---
@@ -538,14 +548,20 @@ await client.mcp.refresh("mcp-id");
538
548
  ## `client.billing`
539
549
 
540
550
  ```ts
541
- const details = await client.billing.getDetails({ start: "2024-01-01", end: "2024-01-31" });
542
- const totals = await client.billing.getTotals({ start: "2024-01-01", end: "2024-01-31" });
551
+ const details = await client.billing.getDetails({
552
+ start: "2024-01-01",
553
+ end: "2024-01-31",
554
+ });
555
+ const totals = await client.billing.getTotals({
556
+ start: "2024-01-01",
557
+ end: "2024-01-31",
558
+ });
543
559
  ```
544
560
 
545
- | Method | HTTP | Path | Description |
546
- |---|---|---|---|
547
- | `getDetails(query)` | GET | `/billing/usage/details` | Detailed billing line items |
548
- | `getTotals(query)` | GET | `/billing/usage/totals` | Aggregated billing totals |
561
+ | Method | HTTP | Path | Description |
562
+ | ------------------- | ---- | ------------------------ | --------------------------- |
563
+ | `getDetails(query)` | GET | `/billing/usage/details` | Detailed billing line items |
564
+ | `getTotals(query)` | GET | `/billing/usage/totals` | Aggregated billing totals |
549
565
 
550
566
  ---
551
567
 
@@ -555,9 +571,9 @@ const totals = await client.billing.getTotals({ start: "2024-01-01", end: "2024-
555
571
  const info = await client.apiKey.describe();
556
572
  ```
557
573
 
558
- | Method | HTTP | Path | Description |
559
- |---|---|---|---|
560
- | `describe()` | GET | `/api-key/describe` | Introspect the current API key (ID, name, org, etc.) |
574
+ | Method | HTTP | Path | Description |
575
+ | ------------ | ---- | ------------------- | ---------------------------------------------------- |
576
+ | `describe()` | GET | `/api-key/describe` | Introspect the current API key (ID, name, org, etc.) |
561
577
 
562
578
  ---
563
579
 
@@ -567,35 +583,43 @@ Adversarial suites group multiple adversarial tests and can auto-generate them f
567
583
 
568
584
  ```ts
569
585
  const { suite } = await client.adversarialSuites.get("suite-id");
570
- await client.adversarialSuites.update("suite-id", { name: "New Name", generation_count: 10 });
586
+ await client.adversarialSuites.update("suite-id", {
587
+ name: "New Name",
588
+ generation_count: 10,
589
+ });
571
590
  await client.adversarialSuites.delete("suite-id");
572
591
 
573
592
  // Generate tests from the suite's generation_prompt using AI
574
593
  await client.adversarialSuites.generate("suite-id", { version_id: "v-id" });
575
594
 
576
595
  // Generate a mermaid workflow graph for visualization
577
- await client.adversarialSuites.generateGraph("suite-id", { version_id: "v-id" });
596
+ await client.adversarialSuites.generateGraph("suite-id", {
597
+ version_id: "v-id",
598
+ });
578
599
 
579
600
  // Run all tests in the suite
580
- const { suite_run_id } = await client.adversarialSuites.run("suite-id", { version_id: "v-id" });
601
+ const { suite_run_id } = await client.adversarialSuites.run("suite-id", {
602
+ version_id: "v-id",
603
+ });
581
604
 
582
605
  // Poll results
583
606
  const { runs } = await client.adversarialSuites.listRuns("suite-id");
584
607
  const { run } = await client.adversarialSuites.getRun("suite-run-id");
585
- const { test_runs } = await client.adversarialSuites.getRunTestRuns("suite-run-id");
608
+ const { test_runs } =
609
+ await client.adversarialSuites.getRunTestRuns("suite-run-id");
586
610
  ```
587
611
 
588
- | Method | HTTP | Path | Description |
589
- |---|---|---|---|
590
- | `get(suiteId)` | GET | `/adversarial-suites/:id` | Get suite with optional mermaid graph |
591
- | `update(suiteId, body)` | PATCH | `/adversarial-suites/:id` | Update name, model, timeout, generation settings |
592
- | `delete(suiteId)` | DELETE | `/adversarial-suites/:id` | Delete a suite |
593
- | `generate(suiteId, body?)` | POST | `/adversarial-suites/:id/generate` | AI-generate tests from the suite's generation prompt |
594
- | `generateGraph(suiteId, body)` | POST | `/adversarial-suites/:id/generate-graph` | Generate a mermaid workflow visualization |
595
- | `run(suiteId, body)` | POST | `/adversarial-suites/:id/run` | Execute all tests asynchronously, returns `suite_run_id` |
596
- | `listRuns(suiteId, query?)` | GET | `/adversarial-suites/:id/runs` | List suite runs |
597
- | `getRun(suiteRunId)` | GET | `/adversarial-suites/runs/:runId` | Get a suite run with aggregate pass/fail counts |
598
- | `getRunTestRuns(suiteRunId)` | GET | `/adversarial-suites/runs/:runId/test-runs` | List individual test results within a suite run |
612
+ | Method | HTTP | Path | Description |
613
+ | ------------------------------ | ------ | ------------------------------------------- | -------------------------------------------------------- |
614
+ | `get(suiteId)` | GET | `/adversarial-suites/:id` | Get suite with optional mermaid graph |
615
+ | `update(suiteId, body)` | PATCH | `/adversarial-suites/:id` | Update name, model, timeout, generation settings |
616
+ | `delete(suiteId)` | DELETE | `/adversarial-suites/:id` | Delete a suite |
617
+ | `generate(suiteId, body?)` | POST | `/adversarial-suites/:id/generate` | AI-generate tests from the suite's generation prompt |
618
+ | `generateGraph(suiteId, body)` | POST | `/adversarial-suites/:id/generate-graph` | Generate a mermaid workflow visualization |
619
+ | `run(suiteId, body)` | POST | `/adversarial-suites/:id/run` | Execute all tests asynchronously, returns `suite_run_id` |
620
+ | `listRuns(suiteId, query?)` | GET | `/adversarial-suites/:id/runs` | List suite runs |
621
+ | `getRun(suiteRunId)` | GET | `/adversarial-suites/runs/:runId` | Get a suite run with aggregate pass/fail counts |
622
+ | `getRunTestRuns(suiteRunId)` | GET | `/adversarial-suites/runs/:runId/test-runs` | List individual test results within a suite run |
599
623
 
600
624
  ---
601
625
 
@@ -605,11 +629,16 @@ Individual adversarial tests simulate a user trying to break the agent's behavio
605
629
 
606
630
  ```ts
607
631
  const { test } = await client.adversarialTests.get("test-id");
608
- await client.adversarialTests.update("test-id", { adversarial_prompt: "Try to get PII", timeout_seconds: 120 });
632
+ await client.adversarialTests.update("test-id", {
633
+ adversarial_prompt: "Try to get PII",
634
+ timeout_seconds: 120,
635
+ });
609
636
  await client.adversarialTests.delete("test-id");
610
637
 
611
638
  // Run a single test
612
- const { test_run_id } = await client.adversarialTests.run("test-id", { version_id: "v-id" });
639
+ const { test_run_id } = await client.adversarialTests.run("test-id", {
640
+ version_id: "v-id",
641
+ });
613
642
 
614
643
  // Poll results
615
644
  const { runs } = await client.adversarialTests.listRuns("test-id");
@@ -617,15 +646,15 @@ const { run } = await client.adversarialTests.getRun("run-id");
617
646
  const { messages } = await client.adversarialTests.getRunMessages("run-id");
618
647
  ```
619
648
 
620
- | Method | HTTP | Path | Description |
621
- |---|---|---|---|
622
- | `get(testId)` | GET | `/adversarial-tests/:id` | Get test details |
623
- | `update(testId, body)` | PATCH | `/adversarial-tests/:id` | Update prompt, model, variables, timeout |
624
- | `delete(testId)` | DELETE | `/adversarial-tests/:id` | Delete a test |
625
- | `run(testId, body)` | POST | `/adversarial-tests/:id/run` | Execute a test asynchronously, returns `test_run_id` |
626
- | `listRuns(testId, query?)` | GET | `/adversarial-tests/:id/runs` | List test runs with audit remarks |
627
- | `getRun(runId)` | GET | `/adversarial-tests/runs/:runId` | Get a single run with full audit remarks |
628
- | `getRunMessages(runId)` | GET | `/adversarial-tests/runs/:runId/messages` | Get the full conversation from a test run |
649
+ | Method | HTTP | Path | Description |
650
+ | -------------------------- | ------ | ----------------------------------------- | ---------------------------------------------------- |
651
+ | `get(testId)` | GET | `/adversarial-tests/:id` | Get test details |
652
+ | `update(testId, body)` | PATCH | `/adversarial-tests/:id` | Update prompt, model, variables, timeout |
653
+ | `delete(testId)` | DELETE | `/adversarial-tests/:id` | Delete a test |
654
+ | `run(testId, body)` | POST | `/adversarial-tests/:id/run` | Execute a test asynchronously, returns `test_run_id` |
655
+ | `listRuns(testId, query?)` | GET | `/adversarial-tests/:id/runs` | List test runs with audit remarks |
656
+ | `getRun(runId)` | GET | `/adversarial-tests/runs/:runId` | Get a single run with full audit remarks |
657
+ | `getRunMessages(runId)` | GET | `/adversarial-tests/runs/:runId/messages` | Get the full conversation from a test run |
629
658
 
630
659
  ---
631
660
 
@@ -635,7 +664,10 @@ Northstars are quality criteria that define how the agent should behave. They ar
635
664
 
636
665
  ```ts
637
666
  const { northstar } = await client.northstars.get("northstar-id");
638
- await client.northstars.update("northstar-id", { enabled: true, priority: "high" });
667
+ await client.northstars.update("northstar-id", {
668
+ enabled: true,
669
+ priority: "high",
670
+ });
639
671
  await client.northstars.delete("northstar-id");
640
672
 
641
673
  // Get full regeneration history
@@ -651,14 +683,14 @@ const { feedback } = await client.northstars.submitFeedback("northstar-id", {
651
683
  await client.northstars.deleteFeedback("northstar-id");
652
684
  ```
653
685
 
654
- | Method | HTTP | Path | Description |
655
- |---|---|---|---|
656
- | `get(northstarId)` | GET | `/northstars/:id` | Get a northstar |
657
- | `update(northstarId, body)` | PATCH | `/northstars/:id` | Update name, description, examples, category, priority, or enabled state |
658
- | `delete(northstarId)` | DELETE | `/northstars/:id` | Delete a northstar |
659
- | `getHistory(northstarId)` | GET | `/northstars/:id/history` | Get the full regeneration chain, oldest first |
660
- | `submitFeedback(northstarId, body)` | POST | `/northstars/:id/feedback` | Rate a northstar's correctness (−2 to +2), optionally trigger regeneration |
661
- | `deleteFeedback(northstarId)` | DELETE | `/northstars/:id/feedback` | Remove your feedback on a northstar |
686
+ | Method | HTTP | Path | Description |
687
+ | ----------------------------------- | ------ | -------------------------- | -------------------------------------------------------------------------- |
688
+ | `get(northstarId)` | GET | `/northstars/:id` | Get a northstar |
689
+ | `update(northstarId, body)` | PATCH | `/northstars/:id` | Update name, description, examples, category, priority, or enabled state |
690
+ | `delete(northstarId)` | DELETE | `/northstars/:id` | Delete a northstar |
691
+ | `getHistory(northstarId)` | GET | `/northstars/:id/history` | Get the full regeneration chain, oldest first |
692
+ | `submitFeedback(northstarId, body)` | POST | `/northstars/:id/feedback` | Rate a northstar's correctness (−2 to +2), optionally trigger regeneration |
693
+ | `deleteFeedback(northstarId)` | DELETE | `/northstars/:id/feedback` | Remove your feedback on a northstar |
662
694
 
663
695
  ---
664
696
 
@@ -675,19 +707,21 @@ await client.customEvals.update("eval-id", {
675
707
  await client.customEvals.delete("eval-id");
676
708
 
677
709
  // Run an eval
678
- const { run_id } = await client.customEvals.run("eval-id", { version_id: "v-id" });
710
+ const { run_id } = await client.customEvals.run("eval-id", {
711
+ version_id: "v-id",
712
+ });
679
713
 
680
714
  // Poll results
681
715
  const { runs } = await client.customEvals.listRuns("eval-id");
682
716
  ```
683
717
 
684
- | Method | HTTP | Path | Description |
685
- |---|---|---|---|
686
- | `get(evalId)` | GET | `/custom-evals/:id` | Get a custom eval |
687
- | `update(evalId, body)` | PATCH | `/custom-evals/:id` | Update messages, expected outputs, variables, or northstar IDs |
688
- | `delete(evalId)` | DELETE | `/custom-evals/:id` | Delete a custom eval |
689
- | `run(evalId, body)` | POST | `/custom-evals/:id/run` | Execute the eval asynchronously, returns `run_id` |
690
- | `listRuns(evalId, query?)` | GET | `/custom-evals/:id/runs` | List runs with pass/fail and judge reasoning |
718
+ | Method | HTTP | Path | Description |
719
+ | -------------------------- | ------ | ------------------------ | -------------------------------------------------------------- |
720
+ | `get(evalId)` | GET | `/custom-evals/:id` | Get a custom eval |
721
+ | `update(evalId, body)` | PATCH | `/custom-evals/:id` | Update messages, expected outputs, variables, or northstar IDs |
722
+ | `delete(evalId)` | DELETE | `/custom-evals/:id` | Delete a custom eval |
723
+ | `run(evalId, body)` | POST | `/custom-evals/:id/run` | Execute the eval asynchronously, returns `run_id` |
724
+ | `listRuns(evalId, query?)` | GET | `/custom-evals/:id/runs` | List runs with pass/fail and judge reasoning |
691
725
 
692
726
  ---
693
727
 
@@ -699,8 +733,8 @@ Issues (quality flags) are raised when a conversation fails a northstar or quali
699
733
  await client.issues.update("issue-id", { status: "approved" });
700
734
  ```
701
735
 
702
- | Method | HTTP | Path | Description |
703
- |---|---|---|---|
736
+ | Method | HTTP | Path | Description |
737
+ | ----------------------- | ----- | ------------- | ----------------------------------------------------------------- |
704
738
  | `update(issueId, body)` | PATCH | `/issues/:id` | Update issue status (`open` / `approved` / `rejected` / `closed`) |
705
739
 
706
740
  ---
@@ -727,11 +761,11 @@ await client.auditRemarks.submitFeedback("audit-remark-id", {
727
761
  await client.auditRemarks.deleteFeedback("audit-remark-id");
728
762
  ```
729
763
 
730
- | Method | HTTP | Path | Description |
731
- |---|---|---|---|
732
- | `getFeedback(auditRemarkId)` | GET | `/audit-remarks/:id/feedback` | Get your feedback for this remark, or `null` |
733
- | `submitFeedback(auditRemarkId, body)` | POST | `/audit-remarks/:id/feedback` | Submit thumbs up/down; a thumbs-up adds the remark as a northstar example |
734
- | `deleteFeedback(auditRemarkId)` | DELETE | `/audit-remarks/:id/feedback` | Delete your feedback |
764
+ | Method | HTTP | Path | Description |
765
+ | ------------------------------------- | ------ | ----------------------------- | ------------------------------------------------------------------------- |
766
+ | `getFeedback(auditRemarkId)` | GET | `/audit-remarks/:id/feedback` | Get your feedback for this remark, or `null` |
767
+ | `submitFeedback(auditRemarkId, body)` | POST | `/audit-remarks/:id/feedback` | Submit thumbs up/down; a thumbs-up adds the remark as a northstar example |
768
+ | `deleteFeedback(auditRemarkId)` | DELETE | `/audit-remarks/:id/feedback` | Delete your feedback |
735
769
 
736
770
  ---
737
771
 
@@ -765,7 +799,9 @@ app.post("/api/chat-token", async (req, res) => {
765
799
  import { HappyRobotChatClient } from "@happyrobot-ai/sdk";
766
800
 
767
801
  // 1. Get a client token from your server
768
- const { token } = await fetch("/api/chat-token", { method: "POST" }).then(r => r.json());
802
+ const { token } = await fetch("/api/chat-token", { method: "POST" }).then((r) =>
803
+ r.json()
804
+ );
769
805
 
770
806
  // 2. Initialize the browser-side client
771
807
  const chat = new HappyRobotChatClient({ token });
@@ -798,7 +834,10 @@ console.log(ack.message.id); // server-assigned message ID
798
834
 
799
835
  // 6. Send messages with file attachments
800
836
  const artifact = await chat.uploadFile(fileBlob, "photo.png", "image/png");
801
- await connection.sendMessage({ content: "Here's the photo", artifacts: [artifact] });
837
+ await connection.sendMessage({
838
+ content: "Here's the photo",
839
+ artifacts: [artifact],
840
+ });
802
841
 
803
842
  // 7. Get history (page reload, reconnect)
804
843
  const { messages } = await chat.getHistory(session_id);
@@ -818,8 +857,15 @@ await connection.sendMessage({
818
857
  });
819
858
 
820
859
  // Option B: Manual 3-step flow for more control
821
- const upload = await chat.getPresignedUpload({ filename: "photo.png", mime_type: "image/png" });
822
- await fetch(upload.upload_url, { method: "PUT", body: fileBlob, headers: { "Content-Type": "image/png" } });
860
+ const upload = await chat.getPresignedUpload({
861
+ filename: "photo.png",
862
+ mime_type: "image/png",
863
+ });
864
+ await fetch(upload.upload_url, {
865
+ method: "PUT",
866
+ body: fileBlob,
867
+ headers: { "Content-Type": "image/png" },
868
+ });
823
869
  await chat.completeUpload({
824
870
  artifact_id: upload.artifact_id,
825
871
  s3_uri: upload.s3_uri,
@@ -829,56 +875,63 @@ await chat.completeUpload({
829
875
  });
830
876
  await connection.sendMessage({
831
877
  content: "Here's the photo",
832
- artifacts: [{ media_id: upload.artifact_id, mime_type: "image/png", filename: "photo.png", size_bytes: fileBlob.size }],
878
+ artifacts: [
879
+ {
880
+ media_id: upload.artifact_id,
881
+ mime_type: "image/png",
882
+ filename: "photo.png",
883
+ size_bytes: fileBlob.size,
884
+ },
885
+ ],
833
886
  });
834
887
  ```
835
888
 
836
889
  ### `HappyRobotClient` (server-side)
837
890
 
838
- | Method | Description |
839
- |---|---|
891
+ | Method | Description |
892
+ | ------------------------------------------------ | -------------------------------------------- |
840
893
  | `client.chat.createToken({ workflow_id, env? })` | Create a scoped client token (1 hour expiry) |
841
894
 
842
895
  ### `HappyRobotChatClient` (browser-side)
843
896
 
844
- | Method | Description |
845
- |---|---|
846
- | `chat.createSession()` | Create a new chat session |
847
- | `chat.connect(sessionId, handlers)` | Open bidirectional WebSocket — returns `ChatConnection` |
897
+ | Method | Description |
898
+ | ------------------------------------------------------ | --------------------------------------------------------- |
899
+ | `chat.createSession()` | Create a new chat session |
900
+ | `chat.connect(sessionId, handlers)` | Open bidirectional WebSocket — returns `ChatConnection` |
848
901
  | `chat.sendMessage(sessionId, { content, artifacts? })` | Send a user message via HTTP (fallback if WS unavailable) |
849
- | `chat.getHistory(sessionId)` | Get message history |
850
- | `chat.uploadFile(file, filename, mimeType)` | Upload a file (convenience method) |
851
- | `chat.getPresignedUpload({ filename, mime_type })` | Get presigned S3 upload URL |
852
- | `chat.completeUpload({ artifact_id, s3_uri, ... })` | Register uploaded artifact |
902
+ | `chat.getHistory(sessionId)` | Get message history |
903
+ | `chat.uploadFile(file, filename, mimeType)` | Upload a file (convenience method) |
904
+ | `chat.getPresignedUpload({ filename, mime_type })` | Get presigned S3 upload URL |
905
+ | `chat.completeUpload({ artifact_id, s3_uri, ... })` | Register uploaded artifact |
853
906
 
854
907
  ### `ChatConnection`
855
908
 
856
- | Method | Description |
857
- |---|---|
909
+ | Method | Description |
910
+ | ------------------------------------------------- | ----------------------------------------------------------------------------------- |
858
911
  | `connection.sendMessage({ content, artifacts? })` | Send a message via WebSocket. Returns a `Promise` that resolves with the server ack |
859
- | `connection.close()` | Close the WebSocket connection |
860
- | `connection.ws` | The underlying `WebSocket` instance |
912
+ | `connection.close()` | Close the WebSocket connection |
913
+ | `connection.ws` | The underlying `WebSocket` instance |
861
914
 
862
915
  ### WebSocket Events
863
916
 
864
917
  **Server → Client:**
865
918
 
866
- | Event | Fields | Description |
867
- |---|---|---|
868
- | `connected` | `session_id` | Connection established |
869
- | `response-start` | `content` | AI started generating a response |
870
- | `response-chunk` | `content` | Partial response text |
871
- | `response-end` | `content` | Complete response text |
872
- | `session-closed` | `session_id`, `status`, `reason`, `duration`, `timestamp` | Session ended |
873
- | `token-expired` | — | JWT expired — reconnect with a fresh token |
874
- | `message-ack` | `id`, `message` | Server confirmed the message was sent |
875
- | `message-error` | `id`, `error` | Server failed to send the message |
876
- | `heartbeat` | — | Keep-alive (every 15s) |
919
+ | Event | Fields | Description |
920
+ | ---------------- | --------------------------------------------------------- | ------------------------------------------ |
921
+ | `connected` | `session_id` | Connection established |
922
+ | `response-start` | `content` | AI started generating a response |
923
+ | `response-chunk` | `content` | Partial response text |
924
+ | `response-end` | `content` | Complete response text |
925
+ | `session-closed` | `session_id`, `status`, `reason`, `duration`, `timestamp` | Session ended |
926
+ | `token-expired` | — | JWT expired — reconnect with a fresh token |
927
+ | `message-ack` | `id`, `message` | Server confirmed the message was sent |
928
+ | `message-error` | `id`, `error` | Server failed to send the message |
929
+ | `heartbeat` | — | Keep-alive (every 15s) |
877
930
 
878
931
  **Client → Server:**
879
932
 
880
- | Event | Fields | Description |
881
- |---|---|---|
933
+ | Event | Fields | Description |
934
+ | --------- | ------------------------------ | ----------------------------------------------------- |
882
935
  | `message` | `content`, `artifacts?`, `id?` | Send a user message. `id` is echoed back in ack/error |
883
936
 
884
937
  ---
@@ -914,7 +967,9 @@ app.post("/api/voice-token", async (req, res) => {
914
967
  import { HappyRobotVoiceClient } from "@happyrobot-ai/sdk/voice";
915
968
 
916
969
  // 1. Get a voice token from your server
917
- const { url, token } = await fetch("/api/voice-token", { method: "POST" }).then(r => r.json());
970
+ const { url, token } = await fetch("/api/voice-token", { method: "POST" }).then(
971
+ (r) => r.json()
972
+ );
918
973
 
919
974
  // 2. Create the voice client and connect
920
975
  const voice = new HappyRobotVoiceClient({ url, token });
@@ -951,39 +1006,39 @@ await connection.disconnect();
951
1006
 
952
1007
  ### `HappyRobotClient` (server-side)
953
1008
 
954
- | Method | Description |
955
- |---|---|
1009
+ | Method | Description |
1010
+ | -------------------------------------------------------- | -------------------------------------- |
956
1011
  | `client.voice.createToken({ workflow_id, data?, env? })` | Create a LiveKit token for voice calls |
957
1012
 
958
1013
  ### `HappyRobotVoiceClient` (browser-side)
959
1014
 
960
- | Method | Description |
961
- |---|---|
962
- | `new HappyRobotVoiceClient({ url, token })` | Create client with LiveKit credentials |
963
- | `voice.connect(handlers?)` | Connect to room, enable microphone — returns `VoiceConnection` |
1015
+ | Method | Description |
1016
+ | ------------------------------------------- | -------------------------------------------------------------- |
1017
+ | `new HappyRobotVoiceClient({ url, token })` | Create client with LiveKit credentials |
1018
+ | `voice.connect(handlers?)` | Connect to room, enable microphone — returns `VoiceConnection` |
964
1019
 
965
1020
  ### `VoiceConnection`
966
1021
 
967
- | Method | Description |
968
- |---|---|
969
- | `connection.disconnect()` | End the call and disconnect from the room |
970
- | `connection.mute()` | Mute the local microphone |
971
- | `connection.unmute()` | Unmute the local microphone |
972
- | `connection.isMuted()` | Check mute state |
973
- | `connection.room` | Underlying LiveKit `Room` instance for advanced use cases |
1022
+ | Method | Description |
1023
+ | ------------------------- | --------------------------------------------------------- |
1024
+ | `connection.disconnect()` | End the call and disconnect from the room |
1025
+ | `connection.mute()` | Mute the local microphone |
1026
+ | `connection.unmute()` | Unmute the local microphone |
1027
+ | `connection.isMuted()` | Check mute state |
1028
+ | `connection.room` | Underlying LiveKit `Room` instance for advanced use cases |
974
1029
 
975
1030
  ### Room Events
976
1031
 
977
- | Handler | Description |
978
- |---|---|
979
- | `onConnected` | Connected to the LiveKit room |
980
- | `onDisconnected` | Disconnected from the room |
981
- | `onAgentConnected` | AI agent participant joined the room |
982
- | `onTrackSubscribed` | Remote audio track subscribed (auto-plays) |
983
- | `onTrackUnsubscribed` | Remote audio track unsubscribed |
984
- | `onReconnecting` | Connection temporarily lost — attempting to reconnect |
985
- | `onReconnected` | Successfully reconnected |
986
- | `onError` | An error occurred |
1032
+ | Handler | Description |
1033
+ | --------------------- | ----------------------------------------------------- |
1034
+ | `onConnected` | Connected to the LiveKit room |
1035
+ | `onDisconnected` | Disconnected from the room |
1036
+ | `onAgentConnected` | AI agent participant joined the room |
1037
+ | `onTrackSubscribed` | Remote audio track subscribed (auto-plays) |
1038
+ | `onTrackUnsubscribed` | Remote audio track unsubscribed |
1039
+ | `onReconnecting` | Connection temporarily lost — attempting to reconnect |
1040
+ | `onReconnected` | Successfully reconnected |
1041
+ | `onError` | An error occurred |
987
1042
 
988
1043
  ---
989
1044
 
@@ -1016,7 +1071,11 @@ for await (const workflow of client.workflows.listAll({ folder_id: "..." })) {
1016
1071
  ## Error Handling
1017
1072
 
1018
1073
  ```ts
1019
- import { ApiError, AuthenticationError, NotFoundError } from "@happyrobot-ai/sdk";
1074
+ import {
1075
+ ApiError,
1076
+ AuthenticationError,
1077
+ NotFoundError,
1078
+ } from "@happyrobot-ai/sdk";
1020
1079
 
1021
1080
  try {
1022
1081
  const wf = await client.workflows.get("nonexistent");