@ingram-cloud/sdk 1.0.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 (64) hide show
  1. package/README.md +74 -0
  2. package/dist/client.js +460 -0
  3. package/dist/events.js +108 -0
  4. package/dist/index.js +19 -0
  5. package/dist/responses.js +12 -0
  6. package/dist/schemas.js +4 -0
  7. package/dist/zod/_page.js +17 -0
  8. package/dist/zod/agents.js +176 -0
  9. package/dist/zod/approvals.js +38 -0
  10. package/dist/zod/budgets.js +62 -0
  11. package/dist/zod/catalog.js +49 -0
  12. package/dist/zod/connections.js +75 -0
  13. package/dist/zod/conversations.js +91 -0
  14. package/dist/zod/customers.js +53 -0
  15. package/dist/zod/deployments.js +81 -0
  16. package/dist/zod/discord.js +32 -0
  17. package/dist/zod/email.js +45 -0
  18. package/dist/zod/files.js +55 -0
  19. package/dist/zod/index.js +35 -0
  20. package/dist/zod/mcp.js +107 -0
  21. package/dist/zod/memories.js +43 -0
  22. package/dist/zod/observability.js +133 -0
  23. package/dist/zod/projects.js +58 -0
  24. package/dist/zod/runs.js +119 -0
  25. package/dist/zod/schedules.js +71 -0
  26. package/dist/zod/slack.js +69 -0
  27. package/dist/zod/smith-revisions.js +42 -0
  28. package/dist/zod/smiths.js +108 -0
  29. package/dist/zod/telegram.js +36 -0
  30. package/dist/zod/tenant.js +219 -0
  31. package/dist/zod/vector-stores.js +251 -0
  32. package/dist/zod/whatsapp.js +47 -0
  33. package/package.json +56 -0
  34. package/ts/client.ts +1187 -0
  35. package/ts/events.ts +119 -0
  36. package/ts/index.ts +20 -0
  37. package/ts/responses.ts +83 -0
  38. package/ts/schemas.ts +4 -0
  39. package/ts/zod/_page.ts +18 -0
  40. package/ts/zod/agents.ts +202 -0
  41. package/ts/zod/approvals.ts +44 -0
  42. package/ts/zod/budgets.ts +75 -0
  43. package/ts/zod/catalog.ts +57 -0
  44. package/ts/zod/connections.ts +87 -0
  45. package/ts/zod/conversations.ts +103 -0
  46. package/ts/zod/customers.ts +62 -0
  47. package/ts/zod/deployments.ts +93 -0
  48. package/ts/zod/discord.ts +39 -0
  49. package/ts/zod/email.ts +52 -0
  50. package/ts/zod/files.ts +62 -0
  51. package/ts/zod/index.ts +35 -0
  52. package/ts/zod/mcp.ts +123 -0
  53. package/ts/zod/memories.ts +53 -0
  54. package/ts/zod/observability.ts +155 -0
  55. package/ts/zod/projects.ts +68 -0
  56. package/ts/zod/runs.ts +135 -0
  57. package/ts/zod/schedules.ts +82 -0
  58. package/ts/zod/slack.ts +79 -0
  59. package/ts/zod/smith-revisions.ts +50 -0
  60. package/ts/zod/smiths.ts +118 -0
  61. package/ts/zod/telegram.ts +43 -0
  62. package/ts/zod/tenant.ts +267 -0
  63. package/ts/zod/vector-stores.ts +296 -0
  64. package/ts/zod/whatsapp.ts +54 -0
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `discord` channel-config resource — the wire's
3
+ * source of truth, mirroring `telegram.ts`.
4
+ *
5
+ * Discord is delivered over its HTTP Interactions endpoint: the tenant registers one
6
+ * Discord application (its public key + a bot token) and Ingram Cloud verifies every
7
+ * inbound interaction's Ed25519 signature with that public key, so there is no shared
8
+ * webhook secret. Secrets are never returned.
9
+ */
10
+ import { z } from "zod";
11
+ /**
12
+ * The tenant's Discord app config status. The bot token is never returned; the
13
+ * optional fields are present once `configured` is true. `webhook_url` is the
14
+ * Interactions Endpoint URL to register in the Discord Developer Portal.
15
+ */
16
+ export const DiscordAppOut = z
17
+ .object({
18
+ configured: z.boolean(),
19
+ application_id: z.string().optional(),
20
+ public_key: z.string().optional(),
21
+ has_bot_token: z.boolean().optional(),
22
+ webhook_url: z.string().optional(),
23
+ })
24
+ .meta({ id: "DiscordAppOut" });
25
+ // ── Request bodies ──────────────────────────────────────────────────────────
26
+ export const DiscordAppIn = z
27
+ .object({
28
+ application_id: z.string(),
29
+ public_key: z.string(),
30
+ bot_token: z.string(),
31
+ })
32
+ .meta({ id: "DiscordAppIn" });
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `email` channel-config resource — the
3
+ * wire's source of truth for the tenant Cloudflare sending config.
4
+ *
5
+ * One source, three outputs: the API imports these into its `createRoute`
6
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
7
+ * type is `z.infer`red from `EmailConfigOut` here and re-exported by
8
+ * `../responses` as `export type` — no Zod is pulled into a type-only consumer.
9
+ *
10
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
11
+ * `#/components/schemas/<id>` rather than inlining it.
12
+ *
13
+ * The out shape is the union of two builders in `api/src/routes/email.ts`
14
+ * (via `runtime/email.ts`):
15
+ * - GET `/v1/tenant/email` (`configStatus`) — `{ configured: false }`, or
16
+ * `{ configured: true, from_domain, display_name, has_token, inbound_url }`.
17
+ * - PUT `/v1/tenant/email` (`configureEmail`) — `{ configured: true,
18
+ * from_domain, display_name, inbound_url, inbound_secret }`.
19
+ * Hence `configured` is the only required field; everything else is optional,
20
+ * and `inbound_secret` is present only on the PUT response (shown once).
21
+ */
22
+ import { z } from "zod";
23
+ export const EmailConfigOut = z
24
+ .object({
25
+ /** False when the tenant has no email config; true otherwise. */
26
+ configured: z.boolean(),
27
+ from_domain: z.string().optional(),
28
+ display_name: z.string().nullish(),
29
+ /** Present on GET when configured — the API token is never returned. */
30
+ has_token: z.boolean().optional(),
31
+ inbound_url: z.string().optional(),
32
+ /** Only present on PUT (shown once) — wire it into the inbound worker. */
33
+ inbound_secret: z.string().optional(),
34
+ })
35
+ .meta({ id: "EmailConfigOut" });
36
+ // ── Request body ─────────────────────────────────────────────────────────────
37
+ export const EmailConfigIn = z
38
+ .object({
39
+ cloudflare_account_id: z.string(),
40
+ cloudflare_api_token: z.string(),
41
+ from_domain: z.string(),
42
+ display_name: z.string().nullish(),
43
+ inbound_secret: z.string().nullish(),
44
+ })
45
+ .meta({ id: "EmailConfigIn" });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `files` resource — the wire's source of
3
+ * truth, mapped onto the OpenAI **Files API** so an OpenAI client library talks
4
+ * to it unchanged.
5
+ *
6
+ * The File object is exactly OpenAI's (`status`/`status_details` included, inert
7
+ * upstream and here). Upload is `multipart/form-data`, so there is no `In`
8
+ * schema — the route reads the form directly. The list uses OpenAI's `list`
9
+ * envelope with `after`/`limit`/`order` paging and enumerates Files-API uploads
10
+ * only; files inlined into a conversation stay reachable by id but are not
11
+ * listed.
12
+ */
13
+ import { z } from "zod";
14
+ /** OpenAI's upload purposes. Vector-store source files are `assistants`. */
15
+ export const FilePurpose = z.enum([
16
+ "assistants",
17
+ "batch",
18
+ "fine-tune",
19
+ "vision",
20
+ "user_data",
21
+ "evals",
22
+ ]);
23
+ /** The OpenAI File object. */
24
+ export const FileOut = z
25
+ .object({
26
+ id: z.string(),
27
+ object: z.literal("file"),
28
+ bytes: z.number().int(),
29
+ /** Unix seconds, like every OpenAI object. */
30
+ created_at: z.number().int(),
31
+ filename: z.string(),
32
+ purpose: z.string(),
33
+ /** Deprecated upstream; always `processed` here. */
34
+ status: z.literal("processed"),
35
+ status_details: z.null(),
36
+ })
37
+ .meta({ id: "FileOut" });
38
+ /** Files, in OpenAI's `list` envelope (not the IC cursor page). */
39
+ export const FileListOut = z
40
+ .object({
41
+ object: z.literal("list"),
42
+ data: z.array(FileOut),
43
+ first_id: z.string().nullable(),
44
+ last_id: z.string().nullable(),
45
+ has_more: z.boolean(),
46
+ })
47
+ .meta({ id: "FileListOut" });
48
+ /** The delete acknowledgement, in OpenAI's `*.deleted` shape. */
49
+ export const FileDeleted = z
50
+ .object({
51
+ id: z.string(),
52
+ object: z.literal("file"),
53
+ deleted: z.literal(true),
54
+ })
55
+ .meta({ id: "FileDeleted" });
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Hand-authored Zod schemas — the wire's source of truth, one resource module
3
+ * per file. The API imports these into its `createRoute` definitions (runtime
4
+ * validation + emitted OpenAPI); `../responses` re-exports the `z.infer`red
5
+ * `IC*` types from them.
6
+ *
7
+ * Resources are migrated here off the generated `../schemas.ts` one at a time;
8
+ * when the last one lands, the generated file and the `openapi-zod-client` step
9
+ * are deleted and this becomes the sole `schemas` source.
10
+ */
11
+ export * from "./_page.js";
12
+ export * from "./agents.js";
13
+ export * from "./approvals.js";
14
+ export * from "./budgets.js";
15
+ export * from "./catalog.js";
16
+ export * from "./connections.js";
17
+ export * from "./conversations.js";
18
+ export * from "./deployments.js";
19
+ export * from "./customers.js";
20
+ export * from "./discord.js";
21
+ export * from "./email.js";
22
+ export * from "./files.js";
23
+ export * from "./mcp.js";
24
+ export * from "./memories.js";
25
+ export * from "./observability.js";
26
+ export * from "./projects.js";
27
+ export * from "./runs.js";
28
+ export * from "./schedules.js";
29
+ export * from "./slack.js";
30
+ export * from "./smith-revisions.js";
31
+ export * from "./smiths.js";
32
+ export * from "./telegram.js";
33
+ export * from "./tenant.js";
34
+ export * from "./vector-stores.js";
35
+ export * from "./whatsapp.js";
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `mcp` resource — the tenant config plane for
3
+ * registering third-party MCP tool servers (`/v1/tenant/mcp/...`).
4
+ *
5
+ * One source, three outputs: the API imports these into its `createRoute`
6
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
7
+ * types are `z.infer`red from them here and re-exported by `../responses`. No
8
+ * Zod is pulled into a type-only consumer — `responses.ts` re-exports these as
9
+ * `export type`.
10
+ *
11
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
12
+ * `#/components/schemas/<id>` rather than inlining it. `ApprovalRule` and
13
+ * `McpTool` are standalone named schemas referenced by `McpServerOut`, so they
14
+ * emit as `$ref` components rather than inlined objects.
15
+ */
16
+ import { z } from "zod";
17
+ /** One approval-policy rule: a name glob that gates matching tools behind a
18
+ * human approval. `require` is always `"approval"` today (the only supported
19
+ * value); arg-conditional (`when`) gating is rejected, not stored. */
20
+ export const ApprovalRule = z
21
+ .object({
22
+ match: z.string(),
23
+ require: z.string().optional(),
24
+ })
25
+ .meta({ id: "ApprovalRule" });
26
+ /** The rule shape on *input* (`McpServerIn.approval_policy`). Loose, so unknown
27
+ * clauses (e.g. an arg-conditional `when`) reach the handler, which rejects them
28
+ * with its own `unsupported_policy_rule` (422) rather than being silently
29
+ * stripped by a strict object. */
30
+ export const ApprovalRuleIn = z.looseObject({
31
+ match: z.string(),
32
+ require: z.string().optional(),
33
+ });
34
+ /** A discovered MCP tool, with its *effective* gating folded in by the
35
+ * serializer: `enabled` reflects the default-deny `tool_allowlist`,
36
+ * `requires_approval` folds the server's destructive hint with the approval
37
+ * policy. */
38
+ export const McpTool = z
39
+ .object({
40
+ name: z.string(),
41
+ description: z.string().nullable(),
42
+ /** Effective gate: server destructiveHint OR an approval_policy match. */
43
+ requires_approval: z.boolean(),
44
+ /** Passes the default-deny tool_allowlist (always true when no allow-list). */
45
+ enabled: z.boolean(),
46
+ })
47
+ .meta({ id: "McpTool" });
48
+ /** Secret-free auth descriptor returned for a registered server. */
49
+ export const McpAuth = z
50
+ .object({
51
+ kind: z.string(),
52
+ provider: z.string().nullable(),
53
+ client_mode: z.string().optional(),
54
+ })
55
+ .meta({ id: "McpAuth" });
56
+ export const McpServerOut = z
57
+ .object({
58
+ id: z.string(),
59
+ name: z.string(),
60
+ url: z.string(),
61
+ auth: McpAuth,
62
+ /** tenant_owned | tenant_registered | catalog. */
63
+ origin: z.string().optional(),
64
+ catalog_slug: z.string().nullish(),
65
+ /** null = expose all discovered tools; otherwise the default-deny set. */
66
+ tool_allowlist: z.array(z.string()).nullish(),
67
+ approval_policy: z.array(ApprovalRule).optional(),
68
+ tools: z.array(McpTool),
69
+ tools_refreshed_at: z.string().nullable(),
70
+ /** `degraded` when the edge failed discovery or its secret can't be decoded
71
+ * at run time; otherwise the stored lifecycle status. */
72
+ status: z.string(),
73
+ /** Last discovery/runtime-load failure, or null when the edge is healthy. */
74
+ discovery_error: z.string().nullable(),
75
+ created_at: z.string().nullable(),
76
+ })
77
+ .meta({ id: "McpServerOut" });
78
+ export const McpServerListOut = z
79
+ .object({ data: z.array(McpServerOut) })
80
+ .meta({ id: "McpServerListOut" });
81
+ /** Register/replace and refresh echo the server back plus the count of tools
82
+ * discovered in the just-run `tools/list`. */
83
+ export const McpServerWriteOut = McpServerOut.extend({
84
+ tools_discovered: z.number().int(),
85
+ }).meta({ id: "McpServerWriteOut" });
86
+ // ── Request bodies ──────────────────────────────────────────────────────────
87
+ /** Auth block on a register/replace body. `secret` is write-only (a static
88
+ * bearer) — never echoed back. */
89
+ export const McpAuthIn = z
90
+ .object({
91
+ kind: z.string().nullish(),
92
+ provider: z.string().nullish(),
93
+ secret: z.string().nullish(),
94
+ client_mode: z.string().nullish(),
95
+ })
96
+ .meta({ id: "McpAuthIn" });
97
+ /** Register or replace a server: supply a raw `url` + `auth`, or a `catalog`
98
+ * slug (catalog defaults are stamped down, body fields override). */
99
+ export const McpServerIn = z
100
+ .object({
101
+ url: z.string().nullish(),
102
+ catalog: z.string().nullish(),
103
+ auth: McpAuthIn.nullish(),
104
+ tool_allowlist: z.array(z.string()).nullish(),
105
+ approval_policy: z.array(ApprovalRuleIn).nullish(),
106
+ })
107
+ .meta({ id: "McpServerIn" });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `memory` resource — the wire's source of
3
+ * truth, imported by the API's `createRoute` definitions (validation + emitted
4
+ * OpenAPI) and `z.infer`red into the consumer-facing `IC*` types re-exported by
5
+ * `../responses`.
6
+ *
7
+ * Memory is Mastra-native (workstream #65): a smith has one **working-memory**
8
+ * doc (structured, auto-maintained) plus automatic **semantic recall** over its
9
+ * past messages. There is no standalone "file a fact" CRUD — recall is over the
10
+ * conversation history the smith already produced.
11
+ *
12
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
13
+ * `#/components/schemas/<id>`.
14
+ */
15
+ import { z } from "zod";
16
+ /** A smith's working-memory doc — the structured text the agent maintains about
17
+ * its end user, shared across the smith's threads (resource-scoped). */
18
+ export const WorkingMemoryOut = z
19
+ .object({ content: z.string() })
20
+ .meta({ id: "WorkingMemoryOut" });
21
+ /** Replace a smith's working-memory doc. */
22
+ export const WorkingMemorySet = z
23
+ .object({ content: z.string() })
24
+ .meta({ id: "WorkingMemorySet" });
25
+ /** Recall query over a smith's past messages. */
26
+ export const RecallBody = z
27
+ .object({
28
+ query: z.string(),
29
+ limit: z.number().int().default(10),
30
+ })
31
+ .meta({ id: "RecallBody" });
32
+ /** One recall hit — a relevant past message range with its similarity `score`. */
33
+ export const RecallHit = z
34
+ .object({
35
+ thread_id: z.string(),
36
+ content: z.string(),
37
+ score: z.number(),
38
+ })
39
+ .meta({ id: "RecallHit" });
40
+ /** Recall response envelope — ranked hits. */
41
+ export const RecallOut = z
42
+ .object({ data: z.array(RecallHit) })
43
+ .meta({ id: "RecallOut" });
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `observability` resource — traces, spans,
3
+ * and the usage breakdown. The wire's source of truth, replacing the loose
4
+ * generated shapes for this resource.
5
+ *
6
+ * One source, three outputs: the API imports these into its `createRoute`
7
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
8
+ * types are `z.infer`red from them here and re-exported by `../responses`. No
9
+ * Zod is pulled into a type-only consumer — `responses.ts` re-exports these as
10
+ * `export type`.
11
+ *
12
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
13
+ * `#/components/schemas/<id>` rather than inlining it.
14
+ *
15
+ * Shapes follow the `responses.ts` interfaces (the source of truth), not the
16
+ * relic's looser `SpanOut`/`TraceOut`: the relic flattened `children`, `spans`,
17
+ * and `span_tree` onto every span/trace and made `kind`/timestamps nullable. We
18
+ * split them — `SpanOut` has no `children`, the recursive `SpanNodeOut` adds
19
+ * it; `TraceOut` carries no `spans`/`span_tree`, `TraceDetailOut` adds them.
20
+ */
21
+ import { z } from "zod";
22
+ import { pageOut } from "./_page.js";
23
+ /** Span kinds emitted by the observability backend. `retrieval` covers vector-store
24
+ * search (the hosted `file_search` tool, and externally-pushed RAG spans). */
25
+ export const ICSpanKindEnum = z
26
+ .enum([
27
+ "run",
28
+ "model_call",
29
+ "tool_call",
30
+ "memory_op",
31
+ "retrieval",
32
+ "runtime_event",
33
+ ])
34
+ .meta({ id: "SpanKind" });
35
+ /** A single timed unit of work inside a trace. */
36
+ export const SpanOut = z
37
+ .object({
38
+ id: z.string(),
39
+ trace_id: z.string(),
40
+ parent_span_id: z.string().nullable(),
41
+ kind: ICSpanKindEnum,
42
+ name: z.string(),
43
+ status: z.string(),
44
+ started_at: z.string(),
45
+ ended_at: z.string().nullable(),
46
+ duration_ms: z.number().int().nullable(),
47
+ model: z.string().nullable(),
48
+ input_tokens: z.number().int().nullable(),
49
+ output_tokens: z.number().int().nullable(),
50
+ cost: z.number().nullable(),
51
+ attributes: z.record(z.string(), z.unknown()),
52
+ })
53
+ .meta({ id: "SpanOut" });
54
+ /** A span node in the nested `span_tree` (same shape + recursive children). */
55
+ export const SpanNodeOut = SpanOut.extend({
56
+ get children() {
57
+ return z.array(SpanNodeOut);
58
+ },
59
+ }).meta({ id: "SpanNodeOut" });
60
+ /** Top-level trace — one end-to-end agent operation. */
61
+ export const TraceOut = z
62
+ .object({
63
+ id: z.string(),
64
+ smith_id: z.string(),
65
+ app_id: z.string().nullable(),
66
+ root_kind: ICSpanKindEnum,
67
+ name: z.string(),
68
+ status: z.string(),
69
+ started_at: z.string(),
70
+ ended_at: z.string().nullable(),
71
+ duration_ms: z.number().int().nullable(),
72
+ total_tokens: z.number().int().nullable(),
73
+ total_cost: z.number().nullable(),
74
+ attributes: z.record(z.string(), z.unknown()),
75
+ })
76
+ .meta({ id: "TraceOut" });
77
+ /** A trace plus its flat spans and nested tree. */
78
+ export const TraceDetailOut = TraceOut.extend({
79
+ spans: z.array(SpanOut),
80
+ span_tree: z.array(SpanNodeOut),
81
+ }).meta({ id: "TraceDetailOut" });
82
+ export const TraceListOut = pageOut(TraceOut, "TraceListOut");
83
+ /** Aggregated usage grouped by app, smith, model, or customer. */
84
+ export const UsageBreakdownOut = z
85
+ .object({
86
+ group_by: z.enum(["app", "smith", "model", "customer"]),
87
+ totals: z.object({
88
+ tokens: z.number(),
89
+ cost: z.number(),
90
+ run_count: z.number(),
91
+ }),
92
+ groups: z.array(z.object({
93
+ app: z.string().nullable().optional(),
94
+ smith: z.string().nullable().optional(),
95
+ model: z.string().nullable().optional(),
96
+ // Customer-grouped views label unassigned usage `principal:<smith id>`.
97
+ customer: z.string().nullable().optional(),
98
+ tokens: z.number(),
99
+ cost: z.number(),
100
+ run_count: z.number(),
101
+ })),
102
+ /** Custom billable events aggregated per meter over the same filters. */
103
+ meters: z
104
+ .array(z.object({
105
+ meter: z.string(),
106
+ customer: z.string().nullable().optional(),
107
+ quantity: z.number(),
108
+ events: z.number(),
109
+ }))
110
+ .optional(),
111
+ })
112
+ .meta({ id: "UsageBreakdownOut" });
113
+ /** One recorded billable usage event. */
114
+ export const UsageEventOut = z
115
+ .object({
116
+ id: z.string(),
117
+ smith_id: z.string(),
118
+ customer_id: z.string().nullable(),
119
+ meter: z.string(),
120
+ quantity: z.number(),
121
+ day: z.string(),
122
+ metadata: z.record(z.string(), z.unknown()),
123
+ created_at: z.string().nullable(),
124
+ })
125
+ .meta({ id: "UsageEventOut" });
126
+ /** A page of usage events (keyset pagination). */
127
+ export const UsageEventListOut = z
128
+ .object({
129
+ data: z.array(UsageEventOut),
130
+ next_cursor: z.string().nullable(),
131
+ has_more: z.boolean(),
132
+ })
133
+ .meta({ id: "UsageEventListOut" });
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `projects` resource — the org control-plane
3
+ * surface (`/v1/organization/projects`). A project's `id` is the `tenant` that
4
+ * scopes all of its runtime data.
5
+ *
6
+ * Source of truth is the handler (`api/src/routes/projects.ts`): `serialize`
7
+ * emits the project shape, and minting (`api/src/tokens.ts::mintToken`) returns
8
+ * the token shape. The relic `sdk/openapi.json` supplied field/required hints
9
+ * only.
10
+ *
11
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
12
+ * `#/components/schemas/<id>` rather than inlining it.
13
+ */
14
+ import { z } from "zod";
15
+ export const ProjectOut = z
16
+ .object({
17
+ id: z.string(),
18
+ organization: z.string(),
19
+ name: z.string(),
20
+ metadata: z.record(z.string(), z.unknown()),
21
+ /** ISO timestamp; null only if the row predates the column being set. */
22
+ created_at: z.string().nullable(),
23
+ /** Set when the project is archived (soft-deleted); null while live. */
24
+ archived_at: z.string().nullable(),
25
+ })
26
+ .meta({ id: "ProjectOut" });
27
+ export const ProjectListOut = z
28
+ .object({ data: z.array(ProjectOut) })
29
+ .meta({ id: "ProjectListOut" });
30
+ /**
31
+ * The secret minted when an org mints a project (tenant-admin) token. Shape
32
+ * matches `mintToken`'s return; the `tenant` module owns the canonical
33
+ * `ICMintedToken` re-export, so this stays project-named and project-scoped.
34
+ */
35
+ export const ProjectTokenOut = z
36
+ .object({
37
+ id: z.string(),
38
+ /** The branded secret handle (`tha_live_…`). Shown once. */
39
+ token: z.string(),
40
+ scope: z.string(),
41
+ sub: z.string(),
42
+ scopes: z.array(z.string()),
43
+ expires_at: z.string().nullable(),
44
+ })
45
+ .meta({ id: "ProjectTokenOut" });
46
+ // ── Request bodies ──────────────────────────────────────────────────────────
47
+ export const ProjectIn = z
48
+ .object({
49
+ name: z.string(),
50
+ metadata: z.record(z.string(), z.unknown()).nullish(),
51
+ })
52
+ .meta({ id: "ProjectIn" });
53
+ export const ProjectTokenIn = z
54
+ .object({
55
+ ttl_seconds: z.number().int().nullish(),
56
+ name: z.string().nullish(),
57
+ })
58
+ .meta({ id: "ProjectTokenIn" });
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `runs` resource — the wire's source of
3
+ * truth, replacing the inline `IC*` run shapes previously declared in
4
+ * `../responses`.
5
+ *
6
+ * One source, three outputs: the API imports these into its `createRoute`
7
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
8
+ * types are `z.infer`red from them here and re-exported by `../responses`. No
9
+ * Zod is pulled into a type-only consumer — `responses.ts` re-exports these as
10
+ * `export type`.
11
+ *
12
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
13
+ * `#/components/schemas/<id>` rather than inlining it. `RunUsage` is standalone
14
+ * (`$ref`'d) so the inferred `ICRunUsage` comes out identical to its hand-written
15
+ * interface ancestor.
16
+ *
17
+ * Only the JSON shapes are modelled here: the run object, the run list, run
18
+ * events + their list, and the create/submit request bodies. The streaming
19
+ * surfaces emit the native `{v:1}` SSE envelope (not a single JSON schema) and
20
+ * are deliberately not modelled.
21
+ */
22
+ import { z } from "zod";
23
+ import { pageOut } from "./_page.js";
24
+ /** One message in a run's `input`. `content` is a plain string for a text-only
25
+ * turn, or an array of content parts (`{type:"text"|"file"|"image", …}`) for a
26
+ * multimodal turn — the OpenAI-compatible surface and inline-file offloading both
27
+ * persist the array form, so the read schema must accept both. */
28
+ export const InputMessage = z
29
+ .object({
30
+ role: z.string(),
31
+ content: z.union([
32
+ z.string(),
33
+ z.array(z.record(z.string(), z.unknown())),
34
+ ]),
35
+ })
36
+ .meta({ id: "InputMessage" });
37
+ /** One run's own token usage (the `usage` map on a run). Distinct from the
38
+ * tenant's aggregated billing summary. Plain numbers, not ints: provider/cache
39
+ * token math can be fractional, and an int assertion on a read surface buys
40
+ * nothing but a 500 risk. */
41
+ export const RunUsage = z
42
+ .object({
43
+ input_tokens: z.number(),
44
+ output_tokens: z.number(),
45
+ total_tokens: z.number(),
46
+ // This turn's priced cost in the account currency, computed at finish from the
47
+ // model's price book entry. Optional: runs metered before pricing landed — and
48
+ // any turn with no resolvable model — carry tokens but no `cost`.
49
+ cost: z.number().optional(),
50
+ })
51
+ .meta({ id: "RunUsage" });
52
+ export const RunOut = z
53
+ .object({
54
+ id: z.string(),
55
+ smith_id: z.string(),
56
+ thread_id: z.string(),
57
+ status: z.string(),
58
+ channel: z.string(),
59
+ input: z.array(InputMessage),
60
+ // `tool_calls` is an array of surface-specific call objects: the OpenAI
61
+ // `{id,type,function}` shape for a client-tools turn, a pending-call dict for
62
+ // an approval pause. Modelled loosely on purpose — a single strict struct here
63
+ // would 500 the read surface on the shapes actually stored.
64
+ output: z
65
+ .object({
66
+ content: z.string().optional(),
67
+ // Set by a structured (`response_format`) run: the media type of `content`
68
+ // (e.g. `application/json`), so a reader knows to parse it.
69
+ content_type: z.string().optional(),
70
+ tool_calls: z.array(z.record(z.string(), z.unknown())).optional(),
71
+ // Quick-reply chips the agent offered for this reply (via the
72
+ // `suggest_replies` tool). Channels with native support render them as
73
+ // tappable buttons; a tap arrives as the user's next message.
74
+ suggested_replies: z.array(z.string()).optional(),
75
+ })
76
+ .nullable(),
77
+ stop_reason: z.string().nullable(),
78
+ usage: RunUsage.nullable(),
79
+ metadata: z.record(z.string(), z.unknown()).optional(),
80
+ created_at: z.string().nullable(),
81
+ updated_at: z.string().nullable(),
82
+ })
83
+ .meta({ id: "RunOut" });
84
+ export const RunListOut = pageOut(RunOut, "RunListOut");
85
+ /** One recorded run event, as replayed from the event log. */
86
+ export const RunEventOut = z
87
+ .object({
88
+ seq: z.number().int(),
89
+ type: z.string(),
90
+ data: z.record(z.string(), z.unknown()),
91
+ created_at: z.string().nullable(),
92
+ })
93
+ .meta({ id: "RunEventOut" });
94
+ export const RunEventListOut = z
95
+ .object({ data: z.array(RunEventOut) })
96
+ .meta({ id: "RunEventListOut" });
97
+ // ── Request bodies ──────────────────────────────────────────────────────────
98
+ export const RunIn = z
99
+ .object({
100
+ input: z.array(InputMessage).optional(),
101
+ thread_id: z.string().nullish(),
102
+ stream: z.boolean().optional(),
103
+ channel: z.string().optional(),
104
+ metadata: z.record(z.string(), z.unknown()).optional(),
105
+ response_format: z.record(z.string(), z.unknown()).nullish(),
106
+ })
107
+ .meta({ id: "RunIn" });
108
+ export const Submit = z
109
+ .object({
110
+ kind: z.string(),
111
+ tool_call_id: z.string().nullish(),
112
+ result: z.record(z.string(), z.unknown()).nullish(),
113
+ approval_id: z.string().nullish(),
114
+ decision: z.string().nullish(),
115
+ actor: z.string().nullish(),
116
+ reason: z.string().nullish(),
117
+ stream: z.boolean().optional(),
118
+ })
119
+ .meta({ id: "Submit" });