@blazingagents/sdk 0.1.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +366 -0
  3. package/dist/chat-transport.d.ts +17 -0
  4. package/dist/chat-transport.js +58 -0
  5. package/dist/client.d.ts +38 -0
  6. package/dist/client.js +86 -0
  7. package/dist/contracts/api.d.ts +256 -0
  8. package/dist/contracts/api.js +189 -0
  9. package/dist/contracts/entities/agent-tools.d.ts +26 -0
  10. package/dist/contracts/entities/agent-tools.js +52 -0
  11. package/dist/contracts/entities/agents.d.ts +183 -0
  12. package/dist/contracts/entities/agents.js +153 -0
  13. package/dist/contracts/entities/artifacts.d.ts +71 -0
  14. package/dist/contracts/entities/artifacts.js +71 -0
  15. package/dist/contracts/entities/attribution.d.ts +27 -0
  16. package/dist/contracts/entities/attribution.js +27 -0
  17. package/dist/contracts/entities/chat.d.ts +269 -0
  18. package/dist/contracts/entities/chat.js +198 -0
  19. package/dist/contracts/entities/mcp-connections.d.ts +421 -0
  20. package/dist/contracts/entities/mcp-connections.js +473 -0
  21. package/dist/contracts/entities/memories.d.ts +56 -0
  22. package/dist/contracts/entities/memories.js +62 -0
  23. package/dist/contracts/entities/prompts.d.ts +61 -0
  24. package/dist/contracts/entities/prompts.js +96 -0
  25. package/dist/contracts/entities/providers.d.ts +123 -0
  26. package/dist/contracts/entities/providers.js +111 -0
  27. package/dist/contracts/entities/sessions.d.ts +156 -0
  28. package/dist/contracts/entities/sessions.js +120 -0
  29. package/dist/contracts/entities/skills.d.ts +167 -0
  30. package/dist/contracts/entities/skills.js +153 -0
  31. package/dist/contracts/entities/tasks.d.ts +457 -0
  32. package/dist/contracts/entities/tasks.js +252 -0
  33. package/dist/contracts/entities/tenants.d.ts +69 -0
  34. package/dist/contracts/entities/tenants.js +54 -0
  35. package/dist/contracts/entities/usage.d.ts +95 -0
  36. package/dist/contracts/entities/usage.js +117 -0
  37. package/dist/contracts/entities/workspaces.d.ts +89 -0
  38. package/dist/contracts/entities/workspaces.js +71 -0
  39. package/dist/contracts/ids.d.ts +57 -0
  40. package/dist/contracts/ids.js +79 -0
  41. package/dist/contracts/index.d.ts +15 -0
  42. package/dist/contracts/index.js +16 -0
  43. package/dist/contracts/limitations.d.ts +138 -0
  44. package/dist/contracts/limitations.js +140 -0
  45. package/dist/contracts/utils.d.ts +3 -0
  46. package/dist/contracts/utils.js +7 -0
  47. package/dist/errors.d.ts +33 -0
  48. package/dist/errors.js +48 -0
  49. package/dist/generation.d.ts +5 -0
  50. package/dist/generation.js +422 -0
  51. package/dist/http.d.ts +21 -0
  52. package/dist/http.js +307 -0
  53. package/dist/index.d.ts +20 -0
  54. package/dist/index.js +13 -0
  55. package/dist/relay.d.ts +20 -0
  56. package/dist/relay.js +113 -0
  57. package/dist/resources/agents.d.ts +8 -0
  58. package/dist/resources/agents.js +82 -0
  59. package/dist/resources/artifacts.d.ts +5 -0
  60. package/dist/resources/artifacts.js +29 -0
  61. package/dist/resources/mcp-connections.d.ts +2 -0
  62. package/dist/resources/mcp-connections.js +40 -0
  63. package/dist/resources/memories.d.ts +7 -0
  64. package/dist/resources/memories.js +33 -0
  65. package/dist/resources/prompts.d.ts +6 -0
  66. package/dist/resources/prompts.js +36 -0
  67. package/dist/resources/providers.d.ts +5 -0
  68. package/dist/resources/providers.js +38 -0
  69. package/dist/resources/sessions.d.ts +8 -0
  70. package/dist/resources/sessions.js +49 -0
  71. package/dist/resources/skills.d.ts +2 -0
  72. package/dist/resources/skills.js +49 -0
  73. package/dist/resources/tasks.d.ts +7 -0
  74. package/dist/resources/tasks.js +63 -0
  75. package/dist/resources/tenant.d.ts +6 -0
  76. package/dist/resources/tenant.js +19 -0
  77. package/dist/resources/usage.d.ts +7 -0
  78. package/dist/resources/usage.js +19 -0
  79. package/dist/resources/workspaces.d.ts +2 -0
  80. package/dist/resources/workspaces.js +31 -0
  81. package/dist/types.d.ts +381 -0
  82. package/dist/types.js +1 -0
  83. package/package.json +65 -0
