@agentuity/server 0.0.105 → 0.0.107

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 (105) hide show
  1. package/dist/api/api.d.ts +11 -6
  2. package/dist/api/api.d.ts.map +1 -1
  3. package/dist/api/api.js +21 -13
  4. package/dist/api/api.js.map +1 -1
  5. package/dist/api/index.d.ts +1 -0
  6. package/dist/api/index.d.ts.map +1 -1
  7. package/dist/api/index.js +1 -0
  8. package/dist/api/index.js.map +1 -1
  9. package/dist/api/project/deploy.d.ts +0 -6
  10. package/dist/api/project/deploy.d.ts.map +1 -1
  11. package/dist/api/project/deploy.js +0 -2
  12. package/dist/api/project/deploy.js.map +1 -1
  13. package/dist/api/project/get.d.ts +2 -1
  14. package/dist/api/project/get.d.ts.map +1 -1
  15. package/dist/api/project/get.js +10 -2
  16. package/dist/api/project/get.js.map +1 -1
  17. package/dist/api/region/create.d.ts +2 -0
  18. package/dist/api/region/create.d.ts.map +1 -1
  19. package/dist/api/region/create.js +1 -0
  20. package/dist/api/region/create.js.map +1 -1
  21. package/dist/api/region/delete.d.ts +12 -2
  22. package/dist/api/region/delete.d.ts.map +1 -1
  23. package/dist/api/region/delete.js +6 -1
  24. package/dist/api/region/delete.js.map +1 -1
  25. package/dist/api/region/resources.d.ts +4 -0
  26. package/dist/api/region/resources.d.ts.map +1 -1
  27. package/dist/api/region/resources.js +2 -0
  28. package/dist/api/region/resources.js.map +1 -1
  29. package/dist/api/sandbox/client.d.ts +125 -0
  30. package/dist/api/sandbox/client.d.ts.map +1 -0
  31. package/dist/api/sandbox/client.js +202 -0
  32. package/dist/api/sandbox/client.js.map +1 -0
  33. package/dist/api/sandbox/create.d.ts +24 -0
  34. package/dist/api/sandbox/create.d.ts.map +1 -0
  35. package/dist/api/sandbox/create.js +133 -0
  36. package/dist/api/sandbox/create.js.map +1 -0
  37. package/dist/api/sandbox/destroy.d.ts +14 -0
  38. package/dist/api/sandbox/destroy.d.ts.map +1 -0
  39. package/dist/api/sandbox/destroy.js +25 -0
  40. package/dist/api/sandbox/destroy.js.map +1 -0
  41. package/dist/api/sandbox/execute.d.ts +18 -0
  42. package/dist/api/sandbox/execute.d.ts.map +1 -0
  43. package/dist/api/sandbox/execute.js +77 -0
  44. package/dist/api/sandbox/execute.js.map +1 -0
  45. package/dist/api/sandbox/execution.d.ts +46 -0
  46. package/dist/api/sandbox/execution.d.ts.map +1 -0
  47. package/dist/api/sandbox/execution.js +101 -0
  48. package/dist/api/sandbox/execution.js.map +1 -0
  49. package/dist/api/sandbox/files.d.ts +41 -0
  50. package/dist/api/sandbox/files.d.ts.map +1 -0
  51. package/dist/api/sandbox/files.js +91 -0
  52. package/dist/api/sandbox/files.js.map +1 -0
  53. package/dist/api/sandbox/get.d.ts +16 -0
  54. package/dist/api/sandbox/get.d.ts.map +1 -0
  55. package/dist/api/sandbox/get.js +57 -0
  56. package/dist/api/sandbox/get.js.map +1 -0
  57. package/dist/api/sandbox/index.d.ts +22 -0
  58. package/dist/api/sandbox/index.d.ts.map +1 -0
  59. package/dist/api/sandbox/index.js +12 -0
  60. package/dist/api/sandbox/index.js.map +1 -0
  61. package/dist/api/sandbox/list.d.ts +15 -0
  62. package/dist/api/sandbox/list.d.ts.map +1 -0
  63. package/dist/api/sandbox/list.js +75 -0
  64. package/dist/api/sandbox/list.js.map +1 -0
  65. package/dist/api/sandbox/run.d.ts +28 -0
  66. package/dist/api/sandbox/run.d.ts.map +1 -0
  67. package/dist/api/sandbox/run.js +269 -0
  68. package/dist/api/sandbox/run.js.map +1 -0
  69. package/dist/api/sandbox/snapshot.d.ts +89 -0
  70. package/dist/api/sandbox/snapshot.d.ts.map +1 -0
  71. package/dist/api/sandbox/snapshot.js +140 -0
  72. package/dist/api/sandbox/snapshot.js.map +1 -0
  73. package/dist/api/sandbox/util.d.ts +37 -0
  74. package/dist/api/sandbox/util.d.ts.map +1 -0
  75. package/dist/api/sandbox/util.js +45 -0
  76. package/dist/api/sandbox/util.js.map +1 -0
  77. package/dist/config.d.ts +1 -0
  78. package/dist/config.d.ts.map +1 -1
  79. package/dist/config.js +1 -0
  80. package/dist/config.js.map +1 -1
  81. package/dist/runtime-bootstrap.d.ts.map +1 -1
  82. package/dist/runtime-bootstrap.js +3 -0
  83. package/dist/runtime-bootstrap.js.map +1 -1
  84. package/package.json +4 -4
  85. package/src/api/api.ts +33 -13
  86. package/src/api/index.ts +1 -0
  87. package/src/api/project/deploy.ts +0 -2
  88. package/src/api/project/get.ts +10 -2
  89. package/src/api/region/create.ts +1 -0
  90. package/src/api/region/delete.ts +9 -2
  91. package/src/api/region/resources.ts +2 -0
  92. package/src/api/sandbox/client.ts +349 -0
  93. package/src/api/sandbox/create.ts +166 -0
  94. package/src/api/sandbox/destroy.ts +41 -0
  95. package/src/api/sandbox/execute.ts +102 -0
  96. package/src/api/sandbox/execution.ts +154 -0
  97. package/src/api/sandbox/files.ts +138 -0
  98. package/src/api/sandbox/get.ts +74 -0
  99. package/src/api/sandbox/index.ts +35 -0
  100. package/src/api/sandbox/list.ts +94 -0
  101. package/src/api/sandbox/run.ts +360 -0
  102. package/src/api/sandbox/snapshot.ts +247 -0
  103. package/src/api/sandbox/util.ts +55 -0
  104. package/src/config.ts +2 -0
  105. package/src/runtime-bootstrap.ts +3 -0
