@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.
Files changed (49) hide show
  1. package/dist/client.js +185 -14
  2. package/dist/index.js +4 -0
  3. package/dist/scopes.js +52 -0
  4. package/dist/zod/_actor.js +33 -0
  5. package/dist/zod/_page.js +18 -4
  6. package/dist/zod/agents.js +17 -3
  7. package/dist/zod/billing.js +136 -0
  8. package/dist/zod/budgets.js +2 -3
  9. package/dist/zod/connections.js +2 -3
  10. package/dist/zod/conversations.js +4 -11
  11. package/dist/zod/deployments.js +32 -0
  12. package/dist/zod/files.js +2 -9
  13. package/dist/zod/index.js +3 -0
  14. package/dist/zod/mcp.js +20 -14
  15. package/dist/zod/observability.js +39 -19
  16. package/dist/zod/projects.js +4 -4
  17. package/dist/zod/runs.js +16 -4
  18. package/dist/zod/schedules.js +2 -7
  19. package/dist/zod/skills.js +73 -0
  20. package/dist/zod/smith-revisions.js +7 -5
  21. package/dist/zod/smiths.js +14 -0
  22. package/dist/zod/tenant.js +41 -4
  23. package/dist/zod/vector-stores.js +36 -23
  24. package/package.json +6 -8
  25. package/ts/client.ts +431 -50
  26. package/ts/index.ts +4 -0
  27. package/ts/responses.ts +40 -2
  28. package/ts/scopes.ts +57 -0
  29. package/ts/zod/.impeccable/hook.cache.json +1 -0
  30. package/ts/zod/_actor.ts +36 -0
  31. package/ts/zod/_page.ts +19 -4
  32. package/ts/zod/agents.ts +17 -3
  33. package/ts/zod/billing.ts +168 -0
  34. package/ts/zod/budgets.ts +2 -3
  35. package/ts/zod/connections.ts +2 -3
  36. package/ts/zod/conversations.ts +7 -11
  37. package/ts/zod/deployments.ts +36 -0
  38. package/ts/zod/files.ts +2 -9
  39. package/ts/zod/index.ts +3 -0
  40. package/ts/zod/mcp.ts +20 -15
  41. package/ts/zod/observability.ts +75 -24
  42. package/ts/zod/projects.ts +4 -4
  43. package/ts/zod/runs.ts +18 -4
  44. package/ts/zod/schedules.ts +2 -7
  45. package/ts/zod/skills.ts +85 -0
  46. package/ts/zod/smith-revisions.ts +7 -5
  47. package/ts/zod/smiths.ts +14 -0
  48. package/ts/zod/tenant.ts +52 -5
  49. package/ts/zod/vector-stores.ts +41 -23
