@agentuity/server 0.0.110 → 0.0.111

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 (37) hide show
  1. package/dist/api/api.d.ts +5 -0
  2. package/dist/api/api.d.ts.map +1 -1
  3. package/dist/api/api.js +23 -4
  4. package/dist/api/api.js.map +1 -1
  5. package/dist/api/project/deploy.d.ts +1 -1
  6. package/dist/api/project/deploy.js +1 -1
  7. package/dist/api/project/deploy.js.map +1 -1
  8. package/dist/api/sandbox/create.d.ts.map +1 -1
  9. package/dist/api/sandbox/create.js +7 -0
  10. package/dist/api/sandbox/create.js.map +1 -1
  11. package/dist/api/sandbox/files.d.ts +120 -0
  12. package/dist/api/sandbox/files.d.ts.map +1 -1
  13. package/dist/api/sandbox/files.js +287 -0
  14. package/dist/api/sandbox/files.js.map +1 -1
  15. package/dist/api/sandbox/get.d.ts.map +1 -1
  16. package/dist/api/sandbox/get.js +5 -0
  17. package/dist/api/sandbox/get.js.map +1 -1
  18. package/dist/api/sandbox/index.d.ts +2 -2
  19. package/dist/api/sandbox/index.d.ts.map +1 -1
  20. package/dist/api/sandbox/index.js +1 -1
  21. package/dist/api/sandbox/index.js.map +1 -1
  22. package/dist/api/sandbox/snapshot.d.ts +0 -1
  23. package/dist/api/sandbox/snapshot.d.ts.map +1 -1
  24. package/dist/api/sandbox/snapshot.js +6 -8
  25. package/dist/api/sandbox/snapshot.js.map +1 -1
  26. package/dist/schema.d.ts.map +1 -1
  27. package/dist/schema.js +3 -1
  28. package/dist/schema.js.map +1 -1
  29. package/package.json +5 -5
  30. package/src/api/api.ts +40 -4
  31. package/src/api/project/deploy.ts +1 -1
  32. package/src/api/sandbox/create.ts +7 -0
  33. package/src/api/sandbox/files.ts +450 -0
  34. package/src/api/sandbox/get.ts +5 -0
  35. package/src/api/sandbox/index.ts +27 -2
  36. package/src/api/sandbox/snapshot.ts +6 -10
  37. package/src/schema.ts +3 -1
@@ -65,6 +65,10 @@ const SandboxCreateRequestSchema = z
65
65
  .array(z.string())
66
66
  .optional()
67
67
  .describe('Apt packages to install when creating the sandbox'),
68
+ metadata: z
69
+ .record(z.string(), z.unknown())
70
+ .optional()
71
+ .describe('Optional user-defined metadata to associate with the sandbox'),
68
72
  })
69
73
  .describe('Request body for creating a new sandbox');
70
74
 
