@agentuity/server 0.1.23 → 0.1.25

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 (132) hide show
  1. package/dist/api/api.d.ts +3 -0
  2. package/dist/api/api.d.ts.map +1 -1
  3. package/dist/api/api.js +3 -0
  4. package/dist/api/api.js.map +1 -1
  5. package/dist/api/apikey/list.d.ts +1 -0
  6. package/dist/api/apikey/list.d.ts.map +1 -1
  7. package/dist/api/eval/get.d.ts +18 -0
  8. package/dist/api/eval/get.d.ts.map +1 -0
  9. package/dist/api/eval/get.js +23 -0
  10. package/dist/api/eval/get.js.map +1 -0
  11. package/dist/api/eval/index.d.ts +5 -0
  12. package/dist/api/eval/index.d.ts.map +1 -0
  13. package/dist/api/eval/index.js +5 -0
  14. package/dist/api/eval/index.js.map +1 -0
  15. package/dist/api/eval/list.d.ts +21 -0
  16. package/dist/api/eval/list.d.ts.map +1 -0
  17. package/dist/api/eval/list.js +30 -0
  18. package/dist/api/eval/list.js.map +1 -0
  19. package/dist/api/eval/run-get.d.ts +24 -0
  20. package/dist/api/eval/run-get.d.ts.map +1 -0
  21. package/dist/api/eval/run-get.js +29 -0
  22. package/dist/api/eval/run-get.js.map +1 -0
  23. package/dist/api/eval/run-list.d.ts +29 -0
  24. package/dist/api/eval/run-list.d.ts.map +1 -0
  25. package/dist/api/eval/run-list.js +40 -0
  26. package/dist/api/eval/run-list.js.map +1 -0
  27. package/dist/api/index.d.ts +1 -0
  28. package/dist/api/index.d.ts.map +1 -1
  29. package/dist/api/index.js +1 -0
  30. package/dist/api/index.js.map +1 -1
  31. package/dist/api/machine/machine.d.ts +3 -1
  32. package/dist/api/machine/machine.d.ts.map +1 -1
  33. package/dist/api/machine/machine.js +6 -5
  34. package/dist/api/machine/machine.js.map +1 -1
  35. package/dist/api/org/list.d.ts +1 -0
  36. package/dist/api/org/list.d.ts.map +1 -1
  37. package/dist/api/org/resources.d.ts +1 -0
  38. package/dist/api/org/resources.d.ts.map +1 -1
  39. package/dist/api/project/create.d.ts +1 -0
  40. package/dist/api/project/create.d.ts.map +1 -1
  41. package/dist/api/project/exists.d.ts +1 -0
  42. package/dist/api/project/exists.d.ts.map +1 -1
  43. package/dist/api/project/index.d.ts +1 -0
  44. package/dist/api/project/index.d.ts.map +1 -1
  45. package/dist/api/project/index.js +1 -0
  46. package/dist/api/project/index.js.map +1 -1
  47. package/dist/api/project/list.d.ts +1 -0
  48. package/dist/api/project/list.d.ts.map +1 -1
  49. package/dist/api/project/malware.d.ts +38 -0
  50. package/dist/api/project/malware.d.ts.map +1 -0
  51. package/dist/api/project/malware.js +39 -0
  52. package/dist/api/project/malware.js.map +1 -0
  53. package/dist/api/queue/types.d.ts +4 -3
  54. package/dist/api/queue/types.d.ts.map +1 -1
  55. package/dist/api/queue/types.js +8 -6
  56. package/dist/api/queue/types.js.map +1 -1
  57. package/dist/api/region/create.d.ts +1 -0
  58. package/dist/api/region/create.d.ts.map +1 -1
  59. package/dist/api/region/delete.d.ts +1 -0
  60. package/dist/api/region/delete.d.ts.map +1 -1
  61. package/dist/api/region/list.d.ts +1 -0
  62. package/dist/api/region/list.d.ts.map +1 -1
  63. package/dist/api/region/resources.d.ts +1 -0
  64. package/dist/api/region/resources.d.ts.map +1 -1
  65. package/dist/api/sandbox/client.d.ts +8 -0
  66. package/dist/api/sandbox/client.d.ts.map +1 -1
  67. package/dist/api/sandbox/client.js +20 -6
  68. package/dist/api/sandbox/client.js.map +1 -1
  69. package/dist/api/sandbox/create.d.ts.map +1 -1
  70. package/dist/api/sandbox/create.js +10 -3
  71. package/dist/api/sandbox/create.js.map +1 -1
  72. package/dist/api/sandbox/destroy.js +2 -2
  73. package/dist/api/sandbox/destroy.js.map +1 -1
  74. package/dist/api/sandbox/execute.d.ts.map +1 -1
  75. package/dist/api/sandbox/execute.js +8 -9
  76. package/dist/api/sandbox/execute.js.map +1 -1
  77. package/dist/api/sandbox/execution.js +3 -3
  78. package/dist/api/sandbox/execution.js.map +1 -1
  79. package/dist/api/sandbox/files.js +8 -8
  80. package/dist/api/sandbox/files.js.map +1 -1
  81. package/dist/api/sandbox/get.d.ts.map +1 -1
  82. package/dist/api/sandbox/get.js +2 -2
  83. package/dist/api/sandbox/get.js.map +1 -1
  84. package/dist/api/sandbox/index.d.ts +2 -1
  85. package/dist/api/sandbox/index.d.ts.map +1 -1
  86. package/dist/api/sandbox/index.js +1 -1
  87. package/dist/api/sandbox/index.js.map +1 -1
  88. package/dist/api/sandbox/list.d.ts.map +1 -1
  89. package/dist/api/sandbox/list.js +2 -2
  90. package/dist/api/sandbox/list.js.map +1 -1
  91. package/dist/api/sandbox/run.js +3 -3
  92. package/dist/api/sandbox/run.js.map +1 -1
  93. package/dist/api/sandbox/runtime.js +2 -2
  94. package/dist/api/sandbox/runtime.js.map +1 -1
  95. package/dist/api/sandbox/snapshot.d.ts.map +1 -1
  96. package/dist/api/sandbox/snapshot.js +11 -11
  97. package/dist/api/sandbox/snapshot.js.map +1 -1
  98. package/dist/api/sandbox/util.d.ts +205 -0
  99. package/dist/api/sandbox/util.d.ts.map +1 -1
  100. package/dist/api/sandbox/util.js +137 -0
  101. package/dist/api/sandbox/util.js.map +1 -1
  102. package/dist/api/session/list.d.ts +1 -0
  103. package/dist/api/session/list.d.ts.map +1 -1
  104. package/dist/api/thread/list.d.ts +1 -0
  105. package/dist/api/thread/list.d.ts.map +1 -1
  106. package/dist/api/user/whoami.d.ts +1 -0
  107. package/dist/api/user/whoami.d.ts.map +1 -1
  108. package/package.json +4 -4
  109. package/src/api/api.ts +3 -0
  110. package/src/api/eval/get.ts +33 -0
  111. package/src/api/eval/index.ts +4 -0
  112. package/src/api/eval/list.ts +47 -0
  113. package/src/api/eval/run-get.ts +39 -0
  114. package/src/api/eval/run-list.ts +57 -0
  115. package/src/api/index.ts +1 -0
  116. package/src/api/machine/machine.ts +7 -6
  117. package/src/api/project/index.ts +1 -0
  118. package/src/api/project/malware.ts +62 -0
  119. package/src/api/queue/types.ts +8 -6
  120. package/src/api/sandbox/client.ts +43 -6
  121. package/src/api/sandbox/create.ts +12 -3
  122. package/src/api/sandbox/destroy.ts +2 -2
  123. package/src/api/sandbox/execute.ts +10 -9
  124. package/src/api/sandbox/execution.ts +3 -3
  125. package/src/api/sandbox/files.ts +8 -8
  126. package/src/api/sandbox/get.ts +5 -3
  127. package/src/api/sandbox/index.ts +12 -1
  128. package/src/api/sandbox/list.ts +5 -3
  129. package/src/api/sandbox/run.ts +3 -3
  130. package/src/api/sandbox/runtime.ts +2 -2
  131. package/src/api/sandbox/snapshot.ts +15 -15
  132. package/src/api/sandbox/util.ts +186 -0
