@dialgem/sdk 0.1.0-beta.1 → 0.1.0-beta.3
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/CHANGELOG.md +23 -1
- package/README.md +89 -10
- package/dist/index.cjs +505 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1713 -48
- package/dist/index.d.ts +1713 -48
- package/dist/index.js +505 -3
- package/dist/index.js.map +1 -1
- package/examples/webhook-express.ts +12 -4
- package/examples/webhook-fastify.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.0-beta.
|
|
3
|
+
## 0.1.0-beta.3
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `phoneNumbers.search({ country?, type?, area_code?, contains?, limit? })` lists numbers that can be bought, with the monthly price, and `phoneNumbers.buy({ phone_number, type?, nickname? })` buys one. **Buying spends the organization's credit**: the first month is debited when you buy and the rental renews monthly until the number is released; nothing is charged if the purchase fails. Both need the deployment to have number purchasing switched on (`search` throws `NotFoundError`, `number_purchase_disabled`, otherwise). Types: `PhoneNumberSearchParams`, `PhoneNumberBuyParams`, `AvailablePhoneNumbers`, `PurchasedPhoneNumber`.
|
|
7
|
+
- A number looked up with `phoneNumbers.retrieve` now carries `own_twilio` (whether it is on a Twilio account you connected yourself). Connecting your own Twilio account and importing its numbers is a dashboard feature; it is not in the SDK, because it handles your Twilio credentials.
|
|
8
|
+
|
|
9
|
+
## 0.1.0-beta.2
|
|
10
|
+
|
|
11
|
+
### Not in this SDK, on purpose
|
|
12
|
+
Campaigns, webhook endpoint management, usage, billing, analytics, and contact erasure / do-not-call are dashboard-only. See the surface policy in the Python SDK's `docs/api-surface.md`.
|
|
4
13
|
|
|
5
14
|
### Breaking changes
|
|
6
15
|
- **The API address is fixed at `https://api.dialgem.com`.** The `baseURL` option and the `DIALGEM_BASE_URL` environment variable are gone. Passing `baseURL` now throws rather than being ignored, so a leftover staging or local URL cannot quietly send your key to production. `DEFAULT_BASE_URL` is renamed `BASE_URL`.
|
|
@@ -9,6 +18,17 @@
|
|
|
9
18
|
- **`calls.list` pages are cursor-based.** A page is `{ data, has_more, pagination_key }`. `page`, `page_size` and `total` are gone; use `limit`.
|
|
10
19
|
|
|
11
20
|
### Added
|
|
21
|
+
- `sessions.say(sessionId, { text, interrupt? })` and `sessions.release(sessionId)`: make the agent speak a line on a live call, and hand a taken-over call back. Off unless the deployment enables live control (`live_control_disabled`). Listening in and taking over run over a WebSocket this SDK does not wrap. `sessions.update` now reaches a call on any service instance.
|
|
22
|
+
|
|
23
|
+
- `sessions.update(sessionId, { system_prompt?, dynamic_variables? })`: change a live call's prompt and/or variables from the agent's next turn. `sessionId` is the session's id or the call's `call_id`. Only that call changes and it is not saved.
|
|
24
|
+
- **Saved LLMs.** `llms` (`create`, `list`, `retrieve`, `update`, `delete`): a prompt and model set up once, attached with `llm_id` on `agents.create` / `agents.update`. Attaching copies the values; later edits or deletion do not change the agent, and `llm_id` cannot be sent with the fields it carries.
|
|
25
|
+
- `agents.mcpServers.listTools(agentId, serverId)`: the server's tools with descriptions and argument schemas, from a live connection; stores nothing.
|
|
26
|
+
- **Saved flows.** `flows` (`create`, `list`, `retrieve`, `update`, `delete`): build and check a conversation flow once, then attach it with `flow_id` on `agents.create` / `agents.update`. Attaching copies the flow; later edits or deletion do not change the agent.
|
|
27
|
+
- **Chats.** `chats` (`create`, `list`, `retrieve`, `update`, `delete`, `sendMessage`, `end`, `rerunAnalysis`): text conversations with a prompt agent, with the agent's own prompt, model and functions.
|
|
28
|
+
- Chats are billed per agent reply (a spent balance is a 402 `insufficient_credit`); `Chat.chat_cost` shows the spend (`null` for a team-member session). Webhook events `chat_started`, `chat_ended` and `chat_analyzed` are in the `WebhookEvent` union (`ChatStartedEvent`, `ChatEndedEvent`, `ChatAnalyzedEvent`); they carry `chat_id` and `chat`, not `call_id`, so narrow on `event` before reading `call`.
|
|
29
|
+
- `calls.rerunAnalysis(callId)`, `contacts.retrieveByPhone(phone, { default_country })` and `apiKey.retrieve()` (who this key is; works for any scope).
|
|
30
|
+
- **Agent simulations.** `simulations.createSuite`, `createCase`, `run` and `retrieveRun` (with the rest of `listSuites`, `retrieveSuite`, `updateSuite`, `deleteSuite`, `updateCase`, `deleteCase`, `listRuns`, `cancelRun`): save conversations a simulated caller has with your agent, run them in text against the draft or a published version, and check what it said and did. A suite's `publish_gate` can warn or block publishing a version until the draft has passed. Nothing is dialled or billed and the agent's tools are never really called.
|
|
31
|
+
- **Inbound routing webhook.** `phoneNumbers.update(id, { inbound_webhook_url })` sets (or, with `null`, removes) a URL Dialgem asks, before an inbound call is answered, which agent should take it, with variables or metadata, or to reject it. `phoneNumbers.testInboundWebhook(id)` sends one signed test request; `phoneNumbers.rotateInboundWebhookSecret(id)` replaces the signing secret. `PhoneNumber` gains `inbound_webhook_url` and `inbound_webhook_secret_hint`, and `inbound_webhook_secret` in the one response that creates or rotates it.
|
|
12
32
|
- `calls.update` (replace metadata), `calls.delete` and `calls.stop`.
|
|
13
33
|
- `metadata` on `createPhoneCall` and `register`.
|
|
14
34
|
- New call record fields: `metadata`, `dynamic_variables`, `start_timestamp`, `end_timestamp`, `ended_at`, `duration_ms`, `transcript_text`, `in_voicemail` and `latency` (per-stage p50/p90/p95/p99). Post-call analysis gains `call_summary` and `in_voicemail`.
|
|
@@ -18,6 +38,8 @@
|
|
|
18
38
|
- **Voice cloning.** `voices.clone({ name, files, consent_confirmed: true })` uploads audio and returns a voice private to your organization; `voices.delete(voiceId)` removes it at the provider and here. `Voice` gains `is_custom` and `created_by`. The upload is never retried, whatever `maxRetries` says.
|
|
19
39
|
- `phoneNumbers.retrieve(phoneNumber)` looks a number up by its E.164 value.
|
|
20
40
|
- **`agent_version: "latest_published"`** on a phone number and on `createPhoneCall` / `register`: a pointer that follows the newest publish rather than naming a version. A call still reports the concrete version it ran.
|
|
41
|
+
- **Contacts.** `contacts` (`create`, `list`, `retrieve`, `update`, `delete`, `calls`), `contactLists` (`list`, `create`, `retrieve`, `update`, `delete`, `addContacts`, `removeContact`) and CSV import under `contacts.imports` (`inspect`, `create`, `list`, `retrieve`, `errors`, `commit`, `cancel`). A contact is keyed on its phone number, stored in E.164 however it is written (pass `default_country` for numbers without a `+`). `do_not_call` on a contact is read from your do-not-call list, not stored on it. Imports run in the background: start one with `dry_run: true`, poll `retrieve` until it is `previewed`, then `commit`. `contacts.list` pages by cursor like `calls.list`. CSV downloads (the export, and the rejected-rows report) are available over the REST API only.
|
|
42
|
+
- **Browser calls.** `webCalls.create({ agent_id, metadata, dialgem_llm_dynamic_variables })` creates a call for one visitor and returns a one-use `access_token` (60 seconds) for `@dialgem/client`, so a web page can talk to an agent without your API key ever reaching the browser. Allow the pages that may start calls with `webCalls.updateSettings({ allowed_origins })` (`retrieveSettings` reads them back); `create` answers 409 `web_origins_not_configured` until at least one is set.
|
|
21
43
|
- **Agent versions.** `agents.versions.publish` freezes an agent — its configuration, functions and MCP servers — as an immutable numbered snapshot; `list` and `retrieve` read them back. Pin one with `inbound_agent_version` / `outbound_agent_version` on a phone number, or `agent_version` on `createPhoneCall` and `register`. The version a call ran is reported as `agent_version` on the call record and in every webhook. The agent itself is the draft, version 0, and stays what every unpinned call runs.
|
|
22
44
|
|
|
23
45
|
## 0.1.0-beta.0 (unreleased)
|
package/README.md
CHANGED
|
@@ -1,11 +1,45 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Dialgem for TypeScript
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
**The official TypeScript SDK for the [Dialgem](https://dialgem.com) voice AI API.**
|
|
6
|
+
|
|
7
|
+
Build voice agents, put them on phone numbers, place calls, steer them live, and read transcripts, all from your backend.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/@dialgem/sdk)
|
|
10
|
+
[](https://www.npmjs.com/package/@dialgem/sdk)
|
|
11
|
+
[](https://github.com/DialgemAI/dialgem-sdk-typescript/actions/workflows/ci.yml)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](https://www.typescriptlang.org/)
|
|
14
|
+
[](https://github.com/DialgemAI/dialgem-sdk-typescript/stargazers)
|
|
15
|
+
|
|
16
|
+
[Website](https://dialgem.com) · [Issues](https://github.com/DialgemAI/dialgem-sdk-typescript/issues) · [Changelog](CHANGELOG.md) · [Python SDK](https://github.com/DialgemAI/dialgem-sdk-python)
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { Dialgem } from "@dialgem/sdk"
|
|
24
|
+
|
|
25
|
+
const dialgem = new Dialgem() // reads DIALGEM_API_KEY
|
|
26
|
+
|
|
27
|
+
const agent = await dialgem.agents.create({ name: "Front desk", system_prompt: "You answer for Acme Dental." })
|
|
28
|
+
const { call_id } = await dialgem.calls.createPhoneCall({ from_: "+14155550100", to: "+14155550123", agent_id: agent.id })
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Why this SDK
|
|
32
|
+
|
|
33
|
+
- **Typed end to end.** Request bodies are typed from the API's own schema, including the full conversation-flow node union, and webhook events are a discriminated union you can `switch` on.
|
|
34
|
+
- **Zero runtime dependencies.** ESM and CommonJS builds, so it works from any Node project.
|
|
35
|
+
- **Runs anywhere with `fetch`.** Node.js 20+, Bun, Deno and serverless runtimes that provide `fetch` and Web Crypto.
|
|
36
|
+
- **Safe by default.** `POST` is never retried (a retry could ring someone twice), other requests retry with backoff and `Retry-After`, and redirects are never followed so your key can't be sent elsewhere.
|
|
37
|
+
- **Everything a backend needs.** Agents (with tools, knowledge, MCP servers and versions), phone numbers, calls and chats, saved flows and LLMs, voices, contacts, live call control, and webhook signature verification.
|
|
38
|
+
- **Server-side only.** Your API key grants full access to your organization. To talk to an agent from a web page, use [`@dialgem/client`](https://github.com/DialgemAI/dialgem-client-sdk).
|
|
39
|
+
|
|
40
|
+
## Contents
|
|
41
|
+
|
|
42
|
+
[Install](#install) · [Quickstart](#quickstart) · [Recipes](#recipes) · [Live call control](#live-call-control) · [Errors](#errors) · [Retries](#retries) · [Coverage](#coverage) · [Development](#development) · [License](#license)
|
|
9
43
|
|
|
10
44
|
## Install
|
|
11
45
|
|
|
@@ -126,13 +160,13 @@ Your Twilio credentials are never shared with Dialgem. `stream_url` is signed an
|
|
|
126
160
|
|
|
127
161
|
### 4. Verify webhooks
|
|
128
162
|
|
|
129
|
-
Set `webhook_url`, `webhook_events` and `webhook_signing_secret` on the agent. Dialgem then POSTs `call_started`, `call_ended`
|
|
163
|
+
Set `webhook_url`, `webhook_events` and `webhook_signing_secret` on the agent (and, optionally, `webhook_timeout_ms`, 1000–30000, default 10000, to bound how long each delivery attempt waits for your server). Dialgem then POSTs the events you subscribe to: `call_started`, `call_ended`, `call_analyzed`, `transcript_updated`, `transfer_started`, `transfer_bridged`, `transfer_cancelled` and `transfer_ended`. Each body is `{ event, call_id, agent_id, call }`, where `call` is the full call record; `transcript_updated` also carries `role`, `turn_index` and the `transcript` so far, and the transfer events carry `transfer: { target?, mode?, reason? }`. Each request is signed:
|
|
130
164
|
|
|
131
165
|
```
|
|
132
166
|
x-dialgem-signature: v=<timestamp_ms>,d=<hex> hex = HMAC-SHA256(secret, raw_body + timestamp_ms)
|
|
133
167
|
```
|
|
134
168
|
|
|
135
|
-
`constructEvent` and `verify` check the HMAC and reject signatures more than 5 minutes old, so a captured request cannot be replayed. `call_ended` arrives as soon as the call ends; `call_analyzed` follows once the summary, sentiment and your extracted variables are ready.
|
|
169
|
+
`constructEvent` and `verify` check the HMAC and reject signatures more than 5 minutes old, so a captured request cannot be replayed. `call_ended` arrives as soon as the call ends; `call_analyzed` follows once the summary, sentiment and your extracted variables are ready. `transcript_updated` is sent per turn and may be retried out of order, so keep the highest `turn_index`. For a cold transfer, `transfer_bridged` is sent when the transferred leg finishes, followed by `transfer_ended`.
|
|
136
170
|
|
|
137
171
|
> **Verify the raw body.** The signature covers the exact bytes Dialgem sent. A body that was parsed and re-serialized, for example by `express.json()`, will never verify, even when the JSON is identical.
|
|
138
172
|
|
|
@@ -255,6 +289,24 @@ than quietly picking one.
|
|
|
255
289
|
`voices.delete(voice.id)` removes it at the provider and here. It refuses with a
|
|
256
290
|
409 while an agent still uses it, rather than leaving that agent without a voice.
|
|
257
291
|
|
|
292
|
+
|
|
293
|
+
## Live call control
|
|
294
|
+
|
|
295
|
+
Steer a call while it is happening. `sessionId` is the session's id from `sessions.list()` or the call's own `call_id`, and the call can be on any service instance.
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
// Change this call's prompt or variables from the agent's next turn (not saved, only this call).
|
|
299
|
+
await dialgem.sessions.update(call_id, { dynamic_variables: { plan: "pro" } })
|
|
300
|
+
|
|
301
|
+
// Make the agent say a line in its own voice; interrupt: true cuts in now.
|
|
302
|
+
await dialgem.sessions.say(call_id, { text: "One moment while I check that." })
|
|
303
|
+
|
|
304
|
+
// Give a taken-over call back to the agent.
|
|
305
|
+
await dialgem.sessions.release(call_id)
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
`say` and `release` are **off unless your deployment enables live control** (`PermissionDeniedError` with `errCode` `live_control_disabled`), and are for owners, admins and API keys only. Listening in and taking a call over run over a WebSocket (`/v1/agent/sessions/{id}/live`), which this SDK does not wrap.
|
|
309
|
+
|
|
258
310
|
## Errors
|
|
259
311
|
|
|
260
312
|
Every error extends `DialgemError`. When the API returns an HTTP error, the SDK throws an `APIError` subclass chosen by status code:
|
|
@@ -303,13 +355,19 @@ The SDK never follows redirects. The API does not issue them, and following one
|
|
|
303
355
|
| `agents.knowledge` | `list`, `create`, `delete` |
|
|
304
356
|
| `agents.mcpServers` | `list`, `create`, `update`, `delete`, `test` |
|
|
305
357
|
| `agents.versions` | `publish`, `list`, `listPage`, `retrieve` |
|
|
306
|
-
| `calls` | `list`, `retrieve`, `update`, `delete`, `stop`, `createPhoneCall`, `register` |
|
|
358
|
+
| `calls` | `list`, `retrieve`, `update`, `delete`, `stop`, `rerunAnalysis`, `createPhoneCall`, `register` |
|
|
307
359
|
| `phoneNumbers` | `create`, `list`, `retrieve`, `update`, `assign`, `delete` |
|
|
308
360
|
| `voices` | `list`, `clone`, `delete` |
|
|
309
361
|
| `flowTemplates`, `promptTemplates` | `list`, `retrieve` |
|
|
362
|
+
| `llms` | `create`, `list`, `retrieve`, `update`, `delete` |
|
|
363
|
+
| `flows` | `create`, `list`, `retrieve`, `update`, `delete` |
|
|
364
|
+
| `chats` | `create`, `list`, `retrieve`, `update`, `delete`, `sendMessage`, `end`, `rerunAnalysis` |
|
|
365
|
+
| `sessions` | `list`, `update`, `say`, `release` |
|
|
366
|
+
| `apiKey` | `retrieve` |
|
|
367
|
+
| `contacts` | `retrieveByPhone` (and the rest: see the reference) |
|
|
310
368
|
| `webhooks` | `verify`, `constructEvent`, `constructFunctionCall` |
|
|
311
369
|
|
|
312
|
-
In-browser web calls are not part of this package.
|
|
370
|
+
In-browser web calls are not part of this package: see [`@dialgem/client`](https://github.com/DialgemAI/dialgem-client-sdk).
|
|
313
371
|
|
|
314
372
|
## Development
|
|
315
373
|
|
|
@@ -328,6 +386,19 @@ pnpm gen:types
|
|
|
328
386
|
DIALGEM_API_KEY=zk_… pnpm test:live # runs against api.dialgem.com — use a test org's key
|
|
329
387
|
```
|
|
330
388
|
|
|
389
|
+
The API address is fixed at `https://api.dialgem.com` and `baseURL` is refused,
|
|
390
|
+
so a key can never start hitting production by accident. To exercise the SDK
|
|
391
|
+
against a local or staging stack, pass a `fetch` that rewrites the origin — it
|
|
392
|
+
is explicit, it stays in your test setup, and it cannot be switched on by an
|
|
393
|
+
environment variable someone forgot to unset:
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
const local = new Dialgem({
|
|
397
|
+
apiKey: "zk_local",
|
|
398
|
+
fetch: (url, init) => fetch(String(url).replace("https://api.dialgem.com", "http://localhost:8002"), init),
|
|
399
|
+
})
|
|
400
|
+
```
|
|
401
|
+
|
|
331
402
|
Request-body types are generated from `openapi/openapi.json`. Response types in `src/types/` are written by hand, so a change to a response shape needs a matching edit there.
|
|
332
403
|
|
|
333
404
|
To release, bump `version` in `package.json` and `src/version.ts`, add a CHANGELOG entry, merge to `main`, and push a matching tag (`git tag v0.1.0 && git push origin v0.1.0`). A version with a hyphen (`0.2.0-beta.1`) publishes to the `next` dist-tag.
|
|
@@ -335,3 +406,11 @@ To release, bump `version` in `package.json` and `src/version.ts`, add a CHANGEL
|
|
|
335
406
|
## License
|
|
336
407
|
|
|
337
408
|
Apache-2.0
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
<div align="center">
|
|
413
|
+
|
|
414
|
+
If this SDK saves you time, a ⭐ on [GitHub](https://github.com/DialgemAI/dialgem-sdk-typescript) helps other developers find it.
|
|
415
|
+
|
|
416
|
+
</div>
|