@agentuity/server 0.1.9 → 0.1.11

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 (53) hide show
  1. package/dist/api/api.d.ts +1 -1
  2. package/dist/api/api.d.ts.map +1 -1
  3. package/dist/api/api.js +7 -3
  4. package/dist/api/api.js.map +1 -1
  5. package/dist/api/org/resources.d.ts +10 -5
  6. package/dist/api/org/resources.d.ts.map +1 -1
  7. package/dist/api/org/resources.js +14 -6
  8. package/dist/api/org/resources.js.map +1 -1
  9. package/dist/api/project/deployment.d.ts +14 -0
  10. package/dist/api/project/deployment.d.ts.map +1 -1
  11. package/dist/api/project/deployment.js +20 -0
  12. package/dist/api/project/deployment.js.map +1 -1
  13. package/dist/api/sandbox/create.d.ts.map +1 -1
  14. package/dist/api/sandbox/create.js +1 -4
  15. package/dist/api/sandbox/create.js.map +1 -1
  16. package/dist/api/sandbox/execution.d.ts.map +1 -1
  17. package/dist/api/sandbox/execution.js +4 -1
  18. package/dist/api/sandbox/execution.js.map +1 -1
  19. package/dist/api/sandbox/get.d.ts.map +1 -1
  20. package/dist/api/sandbox/get.js +33 -0
  21. package/dist/api/sandbox/get.js.map +1 -1
  22. package/dist/api/sandbox/index.d.ts +4 -2
  23. package/dist/api/sandbox/index.d.ts.map +1 -1
  24. package/dist/api/sandbox/index.js +2 -1
  25. package/dist/api/sandbox/index.js.map +1 -1
  26. package/dist/api/sandbox/list.d.ts.map +1 -1
  27. package/dist/api/sandbox/list.js +8 -0
  28. package/dist/api/sandbox/list.js.map +1 -1
  29. package/dist/api/sandbox/runtime.d.ts.map +1 -1
  30. package/dist/api/sandbox/runtime.js.map +1 -1
  31. package/dist/api/sandbox/snapshot-build.d.ts +31 -0
  32. package/dist/api/sandbox/snapshot-build.d.ts.map +1 -0
  33. package/dist/api/sandbox/snapshot-build.js +48 -0
  34. package/dist/api/sandbox/snapshot-build.js.map +1 -0
  35. package/dist/api/sandbox/snapshot.d.ts +129 -47
  36. package/dist/api/sandbox/snapshot.d.ts.map +1 -1
  37. package/dist/api/sandbox/snapshot.js +159 -3
  38. package/dist/api/sandbox/snapshot.js.map +1 -1
  39. package/dist/config.js +1 -1
  40. package/dist/config.js.map +1 -1
  41. package/package.json +4 -4
  42. package/src/api/api.ts +17 -3
  43. package/src/api/org/resources.ts +21 -6
  44. package/src/api/project/deployment.ts +28 -0
  45. package/src/api/sandbox/create.ts +1 -4
  46. package/src/api/sandbox/execution.ts +4 -1
  47. package/src/api/sandbox/get.ts +37 -0
  48. package/src/api/sandbox/index.ts +14 -1
  49. package/src/api/sandbox/list.ts +9 -0
  50. package/src/api/sandbox/runtime.ts +10 -8
  51. package/src/api/sandbox/snapshot-build.ts +62 -0
  52. package/src/api/sandbox/snapshot.ts +194 -51
  53. package/src/config.ts +1 -1
package/src/api/api.ts CHANGED
@@ -208,7 +208,8 @@ export class APIClient {
208
208
  responseSchema?: z.ZodType<TResponse>,
209
209
  body?: TBody,
210
210
  bodySchema?: z.ZodType<TBody>,
211
- signal?: AbortSignal
211
+ signal?: AbortSignal,
212
+ extraHeaders?: Record<string, string>
212
213
  ): Promise<TResponse> {
213
214
  // Validate request body if schema provided
214
215
  if (body !== undefined && bodySchema) {
@@ -221,7 +222,14 @@ export class APIClient {
221
222
  }
222
223
  }
223
224
 
224
- const response = await this.#makeRequest(method, endpoint, body, signal);
225
+ const response = await this.#makeRequest(
226
+ method,
227
+ endpoint,
228
+ body,
229
+ signal,
230
+ undefined,
231
+ extraHeaders
232
+ );
225
233
 
