@happyrobot-ai/sdk 0.1.11 → 0.1.13
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 +347 -286
- package/chat-client.js +8 -3
- package/client.d.ts +20 -20
- package/client.js +20 -20
- package/core/http.d.ts +1 -0
- package/core/http.js +15 -5
- package/core/http.mjs +2 -2
- package/core/sse.js +3 -1
- package/core/types.d.ts +2 -0
- package/helpers/index.d.ts +3 -3
- package/helpers/trigger-and-wait-for-node-output.js +3 -1
- package/index.d.ts +3 -2
- package/index.js +3 -1
- package/index.mjs +2 -2
- package/package.json +4 -16
- package/resources/nodes.d.ts +1 -1
- package/resources/workflows.d.ts +1 -1
- package/types/adversarial-suites.types.d.ts +4 -4
- package/types/adversarial-tests.types.d.ts +2 -2
- package/types/chat.types.d.ts +2 -0
- package/types/custom-evals.types.d.ts +1 -1
- package/types/integrations.types.d.ts +1 -1
- package/types/nodes.types.d.ts +1 -1
- package/types/northstars.types.d.ts +2 -2
- package/types/versions.types.d.ts +1 -1
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_...",
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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,
|
|
69
|
-
pollIntervalMs: 2_000,
|
|
70
|
-
fetchSessions: 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",
|
|
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",
|
|
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
|
|
113
|
-
|
|
114
|
-
| `client.workflows`
|
|
115
|
-
| `client.versions`
|
|
116
|
-
| `client.nodes`
|
|
117
|
-
| `client.runs`
|
|
118
|
-
| `client.sessions`
|
|
119
|
-
| `client.messages`
|
|
120
|
-
| `client.variables`
|
|
121
|
-
| `client.phoneNumbers`
|
|
122
|
-
| `client.sipTrunks`
|
|
123
|
-
| `client.integrations`
|
|
124
|
-
| `client.contacts`
|
|
125
|
-
| `client.knowledgeBases`
|
|
126
|
-
| `client.workflowFolders`
|
|
127
|
-
| `client.mcp`
|
|
128
|
-
| `client.billing`
|
|
129
|
-
| `client.apiKey`
|
|
130
|
-
| `client.artifacts`
|
|
131
|
-
| `client.adversarialSuites` | `AdversarialSuitesResource` | Adversarial suite management and execution
|
|
132
|
-
| `client.adversarialTests`
|
|
133
|
-
| `client.northstars`
|
|
134
|
-
| `client.customEvals`
|
|
135
|
-
| `client.issues`
|
|
136
|
-
| `client.auditRemarks`
|
|
137
|
-
| `client.chat`
|
|
138
|
-
| `client.voice`
|
|
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
|
|
187
|
-
|
|
188
|
-
| `list(query?)`
|
|
189
|
-
| `listAll(query?)`
|
|
190
|
-
| `create(body)`
|
|
191
|
-
| `get(workflowId)`
|
|
192
|
-
| `update(workflowId, body)`
|
|
193
|
-
| `delete(workflowId)`
|
|
194
|
-
| `duplicate(workflowId, body?)`
|
|
195
|
-
| `publish(workflowId, body?)`
|
|
196
|
-
| `unpublish(workflowId)`
|
|
197
|
-
| `cancelRuns(workflowId)`
|
|
198
|
-
| `listTemplates(query?)`
|
|
199
|
-
| `listVersions(workflowId, query?)` | GET
|
|
200
|
-
| `listRuns(workflowId, query?)`
|
|
201
|
-
| `triggerRun(workflowId, body?)`
|
|
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
|
|
220
|
-
|
|
221
|
-
| `get(versionId)`
|
|
222
|
-
| `update(versionId, body)`
|
|
223
|
-
| `fork(versionId)`
|
|
224
|
-
| `publish(versionId, body?)`
|
|
225
|
-
| `unpublish(versionId)`
|
|
226
|
-
| `lock(versionId)`
|
|
227
|
-
| `unlock(versionId)`
|
|
228
|
-
| `testAll(versionId)`
|
|
229
|
-
| `getPromptIssues(versionId)` | GET
|
|
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
|
|
249
|
-
|
|
250
|
-
| `list(versionId)`
|
|
251
|
-
| `addBatch(versionId, body)`
|
|
252
|
-
| `get(versionId, nodeId)`
|
|
253
|
-
| `update(versionId, nodeId, body)`
|
|
254
|
-
| `delete(versionId, nodeId)`
|
|
255
|
-
| `getConfigSchema(versionId, nodeId)`
|
|
256
|
-
| `getAvailableVars(versionId, nodeId)` | GET
|
|
257
|
-
| `test(versionId, nodeId, body?)`
|
|
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
|
|
273
|
-
|
|
274
|
-
| `get(runId)`
|
|
275
|
-
| `getSessions(runId, query?)` | GET
|
|
276
|
-
| `getRecordings(runId)`
|
|
277
|
-
| `getFlags(runId, query?)`
|
|
278
|
-
| `cancel(runId)`
|
|
279
|
-
| `mark(runId, body)`
|
|
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")
|
|
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
|
|
297
|
-
|
|
298
|
-
| `get(sessionId)`
|
|
299
|
-
| `getMessages(sessionId, query?)` | GET
|
|
300
|
-
| `stream(sessionId, query?)`
|
|
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", {
|
|
310
|
+
await client.messages.createFlag("message-id", {
|
|
311
|
+
type: "incorrect",
|
|
312
|
+
note: "...",
|
|
313
|
+
});
|
|
309
314
|
```
|
|
310
315
|
|
|
311
|
-
| Method
|
|
312
|
-
|
|
313
|
-
| `listFlags(messageId, query?)` | GET
|
|
314
|
-
| `createFlag(messageId, body)`
|
|
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
|
|
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", {
|
|
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
|
|
344
|
-
|
|
345
|
-
| `list(workflowId, query?)`
|
|
346
|
-
| `create(workflowId, body)`
|
|
347
|
-
| `update(workflowId, variableId, body)` | PATCH
|
|
348
|
-
| `delete(workflowId, variableId)`
|
|
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
|
|
370
|
-
|
|
371
|
-
| `list(query?)`
|
|
372
|
-
| `buy(body)`
|
|
373
|
-
| `update(id, body)`
|
|
374
|
-
| `getUsage(id)`
|
|
375
|
-
| `getTollFreeVerification(id)`
|
|
376
|
-
| `createTollFreeVerification(id, body)`
|
|
377
|
-
| `deleteTollFreeVerification(verificationSid)` | DELETE | `/phone-numbers/tollfree-verification/:sid` | Delete a toll-free verification
|
|
378
|
-
| `createSipTrunk(id)`
|
|
379
|
-
| `freeUp(id)`
|
|
380
|
-
| `delete(id)`
|
|
381
|
-
| `removeFromWorkflow(id, body)`
|
|
382
|
-
| `validateTollFreeNumbers(body)`
|
|
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
|
|
399
|
-
|
|
400
|
-
| `list()`
|
|
401
|
-
| `listOptions()`
|
|
402
|
-
| `create(body)`
|
|
403
|
-
| `createBulk(body)`
|
|
404
|
-
| `get(trunkId)`
|
|
405
|
-
| `update(trunkId, body)` | PUT
|
|
406
|
-
| `delete(trunkId)`
|
|
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
|
|
439
|
-
|
|
440
|
-
| `list(query?)`
|
|
441
|
-
| `get(id)`
|
|
442
|
-
| `createCredential(id, body)`
|
|
443
|
-
| `googleSheets.spreadsheets(query?)` | GET
|
|
444
|
-
| `googleSheets.worksheets(query)`
|
|
445
|
-
| `googleSheets.columns(query)`
|
|
446
|
-
| `googleSheets.rows(query)`
|
|
447
|
-
| `slack.channels(query?)`
|
|
448
|
-
| `slack.users(query?)`
|
|
449
|
-
| `teams.teams(query?)`
|
|
450
|
-
| `teams.channels(query?)`
|
|
451
|
-
| `teams.users(query?)`
|
|
452
|
-
| `twilioSms.phoneNumbers(query?)`
|
|
453
|
-
| `whatsApp.businesses(query)`
|
|
454
|
-
| `whatsApp.businessAccounts(query)`
|
|
455
|
-
| `whatsApp.phoneNumbers(query)`
|
|
456
|
-
| `whatsApp.messageTemplates(query)`
|
|
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
|
|
471
|
-
|
|
472
|
-
| `list(query?)`
|
|
473
|
-
| `resolve(query)`
|
|
474
|
-
| `get(contactId)`
|
|
475
|
-
| `getInteractions(contactId)` | GET
|
|
476
|
-
| `getMemories(contactId)`
|
|
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", {
|
|
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
|
|
492
|
-
|
|
493
|
-
| `list()`
|
|
494
|
-
| `listFiles(kbId)`
|
|
495
|
-
| `getUploadUrls(kbId, body)` | POST
|
|
496
|
-
| `triggerChunking(kbId)`
|
|
497
|
-
| `deleteFile(kbId, fileId)`
|
|
498
|
-
| `delete(kbId)`
|
|
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
|
|
513
|
-
|
|
514
|
-
| `list(query?)`
|
|
515
|
-
| `create(body)`
|
|
516
|
-
| `get(folderId)`
|
|
517
|
-
| `update(folderId, body)` | PUT
|
|
518
|
-
| `delete(folderId)`
|
|
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,25 +537,33 @@ await client.mcp.create({ name: "My MCP", url: "https://..." });
|
|
|
527
537
|
await client.mcp.refresh("mcp-id");
|
|
528
538
|
```
|
|
529
539
|
|
|
530
|
-
| Method
|
|
531
|
-
|
|
532
|
-
| `list(query?)`
|
|
533
|
-
| `create(body)`
|
|
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
|
|
|
546
|
+
**OAuth2 (`auth_type: "oauth2"`)**: set `oauth2_credential_id` to the UUID of an **OAuth 2.0** integration credential (same org) configured with your provider’s token URL. Do not send `auth_token`; the API fetches a short-lived access token when creating, listing refresh, or when workflows run.
|
|
547
|
+
|
|
536
548
|
---
|
|
537
549
|
|
|
538
550
|
## `client.billing`
|
|
539
551
|
|
|
540
552
|
```ts
|
|
541
|
-
const details = await client.billing.getDetails({
|
|
542
|
-
|
|
553
|
+
const details = await client.billing.getDetails({
|
|
554
|
+
start: "2024-01-01",
|
|
555
|
+
end: "2024-01-31",
|
|
556
|
+
});
|
|
557
|
+
const totals = await client.billing.getTotals({
|
|
558
|
+
start: "2024-01-01",
|
|
559
|
+
end: "2024-01-31",
|
|
560
|
+
});
|
|
543
561
|
```
|
|
544
562
|
|
|
545
|
-
| Method
|
|
546
|
-
|
|
547
|
-
| `getDetails(query)` | GET
|
|
548
|
-
| `getTotals(query)`
|
|
563
|
+
| Method | HTTP | Path | Description |
|
|
564
|
+
| ------------------- | ---- | ------------------------ | --------------------------- |
|
|
565
|
+
| `getDetails(query)` | GET | `/billing/usage/details` | Detailed billing line items |
|
|
566
|
+
| `getTotals(query)` | GET | `/billing/usage/totals` | Aggregated billing totals |
|
|
549
567
|
|
|
550
568
|
---
|
|
551
569
|
|
|
@@ -555,9 +573,9 @@ const totals = await client.billing.getTotals({ start: "2024-01-01", end: "2024-
|
|
|
555
573
|
const info = await client.apiKey.describe();
|
|
556
574
|
```
|
|
557
575
|
|
|
558
|
-
| Method
|
|
559
|
-
|
|
560
|
-
| `describe()` | GET
|
|
576
|
+
| Method | HTTP | Path | Description |
|
|
577
|
+
| ------------ | ---- | ------------------- | ---------------------------------------------------- |
|
|
578
|
+
| `describe()` | GET | `/api-key/describe` | Introspect the current API key (ID, name, org, etc.) |
|
|
561
579
|
|
|
562
580
|
---
|
|
563
581
|
|
|
@@ -567,35 +585,43 @@ Adversarial suites group multiple adversarial tests and can auto-generate them f
|
|
|
567
585
|
|
|
568
586
|
```ts
|
|
569
587
|
const { suite } = await client.adversarialSuites.get("suite-id");
|
|
570
|
-
await client.adversarialSuites.update("suite-id", {
|
|
588
|
+
await client.adversarialSuites.update("suite-id", {
|
|
589
|
+
name: "New Name",
|
|
590
|
+
generation_count: 10,
|
|
591
|
+
});
|
|
571
592
|
await client.adversarialSuites.delete("suite-id");
|
|
572
593
|
|
|
573
594
|
// Generate tests from the suite's generation_prompt using AI
|
|
574
595
|
await client.adversarialSuites.generate("suite-id", { version_id: "v-id" });
|
|
575
596
|
|
|
576
597
|
// Generate a mermaid workflow graph for visualization
|
|
577
|
-
await client.adversarialSuites.generateGraph("suite-id", {
|
|
598
|
+
await client.adversarialSuites.generateGraph("suite-id", {
|
|
599
|
+
version_id: "v-id",
|
|
600
|
+
});
|
|
578
601
|
|
|
579
602
|
// Run all tests in the suite
|
|
580
|
-
const { suite_run_id } = await client.adversarialSuites.run("suite-id", {
|
|
603
|
+
const { suite_run_id } = await client.adversarialSuites.run("suite-id", {
|
|
604
|
+
version_id: "v-id",
|
|
605
|
+
});
|
|
581
606
|
|
|
582
607
|
// Poll results
|
|
583
608
|
const { runs } = await client.adversarialSuites.listRuns("suite-id");
|
|
584
609
|
const { run } = await client.adversarialSuites.getRun("suite-run-id");
|
|
585
|
-
const { test_runs } =
|
|
610
|
+
const { test_runs } =
|
|
611
|
+
await client.adversarialSuites.getRunTestRuns("suite-run-id");
|
|
586
612
|
```
|
|
587
613
|
|
|
588
|
-
| Method
|
|
589
|
-
|
|
590
|
-
| `get(suiteId)`
|
|
591
|
-
| `update(suiteId, body)`
|
|
592
|
-
| `delete(suiteId)`
|
|
593
|
-
| `generate(suiteId, body?)`
|
|
594
|
-
| `generateGraph(suiteId, body)` | POST
|
|
595
|
-
| `run(suiteId, body)`
|
|
596
|
-
| `listRuns(suiteId, query?)`
|
|
597
|
-
| `getRun(suiteRunId)`
|
|
598
|
-
| `getRunTestRuns(suiteRunId)`
|
|
614
|
+
| Method | HTTP | Path | Description |
|
|
615
|
+
| ------------------------------ | ------ | ------------------------------------------- | -------------------------------------------------------- |
|
|
616
|
+
| `get(suiteId)` | GET | `/adversarial-suites/:id` | Get suite with optional mermaid graph |
|
|
617
|
+
| `update(suiteId, body)` | PATCH | `/adversarial-suites/:id` | Update name, model, timeout, generation settings |
|
|
618
|
+
| `delete(suiteId)` | DELETE | `/adversarial-suites/:id` | Delete a suite |
|
|
619
|
+
| `generate(suiteId, body?)` | POST | `/adversarial-suites/:id/generate` | AI-generate tests from the suite's generation prompt |
|
|
620
|
+
| `generateGraph(suiteId, body)` | POST | `/adversarial-suites/:id/generate-graph` | Generate a mermaid workflow visualization |
|
|
621
|
+
| `run(suiteId, body)` | POST | `/adversarial-suites/:id/run` | Execute all tests asynchronously, returns `suite_run_id` |
|
|
622
|
+
| `listRuns(suiteId, query?)` | GET | `/adversarial-suites/:id/runs` | List suite runs |
|
|
623
|
+
| `getRun(suiteRunId)` | GET | `/adversarial-suites/runs/:runId` | Get a suite run with aggregate pass/fail counts |
|
|
624
|
+
| `getRunTestRuns(suiteRunId)` | GET | `/adversarial-suites/runs/:runId/test-runs` | List individual test results within a suite run |
|
|
599
625
|
|
|
600
626
|
---
|
|
601
627
|
|
|
@@ -605,11 +631,16 @@ Individual adversarial tests simulate a user trying to break the agent's behavio
|
|
|
605
631
|
|
|
606
632
|
```ts
|
|
607
633
|
const { test } = await client.adversarialTests.get("test-id");
|
|
608
|
-
await client.adversarialTests.update("test-id", {
|
|
634
|
+
await client.adversarialTests.update("test-id", {
|
|
635
|
+
adversarial_prompt: "Try to get PII",
|
|
636
|
+
timeout_seconds: 120,
|
|
637
|
+
});
|
|
609
638
|
await client.adversarialTests.delete("test-id");
|
|
610
639
|
|
|
611
640
|
// Run a single test
|
|
612
|
-
const { test_run_id } = await client.adversarialTests.run("test-id", {
|
|
641
|
+
const { test_run_id } = await client.adversarialTests.run("test-id", {
|
|
642
|
+
version_id: "v-id",
|
|
643
|
+
});
|
|
613
644
|
|
|
614
645
|
// Poll results
|
|
615
646
|
const { runs } = await client.adversarialTests.listRuns("test-id");
|
|
@@ -617,15 +648,15 @@ const { run } = await client.adversarialTests.getRun("run-id");
|
|
|
617
648
|
const { messages } = await client.adversarialTests.getRunMessages("run-id");
|
|
618
649
|
```
|
|
619
650
|
|
|
620
|
-
| Method
|
|
621
|
-
|
|
622
|
-
| `get(testId)`
|
|
623
|
-
| `update(testId, body)`
|
|
624
|
-
| `delete(testId)`
|
|
625
|
-
| `run(testId, body)`
|
|
626
|
-
| `listRuns(testId, query?)` | GET
|
|
627
|
-
| `getRun(runId)`
|
|
628
|
-
| `getRunMessages(runId)`
|
|
651
|
+
| Method | HTTP | Path | Description |
|
|
652
|
+
| -------------------------- | ------ | ----------------------------------------- | ---------------------------------------------------- |
|
|
653
|
+
| `get(testId)` | GET | `/adversarial-tests/:id` | Get test details |
|
|
654
|
+
| `update(testId, body)` | PATCH | `/adversarial-tests/:id` | Update prompt, model, variables, timeout |
|
|
655
|
+
| `delete(testId)` | DELETE | `/adversarial-tests/:id` | Delete a test |
|
|
656
|
+
| `run(testId, body)` | POST | `/adversarial-tests/:id/run` | Execute a test asynchronously, returns `test_run_id` |
|
|
657
|
+
| `listRuns(testId, query?)` | GET | `/adversarial-tests/:id/runs` | List test runs with audit remarks |
|
|
658
|
+
| `getRun(runId)` | GET | `/adversarial-tests/runs/:runId` | Get a single run with full audit remarks |
|
|
659
|
+
| `getRunMessages(runId)` | GET | `/adversarial-tests/runs/:runId/messages` | Get the full conversation from a test run |
|
|
629
660
|
|
|
630
661
|
---
|
|
631
662
|
|
|
@@ -635,7 +666,10 @@ Northstars are quality criteria that define how the agent should behave. They ar
|
|
|
635
666
|
|
|
636
667
|
```ts
|
|
637
668
|
const { northstar } = await client.northstars.get("northstar-id");
|
|
638
|
-
await client.northstars.update("northstar-id", {
|
|
669
|
+
await client.northstars.update("northstar-id", {
|
|
670
|
+
enabled: true,
|
|
671
|
+
priority: "high",
|
|
672
|
+
});
|
|
639
673
|
await client.northstars.delete("northstar-id");
|
|
640
674
|
|
|
641
675
|
// Get full regeneration history
|
|
@@ -651,14 +685,14 @@ const { feedback } = await client.northstars.submitFeedback("northstar-id", {
|
|
|
651
685
|
await client.northstars.deleteFeedback("northstar-id");
|
|
652
686
|
```
|
|
653
687
|
|
|
654
|
-
| Method
|
|
655
|
-
|
|
656
|
-
| `get(northstarId)`
|
|
657
|
-
| `update(northstarId, body)`
|
|
658
|
-
| `delete(northstarId)`
|
|
659
|
-
| `getHistory(northstarId)`
|
|
660
|
-
| `submitFeedback(northstarId, body)` | POST
|
|
661
|
-
| `deleteFeedback(northstarId)`
|
|
688
|
+
| Method | HTTP | Path | Description |
|
|
689
|
+
| ----------------------------------- | ------ | -------------------------- | -------------------------------------------------------------------------- |
|
|
690
|
+
| `get(northstarId)` | GET | `/northstars/:id` | Get a northstar |
|
|
691
|
+
| `update(northstarId, body)` | PATCH | `/northstars/:id` | Update name, description, examples, category, priority, or enabled state |
|
|
692
|
+
| `delete(northstarId)` | DELETE | `/northstars/:id` | Delete a northstar |
|
|
693
|
+
| `getHistory(northstarId)` | GET | `/northstars/:id/history` | Get the full regeneration chain, oldest first |
|
|
694
|
+
| `submitFeedback(northstarId, body)` | POST | `/northstars/:id/feedback` | Rate a northstar's correctness (−2 to +2), optionally trigger regeneration |
|
|
695
|
+
| `deleteFeedback(northstarId)` | DELETE | `/northstars/:id/feedback` | Remove your feedback on a northstar |
|
|
662
696
|
|
|
663
697
|
---
|
|
664
698
|
|
|
@@ -675,19 +709,21 @@ await client.customEvals.update("eval-id", {
|
|
|
675
709
|
await client.customEvals.delete("eval-id");
|
|
676
710
|
|
|
677
711
|
// Run an eval
|
|
678
|
-
const { run_id } = await client.customEvals.run("eval-id", {
|
|
712
|
+
const { run_id } = await client.customEvals.run("eval-id", {
|
|
713
|
+
version_id: "v-id",
|
|
714
|
+
});
|
|
679
715
|
|
|
680
716
|
// Poll results
|
|
681
717
|
const { runs } = await client.customEvals.listRuns("eval-id");
|
|
682
718
|
```
|
|
683
719
|
|
|
684
|
-
| Method
|
|
685
|
-
|
|
686
|
-
| `get(evalId)`
|
|
687
|
-
| `update(evalId, body)`
|
|
688
|
-
| `delete(evalId)`
|
|
689
|
-
| `run(evalId, body)`
|
|
690
|
-
| `listRuns(evalId, query?)` | GET
|
|
720
|
+
| Method | HTTP | Path | Description |
|
|
721
|
+
| -------------------------- | ------ | ------------------------ | -------------------------------------------------------------- |
|
|
722
|
+
| `get(evalId)` | GET | `/custom-evals/:id` | Get a custom eval |
|
|
723
|
+
| `update(evalId, body)` | PATCH | `/custom-evals/:id` | Update messages, expected outputs, variables, or northstar IDs |
|
|
724
|
+
| `delete(evalId)` | DELETE | `/custom-evals/:id` | Delete a custom eval |
|
|
725
|
+
| `run(evalId, body)` | POST | `/custom-evals/:id/run` | Execute the eval asynchronously, returns `run_id` |
|
|
726
|
+
| `listRuns(evalId, query?)` | GET | `/custom-evals/:id/runs` | List runs with pass/fail and judge reasoning |
|
|
691
727
|
|
|
692
728
|
---
|
|
693
729
|
|
|
@@ -699,8 +735,8 @@ Issues (quality flags) are raised when a conversation fails a northstar or quali
|
|
|
699
735
|
await client.issues.update("issue-id", { status: "approved" });
|
|
700
736
|
```
|
|
701
737
|
|
|
702
|
-
| Method
|
|
703
|
-
|
|
738
|
+
| Method | HTTP | Path | Description |
|
|
739
|
+
| ----------------------- | ----- | ------------- | ----------------------------------------------------------------- |
|
|
704
740
|
| `update(issueId, body)` | PATCH | `/issues/:id` | Update issue status (`open` / `approved` / `rejected` / `closed`) |
|
|
705
741
|
|
|
706
742
|
---
|
|
@@ -727,11 +763,11 @@ await client.auditRemarks.submitFeedback("audit-remark-id", {
|
|
|
727
763
|
await client.auditRemarks.deleteFeedback("audit-remark-id");
|
|
728
764
|
```
|
|
729
765
|
|
|
730
|
-
| Method
|
|
731
|
-
|
|
732
|
-
| `getFeedback(auditRemarkId)`
|
|
733
|
-
| `submitFeedback(auditRemarkId, body)` | POST
|
|
734
|
-
| `deleteFeedback(auditRemarkId)`
|
|
766
|
+
| Method | HTTP | Path | Description |
|
|
767
|
+
| ------------------------------------- | ------ | ----------------------------- | ------------------------------------------------------------------------- |
|
|
768
|
+
| `getFeedback(auditRemarkId)` | GET | `/audit-remarks/:id/feedback` | Get your feedback for this remark, or `null` |
|
|
769
|
+
| `submitFeedback(auditRemarkId, body)` | POST | `/audit-remarks/:id/feedback` | Submit thumbs up/down; a thumbs-up adds the remark as a northstar example |
|
|
770
|
+
| `deleteFeedback(auditRemarkId)` | DELETE | `/audit-remarks/:id/feedback` | Delete your feedback |
|
|
735
771
|
|
|
736
772
|
---
|
|
737
773
|
|
|
@@ -765,7 +801,9 @@ app.post("/api/chat-token", async (req, res) => {
|
|
|
765
801
|
import { HappyRobotChatClient } from "@happyrobot-ai/sdk";
|
|
766
802
|
|
|
767
803
|
// 1. Get a client token from your server
|
|
768
|
-
const { token } = await fetch("/api/chat-token", { method: "POST" }).then(r =>
|
|
804
|
+
const { token } = await fetch("/api/chat-token", { method: "POST" }).then((r) =>
|
|
805
|
+
r.json()
|
|
806
|
+
);
|
|
769
807
|
|
|
770
808
|
// 2. Initialize the browser-side client
|
|
771
809
|
const chat = new HappyRobotChatClient({ token });
|
|
@@ -798,7 +836,10 @@ console.log(ack.message.id); // server-assigned message ID
|
|
|
798
836
|
|
|
799
837
|
// 6. Send messages with file attachments
|
|
800
838
|
const artifact = await chat.uploadFile(fileBlob, "photo.png", "image/png");
|
|
801
|
-
await connection.sendMessage({
|
|
839
|
+
await connection.sendMessage({
|
|
840
|
+
content: "Here's the photo",
|
|
841
|
+
artifacts: [artifact],
|
|
842
|
+
});
|
|
802
843
|
|
|
803
844
|
// 7. Get history (page reload, reconnect)
|
|
804
845
|
const { messages } = await chat.getHistory(session_id);
|
|
@@ -818,8 +859,15 @@ await connection.sendMessage({
|
|
|
818
859
|
});
|
|
819
860
|
|
|
820
861
|
// Option B: Manual 3-step flow for more control
|
|
821
|
-
const upload = await chat.getPresignedUpload({
|
|
822
|
-
|
|
862
|
+
const upload = await chat.getPresignedUpload({
|
|
863
|
+
filename: "photo.png",
|
|
864
|
+
mime_type: "image/png",
|
|
865
|
+
});
|
|
866
|
+
await fetch(upload.upload_url, {
|
|
867
|
+
method: "PUT",
|
|
868
|
+
body: fileBlob,
|
|
869
|
+
headers: { "Content-Type": "image/png" },
|
|
870
|
+
});
|
|
823
871
|
await chat.completeUpload({
|
|
824
872
|
artifact_id: upload.artifact_id,
|
|
825
873
|
s3_uri: upload.s3_uri,
|
|
@@ -829,56 +877,63 @@ await chat.completeUpload({
|
|
|
829
877
|
});
|
|
830
878
|
await connection.sendMessage({
|
|
831
879
|
content: "Here's the photo",
|
|
832
|
-
artifacts: [
|
|
880
|
+
artifacts: [
|
|
881
|
+
{
|
|
882
|
+
media_id: upload.artifact_id,
|
|
883
|
+
mime_type: "image/png",
|
|
884
|
+
filename: "photo.png",
|
|
885
|
+
size_bytes: fileBlob.size,
|
|
886
|
+
},
|
|
887
|
+
],
|
|
833
888
|
});
|
|
834
889
|
```
|
|
835
890
|
|
|
836
891
|
### `HappyRobotClient` (server-side)
|
|
837
892
|
|
|
838
|
-
| Method
|
|
839
|
-
|
|
893
|
+
| Method | Description |
|
|
894
|
+
| ------------------------------------------------ | -------------------------------------------- |
|
|
840
895
|
| `client.chat.createToken({ workflow_id, env? })` | Create a scoped client token (1 hour expiry) |
|
|
841
896
|
|
|
842
897
|
### `HappyRobotChatClient` (browser-side)
|
|
843
898
|
|
|
844
|
-
| Method
|
|
845
|
-
|
|
846
|
-
| `chat.createSession()`
|
|
847
|
-
| `chat.connect(sessionId, handlers)`
|
|
899
|
+
| Method | Description |
|
|
900
|
+
| ------------------------------------------------------ | --------------------------------------------------------- |
|
|
901
|
+
| `chat.createSession()` | Create a new chat session |
|
|
902
|
+
| `chat.connect(sessionId, handlers)` | Open bidirectional WebSocket — returns `ChatConnection` |
|
|
848
903
|
| `chat.sendMessage(sessionId, { content, artifacts? })` | Send a user message via HTTP (fallback if WS unavailable) |
|
|
849
|
-
| `chat.getHistory(sessionId)`
|
|
850
|
-
| `chat.uploadFile(file, filename, mimeType)`
|
|
851
|
-
| `chat.getPresignedUpload({ filename, mime_type })`
|
|
852
|
-
| `chat.completeUpload({ artifact_id, s3_uri, ... })`
|
|
904
|
+
| `chat.getHistory(sessionId)` | Get message history |
|
|
905
|
+
| `chat.uploadFile(file, filename, mimeType)` | Upload a file (convenience method) |
|
|
906
|
+
| `chat.getPresignedUpload({ filename, mime_type })` | Get presigned S3 upload URL |
|
|
907
|
+
| `chat.completeUpload({ artifact_id, s3_uri, ... })` | Register uploaded artifact |
|
|
853
908
|
|
|
854
909
|
### `ChatConnection`
|
|
855
910
|
|
|
856
|
-
| Method
|
|
857
|
-
|
|
911
|
+
| Method | Description |
|
|
912
|
+
| ------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
858
913
|
| `connection.sendMessage({ content, artifacts? })` | Send a message via WebSocket. Returns a `Promise` that resolves with the server ack |
|
|
859
|
-
| `connection.close()`
|
|
860
|
-
| `connection.ws`
|
|
914
|
+
| `connection.close()` | Close the WebSocket connection |
|
|
915
|
+
| `connection.ws` | The underlying `WebSocket` instance |
|
|
861
916
|
|
|
862
917
|
### WebSocket Events
|
|
863
918
|
|
|
864
919
|
**Server → Client:**
|
|
865
920
|
|
|
866
|
-
| Event
|
|
867
|
-
|
|
868
|
-
| `connected`
|
|
869
|
-
| `response-start` | `content`
|
|
870
|
-
| `response-chunk` | `content`
|
|
871
|
-
| `response-end`
|
|
872
|
-
| `session-closed` | `session_id`, `status`, `reason`, `duration`, `timestamp` | Session ended
|
|
873
|
-
| `token-expired`
|
|
874
|
-
| `message-ack`
|
|
875
|
-
| `message-error`
|
|
876
|
-
| `heartbeat`
|
|
921
|
+
| Event | Fields | Description |
|
|
922
|
+
| ---------------- | --------------------------------------------------------- | ------------------------------------------ |
|
|
923
|
+
| `connected` | `session_id` | Connection established |
|
|
924
|
+
| `response-start` | `content` | AI started generating a response |
|
|
925
|
+
| `response-chunk` | `content` | Partial response text |
|
|
926
|
+
| `response-end` | `content` | Complete response text |
|
|
927
|
+
| `session-closed` | `session_id`, `status`, `reason`, `duration`, `timestamp` | Session ended |
|
|
928
|
+
| `token-expired` | — | JWT expired — reconnect with a fresh token |
|
|
929
|
+
| `message-ack` | `id`, `message` | Server confirmed the message was sent |
|
|
930
|
+
| `message-error` | `id`, `error` | Server failed to send the message |
|
|
931
|
+
| `heartbeat` | — | Keep-alive (every 15s) |
|
|
877
932
|
|
|
878
933
|
**Client → Server:**
|
|
879
934
|
|
|
880
|
-
| Event
|
|
881
|
-
|
|
935
|
+
| Event | Fields | Description |
|
|
936
|
+
| --------- | ------------------------------ | ----------------------------------------------------- |
|
|
882
937
|
| `message` | `content`, `artifacts?`, `id?` | Send a user message. `id` is echoed back in ack/error |
|
|
883
938
|
|
|
884
939
|
---
|
|
@@ -914,7 +969,9 @@ app.post("/api/voice-token", async (req, res) => {
|
|
|
914
969
|
import { HappyRobotVoiceClient } from "@happyrobot-ai/sdk/voice";
|
|
915
970
|
|
|
916
971
|
// 1. Get a voice token from your server
|
|
917
|
-
const { url, token } = await fetch("/api/voice-token", { method: "POST" }).then(
|
|
972
|
+
const { url, token } = await fetch("/api/voice-token", { method: "POST" }).then(
|
|
973
|
+
(r) => r.json()
|
|
974
|
+
);
|
|
918
975
|
|
|
919
976
|
// 2. Create the voice client and connect
|
|
920
977
|
const voice = new HappyRobotVoiceClient({ url, token });
|
|
@@ -951,39 +1008,39 @@ await connection.disconnect();
|
|
|
951
1008
|
|
|
952
1009
|
### `HappyRobotClient` (server-side)
|
|
953
1010
|
|
|
954
|
-
| Method
|
|
955
|
-
|
|
1011
|
+
| Method | Description |
|
|
1012
|
+
| -------------------------------------------------------- | -------------------------------------- |
|
|
956
1013
|
| `client.voice.createToken({ workflow_id, data?, env? })` | Create a LiveKit token for voice calls |
|
|
957
1014
|
|
|
958
1015
|
### `HappyRobotVoiceClient` (browser-side)
|
|
959
1016
|
|
|
960
|
-
| Method
|
|
961
|
-
|
|
962
|
-
| `new HappyRobotVoiceClient({ url, token })` | Create client with LiveKit credentials
|
|
963
|
-
| `voice.connect(handlers?)`
|
|
1017
|
+
| Method | Description |
|
|
1018
|
+
| ------------------------------------------- | -------------------------------------------------------------- |
|
|
1019
|
+
| `new HappyRobotVoiceClient({ url, token })` | Create client with LiveKit credentials |
|
|
1020
|
+
| `voice.connect(handlers?)` | Connect to room, enable microphone — returns `VoiceConnection` |
|
|
964
1021
|
|
|
965
1022
|
### `VoiceConnection`
|
|
966
1023
|
|
|
967
|
-
| Method
|
|
968
|
-
|
|
969
|
-
| `connection.disconnect()` | End the call and disconnect from the room
|
|
970
|
-
| `connection.mute()`
|
|
971
|
-
| `connection.unmute()`
|
|
972
|
-
| `connection.isMuted()`
|
|
973
|
-
| `connection.room`
|
|
1024
|
+
| Method | Description |
|
|
1025
|
+
| ------------------------- | --------------------------------------------------------- |
|
|
1026
|
+
| `connection.disconnect()` | End the call and disconnect from the room |
|
|
1027
|
+
| `connection.mute()` | Mute the local microphone |
|
|
1028
|
+
| `connection.unmute()` | Unmute the local microphone |
|
|
1029
|
+
| `connection.isMuted()` | Check mute state |
|
|
1030
|
+
| `connection.room` | Underlying LiveKit `Room` instance for advanced use cases |
|
|
974
1031
|
|
|
975
1032
|
### Room Events
|
|
976
1033
|
|
|
977
|
-
| Handler
|
|
978
|
-
|
|
979
|
-
| `onConnected`
|
|
980
|
-
| `onDisconnected`
|
|
981
|
-
| `onAgentConnected`
|
|
982
|
-
| `onTrackSubscribed`
|
|
983
|
-
| `onTrackUnsubscribed` | Remote audio track unsubscribed
|
|
984
|
-
| `onReconnecting`
|
|
985
|
-
| `onReconnected`
|
|
986
|
-
| `onError`
|
|
1034
|
+
| Handler | Description |
|
|
1035
|
+
| --------------------- | ----------------------------------------------------- |
|
|
1036
|
+
| `onConnected` | Connected to the LiveKit room |
|
|
1037
|
+
| `onDisconnected` | Disconnected from the room |
|
|
1038
|
+
| `onAgentConnected` | AI agent participant joined the room |
|
|
1039
|
+
| `onTrackSubscribed` | Remote audio track subscribed (auto-plays) |
|
|
1040
|
+
| `onTrackUnsubscribed` | Remote audio track unsubscribed |
|
|
1041
|
+
| `onReconnecting` | Connection temporarily lost — attempting to reconnect |
|
|
1042
|
+
| `onReconnected` | Successfully reconnected |
|
|
1043
|
+
| `onError` | An error occurred |
|
|
987
1044
|
|
|
988
1045
|
---
|
|
989
1046
|
|
|
@@ -1016,7 +1073,11 @@ for await (const workflow of client.workflows.listAll({ folder_id: "..." })) {
|
|
|
1016
1073
|
## Error Handling
|
|
1017
1074
|
|
|
1018
1075
|
```ts
|
|
1019
|
-
import {
|
|
1076
|
+
import {
|
|
1077
|
+
ApiError,
|
|
1078
|
+
AuthenticationError,
|
|
1079
|
+
NotFoundError,
|
|
1080
|
+
} from "@happyrobot-ai/sdk";
|
|
1020
1081
|
|
|
1021
1082
|
try {
|
|
1022
1083
|
const wf = await client.workflows.get("nonexistent");
|