package/ts/client.ts CHANGED
@@ -30,6 +30,8 @@ import type {
30
30
  ICAgentVersion,
31
31
  ICApproval,
32
32
  ICAuthorizeRequest,
33
+ ICAutoreload,
34
+ ICBalance,
33
35
  ICBudget,
34
36
  ICBudgetStatus,
35
37
  ICCatalogEntry,
@@ -41,13 +43,18 @@ import type {
41
43
  ICDeploymentCreated,
42
44
  ICDiscordApp,
43
45
  ICEmailConfig,
46
+ ICEmbeddingList,
44
47
  ICEvent,
45
48
  ICFile,
46
49
  ICFileList,
50
+ ICInboundEvent,
51
+ ICLedgerEntry,
47
52
  ICMcpServer,
48
53
  ICMintedToken,
49
54
  ICModelCatalog,
50
55
  ICModelKey,
56
+ ICOrgUsage,
57
+ ICOrgUsageSeries,
51
58
  ICProject,
52
59
  ICProvider,
53
60
  ICRecallHit,
@@ -57,6 +64,7 @@ import type {
57
64
  ICSlackApp,
58
65
  ICSmith,
59
66
  ICSmithRevision,
67
+ ICSpanIn,
60
68
  ICTelegramBot,
61
69
  ICToken,
62
70
  ICTrace,
@@ -83,6 +91,20 @@ import type {
83
91
  RolloutIn,
84
92
  UiResourceIn,
85
93
  } from "./zod/agents.js";
94
+ import type {
95
+ AutoreloadIn,
96
+ CheckoutIn,
97
+ CheckoutOut,
98
+ ConfirmIn,
99
+ ConfirmOut,
100
+ PortalOut,
101
+ RedeemIn,
102
+ RedeemOut,
103
+ ReloadIn,
104
+ ReloadOut,
105
+ SetupIn,
106
+ SetupOut,
107
+ } from "./zod/billing.js";
86
108
  import type { BudgetIn, BudgetPatch } from "./zod/budgets.js";
87
109
  import type {
88
110
  AuthorizeIn,
@@ -95,10 +117,11 @@ import type { CustomerCreate, CustomerPatch } from "./zod/customers.js";
95
117
  import type { DeploymentIn, DeploymentPatch } from "./zod/deployments.js";
96
118
  import type { DiscordAppIn } from "./zod/discord.js";
97
119
  import type { EmailConfigIn } from "./zod/email.js";
98
- import type { McpServerIn, McpServerWriteOut } from "./zod/mcp.js";
120
+ import type { McpServerIn } from "./zod/mcp.js";
99
121
  import type { RecallBody, WorkingMemorySet } from "./zod/memories.js";
100
122
  import type { ProjectIn, ProjectTokenIn, ProjectTokenOut } from "./zod/projects.js";
101
123
  import type { RunIn, Submit } from "./zod/runs.js";
124
+ import type { Skill, SkillUpdateIn, SkillVersion } from "./zod/skills.js";
102
125
  import type {
103
126
  VectorStoreFileBatchIn,
104
127
  VectorStoreFileIn,
@@ -125,6 +148,8 @@ import type {
125
148
  WebhookIn,
126
149
  WebhookPatch,
127
150
  WebhookRedeliverOut,
151
+ WebhookRotateIn,
152
+ WebhookRotateOut,
128
153
  } from "./zod/tenant.js";
129
154
  import type { WhatsAppConfigIn } from "./zod/whatsapp.js";
130
155
 
@@ -141,6 +166,16 @@ export interface ICPage<T> {
141
166
  has_more: boolean;
142
167
  }
143
168
 
169
+ /** An OpenAI-dialect list page (`object:"list"` — files, vector stores,
170
+ * conversations). Page forward by passing `last_id` back as `after`. */
171
+ export interface ICOaiList<T> {
172
+ object: "list";
173
+ data: T[];
174
+ first_id: string | null;
175
+ last_id: string | null;
176
+ has_more: boolean;
177
+ }
178
+
144
179
  /** A non-2xx `/v1` response: HTTP status + the error envelope's `code`.
145
180
  * `message` carries the full context (method, path, status); `detail` is the
146
181
  * envelope's bare `error.message`, suitable for user-facing copy. */
@@ -214,6 +249,66 @@ function qs(query: Query | undefined): string {
214
249
  return s ? `?${s}` : "";
215
250
  }
216
251
 
252
+ /** One file of a bundle, as the caller holds it. The path is relative to — and
253
+ * includes — the skill's root directory, e.g. `invoice-review/SKILL.md`. */
254
+ export interface SkillFileInput {
255
+ path: string;
256
+ content: string | Blob | Uint8Array;
257
+ }
258
+
259
+ /** A bundle to upload: its files, or the whole thing zipped. */
260
+ export type SkillBundle = SkillFileInput[] | Blob;
261
+
262
+ /** Build the multipart body `/v1/skills` accepts.
263
+ *
264
+ * The path rides the part's *filename*, slashes and all — that is how the
265
+ * bundle's directory structure survives a multipart body. `FormData` in Node,
266
+ * Bun and browsers all pass it through verbatim. */
267
+ function bundleForm(bundle: SkillBundle): FormData {
268
+ const form = new FormData();
269
+ if (bundle instanceof Blob) {
270
+ form.append("file", bundle, "bundle.zip");
271
+ return form;
272
+ }
273
+ for (const file of bundle) {
274
+ // A `Uint8Array`'s buffer type is generic (and may be a `SharedArrayBuffer`),
275
+ // which `Blob`'s constructor does not accept — copy into a fresh one, whose
276
+ // buffer is always a plain `ArrayBuffer`.
277
+ const part =
278
+ typeof file.content === "string" || file.content instanceof Blob
279
+ ? file.content
280
+ : new Uint8Array(file.content);
281
+ const blob =
282
+ part instanceof Blob
283
+ ? part
284
+ : new Blob([part], { type: mediaTypeFor(file.path) });
285
+ form.append("files[]", blob, file.path);
286
+ }
287
+ return form;
288
+ }
289
+
290
+ /** A `Blob` built from a string has no type of its own; the server falls back to
291
+ * `application/octet-stream` when a part carries none, which would make every
292
+ * text file non-indexable. Name the common ones from the extension. */
293
+ function mediaTypeFor(path: string): string {
294
+ const ext = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
295
+ const known: Record<string, string> = {
296
+ md: "text/markdown",
297
+ markdown: "text/markdown",
298
+ txt: "text/plain",
299
+ json: "application/json",
300
+ yaml: "text/yaml",
301
+ yml: "text/yaml",
302
+ csv: "text/csv",
303
+ py: "text/x-python",
304
+ sh: "text/x-shellscript",
305
+ js: "text/javascript",
306
+ ts: "text/typescript",
307
+ html: "text/html",
308
+ };
309
+ return known[ext] ?? "application/octet-stream";
310
+ }
311
+
217
312
  export class IngramCloud {
218
313
  private readonly token: IngramCloudOptions["token"];
219
314
  private readonly base: string;
@@ -372,10 +467,10 @@ export class IngramCloud {
372
467
  },
373
468
 
374
469
  revisions: {
375
- list: (pid: string, opts?: RequestOptions) =>
376
- this.data<ICSmithRevision>(
377
- "GET",
470
+ list: (pid: string, query?: PageOpts, opts?: RequestOptions) =>
471
+ this.page<ICSmithRevision>(
378
472
  `/smiths/${enc(pid)}/revisions`,
473
+ query,
379
474
  opts,
380
475
  ),
381
476
  restore: (
@@ -395,8 +490,12 @@ export class IngramCloud {
395
490
  },
396
491
 
397
492
  connections: {
398
- list: (pid: string, opts?: RequestOptions) =>
399
- this.data<ICConnection>("GET", `/smiths/${enc(pid)}/connections`, opts),
493
+ list: (
494
+ pid: string,
495
+ query?: PageOpts & { provider?: string },
496
+ opts?: RequestOptions,
497
+ ) =>
498
+ this.page<ICConnection>(`/smiths/${enc(pid)}/connections`, query, opts),
400
499
  get: (pid: string, cid: string, opts?: RequestOptions) =>
401
500
  this.json<ICConnection>(
402
501
  "GET",
@@ -451,9 +550,33 @@ export class IngramCloud {
451
550
  ),
452
551
  },
453
552
 
454
- schedules: {
553
+ /** End-user BYOK (#170): a smith's own provider keys, resolved ahead of the
554
+ * tenant's so the end-user's provider account is billed. Never read back. */
555
+ modelKeys: {
455
556
  list: (pid: string, opts?: RequestOptions) =>
456
- this.data<ICSchedule>("GET", `/smiths/${enc(pid)}/schedules`, opts),
557
+ this.data<ICModelKey>("GET", `/smiths/${enc(pid)}/model_keys`, opts),
558
+ put: (
559
+ pid: string,
560
+ provider: string,
561
+ body: z.input<typeof ModelKeyIn>,
562
+ opts?: RequestOptions,
563
+ ) =>
564
+ this.json<z.infer<typeof ModelKeyConfiguredOut>>(
565
+ "PUT",
566
+ `/smiths/${enc(pid)}/model_keys/${enc(provider)}`,
567
+ { ...opts, body },
568
+ ),
569
+ delete: (pid: string, provider: string, opts?: RequestOptions) =>
570
+ this.empty(
571
+ "DELETE",
572
+ `/smiths/${enc(pid)}/model_keys/${enc(provider)}`,
573
+ opts,
574
+ ),
575
+ },
576
+
577
+ schedules: {
578
+ list: (pid: string, query?: PageOpts, opts?: RequestOptions) =>
579
+ this.page<ICSchedule>(`/smiths/${enc(pid)}/schedules`, query, opts),
457
580
  create: (
458
581
  pid: string,
459
582
  body: z.input<typeof ScheduleIn>,
@@ -579,6 +702,8 @@ export class IngramCloud {
579
702
  },
580
703
  opts?: RequestOptions,
581
704
  ) => this.page<ICRun>("/runs", query, opts),
705
+ trace: (rid: string, opts?: RequestOptions) =>
706
+ this.json<ICTraceDetail>("GET", `/runs/${enc(rid)}/trace`, opts),
582
707
  };
583
708
 
584
709
  // ── Agents ──────────────────────────────────────────────────────────────
@@ -599,8 +724,8 @@ export class IngramCloud {
599
724
  this.empty("DELETE", `/agents/${enc(aid)}`, opts),
600
725
 
601
726
  versions: {
602
- list: (aid: string, opts?: RequestOptions) =>
603
- this.data<ICAgentVersion>("GET", `/agents/${enc(aid)}/versions`, opts),
727
+ list: (aid: string, query?: PageOpts, opts?: RequestOptions) =>
728
+ this.page<ICAgentVersion>(`/agents/${enc(aid)}/versions`, query, opts),
604
729
  /** Snapshot the draft as the next immutable version. */
605
730
  publish: (
606
731
  aid: string,
@@ -638,7 +763,11 @@ export class IngramCloud {
638
763
  list: (aid: string, opts?: RequestOptions) =>
639
764
  this.data<ICUiResource>("GET", `/agents/${enc(aid)}/ui`, opts),
640
765
  get: (aid: string, name: string, opts?: RequestOptions) =>
641
- this.json<ICUiResource>("GET", `/agents/${enc(aid)}/ui/${enc(name)}`, opts),
766
+ this.json<ICUiResource>(
767
+ "GET",
768
+ `/agents/${enc(aid)}/ui/${enc(name)}`,
769
+ opts,
770
+ ),
642
771
  /** Upload/replace a template — `html` is the bundle, `meta` its
643
772
  * `{ name, csp?, permissions?, tool? }` sidecar. Replaces by name. */
644
773
  put: (
@@ -650,7 +779,9 @@ export class IngramCloud {
650
779
  const form = new FormData();
651
780
  form.append(
652
781
  "file",
653
- html instanceof Blob ? html : new Blob([html], { type: "text/html" }),
782
+ html instanceof Blob
783
+ ? html
784
+ : new Blob([html], { type: "text/html" }),
654
785
  `${meta.name}.html`,
655
786
  );
656
787
  form.append("metadata", JSON.stringify(meta));
@@ -659,20 +790,31 @@ export class IngramCloud {
659
790
  rawBody: form,
660
791
  });
661
792
  },
793
+ /** The template's HTML bundle — the same bytes the agent's MCP endpoint
794
+ * serves, so a host can render a panel without vendoring a copy.
795
+ * Tenant-authed: call it server-side and proxy to your chat UI. */
796
+ content: (aid: string, name: string, opts?: RequestOptions) =>
797
+ this.request("GET", `/agents/${enc(aid)}/ui/${enc(name)}/content`, {
798
+ ...opts,
799
+ headers: { accept: "text/html", ...opts?.headers },
800
+ }).then((r) => r.text()),
662
801
  delete: (aid: string, name: string, opts?: RequestOptions) =>
663
- this.json<{ name: string; deleted: boolean }>(
664
- "DELETE",
665
- `/agents/${enc(aid)}/ui/${enc(name)}`,
666
- opts,
667
- ),
802
+ this.empty("DELETE", `/agents/${enc(aid)}/ui/${enc(name)}`, opts),
668
803
  },
669
804
  };
670
805
 
671
806
  // ── Conversations (smith-scoped: pass `{ smith }` with a tenant token) ──
672
807
 
673
808
  readonly conversations = {
674
- list: (query?: PageOpts, opts?: RequestOptions) =>
675
- this.page<ICConversation>("/conversations", query, opts),
809
+ /** OpenAI `list` envelope; page forward with `after: page.last_id`. */
810
+ list: (
811
+ query?: { limit?: number; order?: "asc" | "desc"; after?: string },
812
+ opts?: RequestOptions,
813
+ ) =>
814
+ this.json<ICOaiList<ICConversation>>("GET", "/conversations", {
815
+ ...opts,
816
+ query,
817
+ }),
676
818
  create: (
677
819
  body: z.input<typeof ConversationCreate> = {},
678
820
  opts?: RequestOptions,
@@ -719,6 +861,18 @@ export class IngramCloud {
719
861
  ) => this.page<ICEvent>("/events", query, opts),
720
862
  };
721
863
 
864
+ /** What arrived, before anything interpreted it — including arrivals that
865
+ * matched no smith (`smith_id: ""`). The `iev_` ids `deployment.inbound`
866
+ * carries resolve here. */
867
+ readonly inboundEvents = {
868
+ list: (
869
+ query?: PageOpts & { source?: string; smith_id?: string; since?: string },
870
+ opts?: RequestOptions,
871
+ ) => this.page<ICInboundEvent>("/inbound_events", query, opts),
872
+ get: (ievId: string, opts?: RequestOptions) =>
873
+ this.json<ICInboundEvent>("GET", `/inbound_events/${enc(ievId)}`, opts),
874
+ };
875
+
722
876
  // ── Customers / budgets ─────────────────────────────────────────────────
723
877
 
724
878
  readonly customers = {
@@ -739,7 +893,8 @@ export class IngramCloud {
739
893
  };
740
894
 
741
895
  readonly budgets = {
742
- list: (opts?: RequestOptions) => this.data<ICBudget>("GET", "/budgets", opts),
896
+ list: (query?: PageOpts, opts?: RequestOptions) =>
897
+ this.page<ICBudget>("/budgets", query, opts),
743
898
  create: (body: z.input<typeof BudgetIn>, opts?: RequestOptions) =>
744
899
  this.json<ICBudget>("POST", "/budgets", { ...opts, body }),
745
900
  get: (bid: string, opts?: RequestOptions) =>
@@ -788,6 +943,18 @@ export class IngramCloud {
788
943
  this.json<ICCatalogEntry>("GET", `/catalog/${enc(slug)}`, opts),
789
944
  };
790
945
 
946
+ // ── Embeddings ──────────────────────────────────────────────────────────
947
+
948
+ /** Embed one string or a batch on the OpenAI-compatible wire. Pure tenant
949
+ * compute — no smith runs. Omit `model` for the project default. Reach for
950
+ * the `openai` SDK instead if you already hold one; this is the same route. */
951
+ readonly embeddings = {
952
+ create: (
953
+ body: { input: string | string[]; model?: string },
954
+ opts?: RequestOptions,
955
+ ) => this.json<ICEmbeddingList>("POST", "/embeddings", { ...opts, body }),
956
+ };
957
+
791
958
  // ── Observability ───────────────────────────────────────────────────────
792
959
 
793
960
  readonly traces = {
@@ -802,6 +969,15 @@ export class IngramCloud {
802
969
  ) => this.page<ICTrace>("/traces", query, opts),
803
970
  get: (traceId: string, opts?: RequestOptions) =>
804
971
  this.json<ICTraceDetail>("GET", `/traces/${enc(traceId)}`, opts),
972
+ /** Push spans from your own runtime or an OTel exporter. The tenant comes
973
+ * from the token; a smith-scoped token may only attribute to its own smith.
974
+ * Unknown `kind`s land as `runtime_event` rather than erroring. Returns the
975
+ * number written. */
976
+ ingest: (spans: ICSpanIn[], opts?: RequestOptions) =>
977
+ this.json<{ accepted: number }>("POST", "/traces:ingest", {
978
+ ...opts,
979
+ body: { spans },
980
+ }),
805
981
  };
806
982
 
807
983
  readonly usage = {
@@ -851,7 +1027,12 @@ export class IngramCloud {
851
1027
  },
852
1028
  /** Uploads only (OpenAI `list` envelope); inline files stay unlisted. */
853
1029
  list: (
854
- query?: { purpose?: string; after?: string; limit?: number; order?: "asc" | "desc" },
1030
+ query?: {
1031
+ purpose?: string;
1032
+ after?: string;
1033
+ limit?: number;
1034
+ order?: "asc" | "desc";
1035
+ },
855
1036
  opts?: RequestOptions,
856
1037
  ) => this.json<ICFileList>("GET", "/files", { ...opts, query }),
857
1038
  get: (id: string, opts?: RequestOptions) =>
@@ -860,7 +1041,11 @@ export class IngramCloud {
860
1041
  content: (id: string, opts?: RequestOptions) =>
861
1042
  this.request("GET", `/files/${enc(id)}/content`, opts),
862
1043
  delete: (id: string, opts?: RequestOptions) =>
863
- this.json<{ id: string; deleted: true }>("DELETE", `/files/${enc(id)}`, opts),
1044
+ this.json<{ id: string; deleted: true }>(
1045
+ "DELETE",
1046
+ `/files/${enc(id)}`,
1047
+ opts,
1048
+ ),
864
1049
  };
865
1050
 
866
1051
  // ── Vector stores (the OpenAI Vector Stores API) ─────────────────────────
@@ -869,14 +1054,18 @@ export class IngramCloud {
869
1054
  create: (body: z.input<typeof VectorStoreIn>, opts?: RequestOptions) =>
870
1055
  this.json<ICVectorStore>("POST", "/vector_stores", { ...opts, body }),
871
1056
  list: (
872
- query?: { limit?: number; order?: "asc" | "desc"; after?: string; before?: string },
1057
+ query?: {
1058
+ limit?: number;
1059
+ order?: "asc" | "desc";
1060
+ after?: string;
1061
+ before?: string;
1062
+ },
873
1063
  opts?: RequestOptions,
874
1064
  ) =>
875
- this.json<{ data: ICVectorStore[]; first_id: string | null; last_id: string | null; has_more: boolean }>(
876
- "GET",
877
- "/vector_stores",
878
- { ...opts, query },
879
- ),
1065
+ this.json<ICOaiList<ICVectorStore>>("GET", "/vector_stores", {
1066
+ ...opts,
1067
+ query,
1068
+ }),
880
1069
  get: (vsId: string, opts?: RequestOptions) =>
881
1070
  this.json<ICVectorStore>("GET", `/vector_stores/${enc(vsId)}`, opts),
882
1071
  /** Modify (OpenAI uses `POST`, not `PATCH`). */
@@ -884,7 +1073,11 @@ export class IngramCloud {
884
1073
  vsId: string,
885
1074
  body: z.input<typeof VectorStorePatch>,
886
1075
  opts?: RequestOptions,
887
- ) => this.json<ICVectorStore>("POST", `/vector_stores/${enc(vsId)}`, { ...opts, body }),
1076
+ ) =>
1077
+ this.json<ICVectorStore>("POST", `/vector_stores/${enc(vsId)}`, {
1078
+ ...opts,
1079
+ body,
1080
+ }),
888
1081
  delete: (vsId: string, opts?: RequestOptions) =>
889
1082
  this.json<{ id: string; deleted: true }>(
890
1083
  "DELETE",
@@ -896,10 +1089,14 @@ export class IngramCloud {
896
1089
  body: z.input<typeof VectorStoreSearchIn>,
897
1090
  opts?: RequestOptions,
898
1091
  ) =>
899
- this.json<ICVectorStoreSearchPage>("POST", `/vector_stores/${enc(vsId)}/search`, {
900
- ...opts,
901
- body,
902
- }),
1092
+ this.json<ICVectorStoreSearchPage>(
1093
+ "POST",
1094
+ `/vector_stores/${enc(vsId)}/search`,
1095
+ {
1096
+ ...opts,
1097
+ body,
1098
+ },
1099
+ ),
903
1100
 
904
1101
  files: {
905
1102
  create: (
@@ -907,10 +1104,14 @@ export class IngramCloud {
907
1104
  body: z.input<typeof VectorStoreFileIn>,
908
1105
  opts?: RequestOptions,
909
1106
  ) =>
910
- this.json<ICVectorStoreFile>("POST", `/vector_stores/${enc(vsId)}/files`, {
911
- ...opts,
912
- body,
913
- }),
1107
+ this.json<ICVectorStoreFile>(
1108
+ "POST",
1109
+ `/vector_stores/${enc(vsId)}/files`,
1110
+ {
1111
+ ...opts,
1112
+ body,
1113
+ },
1114
+ ),
914
1115
  list: (
915
1116
  vsId: string,
916
1117
  query?: {
@@ -922,7 +1123,7 @@ export class IngramCloud {
922
1123
  },
923
1124
  opts?: RequestOptions,
924
1125
  ) =>
925
- this.json<{ data: ICVectorStoreFile[]; first_id: string | null; last_id: string | null; has_more: boolean }>(
1126
+ this.json<ICOaiList<ICVectorStoreFile>>(
926
1127
  "GET",
927
1128
  `/vector_stores/${enc(vsId)}/files`,
928
1129
  { ...opts, query },
@@ -978,7 +1179,12 @@ export class IngramCloud {
978
1179
  files: (
979
1180
  vsId: string,
980
1181
  batchId: string,
981
- query?: { limit?: number; order?: "asc" | "desc"; after?: string; filter?: string },
1182
+ query?: {
1183
+ limit?: number;
1184
+ order?: "asc" | "desc";
1185
+ after?: string;
1186
+ filter?: string;
1187
+ },
982
1188
  opts?: RequestOptions,
983
1189
  ) =>
984
1190
  this.json<{ data: ICVectorStoreFile[]; has_more: boolean }>(
@@ -989,6 +1195,81 @@ export class IngramCloud {
989
1195
  },
990
1196
  };
991
1197
 
1198
+ // ── Agent Skills — a folder anchored by SKILL.md, versioned, attached to
1199
+ // agents. Upload takes either the bundle's files as path/content pairs, or
1200
+ // the whole bundle as a zip Blob — the same two shapes /v1/skills accepts.
1201
+ // Both are runtime-agnostic: nothing here touches a filesystem. ───────────
1202
+
1203
+ readonly skills = {
1204
+ list: (opts?: RequestOptions) =>
1205
+ this.json<{ object: "list"; data: z.infer<typeof Skill>[] }>(
1206
+ "GET",
1207
+ "/skills",
1208
+ opts,
1209
+ ),
1210
+ get: (id: string, opts?: RequestOptions) =>
1211
+ this.json<z.infer<typeof Skill>>("GET", `/skills/${enc(id)}`, opts),
1212
+ create: (bundle: SkillBundle, opts?: RequestOptions) =>
1213
+ this.json<z.infer<typeof Skill>>("POST", "/skills", {
1214
+ ...opts,
1215
+ rawBody: bundleForm(bundle),
1216
+ }),
1217
+ /** Move `default_version` to an existing version. */
1218
+ update: (
1219
+ id: string,
1220
+ body: z.input<typeof SkillUpdateIn>,
1221
+ opts?: RequestOptions,
1222
+ ) =>
1223
+ this.json<z.infer<typeof Skill>>("POST", `/skills/${enc(id)}`, {
1224
+ ...opts,
1225
+ body,
1226
+ }),
1227
+ delete: (id: string, opts?: RequestOptions) =>
1228
+ this.request("DELETE", `/skills/${enc(id)}`, opts).then(() => undefined),
1229
+ versions: {
1230
+ list: (id: string, opts?: RequestOptions) =>
1231
+ this.json<{ object: "list"; data: z.infer<typeof SkillVersion>[] }>(
1232
+ "GET",
1233
+ `/skills/${enc(id)}/versions`,
1234
+ opts,
1235
+ ),
1236
+ get: (id: string, version: number, opts?: RequestOptions) =>
1237
+ this.json<z.infer<typeof SkillVersion>>(
1238
+ "GET",
1239
+ `/skills/${enc(id)}/versions/${version}`,
1240
+ opts,
1241
+ ),
1242
+ create: (id: string, bundle: SkillBundle, opts?: RequestOptions) =>
1243
+ this.json<z.infer<typeof SkillVersion>>(
1244
+ "POST",
1245
+ `/skills/${enc(id)}/versions`,
1246
+ { ...opts, rawBody: bundleForm(bundle) },
1247
+ ),
1248
+ delete: (id: string, version: number, opts?: RequestOptions) =>
1249
+ this.request(
1250
+ "DELETE",
1251
+ `/skills/${enc(id)}/versions/${version}`,
1252
+ opts,
1253
+ ).then(() => undefined),
1254
+ /** One file's bytes, or — with no `path` — the whole version as a zip.
1255
+ * The raw `Response` (matching `files.content`), so a caller streams it
1256
+ * through rather than buffering the whole zip into memory. */
1257
+ content: (
1258
+ id: string,
1259
+ version: number,
1260
+ path?: string,
1261
+ opts?: RequestOptions,
1262
+ ) =>
1263
+ this.request(
1264
+ "GET",
1265
+ `/skills/${enc(id)}/versions/${version}/content${
1266
+ path ? `?path=${encodeURIComponent(path)}` : ""
1267
+ }`,
1268
+ opts,
1269
+ ),
1270
+ },
1271
+ };
1272
+
992
1273
  // ── Tenant config ───────────────────────────────────────────────────────
993
1274
 
994
1275
  readonly tenant = {
@@ -1034,6 +1315,18 @@ export class IngramCloud {
1034
1315
  }),
1035
1316
  delete: (wid: string, opts?: RequestOptions) =>
1036
1317
  this.empty("DELETE", `/tenant/webhooks/${enc(wid)}`, opts),
1318
+ /** Rotate the signing secret, returning the new one exactly once. Pass
1319
+ * `grace_seconds` to keep the old secret accepted during an overlap window. */
1320
+ rotateSecret: (
1321
+ wid: string,
1322
+ body?: z.input<typeof WebhookRotateIn>,
1323
+ opts?: RequestOptions,
1324
+ ) =>
1325
+ this.json<z.infer<typeof WebhookRotateOut>>(
1326
+ "POST",
1327
+ `/tenant/webhooks/${enc(wid)}/rotate_secret`,
1328
+ { ...opts, body: body ?? {} },
1329
+ ),
1037
1330
  test: (wid: string, opts?: RequestOptions) =>
1038
1331
  this.json<{ delivered: boolean }>(
1039
1332
  "POST",
@@ -1104,8 +1397,8 @@ export class IngramCloud {
1104
1397
  },
1105
1398
 
1106
1399
  mcp: {
1107
- list: (opts?: RequestOptions) =>
1108
- this.data<ICMcpServer>("GET", "/tenant/mcp", opts),
1400
+ list: (query?: PageOpts, opts?: RequestOptions) =>
1401
+ this.page<ICMcpServer>("/tenant/mcp", query, opts),
1109
1402
  get: (name: string, opts?: RequestOptions) =>
1110
1403
  this.json<ICMcpServer>("GET", `/tenant/mcp/${enc(name)}`, opts),
1111
1404
  /** Register or replace a server (full replace; probes `tools/list`). */
@@ -1114,13 +1407,12 @@ export class IngramCloud {
1114
1407
  body: z.input<typeof McpServerIn>,
1115
1408
  opts?: RequestOptions,
1116
1409
  ) =>
1117
- this.json<z.infer<typeof McpServerWriteOut>>(
1118
- "PUT",
1119
- `/tenant/mcp/${enc(name)}`,
1120
- { ...opts, body },
1121
- ),
1410
+ this.json<ICMcpServer>("PUT", `/tenant/mcp/${enc(name)}`, {
1411
+ ...opts,
1412
+ body,
1413
+ }),
1122
1414
  refresh: (name: string, opts?: RequestOptions) =>
1123
- this.json<z.infer<typeof McpServerWriteOut>>(
1415
+ this.json<ICMcpServer>(
1124
1416
  "POST",
1125
1417
  `/tenant/mcp/${enc(name)}/refresh`,
1126
1418
  opts,
@@ -1210,12 +1502,101 @@ export class IngramCloud {
1210
1502
  },
1211
1503
  };
1212
1504
 
1213
- // ── Organization (org token: projects + billing) ────────────────────────
1505
+ // ── Organization (org token: projects, tokens, billing) ─────────────────
1214
1506
 
1215
1507
  readonly organization = {
1508
+ /** Platform credits — the org wallet that funds every project's runs.
1509
+ * Amounts are integer minor units of the wallet's `currency`. */
1510
+ billing: {
1511
+ balance: (opts?: RequestOptions) =>
1512
+ this.json<ICBalance>("GET", "/organization/billing/balance", opts),
1513
+ /** Money in (top-ups, grants, codes) and out (usage debits), newest first. */
1514
+ ledger: (
1515
+ query?: PageOpts & { direction?: "credit" | "debit" },
1516
+ opts?: RequestOptions,
1517
+ ) => this.page<ICLedgerEntry>("/organization/billing/ledger", query, opts),
1518
+ /** Per-project draw for a calendar month (`period`, `YYYY-MM`). */
1519
+ usage: (query?: { period?: string }, opts?: RequestOptions) =>
1520
+ this.json<ICOrgUsage>("GET", "/organization/billing/usage", {
1521
+ ...opts,
1522
+ query,
1523
+ }),
1524
+ /** Daily per-project draw over a rolling window of `days`. */
1525
+ usageSeries: (query?: { days?: number }, opts?: RequestOptions) =>
1526
+ this.json<ICOrgUsageSeries>(
1527
+ "GET",
1528
+ "/organization/billing/usage/series",
1529
+ {
1530
+ ...opts,
1531
+ query,
1532
+ },
1533
+ ),
1534
+ /** Open a Stripe Checkout Session to top up; send the user to its `url`. */
1535
+ checkout: (body: z.input<typeof CheckoutIn>, opts?: RequestOptions) =>
1536
+ this.json<z.infer<typeof CheckoutOut>>(
1537
+ "POST",
1538
+ "/organization/billing/checkout",
1539
+ { ...opts, body },
1540
+ ),
1541
+ /** Add a card with no charge, unlocking the one-time welcome credit. */
1542
+ setup: (body: z.input<typeof SetupIn>, opts?: RequestOptions) =>
1543
+ this.json<z.infer<typeof SetupOut>>(
1544
+ "POST",
1545
+ "/organization/billing/setup",
1546
+ {
1547
+ ...opts,
1548
+ body,
1549
+ },
1550
+ ),
1551
+ redeem: (body: z.input<typeof RedeemIn>, opts?: RequestOptions) =>
1552
+ this.json<z.infer<typeof RedeemOut>>(
1553
+ "POST",
1554
+ "/organization/billing/redeem",
1555
+ { ...opts, body },
1556
+ ),
1557
+ /** Credit a returning Checkout Session. Safe to call twice — the ledger
1558
+ * keys on the session id, so it can't double-credit. */
1559
+ confirm: (body: z.input<typeof ConfirmIn>, opts?: RequestOptions) =>
1560
+ this.json<z.infer<typeof ConfirmOut>>(
1561
+ "POST",
1562
+ "/organization/billing/confirm",
1563
+ { ...opts, body },
1564
+ ),
1565
+ autoreload: {
1566
+ get: (opts?: RequestOptions) =>
1567
+ this.json<ICAutoreload>(
1568
+ "GET",
1569
+ "/organization/billing/autoreload",
1570
+ opts,
1571
+ ),
1572
+ put: (body: z.input<typeof AutoreloadIn>, opts?: RequestOptions) =>
1573
+ this.json<ICAutoreload>("PUT", "/organization/billing/autoreload", {
1574
+ ...opts,
1575
+ body,
1576
+ }),
1577
+ },
1578
+ /** Charge the saved card now. `amount_cents` defaults to the auto-reload amount. */
1579
+ reload: (body?: z.input<typeof ReloadIn>, opts?: RequestOptions) =>
1580
+ this.json<z.infer<typeof ReloadOut>>(
1581
+ "POST",
1582
+ "/organization/billing/reload",
1583
+ { ...opts, body: body ?? {} },
1584
+ ),
1585
+ /** A Stripe billing-portal URL for managing cards and invoices. */
1586
+ portal: (query: { return_url: string }, opts?: RequestOptions) =>
1587
+ this.json<z.infer<typeof PortalOut>>(
1588
+ "GET",
1589
+ "/organization/billing/portal",
1590
+ {
1591
+ ...opts,
1592
+ query,
1593
+ },
1594
+ ),
1595
+ },
1596
+
1216
1597
  projects: {
1217
- list: (opts?: RequestOptions) =>
1218
- this.data<ICProject>("GET", "/organization/projects", opts),
1598
+ list: (query?: PageOpts & { name?: string }, opts?: RequestOptions) =>
1599
+ this.page<ICProject>("/organization/projects", query, opts),
1219
1600
  create: (body: z.input<typeof ProjectIn>, opts?: RequestOptions) =>
1220
1601
  this.json<ICProject>("POST", "/organization/projects", {
1221
1602
  ...opts,