226
234
  // Handle empty responses (204 or zero-length body)
227
235
  let data: unknown;
@@ -263,7 +271,8 @@ export class APIClient {
263
271
  endpoint: string,
264
272
  body?: unknown,
265
273
  signal?: AbortSignal,
266
- contentType?: string
274
+ contentType?: string,
275
+ extraHeaders?: Record<string, string>
267
276
  ): Promise<Response> {
268
277
  this.#logger.trace('sending %s to %s%s', method, this.#baseUrl, endpoint);
269
278
 
@@ -294,6 +303,11 @@ export class APIClient {
294
303
  );
295
304
  }
296
305
 
306
+ // Apply per-request extra headers (e.g., x-agentuity-orgid for CLI auth)
307
+ if (extraHeaders) {
308
+ Object.keys(extraHeaders).forEach((key) => (headers[key] = extraHeaders[key]));
309
+ }
310
+
297
311
  const canRetry = !(body instanceof ReadableStream); // we cannot safely retry a ReadableStream as body
298
312
 
299
313
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
@@ -34,27 +34,32 @@ export type OrgDBResource = z.infer<typeof OrgDBResource>;
34
34
  export interface ListOrgResourcesOptions {
35
35
  /** Filter by resource type (default: "all") */
36
36
  type?: 'all' | 's3' | 'db';
37
+ /** Organization ID (required for CLI auth, extracted from context for SDK auth) */
38
+ orgId?: string;
37
39
  }
38
40
 
39
41
  /**
40
42
  * List all resources for the authenticated organization (across all regions)
41
- * Extracts orgId from authentication context (API key, SDK, or CLI token)
42
43
  *
43
44
  * @param client - Catalyst API client (must be authenticated)
44
- * @param options - Optional filters
45
+ * @param options - Optional filters including orgId for CLI auth
45
46
  * @returns List of S3 and DB resources with their cloud regions
46
47
  *
47
48
  * @example
48
- * // Get all resources
49
+ * // Get all resources (SDK auth - orgId from context)
49
50
  * const all = await listOrgResources(client);
50
51
  *
51
52
  * @example
53
+ * // Get all resources (CLI auth - orgId required)
54
+ * const all = await listOrgResources(client, { orgId: 'org_123' });
55
+ *
56
+ * @example
52
57
  * // Get only S3 buckets
53
- * const s3Only = await listOrgResources(client, { type: 's3' });
58
+ * const s3Only = await listOrgResources(client, { type: 's3', orgId: 'org_123' });
54
59
  *
55
60
  * @example
56
61
  * // Get only DBs
57
- * const dbsOnly = await listOrgResources(client, { type: 'db' });
62
+ * const dbsOnly = await listOrgResources(client, { type: 'db', orgId: 'org_123' });
58
63
  */
