codai-sdk 0.2.0 → 0.3.1
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 +181 -4
- package/dist/index.d.ts +7551 -128
- package/dist/index.js +1446 -251
- package/dist/index.js.map +1 -1
- package/package.json +12 -7
package/README.md
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
Official TypeScript SDK for the [codai](https://codai.ro) AI gateway — a single
|
|
7
7
|
OpenAI-compatible endpoint with smart routing, sessions, server-side agents,
|
|
8
|
-
streaming, embeddings, audio,
|
|
8
|
+
streaming, embeddings, audio, outcome-billed tasks, shared sessions, devices,
|
|
9
|
+
hosts, orgs and account — **full parity with the public gateway OpenAPI**.
|
|
9
10
|
|
|
10
11
|
- **Zero dependencies** — uses the platform `fetch`.
|
|
11
12
|
- Works in **Node 18+** and modern edge runtimes.
|
|
12
13
|
- **OpenAI-compatible** chat surface with codai extensions.
|
|
13
|
-
- Fully typed
|
|
14
|
+
- Fully typed — request/response types are **generated from the OpenAPI spec**.
|
|
15
|
+
- Every `operationId` of the gateway has exactly one method (parity-tested).
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
18
|
npm install codai-sdk
|
|
@@ -35,6 +37,38 @@ console.log(res.content);
|
|
|
35
37
|
console.log(res.routedTo); // which upstream model actually served
|
|
36
38
|
```
|
|
37
39
|
|
|
40
|
+
## Resource groups
|
|
41
|
+
|
|
42
|
+
Everything hangs off the `Codai` client. The 0.2.x top-level methods (`chat()`,
|
|
43
|
+
`chatStream()`, `embeddings()`, `models()`, `feedback()`, `mintToken()`,
|
|
44
|
+
`agents.run()`, `audio.*`) still work; the resource groups below are the full
|
|
45
|
+
surface.
|
|
46
|
+
|
|
47
|
+
| Group | Methods | Gateway paths |
|
|
48
|
+
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
49
|
+
| `chat.completions` | `create`, `stream` | `POST /v1/chat/completions` |
|
|
50
|
+
| `messages` | `create`, `stream` | `POST /v1/messages` (Anthropic wire) |
|
|
51
|
+
| `responses` | `create`, `stream` | `POST /v1/responses` (OpenAI Responses wire) |
|
|
52
|
+
| `embeddings` | `create` | `POST /v1/embeddings` |
|
|
53
|
+
| `audio` | `transcribe`, `transcribeDetailed`, `speech`, `speechDetailed` | `POST /v1/audio/transcriptions`, `POST /v1/audio/speech` |
|
|
54
|
+
| `tokens` | `create` | `POST /v1/tokens` |
|
|
55
|
+
| `models` | `list` | `GET /v1/models` |
|
|
56
|
+
| `health` | `get`, `ready`, `status` | `GET /health`, `GET /health/ready`, `GET /status` |
|
|
57
|
+
| `agents` | `run`; `runs.create`, `runs.get`, `runs.steps`, `runs.stats`, `runs.cancel`, `runs.stream` | `/v1/agents/run`, `/v1/agents/runs/*` |
|
|
58
|
+
| `tools` | `search`, `fetch` | `POST /v1/tools/search`, `POST /v1/tools/fetch` |
|
|
59
|
+
| `tasks` | `list`, `pending`, `stats`, `get`, `confirm` | `/v1/tasks/*` |
|
|
60
|
+
| `sessions` | `create`, `list`, `get`, `update`, `delete`, `dispatch`, `stream`; `events.list/append`; `controls.list/submit/markApplied`; `lease.acquire/renew/release`; `shares.list/create/delete/sharedWithMe` | `/v1/sessions/*` |
|
|
61
|
+
| `devices` | `list`, `update`, `delete`, `dispatchInbox` | `/v1/devices/*` |
|
|
62
|
+
| `hosts` | `list`, `exec`, `postResult`, `stream` | `/v1/hosts/*` |
|
|
63
|
+
| `orgs` | `create`, `list`; `members.list/add/remove` | `/v1/orgs/*` |
|
|
64
|
+
| `account` | `get`, `update` | `GET/PATCH /v1/account` |
|
|
65
|
+
| `receipt` | `get` | `GET /v1/receipt` |
|
|
66
|
+
| `feedback` | `submit` | `POST /v1/feedback` |
|
|
67
|
+
| `phoneModels` | `list` | `GET /v1/phone/models` |
|
|
68
|
+
|
|
69
|
+
Every method takes an optional last argument `{ ext, signal }` where `ext` is a
|
|
70
|
+
typed bag of `X-Codai-*` extension headers (see below).
|
|
71
|
+
|
|
38
72
|
## Streaming
|
|
39
73
|
|
|
40
74
|
```ts
|
|
@@ -62,6 +96,30 @@ const { requestId, usage, routedTo, toolCalls } = await stream.final;
|
|
|
62
96
|
if (requestId) await codai.feedback(requestId, 1);
|
|
63
97
|
```
|
|
64
98
|
|
|
99
|
+
`chat.completions.stream()` is the same stream; `stream.chunks()` yields the raw
|
|
100
|
+
`chat.completion.chunk` objects.
|
|
101
|
+
|
|
102
|
+
## Anthropic Messages and OpenAI Responses wires
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
// Anthropic Messages shape — text blocks, tool_use, streaming events
|
|
106
|
+
const msg = await codai.messages.create({
|
|
107
|
+
messages: [{ role: 'user', content: 'Salut!' }],
|
|
108
|
+
max_tokens: 256,
|
|
109
|
+
});
|
|
110
|
+
msg.text; // concatenated text blocks
|
|
111
|
+
|
|
112
|
+
for await (const ev of codai.messages.stream({ messages, max_tokens: 256 })) {
|
|
113
|
+
if (ev.type === 'content_block_delta') {
|
|
114
|
+
/* ev.delta */
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// OpenAI Responses shape
|
|
119
|
+
const r = await codai.responses.create({ input: 'Say hi.' });
|
|
120
|
+
r.outputText;
|
|
121
|
+
```
|
|
122
|
+
|
|
65
123
|
## Server-side agent
|
|
66
124
|
|
|
67
125
|
Run a plan-and-execute loop on the gateway — the heavy lifting (planning, tool
|
|
@@ -76,6 +134,75 @@ const run = await codai.agents.run({
|
|
|
76
134
|
console.log(run.result);
|
|
77
135
|
```
|
|
78
136
|
|
|
137
|
+
Async runs are persisted and can be polled, streamed and cancelled:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
const { id } = await codai.agents.runs.create({ task: '…', client_request_id: 'ci-8812' });
|
|
141
|
+
for await (const ev of codai.agents.runs.stream(id)) {
|
|
142
|
+
if (ev.event === 'step') console.log(ev.data.kind, ev.data.summary);
|
|
143
|
+
if (ev.event === 'done') console.log(ev.data.status, ev.data.result);
|
|
144
|
+
}
|
|
145
|
+
const run = await codai.agents.runs.get(id);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Tools, tasks and receipts
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const hits = await codai.tools.search({ query: 'BNR EUR RON' });
|
|
152
|
+
const page = await codai.tools.fetch({ url: 'https://bnr.ro', format: 'markdown' });
|
|
153
|
+
|
|
154
|
+
const { tasks, next_cursor } = await codai.tasks.list({ outcome: 'unconfirmed', limit: 20 });
|
|
155
|
+
await codai.tasks.confirm(tasks[0].id, { outcome: 'confirmed' });
|
|
156
|
+
|
|
157
|
+
const receipt = await codai.receipt.get({ sessionId: 'my-project' });
|
|
158
|
+
receipt.cost_usd;
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Shared sessions, devices and hosts
|
|
162
|
+
|
|
163
|
+
Shared-sessions and hosts calls need a device UUID (`x-codai-device`). Set it once
|
|
164
|
+
on the client:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
const codai = new Codai({
|
|
168
|
+
apiKey,
|
|
169
|
+
device: '6f1c2b3a-4d5e-4f60-8a9b-0c1d2e3f4a5b',
|
|
170
|
+
deviceName: 'ci-runner',
|
|
171
|
+
devicePlatform: 'cli',
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const session = await codai.sessions.create({ session_key: 'desktop-main', title: 'Refactor' });
|
|
175
|
+
await codai.sessions.lease.acquire(session.id);
|
|
176
|
+
await codai.sessions.events.append(session.id, {
|
|
177
|
+
events: [{ kind: 'user', payload: { text: 'hello' }, client_event_id: 'e1' }],
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
for await (const frame of codai.sessions.stream(session.id, { after: 0 })) {
|
|
181
|
+
// frame.event ∈ 'event' | 'control' | 'lease' | 'presence'
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
await codai.sessions.dispatch(session.id, { device_id: phoneId, text: 'continue on the phone' });
|
|
185
|
+
|
|
186
|
+
// Host relay: run one op on a connected desktop
|
|
187
|
+
const hosts = await codai.hosts.list();
|
|
188
|
+
const out = await codai.hosts.exec(hosts[0].device_id, 'shell', { cmd: 'git status' });
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Orgs and account
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
const org = await codai.orgs.create('Acme Robotics');
|
|
195
|
+
await codai.orgs.members.add(org.id, { email: 'ana@example.com', role: 'admin' });
|
|
196
|
+
await codai.sessions.shares.create(session.id, {
|
|
197
|
+
principal_type: 'org',
|
|
198
|
+
principal_id: org.id,
|
|
199
|
+
role: 'editor',
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const me = await codai.account.get();
|
|
203
|
+
await codai.account.update({ training_opt_out: true });
|
|
204
|
+
```
|
|
205
|
+
|
|
79
206
|
## Feedback
|
|
80
207
|
|
|
81
208
|
```ts
|
|
@@ -114,6 +241,9 @@ const codai = new Codai({
|
|
|
114
241
|
apiKey: process.env.CODAI_API_KEY!,
|
|
115
242
|
baseUrl: 'https://ai.codai.ro', // default
|
|
116
243
|
sessionId: 'my-project', // enables session memory + stickiness
|
|
244
|
+
device: '<uuid>', // shared sessions / hosts (x-codai-device)
|
|
245
|
+
client: 'my-app/1.2.0', // x-codai-client surface tag
|
|
246
|
+
defaults: { effort: 'medium' }, // any other X-Codai-* defaults
|
|
117
247
|
timeoutMs: 120_000,
|
|
118
248
|
maxRetries: 2,
|
|
119
249
|
});
|
|
@@ -121,7 +251,8 @@ const codai = new Codai({
|
|
|
121
251
|
|
|
122
252
|
## codai extensions
|
|
123
253
|
|
|
124
|
-
The chat surface is OpenAI-compatible, with
|
|
254
|
+
The chat surface is OpenAI-compatible, with opt-in extensions. On `chat()` the
|
|
255
|
+
0.2.x option names still work:
|
|
125
256
|
|
|
126
257
|
| Option | Description |
|
|
127
258
|
| ----------------- | ----------------------------------------------------------------------- |
|
|
@@ -130,6 +261,35 @@ The chat surface is OpenAI-compatible, with a few opt-in extensions:
|
|
|
130
261
|
| `compact: "auto"` | Server-side context compaction. |
|
|
131
262
|
| `bestOf` | Best-of-N sampling override (`0` disables, `3` forces). |
|
|
132
263
|
|
|
264
|
+
Every method also accepts `{ ext }` — a typed `CodaiRequestExtensions` bag that
|
|
265
|
+
covers all 41 documented `X-Codai-*` request headers (`effort`, `thinking`,
|
|
266
|
+
`thinkingBudget`, `cache`, `noTask`, `taskId`, `incognito`, `noRecall`,
|
|
267
|
+
`provenOnly`, `repo`, `agentId`, `disableSubagents`, `mode`, `serverTools`,
|
|
268
|
+
`orchestrate`, `cascade`, `bestOf`, `reflect`, `stepVerify`, `plan`, `consensus`,
|
|
269
|
+
`compact`, `retrieval`, `heuristics`, `identity`, `playbook`, `debug`, `device`,
|
|
270
|
+
`shareToken`, …):
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
await codai.chat.completions.create(
|
|
274
|
+
{ messages, model: 'codai' },
|
|
275
|
+
{ ext: { effort: 'high', thinking: true, thinkingBudget: 8192, taskId: 'task_42' } },
|
|
276
|
+
);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Generated types
|
|
280
|
+
|
|
281
|
+
`paths`, `components` and `operations` from the gateway OpenAPI are exported, and
|
|
282
|
+
every resource re-exports friendly aliases (`ChatCompletionRequest`, `Task`,
|
|
283
|
+
`Session`, `AccountView`, …):
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
import type { components, Task, SessionStreamEvent } from 'codai-sdk';
|
|
287
|
+
type Receipt = components['schemas']['AccountReceipt'];
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Regenerate after a spec change with `pnpm gen`; `operations.test.ts` fails when
|
|
291
|
+
the spec and the client drift.
|
|
292
|
+
|
|
133
293
|
## Migrating from the OpenAI SDK
|
|
134
294
|
|
|
135
295
|
The chat payload is OpenAI-shaped, so migration is mostly swapping the client:
|
|
@@ -149,11 +309,28 @@ try {
|
|
|
149
309
|
await codai.chat({ messages: [{ role: 'user', content: 'hi' }] });
|
|
150
310
|
} catch (err) {
|
|
151
311
|
if (err instanceof CodaiError) {
|
|
152
|
-
console.error(err.status, err.
|
|
312
|
+
console.error(err.status, err.code, err.requestId, err.retryAfter, err.body);
|
|
153
313
|
}
|
|
154
314
|
}
|
|
155
315
|
```
|
|
156
316
|
|
|
317
|
+
`code` is the stable gateway error code (`invalid_api_key`, `rate_limit_exceeded`,
|
|
318
|
+
`quota_exceeded`, `lease_held`, `host_offline`, …); `retryAfter` is the
|
|
319
|
+
`Retry-After` value in seconds on 429s.
|
|
320
|
+
|
|
321
|
+
## Migrating from 0.2.x
|
|
322
|
+
|
|
323
|
+
Nothing breaks: every 0.2.x method keeps its signature. What changed underneath:
|
|
324
|
+
|
|
325
|
+
- `chat`, `embeddings`, `models` and `feedback` are now **callable resource
|
|
326
|
+
groups** — `codai.chat({...})` still works and `codai.chat.completions.create({...})`
|
|
327
|
+
is the same call with the raw OpenAI body.
|
|
328
|
+
- `ChatResult` gained `eventId`, `toolCalls`, `headers`; `ChatStreamResult` gained
|
|
329
|
+
`finishReason`, `headers`, `usage.cachedTokens`.
|
|
330
|
+
- `CodaiError` gained `code`, `requestId`, `retryAfter`.
|
|
331
|
+
- Streams are no longer subject to `timeoutMs` and are never retried.
|
|
332
|
+
- New client options: `device`, `deviceName`, `devicePlatform`, `client`, `defaults`, `fetch`.
|
|
333
|
+
|
|
157
334
|
## License
|
|
158
335
|
|
|
159
336
|
[MIT](./LICENSE) © codai
|