@@ -143,6 +147,9 @@ export async function sandboxCreate(
143
147
  if (options.dependencies && options.dependencies.length > 0) {
144
148
  body.dependencies = options.dependencies;
145
149
  }
150
+ if (options.metadata) {
151
+ body.metadata = options.metadata;
152
+ }
146
153
 
147
154
  const queryParams = new URLSearchParams();
148
155
  if (orgId) {
@@ -136,3 +136,453 @@ export async function sandboxReadFile(
136
136
 
137
137
  return response.body;
138
138
  }
139
+
140
+ const MkDirRequestSchema = z
141
+ .object({
142
+ path: z.string().describe('Path to the directory to create'),
143
+ recursive: z.boolean().optional().describe('Create parent directories if needed'),
144
+ })
145
+ .describe('Request body for creating a directory');
146
+
147
+ const MkDirResponseSchema = z.discriminatedUnion('success', [
148
+ z.object({
149
+ success: z.literal<false>(false),
150
+ message: z.string().describe('the error message'),
151
+ }),
152
+ z.object({
153
+ success: z.literal<true>(true),
154
+ }),
155
+ ]);
156
+
157
+ export interface MkDirParams {
158
+ sandboxId: string;
159
+ path: string;
160
+ recursive?: boolean;
161
+ orgId?: string;
162
+ signal?: AbortSignal;
163
+ }
164
+
165
+ /**
166
+ * Creates a directory in a sandbox workspace.
167
+ *
168
+ * @param client - The API client to use for the request
169
+ * @param params - Parameters including sandbox ID, path, and recursive flag
170
+ * @throws {SandboxResponseError} If the mkdir request fails
171
+ */
172
+ export async function sandboxMkDir(client: APIClient, params: MkDirParams): Promise<void> {
173
+ const { sandboxId, path, recursive, orgId, signal } = params;
174
+
175
+ const body: z.infer<typeof MkDirRequestSchema> = {
176
+ path,
177
+ recursive: recursive ?? false,
178
+ };
179
+
180
+ const queryParams = new URLSearchParams();
181
+ if (orgId) {
182
+ queryParams.set('orgId', orgId);
183
+ }
184
+ const queryString = queryParams.toString();
185
+ const url = `/fs/${API_VERSION}/mkdir/${sandboxId}${queryString ? `?${queryString}` : ''}`;
186
+
187
+ const resp = await client.post<z.infer<typeof MkDirResponseSchema>>(
188
+ url,
189
+ body,
190
+ MkDirResponseSchema,
191
+ MkDirRequestSchema,
192
+ signal
193
+ );
194
+
195
+ if (!resp.success) {
196
+ throw new SandboxResponseError({ message: resp.message, sandboxId });
197
+ }
198
+ }
199
+
200
+ const RmDirRequestSchema = z
201
+ .object({
202
+ path: z.string().describe('Path to the directory to remove'),
203
+ recursive: z.boolean().optional().describe('Remove directory and all contents'),
204
+ })
205
+ .describe('Request body for removing a directory');
206
+
207
+ const RmDirResponseSchema = z.discriminatedUnion('success', [
208
+ z.object({
209
+ success: z.literal<false>(false),
210
+ message: z.string().describe('the error message'),
211
+ }),
212
+ z.object({
213
+ success: z.literal<true>(true),
214
+ }),
215
+ ]);
216
+
217
+ export interface RmDirParams {
218
+ sandboxId: string;
219
+ path: string;
220
+ recursive?: boolean;
221
+ orgId?: string;
222
+ signal?: AbortSignal;
223
+ }
224
+
225
+ /**
226
+ * Removes a directory from a sandbox workspace.
227
+ *
228
+ * @param client - The API client to use for the request
229
+ * @param params - Parameters including sandbox ID, path, and recursive flag
230
+ * @throws {SandboxResponseError} If the rmdir request fails
231
+ */
232
+ export async function sandboxRmDir(client: APIClient, params: RmDirParams): Promise<void> {
233
+ const { sandboxId, path, recursive, orgId, signal } = params;
234
+
235
+ const body: z.infer<typeof RmDirRequestSchema> = {
236
+ path,
237
+ recursive: recursive ?? false,
238
+ };
239
+
240
+ const queryParams = new URLSearchParams();
241
+ if (orgId) {
242
+ queryParams.set('orgId', orgId);
243
+ }
244
+ const queryString = queryParams.toString();
245
+ const url = `/fs/${API_VERSION}/rmdir/${sandboxId}${queryString ? `?${queryString}` : ''}`;
246
+
247
+ const resp = await client.post<z.infer<typeof RmDirResponseSchema>>(
248
+ url,
249
+ body,
250
+ RmDirResponseSchema,
251
+ RmDirRequestSchema,
252
+ signal
253
+ );
254
+
255
+ if (!resp.success) {
256
+ throw new SandboxResponseError({ message: resp.message, sandboxId });
257
+ }
258
+ }
259
+
260
+ const RmFileRequestSchema = z
261
+ .object({
262
+ path: z.string().describe('Path to the file to remove'),
263
+ })
264
+ .describe('Request body for removing a file');
265
+
266
+ const RmFileResponseSchema = z.discriminatedUnion('success', [
267
+ z.object({
268
+ success: z.literal<false>(false),
269
+ message: z.string().describe('the error message'),
270
+ }),
271
+ z.object({
272
+ success: z.literal<true>(true),
273
+ }),
274
+ ]);
275
+
276
+ export interface RmFileParams {
277
+ sandboxId: string;
278
+ path: string;
279
+ orgId?: string;
280
+ signal?: AbortSignal;
281
+ }
282
+
283
+ /**
284
+ * Removes a file from a sandbox workspace.
285
+ *
286
+ * @param client - The API client to use for the request
287
+ * @param params - Parameters including sandbox ID and path
288
+ * @throws {SandboxResponseError} If the rm request fails
289
+ */
290
+ export async function sandboxRmFile(client: APIClient, params: RmFileParams): Promise<void> {
291
+ const { sandboxId, path, orgId, signal } = params;
292
+
293
+ const body: z.infer<typeof RmFileRequestSchema> = {
294
+ path,
295
+ };
296
+
297
+ const queryParams = new URLSearchParams();
298
+ if (orgId) {
299
+ queryParams.set('orgId', orgId);
300
+ }
301
+ const queryString = queryParams.toString();
302
+ const url = `/fs/${API_VERSION}/rm/${sandboxId}${queryString ? `?${queryString}` : ''}`;
303
+
304
+ const resp = await client.post<z.infer<typeof RmFileResponseSchema>>(
305
+ url,
306
+ body,
307
+ RmFileResponseSchema,
308
+ RmFileRequestSchema,
309
+ signal
310
+ );
311
+
312
+ if (!resp.success) {
313
+ throw new SandboxResponseError({ message: resp.message, sandboxId });
314
+ }
315
+ }
316
+
317
+ const FileInfoSchema = z.object({
318
+ path: z.string().describe('File path relative to the listed directory'),
319
+ size: z.number().describe('File size in bytes'),
320
+ isDir: z.boolean().describe('Whether the entry is a directory'),
321
+ mode: z.string().describe('Unix permissions as octal string (e.g., "0644")'),
322
+ modTime: z.string().describe('Modification time in RFC3339 format'),
323
+ });
324
+
325
+ const ListFilesDataSchema = z.object({
326
+ files: z.array(FileInfoSchema).describe('Array of file information'),
327
+ });
328
+
329
+ const ListFilesResponseSchema = z.discriminatedUnion('success', [
330
+ z.object({
331
+ success: z.literal<false>(false),
332
+ message: z.string().describe('the error message'),
333
+ }),
334
+ z.object({
335
+ success: z.literal<true>(true),
336
+ data: ListFilesDataSchema,
337
+ }),
338
+ ]);
339
+
340
+ export interface FileInfo {
341
+ path: string;
342
+ size: number;
343
+ isDir: boolean;
344
+ mode: string;
345
+ modTime: string;
346
+ }
347
+
348
+ export interface ListFilesParams {
349
+ sandboxId: string;
350
+ path?: string;
351
+ orgId?: string;
352
+ signal?: AbortSignal;
353
+ }
354
+
355
+ export interface ListFilesResult {
356
+ files: FileInfo[];
357
+ }
358
+
359
+ /**
360
+ * Lists files in a sandbox workspace directory.
361
+ *
362
+ * @param client - The API client to use for the request
363
+ * @param params - Parameters including sandbox ID and optional path
364
+ * @returns The list of files and directories
365
+ * @throws {SandboxResponseError} If the list request fails
366
+ */
367
+ export async function sandboxListFiles(
368
+ client: APIClient,
369
+ params: ListFilesParams
370
+ ): Promise<ListFilesResult> {
371
+ const { sandboxId, path, orgId, signal } = params;
372
+
373
+ const queryParams = new URLSearchParams();
374
+ if (path) {
375
+ queryParams.set('path', path);
376
+ }
377
+ if (orgId) {
378
+ queryParams.set('orgId', orgId);
379
+ }
380
+ const queryString = queryParams.toString();
381
+ const url = `/fs/${API_VERSION}/list/${sandboxId}${queryString ? `?${queryString}` : ''}`;
382
+
383
+ const resp = await client.get<z.infer<typeof ListFilesResponseSchema>>(
384
+ url,
385
+ ListFilesResponseSchema,
386
+ signal
387
+ );
388
+
389
+ if (resp.success) {
390
+ return {
391
+ files: resp.data.files,
392
+ };
393
+ }
394
+
395
+ throw new SandboxResponseError({ message: resp.message, sandboxId });
396
+ }
397
+
398
+ export type ArchiveFormat = 'zip' | 'tar.gz';
399
+
400
+ export interface DownloadArchiveParams {
401
+ sandboxId: string;
402
+ path?: string;
403
+ format?: ArchiveFormat;
404
+ orgId?: string;
405
+ signal?: AbortSignal;
406
+ }
407
+
408
+ /**
409
+ * Downloads files from a sandbox as a compressed archive.
410
+ *
411
+ * @param client - The API client to use for the request
412
+ * @param params - Parameters including sandbox ID, path, and format
413
+ * @returns A ReadableStream of the archive contents
414
+ * @throws {SandboxResponseError} If the download request fails
415
+ */
416
+ export async function sandboxDownloadArchive(
417
+ client: APIClient,
418
+ params: DownloadArchiveParams
419
+ ): Promise<ReadableStream<Uint8Array>> {
420
+ const { sandboxId, path, format, orgId, signal } = params;
421
+
422
+ const queryParams = new URLSearchParams();
423
+ if (path) {
424
+ queryParams.set('path', path);
425
+ }
426
+ if (format) {
427
+ queryParams.set('format', format);
428
+ }
429
+ if (orgId) {
430
+ queryParams.set('orgId', orgId);
431
+ }
432
+ const queryString = queryParams.toString();
433
+ const url = `/fs/${API_VERSION}/download/${sandboxId}${queryString ? `?${queryString}` : ''}`;
434
+
435
+ const response = await client.rawGet(url, signal);
436
+
437
+ if (!response.ok) {
438
+ const text = await response.text().catch(() => 'Unknown error');
439
+ throw new SandboxResponseError({
440
+ message: `Failed to download archive: ${response.status} ${text}`,
441
+ sandboxId,
442
+ });
443
+ }
444
+
445
+ if (!response.body) {
446
+ throw new SandboxResponseError({
447
+ message: 'No response body',
448
+ sandboxId,
449
+ });
450
+ }
451
+
452
+ return response.body;
453
+ }
454
+
455
+ export interface UploadArchiveParams {
456
+ sandboxId: string;
457
+ archive: Uint8Array | ArrayBuffer | ReadableStream<Uint8Array>;
458
+ path?: string;
459
+ format?: ArchiveFormat | '';
460
+ orgId?: string;
461
+ signal?: AbortSignal;
462
+ }
463
+
464
+ const UploadArchiveResponseSchema = z.discriminatedUnion('success', [
465
+ z.object({
466
+ success: z.literal<false>(false),
467
+ message: z.string().describe('the error message'),
468
+ }),
469
+ z.object({
470
+ success: z.literal<true>(true),
471
+ }),
472
+ ]);
473
+
474
+ /**
475
+ * Uploads a compressed archive to a sandbox and extracts it.
476
+ *
477
+ * @param client - The API client to use for the request
478
+ * @param params - Parameters including sandbox ID, archive data, path, and optional format
479
+ * @throws {SandboxResponseError} If the upload request fails
480
+ */
481
+ export async function sandboxUploadArchive(
482
+ client: APIClient,
483
+ params: UploadArchiveParams
484
+ ): Promise<void> {
485
+ const { sandboxId, archive, path, format, orgId, signal } = params;
486
+
487
+ const queryParams = new URLSearchParams();
488
+ if (path) {
489
+ queryParams.set('path', path);
490
+ }
491
+ if (format) {
492
+ queryParams.set('format', format);
493
+ }
494
+ if (orgId) {
495
+ queryParams.set('orgId', orgId);
496
+ }
497
+ const queryString = queryParams.toString();
498
+ const url = `/fs/${API_VERSION}/upload/${sandboxId}${queryString ? `?${queryString}` : ''}`;
499
+
500
+ const response = await client.rawPost(url, archive, 'application/octet-stream', signal);
501
+
502
+ if (!response.ok) {
503
+ const text = await response.text().catch(() => 'Unknown error');
504
+ throw new SandboxResponseError({
505
+ message: `Failed to upload archive: ${response.status} ${text}`,
506
+ sandboxId,
507
+ });
508
+ }
509
+
510
+ const body = await response.json();
511
+ const result = UploadArchiveResponseSchema.parse(body);
512
+
513
+ if (!result.success) {
514
+ throw new SandboxResponseError({ message: result.message, sandboxId });
515
+ }
516
+ }
517
+
518
+ const SetEnvRequestSchema = z.object({
519
+ env: z
520
+ .record(z.string(), z.string().nullable())
521
+ .describe('Environment variables to set (null to delete)'),
522
+ });
523
+
524
+ const SetEnvDataSchema = z.object({
525
+ env: z.record(z.string(), z.string()).describe('Current environment variables after update'),
526
+ });
527
+
528
+ const SetEnvResponseSchema = z.discriminatedUnion('success', [
529
+ z.object({
530
+ success: z.literal<false>(false),
531
+ message: z.string().describe('the error message'),
532
+ }),
533
+ z.object({
534
+ success: z.literal<true>(true),
535
+ data: SetEnvDataSchema,
536
+ }),
537
+ ]);
538
+
539
+ export interface SetEnvParams {
540
+ sandboxId: string;
541
+ env: Record<string, string | null>;
542
+ orgId?: string;
543
+ signal?: AbortSignal;
544
+ }
545
+
546
+ export interface SetEnvResult {
547
+ env: Record<string, string>;
548
+ }
549
+
550
+ /**
551
+ * Sets environment variables on a sandbox. Pass null to delete a variable.
552
+ *
553
+ * @param client - The API client to use for the request
554
+ * @param params - Parameters including sandbox ID and env key/value pairs
555
+ * @returns The current environment variables after the update
556
+ * @throws {SandboxResponseError} If the request fails
557
+ */
558
+ export async function sandboxSetEnv(
559
+ client: APIClient,
560
+ params: SetEnvParams
561
+ ): Promise<SetEnvResult> {
562
+ const { sandboxId, env, orgId, signal } = params;
563
+
564
+ const body: z.infer<typeof SetEnvRequestSchema> = { env };
565
+
566
+ const queryParams = new URLSearchParams();
567
+ if (orgId) {
568
+ queryParams.set('orgId', orgId);
569
+ }
570
+ const queryString = queryParams.toString();
571
+ const url = `/sandbox/env/${API_VERSION}/${sandboxId}${queryString ? `?${queryString}` : ''}`;
572
+
573
+ const resp = await client.patch<z.infer<typeof SetEnvResponseSchema>>(
574
+ url,
575
+ body,
576
+ SetEnvResponseSchema,
577
+ SetEnvRequestSchema,
578
+ signal
579
+ );
580
+
581
+ if (resp.success) {
582
+ return {
583
+ env: resp.data.env,
584
+ };
585
+ }
586
+
587
+ throw new SandboxResponseError({ message: resp.message, sandboxId });
588
+ }
@@ -20,6 +20,10 @@ const SandboxInfoDataSchema = z
20
20
  .array(z.string())
21
21
  .optional()
22
22
  .describe('Apt packages installed in the sandbox'),
23
+ metadata: z
24
+ .record(z.string(), z.unknown())
25
+ .optional()
26
+ .describe('User-defined metadata associated with the sandbox'),
23
27
  })