@@ -0,0 +1,252 @@
1
+ import { Cron } from "croner";
2
+ import { z } from "zod";
3
+ import { paginatedResponseSchema } from "../api.js";
4
+ import { agentIdSchema, sessionIdSchema, taskIdSchema, taskRunIdSchema, tenantIdSchema, turnIdSchema, } from "../ids.js";
5
+ import { MAX_TASK_NAME_LENGTH, MAX_TASK_PROMPT_LENGTH, MIN_TASK_INTERVAL_MS, } from "../limitations.js";
6
+ import { atLeastOneFieldMessage, hasObjectKeys } from "../utils.js";
7
+ import { agentVersionNumberSchema } from "./agents.js";
8
+ import { metadataSchema, userIdSchema } from "./attribution.js";
9
+ import { sessionMessageSchema } from "./sessions.js";
10
+ /**
11
+ * Schedule kinds — discriminated union, Cohand's kinds with croner-forked
12
+ * next-run math. `staggerMs` is an optional cron load-spreading offset.
13
+ */
14
+ export const taskScheduleKindSchema = z.enum(["once", "interval", "cron"]);
15
+ export const taskOnceConfigSchema = z
16
+ .object({
17
+ at: z.iso.datetime({ offset: true }),
18
+ })
19
+ .strict();
20
+ export const taskIntervalConfigSchema = z
21
+ .object({
22
+ everyMs: z.number().int().min(MIN_TASK_INTERVAL_MS),
23
+ })
24
+ .strict();
25
+ const CRON_FIELDS_SEPARATOR = /\s+/;
26
+ const NUMERIC_CRON_EXPRESSION = /^[\d*,/\-\s]+$/;
27
+ /** Croner owns cron grammar; the product limits schedules to five numeric fields. */
28
+ const cronExpressionSchema = z
29
+ .string()
30
+ .trim()
31
+ .min(1)
32
+ .max(120)
33
+ .refine((expression) => expression.split(CRON_FIELDS_SEPARATOR).length === 5 &&
34
+ NUMERIC_CRON_EXPRESSION.test(expression), { message: "Expected a five-field numeric cron expression." });
35
+ /**
36
+ * Canonical IANA timezone: `UTC` or `Area/Location` (optionally
37
+ * `Area/Location/Sublocation`). Rejects legacy abbreviations (`PST`, `GMT`)
38
+ * that `Intl` quietly accepts but `croner` cannot resolve deterministically.
39
+ */
40
+ const IANA_TIMEZONE_REGEX = /^(UTC|[A-Za-z_]+\/[A-Za-z0-9_+-]+(\/[A-Za-z0-9_+-]+)?)$/;
41
+ const ianaTimezoneSchema = z
42
+ .string()
43
+ .trim()
44
+ .min(1)
45
+ .max(64)
46
+ .regex(IANA_TIMEZONE_REGEX, "Expected an IANA timezone (e.g. America/New_York).")
47
+ .refine((tz) => {
48
+ try {
49
+ Intl.DateTimeFormat("en-US", { timeZone: tz });
50
+ return true;
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ }, { message: "Unknown IANA timezone." });
56
+ /**
57
+ * Croner validates the expression in the schedule's own timezone. The DBOS
58
+ * schedule plan uses that validated expression and timezone unchanged.
59
+ */
60
+ export const taskCronConfigSchema = z
61
+ .object({
62
+ expression: cronExpressionSchema,
63
+ staggerMs: z.number().int().min(0).optional(),
64
+ timezone: ianaTimezoneSchema.default("UTC"),
65
+ })
66
+ .strict()
67
+ .superRefine((config, ctx) => {
68
+ try {
69
+ const cron = new Cron(config.expression, {
70
+ paused: true,
71
+ timezone: config.timezone,
72
+ });
73
+ if (cron.nextRun() === null) {
74
+ throw new Error("no next run");
75
+ }
76
+ }
77
+ catch {
78
+ ctx.addIssue({
79
+ code: "custom",
80
+ message: "Invalid cron expression.",
81
+ path: ["expression"],
82
+ });
83
+ }
84
+ });
85
+ export const taskScheduleInputSchema = z.discriminatedUnion("kind", [
86
+ z
87
+ .object({
88
+ kind: z.literal("once"),
89
+ config: taskOnceConfigSchema,
90
+ })
91
+ .strict(),
92
+ z
93
+ .object({
94
+ kind: z.literal("interval"),
95
+ config: taskIntervalConfigSchema,
96
+ })
97
+ .strict(),
98
+ z
99
+ .object({
100
+ kind: z.literal("cron"),
101
+ config: taskCronConfigSchema,
102
+ })
103
+ .strict(),
104
+ ]);
105
+ const taskNameSchema = z.string().trim().min(1).max(MAX_TASK_NAME_LENGTH);
106
+ const taskPromptSchema = z.string().trim().min(1).max(MAX_TASK_PROMPT_LENGTH);
107
+ /**
108
+ * `POST /v1/tasks` — schedule present = scheduled task; absent = on-demand.
109
+ * `submit: true` enqueues a run immediately (on-demand's only trigger
110
+ * alongside creation) with a server-minted random run id. This path is
111
+ * NOT idempotent — each call creates a new task + new run. For run-level
112
+ * idempotency, use `POST /v1/tasks/{taskId}/runs` with an idempotency key
113
+ * (the task must already exist so the deterministic run id is stable
114
+ * across replays).
115
+ */
116
+ export const createTaskBodySchema = z
117
+ .object({
118
+ agentId: agentIdSchema,
119
+ agentVersion: agentVersionNumberSchema.nullable().default(null),
120
+ name: taskNameSchema,
121
+ prompt: taskPromptSchema,
122
+ schedule: taskScheduleInputSchema.nullable().default(null),
123
+ enabled: z.boolean().default(true),
124
+ submit: z.boolean().default(false),
125
+ userId: userIdSchema.default(""),
126
+ metadata: metadataSchema.default({}),
127
+ })
128
+ .strict();
129
+ // `PATCH /v1/tasks/{taskId}` — name/prompt/schedule/enabled/metadata;
130
+ // agentId + userId immutable.
131
+ export const updateTaskBodySchema = z
132
+ .object({
133
+ agentVersion: agentVersionNumberSchema.nullable().optional(),
134
+ name: taskNameSchema.optional(),
135
+ prompt: taskPromptSchema.optional(),
136
+ schedule: taskScheduleInputSchema.nullable().optional(),
137
+ enabled: z.boolean().optional(),
138
+ metadata: metadataSchema.optional(),
139
+ })
140
+ .strict()
141
+ .refine(hasObjectKeys, {
142
+ message: atLeastOneFieldMessage,
143
+ });
144
+ // `POST /v1/tasks/{taskId}/runs` — optional client idempotency key.
145
+ export const createTaskRunBodySchema = z
146
+ .object({
147
+ idempotencyKey: z.string().trim().min(1).optional(),
148
+ })
149
+ .strict();
150
+ /**
151
+ * Task run status. `blocked` is the soft-block terminal state for an expected
152
+ * admission denial, such as quota exhaustion, missing subscription, or
153
+ * insufficient Usage credit. Like the other terminal statuses, it sets
154
+ * `finishedAt` and frees the task's active-run slot for the next scheduled fire.
155
+ */
156
+ export const taskRunStatusSchema = z.enum([
157
+ "queued",
158
+ "running",
159
+ "blocked",
160
+ "succeeded",
161
+ "failed",
162
+ "canceled",
163
+ ]);
164
+ // The task record — pure definition; state lives in its runs.
165
+ export const taskSchema = z
166
+ .object({
167
+ id: taskIdSchema,
168
+ tenantId: tenantIdSchema,
169
+ agentId: agentIdSchema,
170
+ agentVersion: agentVersionNumberSchema.nullable(),
171
+ name: taskNameSchema,
172
+ prompt: taskPromptSchema,
173
+ schedule: taskScheduleInputSchema.nullable(),
174
+ enabled: z.boolean(),
175
+ activeRunId: taskRunIdSchema.nullable(),
176
+ latestRunId: taskRunIdSchema.nullable(),
177
+ userId: userIdSchema,
178
+ metadata: metadataSchema,
179
+ deletedAt: z.iso.datetime({ offset: true }).nullable(),
180
+ createdAt: z.iso.datetime({ offset: true }),
181
+ updatedAt: z.iso.datetime({ offset: true }),
182
+ })
183
+ .strict();
184
+ // Compact run embed for list items — kills N+1 status polling.
185
+ export const taskLatestRunSchema = z
186
+ .object({
187
+ id: taskRunIdSchema,
188
+ status: taskRunStatusSchema,
189
+ finishedAt: z.iso.datetime({ offset: true }).nullable(),
190
+ })
191
+ .strict();
192
+ export const taskListItemSchema = taskSchema.extend({
193
+ latestRun: taskLatestRunSchema.nullable(),
194
+ });
195
+ export const tasksListResponseSchema = paginatedResponseSchema(taskListItemSchema);
196
+ export const tasksListQuerySchema = z
197
+ .object({
198
+ agentId: agentIdSchema.optional(),
199
+ userId: z.string().optional(),
200
+ cursor: z.string().nullable().optional(),
201
+ })
202
+ .strict();
203
+ export const taskResponseSchema = taskSchema;
204
+ // Task run record. `userId`/`metadata` are inherited from the task at
205
+ // enqueue (immutable thereafter); the run's session and usage facts carry
206
+ // the same attribution.
207
+ export const taskRunSchema = z
208
+ .object({
209
+ id: taskRunIdSchema,
210
+ taskId: taskIdSchema,
211
+ tenantId: tenantIdSchema,
212
+ agentId: agentIdSchema,
213
+ agentVersion: agentVersionNumberSchema,
214
+ sessionId: sessionIdSchema.nullable(),
215
+ turnId: turnIdSchema.nullable(),
216
+ status: taskRunStatusSchema,
217
+ error: z.string().nullable(),
218
+ userId: userIdSchema,
219
+ metadata: metadataSchema,
220
+ startedAt: z.iso.datetime({ offset: true }).nullable(),
221
+ finishedAt: z.iso.datetime({ offset: true }).nullable(),
222
+ cancelRequestedAt: z.iso.datetime({ offset: true }).nullable(),
223
+ canceledAt: z.iso.datetime({ offset: true }).nullable(),
224
+ createdAt: z.iso.datetime({ offset: true }),
225
+ updatedAt: z.iso.datetime({ offset: true }),
226
+ })
227
+ .strict();
228
+ export const taskRunResponseSchema = taskRunSchema;
229
+ export const taskRunsListResponseSchema = paginatedResponseSchema(taskRunSchema);
230
+ // `POST /v1/tasks` response — the created task + optional queued run id.
231
+ export const createTaskResponseSchema = z
232
+ .object({
233
+ task: taskSchema,
234
+ runId: taskRunIdSchema.nullable(),
235
+ })
236
+ .strict();
237
+ // `POST /v1/tasks/{taskId}/runs` response — the queued run id.
238
+ export const createTaskRunResponseSchema = z
239
+ .object({
240
+ runId: taskRunIdSchema,
241
+ })
242
+ .strict();
243
+ // `GET .../runs/{runId}/messages` — task-run session transcript, paginated.
244
+ // Mirrors `sessionMessagesResponseSchema`: `latestCursor` is the tail
245
+ // position (newest seq) for the poll loop's `?after=` cursor.
246
+ export const taskRunMessagesResponseSchema = z
247
+ .object({
248
+ data: z.array(sessionMessageSchema),
249
+ nextCursor: z.string().nullable(),
250
+ latestCursor: z.string().nullable(),
251
+ })
252
+ .strict();
@@ -0,0 +1,69 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * `GET /v1/me` (JWT-only) — the tenant record. `authUserId` is a uuid
4
+ * referencing `auth.users(id)` per the migration.
5
+ */
6
+ export declare const tenantSchema: z.ZodObject<{
7
+ id: z.ZodString;
8
+ authUserId: z.ZodUUID;
9
+ email: z.ZodString;
10
+ name: z.ZodString;
11
+ createdAt: z.ZodISODateTime;
12
+ updatedAt: z.ZodISODateTime;
13
+ }, z.core.$strict>;
14
+ export declare const subscriptionStatusSchema: z.ZodEnum<{
15
+ active: "active";
16
+ inactive: "inactive";
17
+ }>;
18
+ export declare const tenantResponseSchema: z.ZodObject<{
19
+ id: z.ZodString;
20
+ authUserId: z.ZodUUID;
21
+ email: z.ZodString;
22
+ name: z.ZodString;
23
+ createdAt: z.ZodISODateTime;
24
+ updatedAt: z.ZodISODateTime;
25
+ subscriptionStatus: z.ZodEnum<{
26
+ active: "active";
27
+ inactive: "inactive";
28
+ }>;
29
+ }, z.core.$strict>;
30
+ /**
31
+ * Quota — `GET/PATCH /v1/tenant` carries the tenant's self-set quota.
32
+ * `null` means unlimited (no quota row).
33
+ */
34
+ export declare const quotaSchema: z.ZodObject<{
35
+ monthlyTokenLimit: z.ZodNullable<z.ZodNumber>;
36
+ monthlyRequestLimit: z.ZodNullable<z.ZodNumber>;
37
+ resetDay: z.ZodNumber;
38
+ }, z.core.$strict>;
39
+ export declare const tenantSettingsSchema: z.ZodObject<{
40
+ name: z.ZodString;
41
+ quota: z.ZodNullable<z.ZodObject<{
42
+ monthlyTokenLimit: z.ZodNullable<z.ZodNumber>;
43
+ monthlyRequestLimit: z.ZodNullable<z.ZodNumber>;
44
+ resetDay: z.ZodNumber;
45
+ }, z.core.$strict>>;
46
+ }, z.core.$strict>;
47
+ export declare const tenantSettingsResponseSchema: z.ZodObject<{
48
+ name: z.ZodString;
49
+ quota: z.ZodNullable<z.ZodObject<{
50
+ monthlyTokenLimit: z.ZodNullable<z.ZodNumber>;
51
+ monthlyRequestLimit: z.ZodNullable<z.ZodNumber>;
52
+ resetDay: z.ZodNumber;
53
+ }, z.core.$strict>>;
54
+ }, z.core.$strict>;
55
+ export declare const updateTenantSettingsBodySchema: z.ZodObject<{
56
+ name: z.ZodOptional<z.ZodString>;
57
+ quota: z.ZodOptional<z.ZodNullable<z.ZodObject<{
58
+ monthlyTokenLimit: z.ZodNullable<z.ZodNumber>;
59
+ monthlyRequestLimit: z.ZodNullable<z.ZodNumber>;
60
+ resetDay: z.ZodNumber;
61
+ }, z.core.$strict>>>;
62
+ }, z.core.$strict>;
63
+ export type Tenant = z.infer<typeof tenantSchema>;
64
+ export type SubscriptionStatus = z.infer<typeof subscriptionStatusSchema>;
65
+ export type TenantResponse = z.infer<typeof tenantResponseSchema>;
66
+ export type Quota = z.infer<typeof quotaSchema>;
67
+ export type TenantSettings = z.infer<typeof tenantSettingsSchema>;
68
+ export type TenantSettingsResponse = z.infer<typeof tenantSettingsResponseSchema>;
69
+ export type UpdateTenantSettingsBody = z.infer<typeof updateTenantSettingsBodySchema>;
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ import { tenantIdSchema } from "../ids.js";
3
+ import { MAX_QUOTA_RESET_DAY, MAX_TENANT_NAME_LENGTH, MIN_QUOTA_RESET_DAY, } from "../limitations.js";
4
+ import { atLeastOneFieldMessage, hasObjectKeys } from "../utils.js";
5
+ /**
6
+ * `GET /v1/me` (JWT-only) — the tenant record. `authUserId` is a uuid
7
+ * referencing `auth.users(id)` per the migration.
8
+ */
9
+ export const tenantSchema = z
10
+ .object({
11
+ id: tenantIdSchema,
12
+ authUserId: z.uuid(),
13
+ email: z.string().min(1),
14
+ name: z.string().min(1),
15
+ createdAt: z.iso.datetime({ offset: true }),
16
+ updatedAt: z.iso.datetime({ offset: true }),
17
+ })
18
+ .strict();
19
+ export const subscriptionStatusSchema = z.enum(["active", "inactive"]);
20
+ export const tenantResponseSchema = tenantSchema
21
+ .extend({ subscriptionStatus: subscriptionStatusSchema })
22
+ .strict();
23
+ /**
24
+ * Quota — `GET/PATCH /v1/tenant` carries the tenant's self-set quota.
25
+ * `null` means unlimited (no quota row).
26
+ */
27
+ export const quotaSchema = z
28
+ .object({
29
+ monthlyTokenLimit: z.number().int().positive().nullable(),
30
+ monthlyRequestLimit: z.number().int().positive().nullable(),
31
+ resetDay: z
32
+ .number()
33
+ .int()
34
+ .min(MIN_QUOTA_RESET_DAY)
35
+ .max(MAX_QUOTA_RESET_DAY),
36
+ })
37
+ .strict()
38
+ .refine(({ monthlyRequestLimit, monthlyTokenLimit }) => monthlyRequestLimit !== null || monthlyTokenLimit !== null, { message: "At least one quota limit is required" });
39
+ export const tenantSettingsSchema = z
40
+ .object({
41
+ name: z.string().trim().min(1).max(MAX_TENANT_NAME_LENGTH),
42
+ quota: quotaSchema.nullable(),
43
+ })
44
+ .strict();
45
+ export const tenantSettingsResponseSchema = tenantSettingsSchema;
46
+ export const updateTenantSettingsBodySchema = z
47
+ .object({
48
+ name: z.string().trim().min(1).max(MAX_TENANT_NAME_LENGTH).optional(),
49
+ quota: quotaSchema.nullable().optional(),
50
+ })
51
+ .strict()
52
+ .refine(hasObjectKeys, {
53
+ message: atLeastOneFieldMessage,
54
+ });
@@ -0,0 +1,95 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * `GET /v1/usage` groupBy — `day|agent|model|session|user`. `session` is
4
+ * top-N by tokens; the others are exhaustive and bounded. `user` is the
5
+ * end-user attribution dimension (ADR-0001) — one bucket per `userId`, with
6
+ * `''` emitted verbatim as the tenant-level bucket.
7
+ */
8
+ export declare const usageGroupBySchema: z.ZodDefault<z.ZodEnum<{
9
+ agent: "agent";
10
+ day: "day";
11
+ model: "model";
12
+ session: "session";
13
+ user: "user";
14
+ }>>;
15
+ /**
16
+ * A `sessionId` filter value — either a real platform session id (`ss_…`)
17
+ * or the `''` sentinel for stateless `completion`/`object` turns. The daily
18
+ * table stores `''` for stateless turns; the bucket wire shape maps `''`
19
+ * back to `null` on read (see `usageBucketSchema.sessionId`).
20
+ */
21
+ export declare const usageSessionFilterSchema: z.ZodString;
22
+ /**
23
+ * `?from=&to=&agentId=&sessionId=&userId=&groupBy=&limit=` — `from`/`to` are
24
+ * date strings (`YYYY-MM-DD`) since the daily table is keyed by `day date`.
25
+ * Range capped at 31 days; default is the last 30 days ending today (UTC).
26
+ * The `sessionId` filter accepts `''` to drill into stateless turns only.
27
+ * The `userId` filter accepts any opaque string (including `''` for
28
+ * tenant-level usage only) — see ADR-0001 for the three filter modes.
29
+ */
30
+ export declare const usageQuerySchema: z.ZodObject<{
31
+ from: z.ZodOptional<z.ZodISODate>;
32
+ to: z.ZodOptional<z.ZodISODate>;
33
+ agentId: z.ZodOptional<z.ZodString>;
34
+ sessionId: z.ZodOptional<z.ZodString>;
35
+ userId: z.ZodOptional<z.ZodString>;
36
+ groupBy: z.ZodDefault<z.ZodEnum<{
37
+ agent: "agent";
38
+ day: "day";
39
+ model: "model";
40
+ session: "session";
41
+ user: "user";
42
+ }>>;
43
+ limit: z.ZodDefault<z.ZodNumber>;
44
+ }, z.core.$strict>;
45
+ /**
46
+ * Usage bucket — one row per group. `sessionId` is the platform session id
47
+ * (`ss_…`) or `null` for the `''` stateless sentinel (mapped at the read
48
+ * seam); `day` is `YYYY-MM-DD` for `groupBy=day`, else `null`. `userId` is
49
+ * the end-user attribution dimension for `groupBy=user` (else `null`); the
50
+ * `''` tenant-level sentinel is emitted verbatim, not mapped to `null`, so
51
+ * callers can distinguish tenant-level usage from a named user.
52
+ */
53
+ export declare const usageBucketSchema: z.ZodObject<{
54
+ day: z.ZodNullable<z.ZodString>;
55
+ agentId: z.ZodNullable<z.ZodString>;
56
+ sessionId: z.ZodNullable<z.ZodString>;
57
+ userId: z.ZodNullable<z.ZodString>;
58
+ provider: z.ZodNullable<z.ZodString>;
59
+ model: z.ZodNullable<z.ZodString>;
60
+ inputTokens: z.ZodNumber;
61
+ outputTokens: z.ZodNumber;
62
+ requestCount: z.ZodNumber;
63
+ durationMs: z.ZodNumber;
64
+ }, z.core.$strict>;
65
+ export declare const usageTotalsSchema: z.ZodObject<{
66
+ inputTokens: z.ZodNumber;
67
+ outputTokens: z.ZodNumber;
68
+ requestCount: z.ZodNumber;
69
+ durationMs: z.ZodNumber;
70
+ }, z.core.$strict>;
71
+ export declare const usageResponseSchema: z.ZodObject<{
72
+ buckets: z.ZodArray<z.ZodObject<{
73
+ day: z.ZodNullable<z.ZodString>;
74
+ agentId: z.ZodNullable<z.ZodString>;
75
+ sessionId: z.ZodNullable<z.ZodString>;
76
+ userId: z.ZodNullable<z.ZodString>;
77
+ provider: z.ZodNullable<z.ZodString>;
78
+ model: z.ZodNullable<z.ZodString>;
79
+ inputTokens: z.ZodNumber;
80
+ outputTokens: z.ZodNumber;
81
+ requestCount: z.ZodNumber;
82
+ durationMs: z.ZodNumber;
83
+ }, z.core.$strict>>;
84
+ totals: z.ZodObject<{
85
+ inputTokens: z.ZodNumber;
86
+ outputTokens: z.ZodNumber;
87
+ requestCount: z.ZodNumber;
88
+ durationMs: z.ZodNumber;
89
+ }, z.core.$strict>;
90
+ }, z.core.$strict>;
91
+ export type UsageGroupBy = z.infer<typeof usageGroupBySchema>;
92
+ export type UsageQuery = z.infer<typeof usageQuerySchema>;
93
+ export type UsageBucket = z.infer<typeof usageBucketSchema>;
94
+ export type UsageTotals = z.infer<typeof usageTotalsSchema>;
95
+ export type UsageResponse = z.infer<typeof usageResponseSchema>;
@@ -0,0 +1,117 @@
1
+ import { z } from "zod";
2
+ import { agentIdSchema, sessionIdSchema } from "../ids.js";
3
+ import { DEFAULT_USAGE_SESSION_TOP_N, MAX_USAGE_RANGE_DAYS, MAX_USAGE_SESSION_TOP_N, } from "../limitations.js";
4
+ import { userIdSchema } from "./attribution.js";
5
+ /**
6
+ * `GET /v1/usage` groupBy — `day|agent|model|session|user`. `session` is
7
+ * top-N by tokens; the others are exhaustive and bounded. `user` is the
8
+ * end-user attribution dimension (ADR-0001) — one bucket per `userId`, with
9
+ * `''` emitted verbatim as the tenant-level bucket.
10
+ */
11
+ export const usageGroupBySchema = z
12
+ .enum(["day", "agent", "model", "session", "user"])
13
+ .default("day");
14
+ /**
15
+ * A `sessionId` filter value — either a real platform session id (`ss_…`)
16
+ * or the `''` sentinel for stateless `completion`/`object` turns. The daily
17
+ * table stores `''` for stateless turns; the bucket wire shape maps `''`
18
+ * back to `null` on read (see `usageBucketSchema.sessionId`).
19
+ */
20
+ export const usageSessionFilterSchema = z
21
+ .string()
22
+ .refine((v) => v === "" || z.validate(sessionIdSchema, v), {
23
+ message: "Must be a session id or '' for stateless turns.",
24
+ });
25
+ /**
26
+ * `?from=&to=&agentId=&sessionId=&userId=&groupBy=&limit=` — `from`/`to` are
27
+ * date strings (`YYYY-MM-DD`) since the daily table is keyed by `day date`.
28
+ * Range capped at 31 days; default is the last 30 days ending today (UTC).
29
+ * The `sessionId` filter accepts `''` to drill into stateless turns only.
30
+ * The `userId` filter accepts any opaque string (including `''` for
31
+ * tenant-level usage only) — see ADR-0001 for the three filter modes.
32
+ */
33
+ export const usageQuerySchema = z
34
+ .object({
35
+ from: z.iso.date().optional(),
36
+ to: z.iso.date().optional(),
37
+ agentId: agentIdSchema.optional(),
38
+ sessionId: usageSessionFilterSchema.optional(),
39
+ userId: userIdSchema.optional(),
40
+ groupBy: usageGroupBySchema,
41
+ limit: z
42
+ .number()
43
+ .int()
44
+ .min(1)
45
+ .max(MAX_USAGE_SESSION_TOP_N)
46
+ .default(DEFAULT_USAGE_SESSION_TOP_N),
47
+ })
48
+ .strict()
49
+ .superRefine((value, ctx) => {
50
+ /**
51
+ * Require either both `from` and `to` or neither — a partial range
52
+ * (only one bound) is rejected so the caller doesn't silently get the
53
+ * default window when they meant to specify a custom range.
54
+ */
55
+ if ((value.from === undefined) !== (value.to === undefined)) {
56
+ ctx.addIssue({
57
+ code: "custom",
58
+ message: "`from` and `to` must both be present or both be absent.",
59
+ path: value.from === undefined ? ["from"] : ["to"],
60
+ });
61
+ }
62
+ if (value.from && value.to) {
63
+ const fromMs = new Date(`${value.from}T00:00:00Z`).getTime();
64
+ const toMs = new Date(`${value.to}T00:00:00Z`).getTime();
65
+ const spanDays = (toMs - fromMs) / (1000 * 60 * 60 * 24);
66
+ if (spanDays > MAX_USAGE_RANGE_DAYS) {
67
+ ctx.addIssue({
68
+ code: "custom",
69
+ message: `Usage range must be at most ${MAX_USAGE_RANGE_DAYS} days.`,
70
+ path: ["to"],
71
+ });
72
+ }
73
+ if (toMs < fromMs) {
74
+ ctx.addIssue({
75
+ code: "custom",
76
+ message: "`to` must be after `from`.",
77
+ path: ["to"],
78
+ });
79
+ }
80
+ }
81
+ });
82
+ /**
83
+ * Usage bucket — one row per group. `sessionId` is the platform session id
84
+ * (`ss_…`) or `null` for the `''` stateless sentinel (mapped at the read
85
+ * seam); `day` is `YYYY-MM-DD` for `groupBy=day`, else `null`. `userId` is
86
+ * the end-user attribution dimension for `groupBy=user` (else `null`); the
87
+ * `''` tenant-level sentinel is emitted verbatim, not mapped to `null`, so
88
+ * callers can distinguish tenant-level usage from a named user.
89
+ */
90
+ export const usageBucketSchema = z
91
+ .object({
92
+ day: z.string().nullable(),
93
+ agentId: agentIdSchema.nullable(),
94
+ sessionId: sessionIdSchema.nullable(),
95
+ userId: userIdSchema.nullable(),
96
+ provider: z.string().nullable(),
97
+ model: z.string().nullable(),
98
+ inputTokens: z.number().int().nonnegative(),
99
+ outputTokens: z.number().int().nonnegative(),
100
+ requestCount: z.number().int().nonnegative(),
101
+ durationMs: z.number().int().nonnegative(),
102
+ })
103
+ .strict();
104
+ export const usageTotalsSchema = z
105
+ .object({
106
+ inputTokens: z.number().int().nonnegative(),
107
+ outputTokens: z.number().int().nonnegative(),
108
+ requestCount: z.number().int().nonnegative(),
109
+ durationMs: z.number().int().nonnegative(),
110
+ })
111
+ .strict();
112
+ export const usageResponseSchema = z
113
+ .object({
114
+ buckets: z.array(usageBucketSchema),
115
+ totals: usageTotalsSchema,
116
+ })
117
+ .strict();
@@ -0,0 +1,89 @@
1
+ import { z } from "zod";
2
+ export declare const workspaceNameSchema: z.ZodString;
3
+ export declare const workspaceBackupSchema: z.ZodObject<{
4
+ dir: z.ZodLiteral<"/workspace">;
5
+ id: z.ZodUUID;
6
+ localBucket: z.ZodOptional<z.ZodBoolean>;
7
+ }, z.core.$strict>;
8
+ export declare const workspaceNetworkPolicySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
9
+ mode: z.ZodLiteral<"unrestricted">;
10
+ }, z.core.$strict>, z.ZodObject<{
11
+ allowedHosts: z.ZodArray<z.ZodString>;
12
+ mode: z.ZodLiteral<"allowlist">;
13
+ }, z.core.$strict>, z.ZodObject<{
14
+ mode: z.ZodLiteral<"offline">;
15
+ }, z.core.$strict>], "mode">;
16
+ export declare const workspaceSchema: z.ZodObject<{
17
+ id: z.ZodString;
18
+ tenantId: z.ZodString;
19
+ name: z.ZodNullable<z.ZodString>;
20
+ userId: z.ZodString;
21
+ metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
22
+ networkPolicy: z.ZodDiscriminatedUnion<[z.ZodObject<{
23
+ mode: z.ZodLiteral<"unrestricted">;
24
+ }, z.core.$strict>, z.ZodObject<{
25
+ allowedHosts: z.ZodArray<z.ZodString>;
26
+ mode: z.ZodLiteral<"allowlist">;
27
+ }, z.core.$strict>, z.ZodObject<{
28
+ mode: z.ZodLiteral<"offline">;
29
+ }, z.core.$strict>], "mode">;
30
+ createdAt: z.ZodISODateTime;
31
+ updatedAt: z.ZodISODateTime;
32
+ }, z.core.$strict>;
33
+ export declare const createWorkspaceBodySchema: z.ZodObject<{
34
+ name: z.ZodOptional<z.ZodString>;
35
+ userId: z.ZodDefault<z.ZodString>;
36
+ metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
37
+ networkPolicy: z.ZodDefault<z.ZodDiscriminatedUnion<[z.ZodObject<{
38
+ mode: z.ZodLiteral<"unrestricted">;
39
+ }, z.core.$strict>, z.ZodObject<{
40
+ allowedHosts: z.ZodArray<z.ZodString>;
41
+ mode: z.ZodLiteral<"allowlist">;
42
+ }, z.core.$strict>, z.ZodObject<{
43
+ mode: z.ZodLiteral<"offline">;
44
+ }, z.core.$strict>], "mode">>;
45
+ }, z.core.$strict>;
46
+ export declare const updateWorkspaceBodySchema: z.ZodObject<{
47
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
48
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
49
+ networkPolicy: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
50
+ mode: z.ZodLiteral<"unrestricted">;
51
+ }, z.core.$strict>, z.ZodObject<{
52
+ allowedHosts: z.ZodArray<z.ZodString>;
53
+ mode: z.ZodLiteral<"allowlist">;
54
+ }, z.core.$strict>, z.ZodObject<{
55
+ mode: z.ZodLiteral<"offline">;
56
+ }, z.core.$strict>], "mode">>;
57
+ }, z.core.$strict>;
58
+ export declare const workspaceListQuerySchema: z.ZodObject<{
59
+ cursor: z.ZodOptional<z.ZodString>;
60
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
61
+ userId: z.ZodOptional<z.ZodString>;
62
+ }, z.core.$strict>;
63
+ export declare const workspacesListResponseSchema: z.ZodObject<{
64
+ data: z.ZodArray<z.ZodObject<{
65
+ id: z.ZodString;
66
+ tenantId: z.ZodString;
67
+ name: z.ZodNullable<z.ZodString>;
68
+ userId: z.ZodString;
69
+ metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
70
+ networkPolicy: z.ZodDiscriminatedUnion<[z.ZodObject<{
71
+ mode: z.ZodLiteral<"unrestricted">;
72
+ }, z.core.$strict>, z.ZodObject<{
73
+ allowedHosts: z.ZodArray<z.ZodString>;
74
+ mode: z.ZodLiteral<"allowlist">;
75
+ }, z.core.$strict>, z.ZodObject<{
76
+ mode: z.ZodLiteral<"offline">;
77
+ }, z.core.$strict>], "mode">;
78
+ createdAt: z.ZodISODateTime;
79
+ updatedAt: z.ZodISODateTime;
80
+ }, z.core.$strict>>;
81
+ nextCursor: z.ZodNullable<z.ZodString>;
82
+ }, z.core.$strict>;
83
+ export type Workspace = z.infer<typeof workspaceSchema>;
84
+ export type WorkspaceBackup = z.infer<typeof workspaceBackupSchema>;
85
+ export type WorkspaceNetworkPolicy = z.infer<typeof workspaceNetworkPolicySchema>;
86
+ export type CreateWorkspaceBody = z.input<typeof createWorkspaceBodySchema>;
87
+ export type UpdateWorkspaceBody = z.infer<typeof updateWorkspaceBodySchema>;
88
+ export type WorkspaceListQuery = z.infer<typeof workspaceListQuerySchema>;
89
+ export type WorkspacesListResponse = z.infer<typeof workspacesListResponseSchema>;