59
64
  export async function listOrgResources(
60
65
  client: APIClient,
@@ -68,10 +73,20 @@ export async function listOrgResources(
68
73
  const query = params.toString();
69
74
  const url = `/resource/2025-11-16${query ? `?${query}` : ''}`;
70
75
 
76
+ // Build headers - include orgId for CLI auth
77
+ const headers: Record<string, string> = {};
78
+ if (options?.orgId) {
79
+ headers['x-agentuity-orgid'] = options.orgId;
80
+ }
81
+
71
82
  const resp = await client.request<OrgResourceListResponse>(
72
83
  'GET',
73
84
  url,
74
- OrgResourceListResponseSchema
85
+ OrgResourceListResponseSchema,
86
+ undefined,
87
+ undefined,
88
+ undefined,
89
+ headers
75
90
  );
76
91
  if (resp.success) {
77
92
  return resp.data;
@@ -90,6 +90,34 @@ export async function projectDeploymentGet(
90
90
  throw new ProjectResponseError({ message: resp.message });
91
91
  }
92
92
 
93
+ const DeploymentLookupSchema = z.object({
94
+ id: z.string(),
95
+ projectId: z.string(),
96
+ orgId: z.string(),
97
+ cloudRegion: z.string().nullable().optional(),
98
+ state: z.string().nullable().optional(),
99
+ active: z.boolean(),
100
+ });
101
+
102
+ const DeploymentLookupResponseSchema = APIResponseSchema(DeploymentLookupSchema);
103
+
104
+ export type DeploymentLookup = z.infer<typeof DeploymentLookupSchema>;
105
+
106
+ /**
107
+ * Get deployment info by ID only (without requiring project ID).
108
+ * Useful for looking up region/project info for a deployment.
109
+ */
110
+ export async function deploymentGet(
111
+ client: APIClient,
112
+ deploymentId: string
113
+ ): Promise<DeploymentLookup> {
114
+ const resp = await client.get(`/cli/deployment/${deploymentId}`, DeploymentLookupResponseSchema);
115
+ if (resp.success) {
116
+ return resp.data;
117
+ }
118
+ throw new ProjectResponseError({ message: resp.message });
119
+ }
120
+
93
121
  export async function projectDeploymentDelete(
94
122
  client: APIClient,
95
123
  projectId: string,
@@ -5,10 +5,7 @@ import type { SandboxCreateOptions, SandboxStatus } from '@agentuity/core';
5
5
 
6
6
  const SandboxCreateRequestSchema = z
7
7
  .object({
8
- runtime: z
9
- .string()
10
- .optional()
11
- .describe('Runtime name (e.g., "bun:1", "python:3.14")'),
8
+ runtime: z.string().optional().describe('Runtime name (e.g., "bun:1", "python:3.14")'),
12
9
  runtimeId: z.string().optional().describe('Runtime ID (e.g., "srt_xxx")'),
13
10
  name: z.string().optional().describe('Optional sandbox name'),
14
11
  description: z.string().optional().describe('Optional sandbox description'),
@@ -7,7 +7,10 @@ const ExecutionInfoSchema = z
7
7
  .object({
8
8
  executionId: z.string().describe('Unique identifier for the execution'),
9
9
  sandboxId: z.string().describe('ID of the sandbox where the execution ran'),
10
- type: z.string().optional().describe('Type of execution (e.g., exec, write_files, read_file)'),
10
+ type: z
11
+ .string()
12
+ .optional()
13
+ .describe('Type of execution (e.g., exec, write_files, read_file)'),
11
14
  status: z
12
15
  .enum(['queued', 'running', 'completed', 'failed', 'timeout', 'cancelled'])
13
16
  .describe('Current status of the execution'),
@@ -11,6 +11,35 @@ const SandboxResourcesSchema = z
11
11
  })
12
12
  .describe('Resource limits for the sandbox');
13
13
 
14
+ const SandboxUserInfoSchema = z
15
+ .object({
16
+ id: z.string().describe('User ID'),
17
+ firstName: z.string().optional().describe("User's first name"),
18
+ lastName: z.string().optional().describe("User's last name"),
19
+ })
20
+ .describe('User who created the sandbox');
21
+
22
+ const SandboxAgentInfoSchema = z
23
+ .object({
24
+ id: z.string().describe('Agent ID'),
25
+ name: z.string().describe('Agent name'),
26
+ })
27
+ .describe('Agent associated with the sandbox');
28
+
29
+ const SandboxProjectInfoSchema = z
30
+ .object({
31
+ id: z.string().describe('Project ID'),
32
+ name: z.string().describe('Project name'),
33
+ })
34
+ .describe('Project associated with the sandbox');
35
+
36
+ const SandboxOrgInfoSchema = z
37
+ .object({
38
+ id: z.string().describe('Organization ID'),
39
+ name: z.string().describe('Organization name'),
40
+ })
41
+ .describe('Organization associated with the sandbox');
42
+
14
43
  const SandboxInfoDataSchema = z
15
44
  .object({
16
45
  sandboxId: z.string().describe('Unique identifier for the sandbox'),
@@ -43,6 +72,10 @@ const SandboxInfoDataSchema = z
43
72
  memoryByteSec: z.number().optional().describe('Total memory usage in byte-seconds'),
44
73
  networkEgressBytes: z.number().optional().describe('Total network egress in bytes'),
45
74
  networkEnabled: z.boolean().optional().describe('Whether network access is enabled'),
75
+ user: SandboxUserInfoSchema.optional().describe('User who created the sandbox'),
76
+ agent: SandboxAgentInfoSchema.optional().describe('Agent associated with the sandbox'),
77
+ project: SandboxProjectInfoSchema.optional().describe('Project associated with the sandbox'),
78
+ org: SandboxOrgInfoSchema.describe('Organization associated with the sandbox'),
46
79
  })
47
80
  .describe('Detailed information about a sandbox');
48
81
 
@@ -106,6 +139,10 @@ export async function sandboxGet(
106
139
  memoryByteSec: resp.data.memoryByteSec,
107
140
  networkEgressBytes: resp.data.networkEgressBytes,
108
141
  networkEnabled: resp.data.networkEnabled,
142
+ user: resp.data.user,
143
+ agent: resp.data.agent,
144
+ project: resp.data.project,
145
+ org: resp.data.org,
109
146
  };
110
147
  }
111
148
 
@@ -49,7 +49,15 @@ export type {
49
49
  SetEnvParams,
50
50
  SetEnvResult,
51
51
  } from './files';
52
- export { snapshotCreate, snapshotGet, snapshotList, snapshotDelete, snapshotTag } from './snapshot';
52
+ export {
53
+ snapshotCreate,
54
+ snapshotGet,
55
+ snapshotList,
56
+ snapshotDelete,
57
+ snapshotTag,
58
+ snapshotBuildInit,
59
+ snapshotBuildFinalize,
60
+ } from './snapshot';
53
61
  export type {
54
62
  SnapshotInfo,
55
63
  SnapshotFileInfo,
@@ -59,4 +67,9 @@ export type {
59
67
  SnapshotListResponse,
60
68
  SnapshotDeleteParams,
61
69
  SnapshotTagParams,
70
+ SnapshotBuildInitParams,
71
+ SnapshotBuildInitResponse,
72
+ SnapshotBuildFinalizeParams,
62
73
  } from './snapshot';
74
+ export { SnapshotBuildFileSchema } from './snapshot-build';
75
+ export type { SnapshotBuildFile } from './snapshot-build';
@@ -3,6 +3,13 @@ import { APIClient, APIResponseSchema } from '../api';
3
3
  import { SandboxResponseError, API_VERSION } from './util';
4
4
  import type { ListSandboxesParams, ListSandboxesResponse, SandboxStatus } from '@agentuity/core';
5
5
 
6
+ const SandboxOrgInfoSchema = z
7
+ .object({
8
+ id: z.string().describe('Organization ID'),
9
+ name: z.string().describe('Organization name'),
10
+ })
11
+ .describe('Organization associated with the sandbox');
12
+
6
13
  const SandboxInfoSchema = z
7
14
  .object({
8
15
  sandboxId: z.string().describe('Unique identifier for the sandbox'),
@@ -23,6 +30,7 @@ const SandboxInfoSchema = z
23
30
  stdoutStreamUrl: z.string().optional().describe('URL for streaming stdout output'),
24
31
  stderrStreamUrl: z.string().optional().describe('URL for streaming stderr output'),
25
32
  networkEnabled: z.boolean().optional().describe('Whether network access is enabled'),
33
+ org: SandboxOrgInfoSchema.describe('Organization associated with the sandbox'),
26
34
  })
27
35
  .describe('Summary information about a sandbox');
28
36
 
@@ -103,6 +111,7 @@ export async function sandboxList(
103
111
  stdoutStreamUrl: s.stdoutStreamUrl,
104
112
  stderrStreamUrl: s.stderrStreamUrl,
105
113
  networkEnabled: s.networkEnabled,
114
+ org: s.org,
106
115
  })),
107
116
  total: resp.data.total,
108
117
  };
@@ -61,14 +61,16 @@ export async function runtimeList(
61
61
 
62
62
  if (resp.success) {
63
63
  return {
64
- runtimes: resp.data.runtimes.map((r): SandboxRuntime => ({
65
- id: r.id,
66
- name: r.name,
67
- description: r.description,
68
- iconUrl: r.iconUrl,
69
- url: r.url,
70
- tags: r.tags,
71
- })),
64
+ runtimes: resp.data.runtimes.map(
65
+ (r): SandboxRuntime => ({
66
+ id: r.id,
67
+ name: r.name,
68
+ description: r.description,
69
+ iconUrl: r.iconUrl,
70
+ url: r.url,
71
+ tags: r.tags,
72
+ })
73
+ ),
72
74
  total: resp.data.total,
73
75
  };
74
76
  }
@@ -0,0 +1,62 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Base schema for snapshot build configuration file (agentuity-snapshot.yaml)
5
+ * This is the canonical schema - used for JSON Schema generation.
6
+ */
7
+ export const SnapshotBuildFileBaseSchema = z
8
+ .object({
9
+ version: z.literal(1).describe('Schema version, must be 1'),
10
+ runtime: z
11
+ .string()
12
+ .describe('Runtime identifier (name:tag format, e.g., bun:1, node:20, python:3.12)'),
13
+ name: z
14
+ .string()
15
+ .regex(/^[a-zA-Z0-9_-]+$/)
16
+ .optional()
17
+ .describe('Snapshot name (alphanumeric, underscores, dashes only)'),
18
+ description: z.string().optional().describe('Human-readable description of the snapshot'),
19
+ dependencies: z
20
+ .array(z.string())
21
+ .optional()
22
+ .describe(
23
+ 'List of apt packages to install. Supports version pinning: package=version or package=version* for prefix matching'
24
+ ),
25
+ files: z
26
+ .array(z.string())
27
+ .optional()
28
+ .describe(
29
+ 'Glob patterns for files to include from the build context. Supports negative patterns with ! prefix for exclusions'
30
+ ),
31
+ env: z
32
+ .record(z.string(), z.string())
33
+ .optional()
34
+ .describe(
35
+ 'Environment variables to set. Use ${VAR} syntax for build-time substitution via --env flag'
36
+ ),
37
+ metadata: z
38
+ .record(z.string(), z.string())
39
+ .optional()
40
+ .describe(
41
+ 'User-defined metadata key-value pairs. Use ${VAR} syntax for build-time substitution via --metadata flag'
42
+ ),
43
+ })
44
+ .describe('Agentuity Snapshot Build File - defines a reproducible sandbox environment');
45
+
46
+ /**
47
+ * Schema with validation refinement - use this for parsing/validation.
48
+ * Ensures at least one of dependencies, files, or env is specified.
49
+ */
50
+ export const SnapshotBuildFileSchema = SnapshotBuildFileBaseSchema.refine(
51
+ (data) => {
52
+ const hasDependencies = data.dependencies && data.dependencies.length > 0;
53
+ const hasFiles = data.files && data.files.length > 0;
54
+ const hasEnv = data.env && Object.keys(data.env).length > 0;
55
+ return hasDependencies || hasFiles || hasEnv;
56
+ },
57
+ {
58
+ message: 'At least one of dependencies, files, or env must be specified',
59
+ }
60
+ );
61
+
62
+ export type SnapshotBuildFile = z.infer<typeof SnapshotBuildFileSchema>;
@@ -12,8 +12,16 @@ const SnapshotFileInfoSchema = z
12
12
  const SnapshotInfoSchema = z
13
13
  .object({
14
14
  snapshotId: z.string().describe('Unique identifier for the snapshot'),
15
- runtimeId: z.string().nullable().optional().describe('Runtime ID associated with this snapshot'),
16
- name: z.string().describe('Display name for the snapshot (URL-safe: letters, numbers, underscores, dashes)'),
15
+ runtimeId: z
16
+ .string()
17
+ .nullable()
18
+ .optional()
19
+ .describe('Runtime ID associated with this snapshot'),
20
+ name: z
21
+ .string()
22
+ .describe(
23
+ 'Display name for the snapshot (URL-safe: letters, numbers, underscores, dashes)'
24
+ ),
17
25
  description: z.string().nullable().optional().describe('Description of the snapshot'),
18
26
  tag: z.string().nullable().optional().describe('Tag for the snapshot (defaults to "latest")'),
19
27
  sizeBytes: z.number().describe('Total size of the snapshot in bytes'),
@@ -25,7 +33,16 @@ const SnapshotInfoSchema = z
25
33
  .describe('ID of the parent snapshot (for incremental snapshots)'),
26
34
  createdAt: z.string().describe('ISO timestamp when the snapshot was created'),
27
35
  downloadUrl: z.string().optional().describe('URL to download the snapshot archive'),
28
- files: z.array(SnapshotFileInfoSchema).nullable().optional().describe('List of files in the snapshot'),
36
+ files: z
37
+ .array(SnapshotFileInfoSchema)
38
+ .nullable()
39
+ .optional()
40
+ .describe('List of files in the snapshot'),
41
+ userMetadata: z
42
+ .record(z.string(), z.string())
43
+ .nullable()
44
+ .optional()
45
+ .describe('User-defined metadata key-value pairs'),
29
46
  })
30
47
  .describe('Detailed information about a snapshot');
31
48
 
@@ -40,60 +57,56 @@ const SnapshotListDataSchema = z
40
57
  const SnapshotListResponseSchema = APIResponseSchema(SnapshotListDataSchema);
41
58
  const SnapshotDeleteResponseSchema = APIResponseSchemaNoData();
42
59
 
43
- export interface SnapshotFileInfo {
44
- path: string;
45
- size: number;
46
- }
47
-
48
- export interface SnapshotInfo {
49
- snapshotId: string;
50
- runtimeId?: string | null;
51
- name: string;
52
- description?: string | null;
53
- tag?: string | null;
54
- sizeBytes: number;
55
- fileCount: number;
56
- parentSnapshotId?: string | null;
57
- createdAt: string;
58
- downloadUrl?: string;
59
- files?: SnapshotFileInfo[] | null;
60
- }
60
+ export type SnapshotFileInfo = z.infer<typeof SnapshotFileInfoSchema>;
61
+ export type SnapshotInfo = z.infer<typeof SnapshotInfoSchema>;
62
+ export type SnapshotListResponse = z.infer<typeof SnapshotListDataSchema>;
61
63
 
62
- export interface SnapshotCreateParams {
63
- sandboxId: string;
64
- name?: string;
65
- description?: string;
66
- tag?: string;
67
- orgId?: string;
68
- }
64
+ const _SnapshotCreateParamsSchema = z
65
+ .object({
66
+ sandboxId: z.string().describe('ID of the sandbox to snapshot'),
67
+ name: z.string().optional().describe('Display name for the snapshot'),
68
+ description: z.string().optional().describe('Description of the snapshot'),
69
+ tag: z.string().optional().describe('Tag for the snapshot'),
70
+ orgId: z.string().optional().describe('Organization ID'),
71
+ })
72
+ .describe('Parameters for creating a snapshot');
69
73
 
70
- export interface SnapshotGetParams {
71
- snapshotId: string;
72
- orgId?: string;
73
- }
74
+ const _SnapshotGetParamsSchema = z
75
+ .object({
76
+ snapshotId: z.string().describe('ID of the snapshot to retrieve'),
77
+ orgId: z.string().optional().describe('Organization ID'),
78
+ })
79
+ .describe('Parameters for getting a snapshot');
74
80
 
75
- export interface SnapshotListParams {
76
- sandboxId?: string;
77
- limit?: number;
78
- offset?: number;
79
- orgId?: string;
80
- }
81
+ const _SnapshotListParamsSchema = z
82
+ .object({
83
+ sandboxId: z.string().optional().describe('Filter by sandbox ID'),
84
+ limit: z.number().optional().describe('Maximum number of snapshots to return'),
85
+ offset: z.number().optional().describe('Number of snapshots to skip'),
86
+ orgId: z.string().optional().describe('Organization ID'),
87
+ })
88
+ .describe('Parameters for listing snapshots');
81
89
 
82
- export interface SnapshotListResponse {
83
- snapshots: SnapshotInfo[];
84
- total: number;
85
- }
90
+ const _SnapshotDeleteParamsSchema = z
91
+ .object({
92
+ snapshotId: z.string().describe('ID of the snapshot to delete'),
93
+ orgId: z.string().optional().describe('Organization ID'),
94
+ })
95
+ .describe('Parameters for deleting a snapshot');
86
96
 
87
- export interface SnapshotDeleteParams {
88
- snapshotId: string;
89
- orgId?: string;
90
- }
97
+ const _SnapshotTagParamsSchema = z
98
+ .object({
99
+ snapshotId: z.string().describe('ID of the snapshot to tag'),
100
+ tag: z.string().nullable().describe('New tag (or null to remove)'),
101
+ orgId: z.string().optional().describe('Organization ID'),
102
+ })
103
+ .describe('Parameters for tagging a snapshot');
91
104
 
92
- export interface SnapshotTagParams {
93
- snapshotId: string;
94
- tag: string | null;
95
- orgId?: string;
96
- }
105
+ export type SnapshotCreateParams = z.infer<typeof _SnapshotCreateParamsSchema>;
106
+ export type SnapshotGetParams = z.infer<typeof _SnapshotGetParamsSchema>;
107
+ export type SnapshotListParams = z.infer<typeof _SnapshotListParamsSchema>;
108
+ export type SnapshotDeleteParams = z.infer<typeof _SnapshotDeleteParamsSchema>;
109
+ export type SnapshotTagParams = z.infer<typeof _SnapshotTagParamsSchema>;
97
110
 
98
111
  function buildQueryString(params: Record<string, string | number | undefined>): string {
99
112
  const query = new URLSearchParams();
@@ -255,3 +268,133 @@ export async function snapshotTag(
255
268
 
256
269
  throw new SandboxResponseError({ message: resp.message });
257
270
  }
271
+
272
+ // ===== Snapshot Build API =====
273
+
274
+ const _SnapshotBuildInitParamsSchema = z
275
+ .object({
276
+ runtime: z.string().describe('Runtime identifier (name:tag or runtime ID)'),
277
+ name: z.string().optional().describe('Display name for the snapshot'),
278
+ tag: z.string().optional().describe('Tag for the snapshot'),
279
+ description: z.string().optional().describe('Description of the snapshot'),
280
+ contentHash: z.string().optional().describe('SHA-256 hash of snapshot content for change detection'),
281
+ force: z.boolean().optional().describe('Force rebuild even if content is unchanged'),
282
+ orgId: z.string().optional().describe('Organization ID'),
283
+ })
284
+ .describe('Parameters for initializing a snapshot build');
285
+
286
+ const SnapshotBuildInitResponseSchema = z
287
+ .object({
288
+ snapshotId: z.string().optional().describe('Unique identifier for the snapshot being built'),
289
+ uploadUrl: z.string().optional().describe('Pre-signed URL for uploading the snapshot archive'),
290
+ s3Key: z.string().optional().describe('S3 key where the snapshot will be stored'),
291
+ unchanged: z.boolean().optional().describe('True if snapshot content is unchanged'),
292
+ existingId: z.string().optional().describe('ID of existing unchanged snapshot'),
293
+ existingName: z.string().optional().describe('Name of existing unchanged snapshot'),
294
+ existingTag: z.string().optional().describe('Tag of existing unchanged snapshot'),
295
+ })
296
+ .describe('Response from snapshot build init API');
297
+
298
+ const SnapshotBuildInitAPIResponseSchema = APIResponseSchema(SnapshotBuildInitResponseSchema);
299
+
300
+ const _SnapshotBuildFinalizeParamsSchema = z
301
+ .object({
302
+ snapshotId: z.string().describe('Snapshot ID from init response'),
303
+ sizeBytes: z.number().describe('Total size of the snapshot in bytes'),
304
+ fileCount: z.number().describe('Number of files in the snapshot'),
305
+ files: z
306
+ .array(SnapshotFileInfoSchema)
307
+ .describe('List of files with path and size'),
308
+ dependencies: z
309
+ .array(z.string())
310
+ .optional()
311
+ .describe('List of apt packages to install'),
312
+ env: z
313
+ .record(z.string(), z.string())
314
+ .optional()
315
+ .describe('Environment variables to set'),
316
+ metadata: z
317
+ .record(z.string(), z.string())
318
+ .optional()
319
+ .describe('User-defined metadata key-value pairs'),
320
+ orgId: z.string().optional().describe('Organization ID'),
321
+ })
322
+ .describe('Parameters for finalizing a snapshot build');
323
+
324
+ export type SnapshotBuildInitParams = z.infer<typeof _SnapshotBuildInitParamsSchema>;
325
+ export type SnapshotBuildInitResponse = z.infer<typeof SnapshotBuildInitResponseSchema>;
326
+ export type SnapshotBuildFinalizeParams = z.infer<typeof _SnapshotBuildFinalizeParamsSchema>;
327
+
328
+ /**
329
+ * Initialize a snapshot build by getting a presigned upload URL.
330
+ *
331
+ * @param client - The API client to use for the request
332
+ * @param params - Parameters including runtime and optional name/tag/description
333
+ * @returns Snapshot ID and presigned upload URL
334
+ * @throws {SandboxResponseError} If the initialization fails
335
+ */
336
+ export async function snapshotBuildInit(
337
+ client: APIClient,
338
+ params: SnapshotBuildInitParams
339
+ ): Promise<SnapshotBuildInitResponse> {
340
+ const { runtime, name, description, tag, contentHash, force, orgId } = params;
341
+ const queryString = buildQueryString({ orgId });
342
+ const url = `/sandbox/${API_VERSION}/snapshots/build${queryString}`;
343
+
344
+ const body: Record<string, string | boolean> = { runtime };
345
+ if (name) body.name = name;
346
+ if (description) body.description = description;
347
+ if (tag) body.tag = tag;
348
+ if (contentHash) body.contentHash = contentHash;
349
+ if (force) body.force = force;
350
+
351
+ const resp = await client.post<z.infer<typeof SnapshotBuildInitAPIResponseSchema>>(
352
+ url,
353
+ body,
354
+ SnapshotBuildInitAPIResponseSchema
355
+ );
356
+
357
+ if (resp.success) {
358
+ return resp.data;
359
+ }
360
+
361
+ throw new SandboxResponseError({ message: resp.message });
362
+ }
363
+
364
+ /**
365
+ * Finalize a snapshot build after uploading the archive.
366
+ *
367
+ * @param client - The API client to use for the request
368
+ * @param params - Parameters including snapshot details and file metadata
369
+ * @returns The created snapshot information
370
+ * @throws {SandboxResponseError} If the finalization fails
371
+ */
372
+ export async function snapshotBuildFinalize(
373
+ client: APIClient,
374
+ params: SnapshotBuildFinalizeParams
375
+ ): Promise<SnapshotInfo> {
376
+ const { snapshotId, sizeBytes, fileCount, files, dependencies, env, metadata, orgId } = params;
377
+ const queryString = buildQueryString({ orgId });
378
+ const url = `/sandbox/${API_VERSION}/snapshots/${snapshotId}/finalize${queryString}`;
379
+
380
+ const body: Record<string, unknown> = {
381
+ sizeBytes,
382
+ fileCount,
383
+ files,
384
+ };
385
+ if (dependencies) body.dependencies = dependencies;
386
+ if (env) body.env = env;
387
+ if (metadata) body.metadata = metadata;
388
+
389
+ const resp = await client.post<z.infer<typeof SnapshotGetResponseSchema>>(
390
+ url,
391
+ body,
392
+ SnapshotGetResponseSchema
393
+ );
394
+
395
+ if (resp.success) {
396
+ return resp.data;
397
+ }
398
+
399
+ throw new SandboxResponseError({ message: resp.message });
400
+ }
package/src/config.ts CHANGED
@@ -41,7 +41,7 @@ export function getServiceUrls(region?: string): ServiceUrls {
41
41
  }
42
42
 
43
43
  function getDomainSuffix(region?: string) {
44
- if (region === 'local') {
44
+ if (region === 'local' || region === 'l') {
45
45
  return 'agentuity.io';
46
46
  }
47
47
  return 'agentuity.cloud';