package/src/api/api.ts CHANGED
@@ -714,6 +714,7 @@ export const APIResponseSchema = <T extends z.ZodType>(dataSchema: T) =>
714
714
  z.object({
715
715
  success: z.literal<false>(false),
716
716
  message: z.string().describe('the error message'),
717
+ code: z.string().optional().describe('machine-readable error code'),
717
718
  }),
718
719
  z.object({
719
720
  success: z.literal<true>(true),
@@ -726,6 +727,7 @@ export const APIResponseSchemaOptionalData = <T extends z.ZodType>(dataSchema: T
726
727
  z.object({
727
728
  success: z.literal<false>(false),
728
729
  message: z.string().describe('the error message'),
730
+ code: z.string().optional().describe('machine-readable error code'),
729
731
  }),
730
732
  z.object({
731
733
  success: z.literal<true>(true),
@@ -738,6 +740,7 @@ export const APIResponseSchemaNoData = () =>
738
740
  z.object({
739
741
  success: z.literal<false>(false),
740
742
  message: z.string().describe('the error message'),
743
+ code: z.string().optional().describe('machine-readable error code'),
741
744
  }),
742
745
  z.object({
743
746
  success: z.literal<true>(true),
@@ -0,0 +1,33 @@
1
+ import { z } from 'zod';
2
+ import { APIClient, APIResponseSchema } from '../api';
3
+
4
+ const EvaluationDetailSchema = z.object({
5
+ id: z.string().describe('Evaluation ID'),
6
+ name: z.string().describe('Evaluation name'),
7
+ description: z.string().nullable().describe('Evaluation description'),
8
+ identifier: z.string().nullable().describe('Stable evaluation identifier'),
9
+ agentIdentifier: z.string().describe('Agent identifier'),
10
+ projectId: z.string().describe('Project ID'),
11
+ orgId: z.string().describe('Organization ID'),
12
+ devmode: z.boolean().describe('Whether this is a devmode evaluation'),
13
+ createdAt: z.string().describe('Creation timestamp'),
14
+ updatedAt: z.string().describe('Last updated timestamp'),
15
+ });
16
+
17
+ const EvalGetResponseSchema = APIResponseSchema(EvaluationDetailSchema);
18
+
19
+ export type EvaluationDetail = z.infer<typeof EvaluationDetailSchema>;
20
+
21
+ export async function evalGet(client: APIClient, id: string): Promise<EvaluationDetail> {
22
+ const resp = await client.request<z.infer<typeof EvalGetResponseSchema>>(
23
+ 'GET',
24
+ `/cli/eval/${encodeURIComponent(id)}`,
25
+ EvalGetResponseSchema
26
+ );
27
+
28
+ if (resp.success) {
29
+ return resp.data;
30
+ }
31
+
32
+ throw new Error(resp.message || 'Failed to get evaluation');
33
+ }
@@ -0,0 +1,4 @@
1
+ export { evalList, type Evaluation, type EvaluationListRequest } from './list';
2
+ export { evalGet, type EvaluationDetail } from './get';
3
+ export { evalRunList, type EvalRunListItem, type EvalRunListRequest } from './run-list';
4
+ export { evalRunGet, type EvalRunDetail } from './run-get';
@@ -0,0 +1,47 @@
1
+ import { z } from 'zod';
2
+ import { APIClient, APIResponseSchema } from '../api';
3
+
4
+ const EvaluationSchema = z.object({
5
+ id: z.string().describe('Evaluation ID'),
6
+ name: z.string().describe('Evaluation name'),
7
+ description: z.string().nullable().describe('Evaluation description'),
8
+ identifier: z.string().nullable().describe('Stable evaluation identifier'),
9
+ agentIdentifier: z.string().describe('Agent identifier'),
10
+ projectId: z.string().describe('Project ID'),
11
+ devmode: z.boolean().describe('Whether this is a devmode evaluation'),
12
+ createdAt: z.string().describe('Creation timestamp'),
13
+ updatedAt: z.string().describe('Last updated timestamp'),
14
+ });
15
+
16
+ const EvalListResponseData = z.array(EvaluationSchema);
17
+ const EvalListResponseSchema = APIResponseSchema(EvalListResponseData);
18
+
19
+ export type Evaluation = z.infer<typeof EvaluationSchema>;
20
+ export type EvaluationListRequest = {
21
+ projectId?: string;
22
+ agentId?: string;
23
+ };
24
+
25
+ export async function evalList(
26
+ client: APIClient,
27
+ request: EvaluationListRequest = {}
28
+ ): Promise<Evaluation[]> {
29
+ const params = new URLSearchParams();
30
+ if (request.projectId) params.set('projectId', request.projectId);
31
+ if (request.agentId) params.set('agentId', request.agentId);
32
+
33
+ const queryString = params.toString();
34
+ const url = `/cli/eval${queryString ? `?${queryString}` : ''}`;
35
+
36
+ const resp = await client.request<z.infer<typeof EvalListResponseSchema>>(
37
+ 'GET',
38
+ url,
39
+ EvalListResponseSchema
40
+ );
41
+
42
+ if (resp.success) {
43
+ return resp.data;
44
+ }
45
+
46
+ throw new Error(resp.message || 'Failed to list evaluations');
47
+ }
@@ -0,0 +1,39 @@
1
+ import { z } from 'zod';
2
+ import { APIClient, APIResponseSchema } from '../api';
3
+
4
+ const EvalRunDetailSchema = z.object({
5
+ id: z.string().describe('Eval run ID'),
6
+ sessionId: z.string().describe('Session ID'),
7
+ evalId: z.string().describe('Evaluation record ID'),
8
+ evalIdentifier: z.string().nullable().describe('Stable evaluation identifier'),
9
+ evalName: z.string().nullable().describe('Evaluation name'),
10
+ agentIdentifier: z.string().nullable().describe('Agent identifier'),
11
+ projectId: z.string().describe('Project ID'),
12
+ orgId: z.string().describe('Organization ID'),
13
+ deploymentId: z.string().nullable().describe('Deployment ID'),
14
+ devmode: z.boolean().describe('Whether this is a devmode run'),
15
+ pending: z.boolean().describe('Whether the eval run is pending'),
16
+ success: z.boolean().describe('Whether the eval run succeeded'),
17
+ error: z.string().nullable().describe('Error message if failed'),
18
+ result: z.any().nullable().describe('Eval run result'),
19
+ createdAt: z.string().describe('Creation timestamp'),
20
+ updatedAt: z.string().describe('Last updated timestamp'),
21
+ });
22
+
23
+ const EvalRunGetResponseSchema = APIResponseSchema(EvalRunDetailSchema);
24
+
25
+ export type EvalRunDetail = z.infer<typeof EvalRunDetailSchema>;
26
+
27
+ export async function evalRunGet(client: APIClient, id: string): Promise<EvalRunDetail> {
28
+ const resp = await client.request<z.infer<typeof EvalRunGetResponseSchema>>(
29
+ 'GET',
30
+ `/cli/eval-run/${encodeURIComponent(id)}`,
31
+ EvalRunGetResponseSchema
32
+ );
33
+
34
+ if (resp.success) {
35
+ return resp.data;
36
+ }
37
+
38
+ throw new Error(resp.message || 'Failed to get eval run');
39
+ }
@@ -0,0 +1,57 @@
1
+ import { z } from 'zod';
2
+ import { APIClient, APIResponseSchema } from '../api';
3
+
4
+ const EvalRunSchema = z.object({
5
+ id: z.string().describe('Eval run ID'),
6
+ sessionId: z.string().describe('Session ID'),
7
+ evalId: z.string().describe('Evaluation record ID'),
8
+ evalIdentifier: z.string().nullable().describe('Stable evaluation identifier'),
9
+ evalName: z.string().nullable().describe('Evaluation name'),
10
+ agentIdentifier: z.string().nullable().describe('Agent identifier'),
11
+ projectId: z.string().describe('Project ID'),
12
+ deploymentId: z.string().nullable().describe('Deployment ID'),
13
+ devmode: z.boolean().describe('Whether this is a devmode run'),
14
+ pending: z.boolean().describe('Whether the eval run is pending'),
15
+ success: z.boolean().describe('Whether the eval run succeeded'),
16
+ error: z.string().nullable().describe('Error message if failed'),
17
+ result: z.any().nullable().describe('Eval run result'),
18
+ createdAt: z.string().describe('Creation timestamp'),
19
+ updatedAt: z.string().describe('Last updated timestamp'),
20
+ });
21
+
22
+ const EvalRunListResponseData = z.array(EvalRunSchema);
23
+ const EvalRunListResponseSchema = APIResponseSchema(EvalRunListResponseData);
24
+
25
+ export type EvalRunListItem = z.infer<typeof EvalRunSchema>;
26
+ export type EvalRunListRequest = {
27
+ projectId?: string;
28
+ agentId?: string;
29
+ evalId?: string;
30
+ sessionId?: string;
31
+ };
32
+
33
+ export async function evalRunList(
34
+ client: APIClient,
35
+ request: EvalRunListRequest = {}
36
+ ): Promise<EvalRunListItem[]> {
37
+ const params = new URLSearchParams();
38
+ if (request.projectId) params.set('projectId', request.projectId);
39
+ if (request.agentId) params.set('agentId', request.agentId);
40
+ if (request.evalId) params.set('evalId', request.evalId);
41
+ if (request.sessionId) params.set('sessionId', request.sessionId);
42
+
43
+ const queryString = params.toString();
44
+ const url = `/cli/eval-run${queryString ? `?${queryString}` : ''}`;
45
+
46
+ const resp = await client.request<z.infer<typeof EvalRunListResponseSchema>>(
47
+ 'GET',
48
+ url,
49
+ EvalRunListResponseSchema
50
+ );
51
+
52
+ if (resp.success) {
53
+ return resp.data;
54
+ }
55
+
56
+ throw new Error(resp.message || 'Failed to list eval runs');
57
+ }
package/src/api/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './api';
2
2
  export * from './apikey';
3
3
  export * from './db';
4
+ export * from './eval';
4
5
  export * from './machine';
5
6
  export * from './org';
6
7
  export * from './project';
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { APIResponseSchema, APIClient } from '../api';
2
+ import { APIResponseSchema, APIResponseSchemaNoData, APIClient } from '../api';
3
3
  import { MachineResponseError } from './util';
4
4
 
5
5
  const MachineSchema = z.object({
@@ -7,6 +7,8 @@ const MachineSchema = z.object({
7
7
  instanceId: z.string().nullable().optional(),
8
8
  privateIPv4: z.string().nullable().optional(),
9
9
  availabilityZone: z.string().nullable().optional(),
10
+ instanceType: z.string().nullable().optional(),
11
+ instanceTags: z.array(z.string()).nullable().optional(),
10
12
  deploymentCount: z.number().optional(),
11
13
  status: z.string(),
12
14
  provider: z.string(),
@@ -25,7 +27,7 @@ const MachineSchema = z.object({
25
27
 
26
28
  const MachineListResponseSchema = APIResponseSchema(z.array(MachineSchema));
27
29
  const MachineGetResponseSchema = APIResponseSchema(MachineSchema);
28
- const MachineDeleteResponseSchema = APIResponseSchema(z.boolean());
30
+ const MachineDeleteResponseSchema = APIResponseSchemaNoData();
29
31
 
30
32
  export type Machine = z.infer<typeof MachineSchema>;
31
33
 
@@ -45,12 +47,11 @@ export async function machineGet(client: APIClient, machineId: string): Promise<
45
47
  throw new MachineResponseError({ message: resp.message });
46
48
  }
47
49
 
48
- export async function machineDelete(client: APIClient, machineId: string): Promise<boolean> {
50
+ export async function machineDelete(client: APIClient, machineId: string): Promise<void> {
49
51
  const resp = await client.delete(`/machine/${machineId}`, MachineDeleteResponseSchema);
50
- if (resp.success) {
51
- return resp.data;
52
+ if (!resp.success) {
53
+ throw new MachineResponseError({ message: resp.message });
52
54
  }
53
- throw new MachineResponseError({ message: resp.message });
54
55
  }
55
56
 
56
57
  const MachineDeploymentProjectSchema = z.object({
@@ -8,3 +8,4 @@ export * from './env-update';
8
8
  export * from './exists';
9
9
  export * from './get';
10
10
  export * from './list';
11
+ export * from './malware';
@@ -0,0 +1,62 @@
1
+ import { z } from 'zod';
2
+ import { type APIClient, APIResponseSchema } from '../api';
3
+
4
+ const PackageRef = z.object({
5
+ name: z.string(),
6
+ version: z.string(),
7
+ });
8
+
9
+ export type PackageRef = z.infer<typeof PackageRef>;
10
+
11
+ const MalwareFinding = z.object({
12
+ name: z.string(),
13
+ version: z.string(),
14
+ reason: z.string(),
15
+ });
16
+
17
+ export type MalwareFinding = z.infer<typeof MalwareFinding>;
18
+
19
+ const MalwareCheckSummary = z.object({
20
+ scanned: z.number(),
21
+ flagged: z.number(),
22
+ });
23
+
24
+ const MalwareCheckListMetadata = z.object({
25
+ fetchedAt: z.string(),
26
+ count: z.number(),
27
+ });
28
+
29
+ const MalwareCheckResult = z.object({
30
+ success: z.boolean(),
31
+ action: z.enum(['allow', 'block']),
32
+ summary: MalwareCheckSummary,
33
+ findings: z.array(MalwareFinding),
34
+ list: MalwareCheckListMetadata.optional(),
35
+ error: z.string().optional(),
36
+ });
37
+
38
+ const MalwareCheckResponseSchema = APIResponseSchema(MalwareCheckResult);
39
+
40
+ export type MalwareCheckResult = z.infer<typeof MalwareCheckResult>;
41
+
42
+ export async function projectDeploymentMalwareCheck(
43
+ client: APIClient,
44
+ deploymentId: string,
45
+ packages: PackageRef[]
46
+ ): Promise<MalwareCheckResult> {
47
+ const resp = await client.request<z.infer<typeof MalwareCheckResponseSchema>>(
48
+ 'POST',
49
+ `/security/2026-01-22/${deploymentId}/malware-check`,
50
+ MalwareCheckResponseSchema,
51
+ {
52
+ ecosystem: 'npm',
53
+ packages,
54
+ }
55
+ );
56
+
57
+ if (!resp.success) {
58
+ throw new Error(resp.message || 'Malware check request failed');
59
+ }
60
+
61
+ return resp.data;
62
+ }
@@ -372,8 +372,8 @@ export const DeadLetterMessageSchema = z.object({
372
372
  id: z.string(),
373
373
  /** ID of the queue this message belongs to. */
374
374
  queue_id: z.string(),
375
- /** ID of the original message that failed. */
376
- original_message_id: z.string(),
375
+ /** ID of the original message that failed (optional until backend includes it). */
376
+ original_message_id: z.string().optional(),
377
377
  /** Offset of the original message in the queue. */
378
378
  offset: z.number(),
379
379
  /** The message payload (JSON object). */
@@ -384,10 +384,12 @@ export const DeadLetterMessageSchema = z.object({
384
384
  failure_reason: z.string().nullable().optional(),
385
385
  /** Number of delivery attempts before failure. */
386
386
  delivery_attempts: z.number(),
387
- /** ISO 8601 timestamp when the message was moved to DLQ. */
388
- moved_at: z.string(),
389
- /** ISO 8601 timestamp when the original message was published. */
390
- original_published_at: z.string(),
387
+ /** ISO 8601 timestamp when the message was moved to DLQ (optional until backend includes it). */
388
+ moved_at: z.string().optional(),
389
+ /** ISO 8601 timestamp when the original message was published (optional, falls back to published_at). */
390
+ original_published_at: z.string().optional(),
391
+ /** ISO 8601 timestamp when the message was published (from base message). */
392
+ published_at: z.string().optional(),
391
393
  /** ISO 8601 timestamp when the DLQ entry was created. */
392
394
  created_at: z.string(),
393
395
  });
@@ -19,6 +19,7 @@ import { sandboxRun } from './run';
19
19
  import { executionGet, type ExecutionInfo } from './execution';
20
20
  import { ConsoleLogger } from '../../logger';
21
21
  import { getServiceUrls } from '../../config';
22
+ import { writeAndDrain } from './util';
22
23
 
23
24
  const POLL_INTERVAL_MS = 100;
24
25
  const MAX_POLL_TIME_MS = 300000; // 5 minutes
@@ -67,10 +68,14 @@ async function waitForExecution(
67
68
  }
68
69
 
69
70
  /**
70
- * Pipes a remote stream URL to a local writable stream
71
+ * Pipes a remote stream URL to a local writable stream with proper backpressure handling
71
72
  */
72
- async function pipeStreamToWritable(streamUrl: string, writable: Writable): Promise<void> {
73
- const response = await fetch(streamUrl);
73
+ async function pipeStreamToWritable(
74
+ streamUrl: string,
75
+ writable: Writable,
76
+ signal?: AbortSignal
77
+ ): Promise<void> {
78
+ const response = await fetch(streamUrl, { signal });
74
79
  if (!response.ok) {
75
80
  throw new Error(`Failed to fetch stream: ${response.status} ${response.statusText}`);
76
81
  }
@@ -84,10 +89,15 @@ async function pipeStreamToWritable(streamUrl: string, writable: Writable): Prom
84
89
  const { done, value } = await reader.read();
85
90
  if (done) break;
86
91
  if (value) {
87
- writable.write(value);
92
+ await writeAndDrain(writable, value);
88
93
  }
89
94
  }
90
95
  } finally {
96
+ try {
97
+ await reader.cancel();
98
+ } catch {
99
+ // Ignore cancel errors - stream may already be closed
100
+ }
91
101
  reader.releaseLock();
92
102
  }
93
103
  }
@@ -191,6 +201,16 @@ export interface SandboxInstance {
191
201
  */
192
202
  execute(options: ExecuteOptions): Promise<Execution>;
193
203
 
204
+ /**
205
+ * Write files to the sandbox workspace
206
+ */
207
+ writeFiles(files: FileToWrite[]): Promise<number>;
208
+
209
+ /**
210
+ * Read a file from the sandbox workspace
211
+ */
212
+ readFile(path: string): Promise<ReadableStream<Uint8Array>>;
213
+
194
214
  /**
195
215
  * Get current sandbox information
196
216
  */
@@ -327,12 +347,20 @@ export class SandboxClient {
327
347
 
328
348
  if (pipe.stdout && initialResult.stdoutStreamUrl) {
329
349
  streamPromises.push(
330
- pipeStreamToWritable(initialResult.stdoutStreamUrl, pipe.stdout)
350
+ pipeStreamToWritable(
351
+ initialResult.stdoutStreamUrl,
352
+ pipe.stdout,
353
+ coreOptions.signal
354
+ )
331
355
  );
332
356
  }
333
357
  if (pipe.stderr && initialResult.stderrStreamUrl) {
334
358
  streamPromises.push(
335
- pipeStreamToWritable(initialResult.stderrStreamUrl, pipe.stderr)
359
+ pipeStreamToWritable(
360
+ initialResult.stderrStreamUrl,
361
+ pipe.stderr,
362
+ coreOptions.signal
363
+ )
336
364
  );
337
365
  }
338
366
 
@@ -360,6 +388,15 @@ export class SandboxClient {
360
388
  };
361
389
  },
362
390
 
391
+ async writeFiles(files: FileToWrite[]): Promise<number> {
392
+ const result = await sandboxWriteFiles(client, { sandboxId, files, orgId });
393
+ return result.filesWritten;
394
+ },
395
+
396
+ async readFile(path: string): Promise<ReadableStream<Uint8Array>> {
397
+ return sandboxReadFile(client, { sandboxId, path, orgId });
398
+ },
399
+
363
400
  async get(): Promise<SandboxInfo> {
364
401
  return sandboxGet(client, { sandboxId, orgId });
365
402
  },
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { APIClient, APIResponseSchema } from '../api';
3
- import { SandboxResponseError, API_VERSION } from './util';
3
+ import { throwSandboxError, API_VERSION } from './util';
4
4
  import type { SandboxCreateOptions, SandboxStatus } from '@agentuity/core';
5
5
 
6
6
  const SandboxCreateRequestSchema = z
@@ -64,7 +64,7 @@ const SandboxCreateRequestSchema = z
64
64
  })
65
65
  )
66
66
  .optional()
67
- .describe('Files to write before execution'),
67
+ .describe('Files to write before execution (deprecated: use top-level files)'),
68
68
  mode: z
69
69
  .enum(['oneshot', 'interactive'])
70
70
  .optional()
@@ -72,6 +72,10 @@ const SandboxCreateRequestSchema = z
72
72
  })
73
73
  .optional()
74
74
  .describe('Initial command to run in the sandbox'),
75
+ files: z
76
+ .record(z.string(), z.string())
77
+ .optional()
78
+ .describe('Files to write to sandbox on creation (path -> base64 content)'),
75
79
  snapshot: z.string().optional().describe('Snapshot ID to restore the sandbox from'),
76
80
  dependencies: z
77
81
  .array(z.string())
@@ -168,6 +172,11 @@ export async function sandboxCreate(
168
172
  })),
169
173
  };
170
174
  }
175
+ if (options.files && options.files.length > 0) {
176
+ body.files = Object.fromEntries(
177
+ options.files.map((f) => [f.path, f.content.toString('base64')])
178
+ );
179
+ }
171
180
  if (options.snapshot) {
172
181
  body.snapshot = options.snapshot;
173
182
  }
@@ -196,5 +205,5 @@ export async function sandboxCreate(
196
205
  return resp.data;
197
206
  }
198
207
 
199
- throw new SandboxResponseError({ message: resp.message });
208
+ throwSandboxError(resp, {});
200
209
  }
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { APIClient, APIResponseSchemaNoData } from '../api';
3
- import { SandboxResponseError, API_VERSION } from './util';
3
+ import { throwSandboxError, API_VERSION } from './util';
4
4
 
5
5
  const DestroyResponseSchema = APIResponseSchemaNoData();
6
6
 
@@ -37,5 +37,5 @@ export async function sandboxDestroy(
37
37
  return;
38
38
  }
39
39
 
40
- throw new SandboxResponseError({ message: resp.message, sandboxId });
40
+ throwSandboxError(resp, { sandboxId });
41
41
  }
@@ -1,13 +1,15 @@
1
1
  import { z } from 'zod';
2
2
  import { APIClient, APIResponseSchema } from '../api';
3
- import { SandboxResponseError, API_VERSION } from './util';
4
- import { FileToWriteSchema } from './files';
3
+ import { throwSandboxError, API_VERSION } from './util';
5
4
  import type { ExecuteOptions, Execution, ExecutionStatus } from '@agentuity/core';
6
5
 
7
6
  const ExecuteRequestSchema = z
8
7
  .object({
9
8
  command: z.array(z.string()).describe('Command and arguments to execute'),
10
- files: z.array(FileToWriteSchema).optional().describe('Files to write before execution'),
9
+ files: z
10
+ .record(z.string(), z.string())
11
+ .optional()
12
+ .describe('Files to write before execution (path -> base64 content)'),
11
13
  timeout: z.string().optional().describe('Execution timeout (e.g., "30s", "5m")'),
12
14
  stream: z
13
15
  .object({
@@ -59,11 +61,10 @@ export async function sandboxExecute(
59
61
  command: options.command,
60
62
  };
61
63
 
62
- if (options.files) {
63
- body.files = options.files.map((f) => ({
64
- path: f.path,
65
- content: f.content.toString('base64'),
66
- }));
64
+ if (options.files && options.files.length > 0) {
65
+ body.files = Object.fromEntries(
66
+ options.files.map((f) => [f.path, f.content.toString('base64')])
67
+ );
67
68
  }
68
69
  if (options.timeout) {
69
70
  body.timeout = options.timeout;
@@ -98,5 +99,5 @@ export async function sandboxExecute(
98
99
  };
99
100
  }
100
101
 
101
- throw new SandboxResponseError({ message: resp.message, sandboxId });
102
+ throwSandboxError(resp, { sandboxId });
102
103
  }
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { APIClient, APIResponseSchema } from '../api';
3
- import { SandboxResponseError, API_VERSION } from './util';
3
+ import { throwSandboxError, API_VERSION } from './util';
4
4
  import type { ExecutionStatus } from '@agentuity/core';
5
5
 
6
6
  const ExecutionInfoSchema = z
@@ -97,7 +97,7 @@ export async function executionGet(
97
97
  };
98
98
  }
99
99
 
100
- throw new SandboxResponseError({ message: resp.message, executionId });
100
+ throwSandboxError(resp, { executionId });
101
101
  }
102
102
 
103
103
  export interface ExecutionListParams {
@@ -157,5 +157,5 @@ export async function executionList(
157
157
  };
158
158
  }
159
159
 
160
- throw new SandboxResponseError({ message: resp.message, sandboxId });
160
+ throwSandboxError(resp, { sandboxId });
161
161
  }
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { APIClient } from '../api';
3
- import { SandboxResponseError, API_VERSION } from './util';
3
+ import { SandboxResponseError, throwSandboxError, API_VERSION } from './util';
4
4
  import type { FileToWrite } from '@agentuity/core';
5
5
 
6
6
  export const FileToWriteSchema = z.object({
@@ -85,7 +85,7 @@ export async function sandboxWriteFiles(
85
85
  };
86
86
  }
87
87
 
88
- throw new SandboxResponseError({ message: resp.message, sandboxId });
88
+ throwSandboxError(resp, { sandboxId });
89
89
  }
90
90
 
91
91
  export interface ReadFileParams {
@@ -196,7 +196,7 @@ export async function sandboxMkDir(client: APIClient, params: MkDirParams): Prom
196
196
  );
197
197
 
198
198
  if (!resp.success) {
199
- throw new SandboxResponseError({ message: resp.message, sandboxId });
199
+ throwSandboxError(resp, { sandboxId });
200
200
  }
201
201
  }
202
202
 
@@ -256,7 +256,7 @@ export async function sandboxRmDir(client: APIClient, params: RmDirParams): Prom
256
256
  );
257
257
 
258
258
  if (!resp.success) {
259
- throw new SandboxResponseError({ message: resp.message, sandboxId });
259
+ throwSandboxError(resp, { sandboxId });
260
260
  }
261
261
  }
262
262
 
@@ -313,7 +313,7 @@ export async function sandboxRmFile(client: APIClient, params: RmFileParams): Pr
313
313
  );
314
314
 
315
315
  if (!resp.success) {
316
- throw new SandboxResponseError({ message: resp.message, sandboxId });
316
+ throwSandboxError(resp, { sandboxId });
317
317
  }
318
318
  }
319
319
 
@@ -395,7 +395,7 @@ export async function sandboxListFiles(
395
395
  };
396
396
  }
397
397
 
398
- throw new SandboxResponseError({ message: resp.message, sandboxId });
398
+ throwSandboxError(resp, { sandboxId });
399
399
  }
400
400
 
401
401
  export type ArchiveFormat = 'zip' | 'tar.gz';
@@ -519,7 +519,7 @@ export async function sandboxUploadArchive(
519
519
  const result = UploadArchiveResponseSchema.parse(body);
520
520
 
521
521
  if (!result.success) {
522
- throw new SandboxResponseError({ message: result.message, sandboxId, sessionId });
522
+ throwSandboxError(result, { sandboxId, sessionId });
523
523
  }
524
524
  }
525
525
 
@@ -592,5 +592,5 @@ export async function sandboxSetEnv(
592
592
  };
593
593
  }
