@happyrobot-ai/sdk 0.1.10 → 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 +345 -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,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
|
|
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
|
|
|
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({
|
|
542
|
-
|
|
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
|
|
546
|
-
|
|
547
|
-
| `getDetails(query)` | GET
|
|
548
|
-
| `getTotals(query)`
|
|
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
|
|
559
|
-
|
|
560
|
-
| `describe()` | GET
|
|
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", {
|
|
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", {
|
|
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", {
|
|
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 } =
|
|
608
|
+
const { test_runs } =
|
|
609
|
+
await client.adversarialSuites.getRunTestRuns("suite-run-id");
|
|
586
610
|
```
|
|
587
611
|
|
|
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)`
|
|
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", {
|
|
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", {
|
|
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
|
|
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)`
|
|
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", {
|
|
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
|
|
655
|
-
|
|
656
|
-
| `get(northstarId)`
|
|
657
|
-
| `update(northstarId, body)`
|
|
658
|
-
| `delete(northstarId)`
|
|
659
|
-
| `getHistory(northstarId)`
|
|
660
|
-
| `submitFeedback(northstarId, body)` | POST
|
|
661
|
-
| `deleteFeedback(northstarId)`
|
|
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", {
|
|
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
|
|
685
|
-
|
|
686
|
-
| `get(evalId)`
|
|
687
|
-
| `update(evalId, body)`
|
|
688
|
-
| `delete(evalId)`
|
|
689
|
-
| `run(evalId, body)`
|
|
690
|
-
| `listRuns(evalId, query?)` | GET
|
|
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
|
|
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
|
|
731
|
-
|
|
732
|
-
| `getFeedback(auditRemarkId)`
|
|
733
|
-
| `submitFeedback(auditRemarkId, body)` | POST
|
|
734
|
-
| `deleteFeedback(auditRemarkId)`
|
|
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 =>
|
|
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({
|
|
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({
|
|
822
|
-
|
|
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: [
|
|
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
|
|
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
|
|
845
|
-
|
|
846
|
-
| `chat.createSession()`
|
|
847
|
-
| `chat.connect(sessionId, handlers)`
|
|
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)`
|
|
850
|
-
| `chat.uploadFile(file, filename, mimeType)`
|
|
851
|
-
| `chat.getPresignedUpload({ filename, mime_type })`
|
|
852
|
-
| `chat.completeUpload({ artifact_id, s3_uri, ... })`
|
|
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
|
|
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()`
|
|
860
|
-
| `connection.ws`
|
|
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
|
|
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`
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
961
|
-
|
|
962
|
-
| `new HappyRobotVoiceClient({ url, token })` | Create client with LiveKit credentials
|
|
963
|
-
| `voice.connect(handlers?)`
|
|
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
|
|
968
|
-
|
|
969
|
-
| `connection.disconnect()` | End the call and disconnect from the room
|
|
970
|
-
| `connection.mute()`
|
|
971
|
-
| `connection.unmute()`
|
|
972
|
-
| `connection.isMuted()`
|
|
973
|
-
| `connection.room`
|
|
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
|
|
978
|
-
|
|
979
|
-
| `onConnected`
|
|
980
|
-
| `onDisconnected`
|
|
981
|
-
| `onAgentConnected`
|
|
982
|
-
| `onTrackSubscribed`
|
|
983
|
-
| `onTrackUnsubscribed` | Remote audio track unsubscribed
|
|
984
|
-
| `onReconnecting`
|
|
985
|
-
| `onReconnected`
|
|
986
|
-
| `onError`
|
|
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 {
|
|
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");
|