@ingram-cloud/sdk 1.2.0 → 1.5.0
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/dist/client.js +185 -14
- package/dist/index.js +4 -0
- package/dist/scopes.js +52 -0
- package/dist/zod/_actor.js +33 -0
- package/dist/zod/_page.js +18 -4
- package/dist/zod/agents.js +17 -3
- package/dist/zod/billing.js +136 -0
- package/dist/zod/budgets.js +2 -3
- package/dist/zod/connections.js +2 -3
- package/dist/zod/conversations.js +4 -11
- package/dist/zod/deployments.js +32 -0
- package/dist/zod/files.js +2 -9
- package/dist/zod/index.js +3 -0
- package/dist/zod/mcp.js +20 -14
- package/dist/zod/observability.js +39 -19
- package/dist/zod/projects.js +4 -4
- package/dist/zod/runs.js +16 -4
- package/dist/zod/schedules.js +2 -7
- package/dist/zod/skills.js +73 -0
- package/dist/zod/smith-revisions.js +7 -5
- package/dist/zod/smiths.js +14 -0
- package/dist/zod/tenant.js +41 -4
- package/dist/zod/vector-stores.js +36 -23
- package/package.json +6 -8
- package/ts/client.ts +431 -50
- package/ts/index.ts +4 -0
- package/ts/responses.ts +40 -2
- package/ts/scopes.ts +57 -0
- package/ts/zod/.impeccable/hook.cache.json +1 -0
- package/ts/zod/_actor.ts +36 -0
- package/ts/zod/_page.ts +19 -4
- package/ts/zod/agents.ts +17 -3
- package/ts/zod/billing.ts +168 -0
- package/ts/zod/budgets.ts +2 -3
- package/ts/zod/connections.ts +2 -3
- package/ts/zod/conversations.ts +7 -11
- package/ts/zod/deployments.ts +36 -0
- package/ts/zod/files.ts +2 -9
- package/ts/zod/index.ts +3 -0
- package/ts/zod/mcp.ts +20 -15
- package/ts/zod/observability.ts +75 -24
- package/ts/zod/projects.ts +4 -4
- package/ts/zod/runs.ts +18 -4
- package/ts/zod/schedules.ts +2 -7
- package/ts/zod/skills.ts +85 -0
- package/ts/zod/smith-revisions.ts +7 -5
- package/ts/zod/smiths.ts +14 -0
- package/ts/zod/tenant.ts +52 -5
- package/ts/zod/vector-stores.ts +41 -23
package/dist/client.js
CHANGED
|
@@ -31,6 +31,52 @@ function qs(query) {
|
|
|
31
31
|
const s = p.toString();
|
|
32
32
|
return s ? `?${s}` : "";
|
|
33
33
|
}
|
|
34
|
+
/** Build the multipart body `/v1/skills` accepts.
|
|
35
|
+
*
|
|
36
|
+
* The path rides the part's *filename*, slashes and all — that is how the
|
|
37
|
+
* bundle's directory structure survives a multipart body. `FormData` in Node,
|
|
38
|
+
* Bun and browsers all pass it through verbatim. */
|
|
39
|
+
function bundleForm(bundle) {
|
|
40
|
+
const form = new FormData();
|
|
41
|
+
if (bundle instanceof Blob) {
|
|
42
|
+
form.append("file", bundle, "bundle.zip");
|
|
43
|
+
return form;
|
|
44
|
+
}
|
|
45
|
+
for (const file of bundle) {
|
|
46
|
+
// A `Uint8Array`'s buffer type is generic (and may be a `SharedArrayBuffer`),
|
|
47
|
+
// which `Blob`'s constructor does not accept — copy into a fresh one, whose
|
|
48
|
+
// buffer is always a plain `ArrayBuffer`.
|
|
49
|
+
const part = typeof file.content === "string" || file.content instanceof Blob
|
|
50
|
+
? file.content
|
|
51
|
+
: new Uint8Array(file.content);
|
|
52
|
+
const blob = part instanceof Blob
|
|
53
|
+
? part
|
|
54
|
+
: new Blob([part], { type: mediaTypeFor(file.path) });
|
|
55
|
+
form.append("files[]", blob, file.path);
|
|
56
|
+
}
|
|
57
|
+
return form;
|
|
58
|
+
}
|
|
59
|
+
/** A `Blob` built from a string has no type of its own; the server falls back to
|
|
60
|
+
* `application/octet-stream` when a part carries none, which would make every
|
|
61
|
+
* text file non-indexable. Name the common ones from the extension. */
|
|
62
|
+
function mediaTypeFor(path) {
|
|
63
|
+
const ext = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
64
|
+
const known = {
|
|
65
|
+
md: "text/markdown",
|
|
66
|
+
markdown: "text/markdown",
|
|
67
|
+
txt: "text/plain",
|
|
68
|
+
json: "application/json",
|
|
69
|
+
yaml: "text/yaml",
|
|
70
|
+
yml: "text/yaml",
|
|
71
|
+
csv: "text/csv",
|
|
72
|
+
py: "text/x-python",
|
|
73
|
+
sh: "text/x-shellscript",
|
|
74
|
+
js: "text/javascript",
|
|
75
|
+
ts: "text/typescript",
|
|
76
|
+
html: "text/html",
|
|
77
|
+
};
|
|
78
|
+
return known[ext] ?? "application/octet-stream";
|
|
79
|
+
}
|
|
34
80
|
export class IngramCloud {
|
|
35
81
|
token;
|
|
36
82
|
base;
|
|
@@ -121,14 +167,14 @@ export class IngramCloud {
|
|
|
121
167
|
}),
|
|
122
168
|
},
|
|
123
169
|
revisions: {
|
|
124
|
-
list: (pid, opts) => this.
|
|
170
|
+
list: (pid, query, opts) => this.page(`/smiths/${enc(pid)}/revisions`, query, opts),
|
|
125
171
|
restore: (pid, version, body = {}, opts) => this.json("POST", `/smiths/${enc(pid)}/revisions/${version}/restore`, {
|
|
126
172
|
...opts,
|
|
127
173
|
body,
|
|
128
174
|
}),
|
|
129
175
|
},
|
|
130
176
|
connections: {
|
|
131
|
-
list: (pid, opts) => this.
|
|
177
|
+
list: (pid, query, opts) => this.page(`/smiths/${enc(pid)}/connections`, query, opts),
|
|
132
178
|
get: (pid, cid, opts) => this.json("GET", `/smiths/${enc(pid)}/connections/${enc(cid)}`, opts),
|
|
133
179
|
create: (pid, body, opts) => this.json("POST", `/smiths/${enc(pid)}/connections`, {
|
|
134
180
|
...opts,
|
|
@@ -143,8 +189,15 @@ export class IngramCloud {
|
|
|
143
189
|
body,
|
|
144
190
|
}),
|
|
145
191
|
},
|
|
192
|
+
/** End-user BYOK (#170): a smith's own provider keys, resolved ahead of the
|
|
193
|
+
* tenant's so the end-user's provider account is billed. Never read back. */
|
|
194
|
+
modelKeys: {
|
|
195
|
+
list: (pid, opts) => this.data("GET", `/smiths/${enc(pid)}/model_keys`, opts),
|
|
196
|
+
put: (pid, provider, body, opts) => this.json("PUT", `/smiths/${enc(pid)}/model_keys/${enc(provider)}`, { ...opts, body }),
|
|
197
|
+
delete: (pid, provider, opts) => this.empty("DELETE", `/smiths/${enc(pid)}/model_keys/${enc(provider)}`, opts),
|
|
198
|
+
},
|
|
146
199
|
schedules: {
|
|
147
|
-
list: (pid, opts) => this.
|
|
200
|
+
list: (pid, query, opts) => this.page(`/smiths/${enc(pid)}/schedules`, query, opts),
|
|
148
201
|
create: (pid, body, opts) => this.json("POST", `/smiths/${enc(pid)}/schedules`, {
|
|
149
202
|
...opts,
|
|
150
203
|
body,
|
|
@@ -206,6 +259,7 @@ export class IngramCloud {
|
|
|
206
259
|
// ── Runs (tenant-wide feed) ─────────────────────────────────────────────
|
|
207
260
|
runs = {
|
|
208
261
|
list: (query, opts) => this.page("/runs", query, opts),
|
|
262
|
+
trace: (rid, opts) => this.json("GET", `/runs/${enc(rid)}/trace`, opts),
|
|
209
263
|
};
|
|
210
264
|
// ── Agents ──────────────────────────────────────────────────────────────
|
|
211
265
|
agents = {
|
|
@@ -215,7 +269,7 @@ export class IngramCloud {
|
|
|
215
269
|
update: (aid, body, opts) => this.json("PATCH", `/agents/${enc(aid)}`, { ...opts, body }),
|
|
216
270
|
delete: (aid, opts) => this.empty("DELETE", `/agents/${enc(aid)}`, opts),
|
|
217
271
|
versions: {
|
|
218
|
-
list: (aid, opts) => this.
|
|
272
|
+
list: (aid, query, opts) => this.page(`/agents/${enc(aid)}/versions`, query, opts),
|
|
219
273
|
/** Snapshot the draft as the next immutable version. */
|
|
220
274
|
publish: (aid, body = {}, opts) => this.json("POST", `/agents/${enc(aid)}/versions`, {
|
|
221
275
|
...opts,
|
|
@@ -239,19 +293,32 @@ export class IngramCloud {
|
|
|
239
293
|
* `{ name, csp?, permissions?, tool? }` sidecar. Replaces by name. */
|
|
240
294
|
put: (aid, html, meta, opts) => {
|
|
241
295
|
const form = new FormData();
|
|
242
|
-
form.append("file", html instanceof Blob
|
|
296
|
+
form.append("file", html instanceof Blob
|
|
297
|
+
? html
|
|
298
|
+
: new Blob([html], { type: "text/html" }), `${meta.name}.html`);
|
|
243
299
|
form.append("metadata", JSON.stringify(meta));
|
|
244
300
|
return this.json("POST", `/agents/${enc(aid)}/ui`, {
|
|
245
301
|
...opts,
|
|
246
302
|
rawBody: form,
|
|
247
303
|
});
|
|
248
304
|
},
|
|
249
|
-
|
|
305
|
+
/** The template's HTML bundle — the same bytes the agent's MCP endpoint
|
|
306
|
+
* serves, so a host can render a panel without vendoring a copy.
|
|
307
|
+
* Tenant-authed: call it server-side and proxy to your chat UI. */
|
|
308
|
+
content: (aid, name, opts) => this.request("GET", `/agents/${enc(aid)}/ui/${enc(name)}/content`, {
|
|
309
|
+
...opts,
|
|
310
|
+
headers: { accept: "text/html", ...opts?.headers },
|
|
311
|
+
}).then((r) => r.text()),
|
|
312
|
+
delete: (aid, name, opts) => this.empty("DELETE", `/agents/${enc(aid)}/ui/${enc(name)}`, opts),
|
|
250
313
|
},
|
|
251
314
|
};
|
|
252
315
|
// ── Conversations (smith-scoped: pass `{ smith }` with a tenant token) ──
|
|
253
316
|
conversations = {
|
|
254
|
-
list
|
|
317
|
+
/** OpenAI `list` envelope; page forward with `after: page.last_id`. */
|
|
318
|
+
list: (query, opts) => this.json("GET", "/conversations", {
|
|
319
|
+
...opts,
|
|
320
|
+
query,
|
|
321
|
+
}),
|
|
255
322
|
create: (body = {}, opts) => this.json("POST", "/conversations", { ...opts, body }),
|
|
256
323
|
get: (cnvId, opts) => this.json("GET", `/conversations/${enc(cnvId)}`, opts),
|
|
257
324
|
/** OpenAI-style modify — a POST, not a PATCH. */
|
|
@@ -274,6 +341,13 @@ export class IngramCloud {
|
|
|
274
341
|
events = {
|
|
275
342
|
list: (query, opts) => this.page("/events", query, opts),
|
|
276
343
|
};
|
|
344
|
+
/** What arrived, before anything interpreted it — including arrivals that
|
|
345
|
+
* matched no smith (`smith_id: ""`). The `iev_` ids `deployment.inbound`
|
|
346
|
+
* carries resolve here. */
|
|
347
|
+
inboundEvents = {
|
|
348
|
+
list: (query, opts) => this.page("/inbound_events", query, opts),
|
|
349
|
+
get: (ievId, opts) => this.json("GET", `/inbound_events/${enc(ievId)}`, opts),
|
|
350
|
+
};
|
|
277
351
|
// ── Customers / budgets ─────────────────────────────────────────────────
|
|
278
352
|
customers = {
|
|
279
353
|
list: (query, opts) => this.page("/customers", query, opts),
|
|
@@ -283,7 +357,7 @@ export class IngramCloud {
|
|
|
283
357
|
delete: (cid, opts) => this.empty("DELETE", `/customers/${enc(cid)}`, opts),
|
|
284
358
|
};
|
|
285
359
|
budgets = {
|
|
286
|
-
list: (opts) => this.
|
|
360
|
+
list: (query, opts) => this.page("/budgets", query, opts),
|
|
287
361
|
create: (body, opts) => this.json("POST", "/budgets", { ...opts, body }),
|
|
288
362
|
get: (bid, opts) => this.json("GET", `/budgets/${enc(bid)}`, opts),
|
|
289
363
|
update: (bid, body, opts) => this.json("PATCH", `/budgets/${enc(bid)}`, { ...opts, body }),
|
|
@@ -306,10 +380,25 @@ export class IngramCloud {
|
|
|
306
380
|
list: (opts) => this.data("GET", "/catalog", opts),
|
|
307
381
|
get: (slug, opts) => this.json("GET", `/catalog/${enc(slug)}`, opts),
|
|
308
382
|
};
|
|
383
|
+
// ── Embeddings ──────────────────────────────────────────────────────────
|
|
384
|
+
/** Embed one string or a batch on the OpenAI-compatible wire. Pure tenant
|
|
385
|
+
* compute — no smith runs. Omit `model` for the project default. Reach for
|
|
386
|
+
* the `openai` SDK instead if you already hold one; this is the same route. */
|
|
387
|
+
embeddings = {
|
|
388
|
+
create: (body, opts) => this.json("POST", "/embeddings", { ...opts, body }),
|
|
389
|
+
};
|
|
309
390
|
// ── Observability ───────────────────────────────────────────────────────
|
|
310
391
|
traces = {
|
|
311
392
|
list: (query, opts) => this.page("/traces", query, opts),
|
|
312
393
|
get: (traceId, opts) => this.json("GET", `/traces/${enc(traceId)}`, opts),
|
|
394
|
+
/** Push spans from your own runtime or an OTel exporter. The tenant comes
|
|
395
|
+
* from the token; a smith-scoped token may only attribute to its own smith.
|
|
396
|
+
* Unknown `kind`s land as `runtime_event` rather than erroring. Returns the
|
|
397
|
+
* number written. */
|
|
398
|
+
ingest: (spans, opts) => this.json("POST", "/traces:ingest", {
|
|
399
|
+
...opts,
|
|
400
|
+
body: { spans },
|
|
401
|
+
}),
|
|
313
402
|
};
|
|
314
403
|
usage = {
|
|
315
404
|
/** Token/cost/run totals grouped by app, smith, model, or customer. */
|
|
@@ -338,10 +427,16 @@ export class IngramCloud {
|
|
|
338
427
|
// ── Vector stores (the OpenAI Vector Stores API) ─────────────────────────
|
|
339
428
|
vectorStores = {
|
|
340
429
|
create: (body, opts) => this.json("POST", "/vector_stores", { ...opts, body }),
|
|
341
|
-
list: (query, opts) => this.json("GET", "/vector_stores", {
|
|
430
|
+
list: (query, opts) => this.json("GET", "/vector_stores", {
|
|
431
|
+
...opts,
|
|
432
|
+
query,
|
|
433
|
+
}),
|
|
342
434
|
get: (vsId, opts) => this.json("GET", `/vector_stores/${enc(vsId)}`, opts),
|
|
343
435
|
/** Modify (OpenAI uses `POST`, not `PATCH`). */
|
|
344
|
-
update: (vsId, body, opts) => this.json("POST", `/vector_stores/${enc(vsId)}`, {
|
|
436
|
+
update: (vsId, body, opts) => this.json("POST", `/vector_stores/${enc(vsId)}`, {
|
|
437
|
+
...opts,
|
|
438
|
+
body,
|
|
439
|
+
}),
|
|
345
440
|
delete: (vsId, opts) => this.json("DELETE", `/vector_stores/${enc(vsId)}`, opts),
|
|
346
441
|
search: (vsId, body, opts) => this.json("POST", `/vector_stores/${enc(vsId)}/search`, {
|
|
347
442
|
...opts,
|
|
@@ -364,6 +459,34 @@ export class IngramCloud {
|
|
|
364
459
|
files: (vsId, batchId, query, opts) => this.json("GET", `/vector_stores/${enc(vsId)}/file_batches/${enc(batchId)}/files`, { ...opts, query }),
|
|
365
460
|
},
|
|
366
461
|
};
|
|
462
|
+
// ── Agent Skills — a folder anchored by SKILL.md, versioned, attached to
|
|
463
|
+
// agents. Upload takes either the bundle's files as path/content pairs, or
|
|
464
|
+
// the whole bundle as a zip Blob — the same two shapes /v1/skills accepts.
|
|
465
|
+
// Both are runtime-agnostic: nothing here touches a filesystem. ───────────
|
|
466
|
+
skills = {
|
|
467
|
+
list: (opts) => this.json("GET", "/skills", opts),
|
|
468
|
+
get: (id, opts) => this.json("GET", `/skills/${enc(id)}`, opts),
|
|
469
|
+
create: (bundle, opts) => this.json("POST", "/skills", {
|
|
470
|
+
...opts,
|
|
471
|
+
rawBody: bundleForm(bundle),
|
|
472
|
+
}),
|
|
473
|
+
/** Move `default_version` to an existing version. */
|
|
474
|
+
update: (id, body, opts) => this.json("POST", `/skills/${enc(id)}`, {
|
|
475
|
+
...opts,
|
|
476
|
+
body,
|
|
477
|
+
}),
|
|
478
|
+
delete: (id, opts) => this.request("DELETE", `/skills/${enc(id)}`, opts).then(() => undefined),
|
|
479
|
+
versions: {
|
|
480
|
+
list: (id, opts) => this.json("GET", `/skills/${enc(id)}/versions`, opts),
|
|
481
|
+
get: (id, version, opts) => this.json("GET", `/skills/${enc(id)}/versions/${version}`, opts),
|
|
482
|
+
create: (id, bundle, opts) => this.json("POST", `/skills/${enc(id)}/versions`, { ...opts, rawBody: bundleForm(bundle) }),
|
|
483
|
+
delete: (id, version, opts) => this.request("DELETE", `/skills/${enc(id)}/versions/${version}`, opts).then(() => undefined),
|
|
484
|
+
/** One file's bytes, or — with no `path` — the whole version as a zip.
|
|
485
|
+
* The raw `Response` (matching `files.content`), so a caller streams it
|
|
486
|
+
* through rather than buffering the whole zip into memory. */
|
|
487
|
+
content: (id, version, path, opts) => this.request("GET", `/skills/${enc(id)}/versions/${version}/content${path ? `?path=${encodeURIComponent(path)}` : ""}`, opts),
|
|
488
|
+
},
|
|
489
|
+
};
|
|
367
490
|
// ── Tenant config ───────────────────────────────────────────────────────
|
|
368
491
|
tenant = {
|
|
369
492
|
usage: (opts) => this.json("GET", "/tenant/usage", opts),
|
|
@@ -384,6 +507,9 @@ export class IngramCloud {
|
|
|
384
507
|
body,
|
|
385
508
|
}),
|
|
386
509
|
delete: (wid, opts) => this.empty("DELETE", `/tenant/webhooks/${enc(wid)}`, opts),
|
|
510
|
+
/** Rotate the signing secret, returning the new one exactly once. Pass
|
|
511
|
+
* `grace_seconds` to keep the old secret accepted during an overlap window. */
|
|
512
|
+
rotateSecret: (wid, body, opts) => this.json("POST", `/tenant/webhooks/${enc(wid)}/rotate_secret`, { ...opts, body: body ?? {} }),
|
|
387
513
|
test: (wid, opts) => this.json("POST", `/tenant/webhooks/${enc(wid)}/test`, opts),
|
|
388
514
|
/** The persisted delivery attempts for a webhook (durable retry audit trail). */
|
|
389
515
|
deliveries: (wid, query, opts) => this.page(`/tenant/webhooks/${enc(wid)}/deliveries`, query, opts),
|
|
@@ -409,10 +535,13 @@ export class IngramCloud {
|
|
|
409
535
|
delete: (provider, opts) => this.empty("DELETE", `/tenant/model_keys/${enc(provider)}`, opts),
|
|
410
536
|
},
|
|
411
537
|
mcp: {
|
|
412
|
-
list: (opts) => this.
|
|
538
|
+
list: (query, opts) => this.page("/tenant/mcp", query, opts),
|
|
413
539
|
get: (name, opts) => this.json("GET", `/tenant/mcp/${enc(name)}`, opts),
|
|
414
540
|
/** Register or replace a server (full replace; probes `tools/list`). */
|
|
415
|
-
put: (name, body, opts) => this.json("PUT", `/tenant/mcp/${enc(name)}`, {
|
|
541
|
+
put: (name, body, opts) => this.json("PUT", `/tenant/mcp/${enc(name)}`, {
|
|
542
|
+
...opts,
|
|
543
|
+
body,
|
|
544
|
+
}),
|
|
416
545
|
refresh: (name, opts) => this.json("POST", `/tenant/mcp/${enc(name)}/refresh`, opts),
|
|
417
546
|
delete: (name, opts) => this.empty("DELETE", `/tenant/mcp/${enc(name)}`, opts),
|
|
418
547
|
},
|
|
@@ -456,10 +585,52 @@ export class IngramCloud {
|
|
|
456
585
|
decline: (requestId, opts) => this.json("POST", `/oauth/authorize-requests/${enc(requestId)}/decline`, opts),
|
|
457
586
|
},
|
|
458
587
|
};
|
|
459
|
-
// ── Organization (org token: projects
|
|
588
|
+
// ── Organization (org token: projects, tokens, billing) ─────────────────
|
|
460
589
|
organization = {
|
|
590
|
+
/** Platform credits — the org wallet that funds every project's runs.
|
|
591
|
+
* Amounts are integer minor units of the wallet's `currency`. */
|
|
592
|
+
billing: {
|
|
593
|
+
balance: (opts) => this.json("GET", "/organization/billing/balance", opts),
|
|
594
|
+
/** Money in (top-ups, grants, codes) and out (usage debits), newest first. */
|
|
595
|
+
ledger: (query, opts) => this.page("/organization/billing/ledger", query, opts),
|
|
596
|
+
/** Per-project draw for a calendar month (`period`, `YYYY-MM`). */
|
|
597
|
+
usage: (query, opts) => this.json("GET", "/organization/billing/usage", {
|
|
598
|
+
...opts,
|
|
599
|
+
query,
|
|
600
|
+
}),
|
|
601
|
+
/** Daily per-project draw over a rolling window of `days`. */
|
|
602
|
+
usageSeries: (query, opts) => this.json("GET", "/organization/billing/usage/series", {
|
|
603
|
+
...opts,
|
|
604
|
+
query,
|
|
605
|
+
}),
|
|
606
|
+
/** Open a Stripe Checkout Session to top up; send the user to its `url`. */
|
|
607
|
+
checkout: (body, opts) => this.json("POST", "/organization/billing/checkout", { ...opts, body }),
|
|
608
|
+
/** Add a card with no charge, unlocking the one-time welcome credit. */
|
|
609
|
+
setup: (body, opts) => this.json("POST", "/organization/billing/setup", {
|
|
610
|
+
...opts,
|
|
611
|
+
body,
|
|
612
|
+
}),
|
|
613
|
+
redeem: (body, opts) => this.json("POST", "/organization/billing/redeem", { ...opts, body }),
|
|
614
|
+
/** Credit a returning Checkout Session. Safe to call twice — the ledger
|
|
615
|
+
* keys on the session id, so it can't double-credit. */
|
|
616
|
+
confirm: (body, opts) => this.json("POST", "/organization/billing/confirm", { ...opts, body }),
|
|
617
|
+
autoreload: {
|
|
618
|
+
get: (opts) => this.json("GET", "/organization/billing/autoreload", opts),
|
|
619
|
+
put: (body, opts) => this.json("PUT", "/organization/billing/autoreload", {
|
|
620
|
+
...opts,
|
|
621
|
+
body,
|
|
622
|
+
}),
|
|
623
|
+
},
|
|
624
|
+
/** Charge the saved card now. `amount_cents` defaults to the auto-reload amount. */
|
|
625
|
+
reload: (body, opts) => this.json("POST", "/organization/billing/reload", { ...opts, body: body ?? {} }),
|
|
626
|
+
/** A Stripe billing-portal URL for managing cards and invoices. */
|
|
627
|
+
portal: (query, opts) => this.json("GET", "/organization/billing/portal", {
|
|
628
|
+
...opts,
|
|
629
|
+
query,
|
|
630
|
+
}),
|
|
631
|
+
},
|
|
461
632
|
projects: {
|
|
462
|
-
list: (opts) => this.
|
|
633
|
+
list: (query, opts) => this.page("/organization/projects", query, opts),
|
|
463
634
|
create: (body, opts) => this.json("POST", "/organization/projects", {
|
|
464
635
|
...opts,
|
|
465
636
|
body,
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,11 @@
|
|
|
13
13
|
* `./events` is the hand-authored `{v:1}` webhook/feed envelope and the SSE
|
|
14
14
|
* run-stream frames, which OpenAPI can't express.
|
|
15
15
|
*
|
|
16
|
+
* `./scopes` is the closed permission vocabulary a smith token may carry — you
|
|
17
|
+
* must name the scopes you want when minting one.
|
|
18
|
+
*
|
|
16
19
|
* See `../README.md`.
|
|
17
20
|
*/
|
|
18
21
|
export { schemas } from "./schemas.js";
|
|
19
22
|
export * from "./events.js";
|
|
23
|
+
export * from "./scopes.js";
|
package/dist/scopes.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The closed permission vocabulary a smith token may carry, in mint order.
|
|
3
|
+
*
|
|
4
|
+
* It lives here rather than in the API because it is wire contract: a caller
|
|
5
|
+
* minting a token has to name the scopes it wants (`permissions` is required —
|
|
6
|
+
* there is no "grant everything" default), and the console's token form needs
|
|
7
|
+
* the same list to offer full access. One definition, so a new scope reaches
|
|
8
|
+
* every minting surface at once instead of drifting into a stale copy.
|
|
9
|
+
*
|
|
10
|
+
* Not in here: the admin markers (`tenant:*`, `operator:*`) and the account key
|
|
11
|
+
* (`organization:*`). Those are postures, not permissions — they are never a
|
|
12
|
+
* legal `permissions` entry, and the API refuses them as unknown scopes.
|
|
13
|
+
*/
|
|
14
|
+
export const V1_SCOPES = [
|
|
15
|
+
"runs:read",
|
|
16
|
+
"runs:write",
|
|
17
|
+
"conversations:read",
|
|
18
|
+
"conversations:write",
|
|
19
|
+
"memories:read",
|
|
20
|
+
"memories:write",
|
|
21
|
+
"connections:read",
|
|
22
|
+
"connections:write",
|
|
23
|
+
"deployments:read",
|
|
24
|
+
"deployments:write",
|
|
25
|
+
"schedules:read",
|
|
26
|
+
"schedules:write",
|
|
27
|
+
"approvals:read",
|
|
28
|
+
"approvals:write",
|
|
29
|
+
"traces:read",
|
|
30
|
+
"traces:write",
|
|
31
|
+
"usage:read",
|
|
32
|
+
"usage:write",
|
|
33
|
+
"customers:read",
|
|
34
|
+
"customers:write",
|
|
35
|
+
"files:read",
|
|
36
|
+
"files:write",
|
|
37
|
+
"vector_stores:read",
|
|
38
|
+
"vector_stores:write",
|
|
39
|
+
// Smith-level provider keys (#170, end-user BYOK): an end-user sets their own
|
|
40
|
+
// key; a tenant token manages any of its smiths' keys.
|
|
41
|
+
"model_keys:read",
|
|
42
|
+
"model_keys:write",
|
|
43
|
+
// Agent Skills (#175): a tenant's skill bundles and their immutable versions.
|
|
44
|
+
"skills:read",
|
|
45
|
+
"skills:write",
|
|
46
|
+
// Embeddings: the stateless text→vector compute endpoint (POST /v1/embeddings).
|
|
47
|
+
// Write-only — it produces a result, it reads no stored state.
|
|
48
|
+
"embeddings:write",
|
|
49
|
+
];
|
|
50
|
+
/** The read half of the vocabulary — the scope set for a token that must not
|
|
51
|
+
* change anything. Derived, so it cannot fall behind {@link V1_SCOPES}. */
|
|
52
|
+
export const V1_READ_SCOPES = V1_SCOPES.filter((s) => s.endsWith(":read"));
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The acting principal — who a run or an event is attributable to.
|
|
3
|
+
*
|
|
4
|
+
* Resolved from the authenticated caller at the point of action and stamped on
|
|
5
|
+
* the record it produced; never inferred afterwards. Every event a run produces
|
|
6
|
+
* inherits the run's actor, so a whole turn is attributable to one identity.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
export const Actor = z
|
|
10
|
+
.object({
|
|
11
|
+
/** `smith` — a smith acted (a smith-bound token, or the smith itself on an
|
|
12
|
+
* autonomous turn); `tenant` — a tenant-admin token acted on a smith's
|
|
13
|
+
* behalf; `operator` — Ingram staff acted through the operator console. */
|
|
14
|
+
kind: z.enum(["smith", "tenant", "operator"]),
|
|
15
|
+
/** The smith id, tenant id, or operator email, per `kind`. */
|
|
16
|
+
id: z.string(),
|
|
17
|
+
/** `jti` of the token that authorized the action. Empty when no token
|
|
18
|
+
* acted — a scheduled or channel-driven turn the platform ran itself, or a
|
|
19
|
+
* console session, which signs a short-lived per-request token that is never
|
|
20
|
+
* registered. Read it with `email`: both empty means the platform acted. */
|
|
21
|
+
token_id: z.string(),
|
|
22
|
+
/** The human behind the action, when one is named — the signed-in console user
|
|
23
|
+
* or the Ingram operator. Empty for a machine caller (an API token, a smith
|
|
24
|
+
* acting for itself) and for autonomous work.
|
|
25
|
+
*
|
|
26
|
+
* This is what makes a config change attributable to a *person* rather than to
|
|
27
|
+
* the tenant they share: console mutations all carry `kind: "tenant"`, so
|
|
28
|
+
* without this every colleague's action looked identical. Defaulted rather than
|
|
29
|
+
* optional so records written before it existed read as "no human named"
|
|
30
|
+
* instead of failing to parse. */
|
|
31
|
+
email: z.string().default(""),
|
|
32
|
+
})
|
|
33
|
+
.meta({ id: "Actor" });
|
package/dist/zod/_page.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* The two `/v1` list envelopes, one definition each. Native resources page by
|
|
3
|
+
* keyset: `data` + the opaque `next_cursor` (null on the last page) + `has_more`
|
|
4
|
+
* — the cursor is an opaque, short-lived token; pass it straight back as
|
|
5
|
+
* `?cursor=`, never parse it. OpenAI-mirrored resources use the OpenAI `list`
|
|
6
|
+
* envelope instead: `object:"list"` + `first_id`/`last_id` + `has_more`, paged
|
|
7
|
+
* by passing `last_id` back as `?after=`.
|
|
6
8
|
*/
|
|
7
9
|
import { z } from "zod";
|
|
8
10
|
/** Wrap an item schema as a cursor-paginated list out, named `id` in the spec. */
|
|
@@ -15,3 +17,15 @@ export function pageOut(item, id) {
|
|
|
15
17
|
})
|
|
16
18
|
.meta({ id });
|
|
17
19
|
}
|
|
20
|
+
/** Wrap an item schema in the OpenAI `list` envelope, named `id` in the spec. */
|
|
21
|
+
export function oaiListOut(item, id) {
|
|
22
|
+
return z
|
|
23
|
+
.object({
|
|
24
|
+
object: z.literal("list"),
|
|
25
|
+
data: z.array(item),
|
|
26
|
+
first_id: z.string().nullable(),
|
|
27
|
+
last_id: z.string().nullable(),
|
|
28
|
+
has_more: z.boolean(),
|
|
29
|
+
})
|
|
30
|
+
.meta({ id });
|
|
31
|
+
}
|
package/dist/zod/agents.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
import { pageOut } from "./_page.js";
|
|
16
|
+
import { SkillRef } from "./skills.js";
|
|
16
17
|
/** A per-smith variable an agent declares; bound at run time. */
|
|
17
18
|
export const AgentVariable = z
|
|
18
19
|
.object({
|
|
@@ -67,6 +68,10 @@ export const AgentDraft = z
|
|
|
67
68
|
model: z.string().nullable(),
|
|
68
69
|
enabled_hosted_tools: z.array(z.string()),
|
|
69
70
|
vector_store_ids: z.array(z.string()),
|
|
71
|
+
/** Registered MCP servers this agent's smiths load, by name. Null = all. */
|
|
72
|
+
mcp_servers: z.array(z.string()).nullable(),
|
|
73
|
+
/** Skills this agent's smiths carry. Frozen into the snapshot at publish. */
|
|
74
|
+
skills: z.array(SkillRef),
|
|
70
75
|
auto_memory: z.boolean().nullable(),
|
|
71
76
|
memory_consolidation: z.boolean().nullable(),
|
|
72
77
|
variables: z.array(AgentVariable),
|
|
@@ -87,6 +92,8 @@ export const AgentOut = z
|
|
|
87
92
|
rollout_version: z.number().int().nullable(),
|
|
88
93
|
rollout_percent: z.number().int(),
|
|
89
94
|
smith_count: z.number().int().optional(),
|
|
95
|
+
/** Newest run across every smith of this agent. Null until one runs. */
|
|
96
|
+
last_activity_at: z.string().nullable().optional(),
|
|
90
97
|
created_at: z.string().nullable(),
|
|
91
98
|
updated_at: z.string().nullable(),
|
|
92
99
|
})
|
|
@@ -101,6 +108,8 @@ export const AgentVersionOut = z
|
|
|
101
108
|
model: z.string().nullish(),
|
|
102
109
|
enabled_hosted_tools: z.array(z.string()).optional(),
|
|
103
110
|
vector_store_ids: z.array(z.string()).optional(),
|
|
111
|
+
mcp_servers: z.array(z.string()).nullish(),
|
|
112
|
+
skills: z.array(SkillRef).optional(),
|
|
104
113
|
auto_memory: z.boolean().nullish(),
|
|
105
114
|
memory_consolidation: z.boolean().nullish(),
|
|
106
115
|
variables: z.array(AgentVariable).optional(),
|
|
@@ -111,9 +120,7 @@ export const AgentVersionOut = z
|
|
|
111
120
|
created_at: z.string().nullable(),
|
|
112
121
|
})
|
|
113
122
|
.meta({ id: "AgentVersionOut" });
|
|
114
|
-
export const AgentVersionListOut =
|
|
115
|
-
.object({ data: z.array(AgentVersionOut) })
|
|
116
|
-
.meta({ id: "AgentVersionListOut" });
|
|
123
|
+
export const AgentVersionListOut = pageOut(AgentVersionOut, "AgentVersionListOut");
|
|
117
124
|
// ── Request bodies ──────────────────────────────────────────────────────────
|
|
118
125
|
export const AgentIn = z
|
|
119
126
|
.object({
|
|
@@ -123,6 +130,9 @@ export const AgentIn = z
|
|
|
123
130
|
model: z.string().nullish(),
|
|
124
131
|
enabled_hosted_tools: z.array(z.string()).nullish(),
|
|
125
132
|
vector_store_ids: z.array(z.string()).nullish(),
|
|
133
|
+
/** Scope runs to these registered MCP servers (by name). Null/omitted = all. */
|
|
134
|
+
mcp_servers: z.array(z.string()).nullish(),
|
|
135
|
+
skills: z.array(SkillRef).nullish(),
|
|
126
136
|
auto_memory: z.boolean().nullish(),
|
|
127
137
|
memory_consolidation: z.boolean().nullish(),
|
|
128
138
|
variables: z.array(AgentVariable).nullish(),
|
|
@@ -135,6 +145,10 @@ export const AgentPatch = z
|
|
|
135
145
|
model: z.string().nullish(),
|
|
136
146
|
enabled_hosted_tools: z.array(z.string()).nullish(),
|
|
137
147
|
vector_store_ids: z.array(z.string()).nullish(),
|
|
148
|
+
/** Scope runs to these registered MCP servers (by name). An explicit null
|
|
149
|
+
* clears the restriction (= all); omitted leaves it unchanged. */
|
|
150
|
+
mcp_servers: z.array(z.string()).nullish(),
|
|
151
|
+
skills: z.array(SkillRef).nullish(),
|
|
138
152
|
auto_memory: z.boolean().nullish(),
|
|
139
153
|
memory_consolidation: z.boolean().nullish(),
|
|
140
154
|
variables: z.array(AgentVariable).nullish(),
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand-authored Zod schemas for platform credits — the org wallet the tenant
|
|
3
|
+
* funds to pay *Ingram* (`/v1/organization/billing/*`). One wallet pools across
|
|
4
|
+
* all of the org's projects; every endpoint needs an organization-scoped token.
|
|
5
|
+
*
|
|
6
|
+
* Source of truth is the handler (`api/src/routes/billing.ts`), which imports
|
|
7
|
+
* these for request validation and response typing. Amounts are always integer
|
|
8
|
+
* **minor units** (cents) of `currency` (ISO-4217, lower-case) — never floats.
|
|
9
|
+
*
|
|
10
|
+
* The per-endpoint query schemas stay in the handler: they carry OpenAPI
|
|
11
|
+
* `param` metadata, and the client types query args as plain TS.
|
|
12
|
+
*
|
|
13
|
+
* `.meta({ id })` names the component so the emitted OpenAPI references it as
|
|
14
|
+
* `#/components/schemas/<id>` rather than inlining it.
|
|
15
|
+
*/
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
// ── Balance + ledger ────────────────────────────────────────────────────────
|
|
18
|
+
export const BalanceOut = z
|
|
19
|
+
.object({
|
|
20
|
+
/** ISO-4217, lower-case. Clients format `balance_cents` in this currency. */
|
|
21
|
+
currency: z.string(),
|
|
22
|
+
balance_cents: z.number().int(),
|
|
23
|
+
/** Whether the org has a Stripe Customer yet (materialized on first payment). */
|
|
24
|
+
stripe_customer: z.boolean(),
|
|
25
|
+
})
|
|
26
|
+
.meta({ id: "BalanceOut" });
|
|
27
|
+
/** One credit-ledger row. `amount_cents` is positive for money in (top-ups,
|
|
28
|
+
* grants, redeemed codes) and negative for usage debits. */
|
|
29
|
+
export const LedgerEntryOut = z
|
|
30
|
+
.object({
|
|
31
|
+
id: z.string(),
|
|
32
|
+
amount_cents: z.number().int(),
|
|
33
|
+
currency: z.string(),
|
|
34
|
+
kind: z.string(),
|
|
35
|
+
description: z.string(),
|
|
36
|
+
created_at: z.string().nullable(),
|
|
37
|
+
})
|
|
38
|
+
.meta({ id: "LedgerEntryOut" });
|
|
39
|
+
/** A page of ledger rows (keyset pagination). */
|
|
40
|
+
export const LedgerListOut = z
|
|
41
|
+
.object({
|
|
42
|
+
data: z.array(LedgerEntryOut),
|
|
43
|
+
next_cursor: z.string().nullable(),
|
|
44
|
+
has_more: z.boolean(),
|
|
45
|
+
})
|
|
46
|
+
.meta({ id: "LedgerListOut" });
|
|
47
|
+
// ── Per-project draw from the wallet ────────────────────────────────────────
|
|
48
|
+
/** One project's draw for a calendar month — which project is spending the
|
|
49
|
+
* shared funds, and against what cap. */
|
|
50
|
+
export const OrgUsageProject = z
|
|
51
|
+
.object({
|
|
52
|
+
project_id: z.string(),
|
|
53
|
+
name: z.string(),
|
|
54
|
+
/** Credits drawn this period (sum of the project's debit rows). */
|
|
55
|
+
drawn_cents: z.number().int(),
|
|
56
|
+
/** Tokens the project's runs consumed this period (priced daily rollup). */
|
|
57
|
+
tokens: z.number().int(),
|
|
58
|
+
/** The project's tenant-scope budget limit (billing currency, major units),
|
|
59
|
+
* or null when it draws freely from the org wallet. */
|
|
60
|
+
budget_limit: z.number().nullable(),
|
|
61
|
+
budget_action: z.string().nullable(),
|
|
62
|
+
})
|
|
63
|
+
.meta({ id: "OrgUsageProject" });
|
|
64
|
+
export const OrgUsageOut = z
|
|
65
|
+
.object({
|
|
66
|
+
period: z.string(),
|
|
67
|
+
currency: z.string(),
|
|
68
|
+
total_drawn_cents: z.number().int(),
|
|
69
|
+
total_tokens: z.number().int(),
|
|
70
|
+
projects: z.array(OrgUsageProject),
|
|
71
|
+
})
|
|
72
|
+
.meta({ id: "OrgUsageOut" });
|
|
73
|
+
/** One day/project draw. Points are sparse — a day with no draw is absent, and
|
|
74
|
+
* the client fills the gaps with zero. */
|
|
75
|
+
export const OrgUsageSeriesPoint = z
|
|
76
|
+
.object({
|
|
77
|
+
day: z.string(),
|
|
78
|
+
project_id: z.string(),
|
|
79
|
+
drawn_cents: z.number().int(),
|
|
80
|
+
})
|
|
81
|
+
.meta({ id: "OrgUsageSeriesPoint" });
|
|
82
|
+
export const OrgUsageSeriesOut = z
|
|
83
|
+
.object({
|
|
84
|
+
currency: z.string(),
|
|
85
|
+
from: z.string(),
|
|
86
|
+
to: z.string(),
|
|
87
|
+
/** Projects with any draw in the window, ranked by total draw. */
|
|
88
|
+
projects: z.array(z.object({ project_id: z.string(), name: z.string() })),
|
|
89
|
+
points: z.array(OrgUsageSeriesPoint),
|
|
90
|
+
})
|
|
91
|
+
.meta({ id: "OrgUsageSeriesOut" });
|
|
92
|
+
// ── Money movement ──────────────────────────────────────────────────────────
|
|
93
|
+
export const CheckoutIn = z
|
|
94
|
+
.object({
|
|
95
|
+
amount_cents: z.number().int(),
|
|
96
|
+
/** The console's own origin URL to return to; must carry the Stripe session
|
|
97
|
+
* template so the page can reflect the result. */
|
|
98
|
+
return_url: z.string(),
|
|
99
|
+
})
|
|
100
|
+
.meta({ id: "CheckoutIn" });
|
|
101
|
+
export const CheckoutOut = z.object({ url: z.string() }).meta({ id: "CheckoutOut" });
|
|
102
|
+
export const ConfirmIn = z.object({ session_id: z.string() }).meta({ id: "ConfirmIn" });
|
|
103
|
+
export const ConfirmOut = z
|
|
104
|
+
.object({ credited: z.boolean(), payment_status: z.string() })
|
|
105
|
+
.meta({ id: "ConfirmOut" });
|
|
106
|
+
/** Add a card with no charge (Stripe setup-mode Checkout); on success it unlocks
|
|
107
|
+
* the one-time welcome credit. Same return-url contract as checkout. */
|
|
108
|
+
export const SetupIn = z.object({ return_url: z.string() }).meta({ id: "SetupIn" });
|
|
109
|
+
export const SetupOut = z.object({ url: z.string() }).meta({ id: "SetupOut" });
|
|
110
|
+
/** Redeem a one-time credit code, matched case-insensitively. */
|
|
111
|
+
export const RedeemIn = z.object({ code: z.string() }).meta({ id: "RedeemIn" });
|
|
112
|
+
export const RedeemOut = z
|
|
113
|
+
.object({
|
|
114
|
+
amount_cents: z.number().int(),
|
|
115
|
+
currency: z.string(),
|
|
116
|
+
})
|
|
117
|
+
.meta({ id: "RedeemOut" });
|
|
118
|
+
export const AutoreloadOut = z
|
|
119
|
+
.object({
|
|
120
|
+
enabled: z.boolean(),
|
|
121
|
+
/** When the balance drops below `threshold_cents`, the saved card is charged
|
|
122
|
+
* for `amount_cents`. Both are integer minor units of the billing currency. */
|
|
123
|
+
threshold_cents: z.number().int(),
|
|
124
|
+
amount_cents: z.number().int(),
|
|
125
|
+
})
|
|
126
|
+
.meta({ id: "AutoreloadOut" });
|
|
127
|
+
/** Set the same shape you read back. */
|
|
128
|
+
export const AutoreloadIn = AutoreloadOut;
|
|
129
|
+
/** `amount_cents` is optional — it defaults to the configured auto-reload amount. */
|
|
130
|
+
export const ReloadIn = z
|
|
131
|
+
.object({ amount_cents: z.number().int().optional() })
|
|
132
|
+
.meta({ id: "ReloadIn" });
|
|
133
|
+
export const ReloadOut = z
|
|
134
|
+
.object({ credited: z.boolean(), payment_status: z.string() })
|
|
135
|
+
.meta({ id: "ReloadOut" });
|
|
136
|
+
export const PortalOut = z.object({ url: z.string() }).meta({ id: "PortalOut" });
|