codai-sdk 0.1.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 +198 -4
- package/dist/index.d.ts +7562 -104
- package/dist/index.js +1476 -190
- 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
|
|
@@ -45,6 +79,47 @@ for await (const delta of codai.chatStream({
|
|
|
45
79
|
}
|
|
46
80
|
```
|
|
47
81
|
|
|
82
|
+
After the stream ends, await `.final` for metadata (request id, token usage,
|
|
83
|
+
which model served, and any tool calls) — e.g. to submit feedback on a
|
|
84
|
+
streamed response:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const stream = codai.chatStream({
|
|
88
|
+
messages: [{ role: 'user', content: 'Write a haiku about TypeScript.' }],
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
for await (const delta of stream) {
|
|
92
|
+
process.stdout.write(delta);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const { requestId, usage, routedTo, toolCalls } = await stream.final;
|
|
96
|
+
if (requestId) await codai.feedback(requestId, 1);
|
|
97
|
+
```
|
|
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
|
+
|
|
48
123
|
## Server-side agent
|
|
49
124
|
|
|
50
125
|
Run a plan-and-execute loop on the gateway — the heavy lifting (planning, tool
|
|
@@ -59,6 +134,75 @@ const run = await codai.agents.run({
|
|
|
59
134
|
console.log(run.result);
|
|
60
135
|
```
|
|
61
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
|
+
|
|
62
206
|
## Feedback
|
|
63
207
|
|
|
64
208
|
```ts
|
|
@@ -97,6 +241,9 @@ const codai = new Codai({
|
|
|
97
241
|
apiKey: process.env.CODAI_API_KEY!,
|
|
98
242
|
baseUrl: 'https://ai.codai.ro', // default
|
|
99
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
|
|
100
247
|
timeoutMs: 120_000,
|
|
101
248
|
maxRetries: 2,
|
|
102
249
|
});
|
|
@@ -104,7 +251,8 @@ const codai = new Codai({
|
|
|
104
251
|
|
|
105
252
|
## codai extensions
|
|
106
253
|
|
|
107
|
-
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:
|
|
108
256
|
|
|
109
257
|
| Option | Description |
|
|
110
258
|
| ----------------- | ----------------------------------------------------------------------- |
|
|
@@ -113,6 +261,35 @@ The chat surface is OpenAI-compatible, with a few opt-in extensions:
|
|
|
113
261
|
| `compact: "auto"` | Server-side context compaction. |
|
|
114
262
|
| `bestOf` | Best-of-N sampling override (`0` disables, `3` forces). |
|
|
115
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
|
+
|
|
116
293
|
## Migrating from the OpenAI SDK
|
|
117
294
|
|
|
118
295
|
The chat payload is OpenAI-shaped, so migration is mostly swapping the client:
|
|
@@ -132,11 +309,28 @@ try {
|
|
|
132
309
|
await codai.chat({ messages: [{ role: 'user', content: 'hi' }] });
|
|
133
310
|
} catch (err) {
|
|
134
311
|
if (err instanceof CodaiError) {
|
|
135
|
-
console.error(err.status, err.
|
|
312
|
+
console.error(err.status, err.code, err.requestId, err.retryAfter, err.body);
|
|
136
313
|
}
|
|
137
314
|
}
|
|
138
315
|
```
|
|
139
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
|
+
|
|
140
334
|
## License
|
|
141
335
|
|
|
142
336
|
[MIT](./LICENSE) © codai
|