@@ -51,6 +51,9 @@ export function bootstrapRuntimeEnv(options = {}) {
51
51
  if (!process.env.AGENTUITY_KEYVALUE_URL) {
52
52
  process.env.AGENTUITY_KEYVALUE_URL = serviceUrls.keyvalue;
53
53
  }
54
+ if (!process.env.AGENTUITY_SANDBOX_URL) {
55
+ process.env.AGENTUITY_SANDBOX_URL = serviceUrls.sandbox;
56
+ }
54
57
  if (!process.env.AGENTUITY_STREAM_URL) {
55
58
  process.env.AGENTUITY_STREAM_URL = serviceUrls.stream;
56
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-bootstrap.js","sourceRoot":"","sources":["../src/runtime-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAe1C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAmC,EAAE;IACxE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC;IAE5E,6DAA6D;IAC7D,IACC,CAAC,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC;QAC/D,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAC5B,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,OAAO,CAAC;IACxC,CAAC;IAED,kDAAkD;IAClD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,OAAO,CAAC;IACzC,CAAC;IAED,mCAAmC;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC5C,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAE3C,2EAA2E;IAC3E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,WAAW,CAAC,IAAI,CAAC;IACnD,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"runtime-bootstrap.js","sourceRoot":"","sources":["../src/runtime-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAe1C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAmC,EAAE;IACxE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC;IAE5E,6DAA6D;IAC7D,IACC,CAAC,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC;QAC/D,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAC5B,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,OAAO,CAAC;IACxC,CAAC;IAED,kDAAkD;IAClD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,OAAO,CAAC;IACzC,CAAC;IAED,mCAAmC;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC5C,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAE3C,2EAA2E;IAC3E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,qBAAqB,GAAG,WAAW,CAAC,OAAO,CAAC;IACzD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,WAAW,CAAC,IAAI,CAAC;IACnD,CAAC;AACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentuity/server",
3
- "version": "0.0.105",
3
+ "version": "0.0.107",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Agentuity employees and contributors",
6
6
  "type": "module",
@@ -25,12 +25,12 @@
25
25
  "prepublishOnly": "bun run clean && bun run build"
26
26
  },
27
27
  "dependencies": {
28
- "@agentuity/core": "0.0.105",
29
- "@agentuity/schema": "0.0.105",
28
+ "@agentuity/core": "0.0.107",
29
+ "@agentuity/schema": "0.0.107",
30
30
  "zod": "^4.1.12"
31
31
  },
32
32
  "devDependencies": {
33
- "@agentuity/test-utils": "0.0.105",
33
+ "@agentuity/test-utils": "0.0.107",
34
34
  "@types/bun": "latest",
35
35
  "@types/node": "^22.0.0",
36
36
  "bun-types": "latest",
package/src/api/api.ts CHANGED
@@ -122,9 +122,10 @@ export class APIClient {
122
122
  */
123
123
  async get<TResponse = void>(
124
124
  endpoint: string,
125
- responseSchema?: z.ZodType<TResponse>
125
+ responseSchema?: z.ZodType<TResponse>,
126
+ signal?: AbortSignal
126
127
  ): Promise<TResponse> {
127
- return this.request('GET', endpoint, responseSchema);
128
+ return this.request('GET', endpoint, responseSchema, undefined, undefined, signal);
128
129
  }
129
130
 
130
131
  /**
@@ -134,9 +135,10 @@ export class APIClient {
134
135
  endpoint: string,
135
136
  body?: TBody,
136
137
  responseSchema?: z.ZodType<TResponse>,
137
- bodySchema?: z.ZodType<TBody>
138
+ bodySchema?: z.ZodType<TBody>,
139
+ signal?: AbortSignal
138
140
  ): Promise<TResponse> {
139
- return this.request('POST', endpoint, responseSchema, body, bodySchema);
141
+ return this.request('POST', endpoint, responseSchema, body, bodySchema, signal);
140
142
  }
141
143
 
142
144
  /**
@@ -146,9 +148,10 @@ export class APIClient {
146
148
  endpoint: string,
147
149
  body?: TBody,
148
150
  responseSchema?: z.ZodType<TResponse>,
149
- bodySchema?: z.ZodType<TBody>
151
+ bodySchema?: z.ZodType<TBody>,
152
+ signal?: AbortSignal
150
153
  ): Promise<TResponse> {
151
- return this.request('PUT', endpoint, responseSchema, body, bodySchema);
154
+ return this.request('PUT', endpoint, responseSchema, body, bodySchema, signal);
152
155
  }
153
156
 
154
157
  /**
@@ -156,9 +159,10 @@ export class APIClient {
156
159
  */
157
160
  async delete<TResponse = void>(
158
161
  endpoint: string,
159
- responseSchema?: z.ZodType<TResponse>
162
+ responseSchema?: z.ZodType<TResponse>,
163
+ signal?: AbortSignal
160
164
  ): Promise<TResponse> {
161
- return this.request('DELETE', endpoint, responseSchema);
165
+ return this.request('DELETE', endpoint, responseSchema, undefined, undefined, signal);
162
166
  }
163
167
 
164
168
  /**
@@ -168,9 +172,18 @@ export class APIClient {
168
172
  endpoint: string,
169
173
  body?: TBody,
170
174
  responseSchema?: z.ZodType<TResponse>,
171
- bodySchema?: z.ZodType<TBody>
175
+ bodySchema?: z.ZodType<TBody>,
176
+ signal?: AbortSignal
172
177
  ): Promise<TResponse> {
173
- return this.request('PATCH', endpoint, responseSchema, body, bodySchema);
178
+ return this.request('PATCH', endpoint, responseSchema, body, bodySchema, signal);
179
+ }
180
+
181
+ /**
182
+ * Raw GET request that returns the Response object directly.
183
+ * Useful for streaming responses where you need access to the body stream.
184
+ */
185
+ async rawGet(endpoint: string, signal?: AbortSignal): Promise<Response> {
186
+ return this.#makeRequest('GET', endpoint, undefined, signal);
174
187
  }
175
188
 
176
189
  /**
@@ -181,7 +194,8 @@ export class APIClient {
181
194
  endpoint: string,
182
195
  responseSchema?: z.ZodType<TResponse>,
183
196
  body?: TBody,
184
- bodySchema?: z.ZodType<TBody>
197
+ bodySchema?: z.ZodType<TBody>,
198
+ signal?: AbortSignal
185
199
  ): Promise<TResponse> {
186
200
  // Validate request body if schema provided
187
201
  if (body !== undefined && bodySchema) {
@@ -194,7 +208,7 @@ export class APIClient {
194
208
  }
195
209
  }
196
210
 
197
- const response = await this.#makeRequest(method, endpoint, body);
211
+ const response = await this.#makeRequest(method, endpoint, body, signal);
198
212
 
199
213
  // Handle empty responses (204 or zero-length body)
200
214
  let data: unknown;
@@ -231,7 +245,12 @@ export class APIClient {
231
245
  return undefined as TResponse;
232
246
  }
233
247
 
234
- async #makeRequest(method: string, endpoint: string, body?: unknown): Promise<Response> {
248
+ async #makeRequest(
249
+ method: string,
250
+ endpoint: string,
251
+ body?: unknown,
252
+ signal?: AbortSignal
253
+ ): Promise<Response> {
235
254
  this.#logger.trace('sending %s to %s%s', method, this.#baseUrl, endpoint);
236
255
 
237
256
  const maxRetries = this.#config?.maxRetries ?? 3;
@@ -266,6 +285,7 @@ export class APIClient {
266
285
  method,
267
286
  headers,
268
287
  body: body !== undefined ? JSON.stringify(body) : undefined,
288
+ signal,
269
289
  });
270
290
  } catch (ex) {
271
291
  const _ex = ex as { code?: string; name: string };
package/src/api/index.ts CHANGED
@@ -4,6 +4,7 @@ export * from './db';
4
4
  export * from './org';
5
5
  export * from './project';
6
6
  export * from './region';
7
+ export * from './sandbox';
7
8
  export * from './session';
8
9
  export * from './thread';
9
10
  export * from './user';
@@ -6,8 +6,6 @@ export const Resources = z.object({
6
6
  memory: z.string().default('500Mi').describe('The memory requirements'),
7
7
  cpu: z.string().default('500m').describe('The CPU requirements'),
8
8
  disk: z.string().default('500Mi').describe('The disk requirements'),
9
- db: z.string().optional().describe('the name of the database to use'),
10
- storage: z.string().optional().describe('the name of the storage bucket to use'),
11
9
  });
12
10
 
13
11
  export const Mode = z.object({
@@ -4,7 +4,8 @@ import { ProjectResponseError } from './util';
4
4
 
5
5
  const _ProjectGetRequestSchema = z.object({
6
6
  id: z.string().describe('the project id'),
7
- mask: z.boolean().default(true).describe('if the secrets should be returned masked'),
7
+ mask: z.boolean().default(true).optional().describe('if the secrets should be returned masked'),
8
+ keys: z.boolean().default(true).optional().describe('if the project keys should be returned'),
8
9
  });
9
10
 
10
11
  const ProjectSchema = z.object({
@@ -27,12 +28,19 @@ type ProjectGetResponse = z.infer<typeof ProjectGetResponseSchema>;
27
28
  export type Project = z.infer<typeof ProjectSchema>;
28
29
 
29
30
  export async function projectGet(client: APIClient, request: ProjectGetRequest): Promise<Project> {
31
+ const keys = request.keys ?? true;
30
32
  const resp = await client.get<ProjectGetResponse>(
31
- `/cli/project/${request.id}?mask=${request.mask ?? true}`,
33
+ `/cli/project/${request.id}?mask=${request.mask ?? true}&includeProjectKeys=${keys}`,
32
34
  ProjectGetResponseSchema
33
35
  );
34
36
 
35
37
  if (resp.success) {
38
+ if (keys && resp.data.secrets?.AGENTUITY_SDK_KEY) {
39
+ return {
40
+ ...resp.data,
41
+ api_key: resp.data.secrets.AGENTUITY_SDK_KEY,
42
+ };
43
+ }
36
44
  return resp.data;
37
45
  }
38
46
 
@@ -14,6 +14,7 @@ const CreateResourcesRequest = z.object({
14
14
  const CreatedResource = z.object({
15
15
  type: z.string().describe('the resource type'),
16
16
  name: z.string().describe('the resource name'),
17
+ env: z.record(z.string(), z.string()).describe('environment variables for the resource'),
17
18
  });
18
19
 
19
20
  const CreateResourcesResponse = z.object({
@@ -11,14 +11,21 @@ const DeleteResourcesRequest = z.object({
11
11
  resources: z.array(DeleteResourceSpec).describe('list of resources to delete'),
12
12
  });
13
13
 
14
+ const DeletedResource = z.object({
15
+ type: z.string().describe('the resource type'),
16
+ name: z.string().describe('the resource name'),
17
+ env_keys: z.array(z.string()).describe('environment variable keys to remove'),
18
+ });
19
+
14
20
  const DeleteResourcesResponse = z.object({
15
- deleted: z.array(z.string()).describe('list of deleted resource names'),
21
+ deleted: z.array(DeletedResource).describe('list of deleted resources'),
16
22
  });
17
23
 
18
24
  const DeleteResourcesResponseSchema = APIResponseSchema(DeleteResourcesResponse);
19
25
 
20
26
  export type DeleteResourcesRequest = z.infer<typeof DeleteResourcesRequest>;
21
27
  export type DeleteResourcesResponse = z.infer<typeof DeleteResourcesResponseSchema>;
28
+ export type DeletedResource = z.infer<typeof DeletedResource>;
22
29
 
23
30
  /**
24
31
  * Delete one or more resources (DB or S3) for an organization in a specific region
@@ -35,7 +42,7 @@ export async function deleteResources(
35
42
  orgId: string,
36
43
  region: string,
37
44
  resources: Array<{ type: 'db' | 's3'; name: string }>
38
- ): Promise<string[]> {
45
+ ): Promise<DeletedResource[]> {
39
46
  const resp = await client.request<DeleteResourcesResponse, DeleteResourcesRequest>(
40
47
  'DELETE',
41
48
  `/resource/2025-11-16/${orgId}/${region}`,
@@ -11,6 +11,7 @@ const ResourceListResponse = z.object({
11
11
  region: z.string().nullable().optional().describe('the S3 region'),
12
12
  endpoint: z.string().nullable().optional().describe('the S3 endpoint'),
13
13
  cname: z.string().nullable().optional().describe('the S3 CNAME'),
14
+ env: z.record(z.string(), z.string()).describe('environment variables for the resource'),
14
15
  })
15
16
  ),
16
17
  db: z.array(
@@ -19,6 +20,7 @@ const ResourceListResponse = z.object({
19
20
  username: z.string().nullable().optional().describe('the database username'),
20
21
  password: z.string().nullable().optional().describe('the database password'),
21
22
  url: z.string().nullable().optional().describe('the full database connection URL'),
23
+ env: z.record(z.string(), z.string()).describe('environment variables for the resource'),
22
24
  })
23
25
  ),
24
26
  redis: z
@@ -0,0 +1,349 @@
1
+ import type {
2
+ Logger,
3
+ SandboxCreateOptions,
4
+ SandboxInfo,
5
+ ExecuteOptions as CoreExecuteOptions,
6
+ Execution,
7
+ FileToWrite,
8
+ } from '@agentuity/core';
9
+ import type { Writable } from 'node:stream';
10
+ import { APIClient } from '../api';
11
+ import { sandboxCreate, type SandboxCreateResponse } from './create';
12
+ import { sandboxDestroy } from './destroy';
13
+ import { sandboxGet } from './get';
14
+ import { sandboxExecute } from './execute';
15
+ import { sandboxWriteFiles, sandboxReadFile } from './files';
16
+ import { executionGet, type ExecutionInfo } from './execution';
17
+ import { ConsoleLogger } from '../../logger';
18
+ import { getServiceUrls } from '../../config';
19
+
20
+ const POLL_INTERVAL_MS = 100;
21
+ const MAX_POLL_TIME_MS = 300000; // 5 minutes
22
+
23
+ /**
24
+ * Poll for execution completion
25
+ */
26
+ async function waitForExecution(
27
+ client: APIClient,
28
+ executionId: string,
29
+ orgId?: string,
30
+ signal?: AbortSignal
31
+ ): Promise<ExecutionInfo> {
32
+ const startTime = Date.now();
33
+
34
+ while (Date.now() - startTime < MAX_POLL_TIME_MS) {
35
+ if (signal?.aborted) {
36
+ throw new DOMException('The operation was aborted.', 'AbortError');
37
+ }
38
+
39
+ const info = await executionGet(client, { executionId, orgId });
40
+
41
+ if (
42
+ info.status === 'completed' ||
43
+ info.status === 'failed' ||
44
+ info.status === 'timeout' ||
45
+ info.status === 'cancelled'
46
+ ) {
47
+ return info;
48
+ }
49
+
50
+ await new Promise((resolve, reject) => {
51
+ const timeoutId = setTimeout(resolve, POLL_INTERVAL_MS);
52
+ signal?.addEventListener(
53
+ 'abort',
54
+ () => {
55
+ clearTimeout(timeoutId);
56
+ reject(new DOMException('The operation was aborted.', 'AbortError'));
57
+ },
58
+ { once: true }
59
+ );
60
+ });
61
+ }
62
+
63
+ throw new Error(`Execution ${executionId} timed out waiting for completion`);
64
+ }
65
+
66
+ /**
67
+ * Pipes a remote stream URL to a local writable stream
68
+ */
69
+ async function pipeStreamToWritable(streamUrl: string, writable: Writable): Promise<void> {
70
+ const response = await fetch(streamUrl);
71
+ if (!response.ok) {
72
+ throw new Error(`Failed to fetch stream: ${response.status} ${response.statusText}`);
73
+ }
74
+ if (!response.body) {
75
+ return;
76
+ }
77
+
78
+ const reader = response.body.getReader();
79
+ try {
80
+ while (true) {
81
+ const { done, value } = await reader.read();
82
+ if (done) break;
83
+ if (value) {
84
+ writable.write(value);
85
+ }
86
+ }
87
+ } finally {
88
+ reader.releaseLock();
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Extended execute options that support piping output to writable streams
94
+ */
95
+ export interface ExecuteOptions extends CoreExecuteOptions {
96
+ /**
97
+ * Pipe stdout/stderr to writable streams (e.g., process.stdout)
98
+ */
99
+ pipe?: {
100
+ stdout?: Writable;
101
+ stderr?: Writable;
102
+ };
103
+ }
104
+
105
+ export interface SandboxClientOptions {
106
+ /**
107
+ * API key for authentication.
108
+ * Defaults to process.env.AGENTUITY_SDK_KEY || process.env.AGENTUITY_CLI_KEY
109
+ */
110
+ apiKey?: string;
111
+
112
+ /**
113
+ * Base URL for the sandbox API.
114
+ * Defaults to process.env.AGENTUITY_SANDBOX_URL ||
115
+ * process.env.AGENTUITY_CATALYST_URL ||
116
+ * process.env.AGENTUITY_TRANSPORT_URL ||
117
+ * regional catalyst URL
118
+ */
119
+ url?: string;
120
+
121
+ /**
122
+ * Organization ID for multi-tenant operations
123
+ */
124
+ orgId?: string;
125
+
126
+ /**
127
+ * Custom logger instance
128
+ */
129
+ logger?: Logger;
130
+ }
131
+
132
+ /**
133
+ * A sandbox instance returned by SandboxClient.create()
134
+ */
135
+ export interface SandboxInstance {
136
+ /**
137
+ * Unique sandbox identifier
138
+ */
139
+ id: string;
140
+
141
+ /**
142
+ * Sandbox status at creation time
143
+ */
144
+ status: SandboxCreateResponse['status'];
145
+
146
+ /**
147
+ * URL to stream stdout output
148
+ */
149
+ stdoutStreamUrl?: string;
150
+
151
+ /**
152
+ * URL to stream stderr output
153
+ */
154
+ stderrStreamUrl?: string;
155
+
156
+ /**
157
+ * Execute a command in the sandbox
158
+ */
159
+ execute(options: ExecuteOptions): Promise<Execution>;
160
+
161
+ /**
162
+ * Get current sandbox information
163
+ */
164
+ get(): Promise<SandboxInfo>;
165
+
166
+ /**
167
+ * Destroy the sandbox and release all resources
168
+ */
169
+ destroy(): Promise<void>;
170
+ }
171
+
172
+ /**
173
+ * Convenience client for sandbox operations.
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * const client = new SandboxClient();
178
+ * const sandbox = await client.create();
179
+ * const result = await sandbox.execute({ command: ['echo', 'hello'] });
180
+ * await sandbox.destroy();
181
+ * ```
182
+ */
183
+ export class SandboxClient {
184
+ readonly #client: APIClient;
185
+ readonly #orgId?: string;
186
+
187
+ constructor(options: SandboxClientOptions = {}) {
188
+ const apiKey =
189
+ options.apiKey || process.env.AGENTUITY_SDK_KEY || process.env.AGENTUITY_CLI_KEY;
190
+
191
+ const region = process.env.AGENTUITY_REGION ?? 'usc';
192
+ const serviceUrls = getServiceUrls(region);
193
+
194
+ const url =
195
+ options.url ||
196
+ process.env.AGENTUITY_SANDBOX_URL ||
197
+ process.env.AGENTUITY_CATALYST_URL ||
198
+ process.env.AGENTUITY_TRANSPORT_URL ||
199
+ serviceUrls.sandbox;
200
+
201
+ const logger = options.logger ?? new ConsoleLogger('warn');
202
+
203
+ this.#client = new APIClient(url, logger, apiKey ?? '', {});
204
+ this.#orgId = options.orgId;
205
+ }
206
+
207
+ /**
208
+ * Create a new sandbox instance
209
+ *
210
+ * @param options - Optional sandbox configuration
211
+ * @returns A sandbox instance with execute and destroy methods
212
+ */
213
+ async create(options?: SandboxCreateOptions): Promise<SandboxInstance> {
214
+ const response = await sandboxCreate(this.#client, {
215
+ options,
216
+ orgId: this.#orgId,
217
+ });
218
+
219
+ const sandboxId = response.sandboxId;
220
+ const client = this.#client;
221
+ const orgId = this.#orgId;
222
+
223
+ return {
224
+ id: sandboxId,
225
+ status: response.status,
226
+ stdoutStreamUrl: response.stdoutStreamUrl,
227
+ stderrStreamUrl: response.stderrStreamUrl,
228
+
229
+ async execute(executeOptions: ExecuteOptions): Promise<Execution> {
230
+ const { pipe, ...coreOptions } = executeOptions;
231
+
232
+ const initialResult = await sandboxExecute(client, {
233
+ sandboxId,
234
+ options: coreOptions,
235
+ orgId,
236
+ signal: coreOptions.signal,
237
+ });
238
+
239
+ // If pipe options provided, stream the output to the writable streams
240
+ if (pipe) {
241
+ const streamPromises: Promise<void>[] = [];
242
+
243
+ if (pipe.stdout && initialResult.stdoutStreamUrl) {
244
+ streamPromises.push(
245
+ pipeStreamToWritable(initialResult.stdoutStreamUrl, pipe.stdout)
246
+ );
247
+ }
248
+ if (pipe.stderr && initialResult.stderrStreamUrl) {
249
+ streamPromises.push(
250
+ pipeStreamToWritable(initialResult.stderrStreamUrl, pipe.stderr)
251
+ );
252
+ }
253
+
254
+ // Wait for all streams to complete
255
+ if (streamPromises.length > 0) {
256
+ await Promise.all(streamPromises);
257
+ }
258
+ }
259
+
260
+ // Wait for execution to complete and get final result with exit code
261
+ const finalResult = await waitForExecution(
262
+ client,
263
+ initialResult.executionId,
264
+ orgId,
265
+ coreOptions.signal
266
+ );
267
+
268
+ return {
269
+ executionId: finalResult.executionId,
270
+ status: finalResult.status,
271
+ exitCode: finalResult.exitCode,
272
+ durationMs: finalResult.durationMs,
273
+ stdoutStreamUrl: initialResult.stdoutStreamUrl,
274
+ stderrStreamUrl: initialResult.stderrStreamUrl,
275
+ };
276
+ },
277
+
278
+ async get(): Promise<SandboxInfo> {
279
+ return sandboxGet(client, { sandboxId, orgId });
280
+ },
281
+
282
+ async destroy(): Promise<void> {
283
+ return sandboxDestroy(client, { sandboxId, orgId });
284
+ },
285
+ };
286
+ }
287
+
288
+ /**
289
+ * Get sandbox information by ID
290
+ *
291
+ * @param sandboxId - The sandbox ID
292
+ * @returns Sandbox information
293
+ */
294
+ async get(sandboxId: string): Promise<SandboxInfo> {
295
+ return sandboxGet(this.#client, { sandboxId, orgId: this.#orgId });
296
+ }
297
+
298
+ /**
299
+ * Destroy a sandbox by ID
300
+ *
301
+ * @param sandboxId - The sandbox ID to destroy
302
+ */
303
+ async destroy(sandboxId: string): Promise<void> {
304
+ return sandboxDestroy(this.#client, { sandboxId, orgId: this.#orgId });
305
+ }
306
+
307
+ /**
308
+ * Write files to a sandbox workspace
309
+ *
310
+ * @param sandboxId - The sandbox ID
311
+ * @param files - Array of files to write with path and content
312
+ * @param signal - Optional AbortSignal to cancel the operation
313
+ * @returns The number of files written
314
+ */
315
+ async writeFiles(
316
+ sandboxId: string,
317
+ files: FileToWrite[],
318
+ signal?: AbortSignal
319
+ ): Promise<number> {
320
+ const result = await sandboxWriteFiles(this.#client, {
321
+ sandboxId,
322
+ files,
323
+ orgId: this.#orgId,
324
+ signal,
325
+ });
326
+ return result.filesWritten;
327
+ }
328
+
329
+ /**
330
+ * Read a file from a sandbox workspace
331
+ *
332
+ * @param sandboxId - The sandbox ID
333
+ * @param path - Path to the file relative to the sandbox workspace
334
+ * @param signal - Optional AbortSignal to cancel the operation
335
+ * @returns A ReadableStream of the file contents
336
+ */
337
+ async readFile(
338
+ sandboxId: string,
339
+ path: string,
340
+ signal?: AbortSignal
341
+ ): Promise<ReadableStream<Uint8Array>> {
342
+ return sandboxReadFile(this.#client, {
343
+ sandboxId,
344
+ path,
345
+ orgId: this.#orgId,
346
+ signal,
347
+ });
348
+ }
349
+ }