24
28
  .describe('Detailed information about a sandbox');
25
29
 
@@ -67,6 +71,7 @@ export async function sandboxGet(
67
71
  stdoutStreamUrl: resp.data.stdoutStreamUrl,
68
72
  stderrStreamUrl: resp.data.stderrStreamUrl,
69
73
  dependencies: resp.data.dependencies,
74
+ metadata: resp.data.metadata as Record<string, unknown> | undefined,
70
75
  };
71
76
  }
72
77
 
@@ -20,8 +20,33 @@ export type {
20
20
  export { SandboxResponseError, writeAndDrain } from './util';
21
21
  export { SandboxClient } from './client';
22
22
  export type { SandboxClientOptions, SandboxInstance, ExecuteOptions } from './client';
23
- export { sandboxWriteFiles, sandboxReadFile } from './files';
24
- export type { WriteFilesParams, WriteFilesResult, ReadFileParams } from './files';
23
+ export {
24
+ sandboxWriteFiles,
25
+ sandboxReadFile,
26
+ sandboxMkDir,
27
+ sandboxRmDir,
28
+ sandboxRmFile,
29
+ sandboxListFiles,
30
+ sandboxDownloadArchive,
31
+ sandboxUploadArchive,
32
+ sandboxSetEnv,
33
+ } from './files';
34
+ export type {
35
+ WriteFilesParams,
36
+ WriteFilesResult,
37
+ ReadFileParams,
38
+ MkDirParams,
39
+ RmDirParams,
40
+ RmFileParams,
41
+ ListFilesParams,
42
+ ListFilesResult,
43
+ FileInfo,
44
+ ArchiveFormat,
45
+ DownloadArchiveParams,
46
+ UploadArchiveParams,
47
+ SetEnvParams,
48
+ SetEnvResult,
49
+ } from './files';
25
50
  export { snapshotCreate, snapshotGet, snapshotList, snapshotDelete, snapshotTag } from './snapshot';
26
51
  export type {
27
52
  SnapshotInfo,
@@ -1,8 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { APIClient, APIResponseSchema, APIResponseSchemaNoData } from '../api';
3
- import { SandboxResponseError } from './util';
4
-
5
- const SNAPSHOT_API_VERSION = '2025-06-26';
3
+ import { SandboxResponseError, API_VERSION } from './util';
6
4
 
7
5
  const SnapshotFileInfoSchema = z
8
6
  .object({
@@ -14,7 +12,6 @@ const SnapshotFileInfoSchema = z
14
12
  const SnapshotInfoSchema = z
15
13
  .object({
16
14
  snapshotId: z.string().describe('Unique identifier for the snapshot'),
17
- sandboxId: z.string().describe('ID of the sandbox this snapshot was created from'),
18
15
  tag: z.string().nullable().optional().describe('User-defined tag for the snapshot'),
19
16
  sizeBytes: z.number().describe('Total size of the snapshot in bytes'),
20
17
  fileCount: z.number().describe('Number of files in the snapshot'),
@@ -47,7 +44,6 @@ export interface SnapshotFileInfo {
47
44
 
48
45
  export interface SnapshotInfo {
49
46
  snapshotId: string;
50
- sandboxId: string;
51
47
  tag?: string | null;
52
48
  sizeBytes: number;
53
49
  fileCount: number;
@@ -116,7 +112,7 @@ export async function snapshotCreate(
116
112
  ): Promise<SnapshotInfo> {
117
113
  const { sandboxId, tag, orgId } = params;
118
114
  const queryString = buildQueryString({ orgId });
119
- const url = `/sandbox/${SNAPSHOT_API_VERSION}/${sandboxId}/snapshot${queryString}`;
115
+ const url = `/sandbox/${API_VERSION}/${sandboxId}/snapshot${queryString}`;
120
116
 
121
117
  const body: Record<string, string> = {};
122
118
  if (tag) {
@@ -150,7 +146,7 @@ export async function snapshotGet(
150
146
  ): Promise<SnapshotInfo> {
151
147
  const { snapshotId, orgId } = params;
152
148
  const queryString = buildQueryString({ orgId });
153
- const url = `/sandbox/${SNAPSHOT_API_VERSION}/snapshots/${snapshotId}${queryString}`;
149
+ const url = `/sandbox/${API_VERSION}/snapshots/${snapshotId}${queryString}`;
154
150
 
155
151
  const resp = await client.get<z.infer<typeof SnapshotGetResponseSchema>>(
156
152
  url,
@@ -178,7 +174,7 @@ export async function snapshotList(
178
174
  ): Promise<SnapshotListResponse> {
179
175
  const { sandboxId, limit, offset, orgId } = params;
180
176
  const queryString = buildQueryString({ sandboxId, limit, offset, orgId });
181
- const url = `/sandbox/${SNAPSHOT_API_VERSION}/snapshots${queryString}`;
177
+ const url = `/sandbox/${API_VERSION}/snapshots${queryString}`;
182
178
 
183
179
  const resp = await client.get<z.infer<typeof SnapshotListResponseSchema>>(
184
180
  url,
@@ -205,7 +201,7 @@ export async function snapshotDelete(
205
201
  ): Promise<void> {
206
202
  const { snapshotId, orgId } = params;
207
203
  const queryString = buildQueryString({ orgId });
208
- const url = `/sandbox/${SNAPSHOT_API_VERSION}/snapshots/${snapshotId}${queryString}`;
204
+ const url = `/sandbox/${API_VERSION}/snapshots/${snapshotId}${queryString}`;
209
205
 
210
206
  const resp = await client.delete<z.infer<typeof SnapshotDeleteResponseSchema>>(
211
207
  url,
@@ -231,7 +227,7 @@ export async function snapshotTag(
231
227
  ): Promise<SnapshotInfo> {
232
228
  const { snapshotId, tag, orgId } = params;
233
229
  const queryString = buildQueryString({ orgId });
234
- const url = `/sandbox/${SNAPSHOT_API_VERSION}/snapshots/${snapshotId}${queryString}`;
230
+ const url = `/sandbox/${API_VERSION}/snapshots/${snapshotId}${queryString}`;
235
231
 
236
232
  const resp = await client.patch<z.infer<typeof SnapshotGetResponseSchema>>(
237
233
  url,
package/src/schema.ts CHANGED
@@ -13,7 +13,9 @@ export const toJSONSchema = (schema: any): JSONSchema => {
13
13
  return agentuityToJSONSchema(schema);
14
14
  }
15
15
  // Check if it's a Zod schema
16
- if (schema?._def?.typeName) {
16
+ // Zod 3 uses _def.typeName (e.g., "ZodObject")
17
+ // Zod 4 uses _def.type (e.g., "object")
18
+ if (schema?._def?.typeName || schema?._def?.type) {
17
19
  try {
18
20
  return z.toJSONSchema(schema) as JSONSchema;
19
21
  } catch {