594
594
 
595
- throw new SandboxResponseError({ message: resp.message, sandboxId });
595
+ throwSandboxError(resp, { sandboxId });
596
596
  }
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { APIClient, APIResponseSchema } from '../api';
3
- import { SandboxResponseError, API_VERSION } from './util';
3
+ import { throwSandboxError, API_VERSION } from './util';
4
4
  import type {
5
5
  SandboxInfo,
6
6
  SandboxStatus,
@@ -80,7 +80,9 @@ const SandboxSnapshotInfoSchema = z
80
80
  tag: z.string().optional().describe('Snapshot tag'),
81
81
  fullName: z.string().optional().describe('Full name with org slug (@slug/name:tag)'),
82
82
  public: z.literal(true).describe('Public snapshot'),
83
- org: SandboxSnapshotOrgInfoSchema.describe('Organization that owns the public snapshot'),
83
+ org: SandboxSnapshotOrgInfoSchema.describe(
84
+ 'Organization that owns the public snapshot'
85
+ ),
84
86
  })
85
87
  .describe('Public snapshot'),
86
88
  z
@@ -210,5 +212,5 @@ export async function sandboxGet(
210
212
  };
211
213
  }
212
214
 
213
- throw new SandboxResponseError({ message: resp.message, sandboxId });
215
+ throwSandboxError(resp, { sandboxId });
214
216
  }