@langchain/daytona 0.0.1

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.
package/dist/index.cjs ADDED
@@ -0,0 +1,696 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let _daytonaio_sdk = require("@daytonaio/sdk");
3
+ let deepagents = require("deepagents");
4
+
5
+ //#region src/auth.ts
6
+ /** Default Daytona API URL */
7
+ const DEFAULT_API_URL = "https://app.daytona.io/api";
8
+ /**
9
+ * Get the API key for Daytona API.
10
+ *
11
+ * Authentication is resolved in the following priority order:
12
+ *
13
+ * 1. **Explicit API key**: If `options.apiKey` is provided, it is used directly.
14
+ * 2. **DAYTONA_API_KEY**: Environment variable for Daytona API key.
15
+ *
16
+ * If no API key is found, an error is thrown with setup instructions.
17
+ *
18
+ * ## Environment Variable Setup
19
+ *
20
+ * ```bash
21
+ * # Get your API key from https://app.daytona.io
22
+ * export DAYTONA_API_KEY=your_api_key_here
23
+ * ```
24
+ *
25
+ * @param options - Optional authentication configuration from DaytonaSandboxOptions
26
+ * @returns The API key string
27
+ * @throws {Error} If no API key is available
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // With explicit API key
32
+ * const apiKey = getAuthApiKey({ apiKey: "my-api-key" });
33
+ *
34
+ * // Using environment variables (auto-detected)
35
+ * const apiKey = getAuthApiKey();
36
+ *
37
+ * // From DaytonaSandboxOptions
38
+ * const options: DaytonaSandboxOptions = {
39
+ * auth: { apiKey: "my-api-key" }
40
+ * };
41
+ * const apiKey = getAuthApiKey(options.auth);
42
+ * ```
43
+ */
44
+ function getAuthApiKey(options) {
45
+ if (options?.apiKey) return options.apiKey;
46
+ const apiKey = process.env.DAYTONA_API_KEY;
47
+ if (apiKey) return apiKey;
48
+ throw new Error("Daytona authentication required. Provide an API key using one of these methods:\n\n1. Set DAYTONA_API_KEY environment variable:\n Get your API key from https://app.daytona.io\n Run: export DAYTONA_API_KEY=your_api_key_here\n\n2. Pass API key directly in options:\n new DaytonaSandbox({ auth: { apiKey: '...' } })");
49
+ }
50
+ /**
51
+ * Get the API URL for Daytona API.
52
+ *
53
+ * URL is resolved in the following priority order:
54
+ *
55
+ * 1. **Explicit API URL**: If `options.apiUrl` is provided, it is used directly.
56
+ * 2. **DAYTONA_API_URL**: Environment variable for Daytona API URL.
57
+ * 3. **Default**: Uses the default Daytona API URL.
58
+ *
59
+ * @param options - Optional authentication configuration from DaytonaSandboxOptions
60
+ * @returns The API URL string
61
+ */
62
+ function getAuthApiUrl(options) {
63
+ if (options?.apiUrl) return options.apiUrl;
64
+ const apiUrl = process.env.DAYTONA_API_URL;
65
+ if (apiUrl) return apiUrl;
66
+ return DEFAULT_API_URL;
67
+ }
68
+ /**
69
+ * Get authentication credentials for Daytona API.
70
+ *
71
+ * This function returns the credentials needed for the Daytona SDK.
72
+ *
73
+ * @param options - Optional authentication configuration from DaytonaSandboxOptions
74
+ * @param target - Optional target region
75
+ * @returns Complete authentication credentials
76
+ * @throws {Error} If no API key is available
77
+ */
78
+ function getAuthCredentials(options, target) {
79
+ return {
80
+ apiKey: getAuthApiKey(options),
81
+ apiUrl: getAuthApiUrl(options),
82
+ target: target ?? process.env.DAYTONA_TARGET
83
+ };
84
+ }
85
+
86
+ //#endregion
87
+ //#region src/types.ts
88
+ /**
89
+ * Custom error class for Daytona Sandbox operations.
90
+ *
91
+ * Provides structured error information including:
92
+ * - Human-readable message
93
+ * - Error code for programmatic handling
94
+ * - Original cause for debugging
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * try {
99
+ * await sandbox.execute("some command");
100
+ * } catch (error) {
101
+ * if (error instanceof DaytonaSandboxError) {
102
+ * switch (error.code) {
103
+ * case "NOT_INITIALIZED":
104
+ * await sandbox.initialize();
105
+ * break;
106
+ * case "COMMAND_TIMEOUT":
107
+ * console.error("Command took too long");
108
+ * break;
109
+ * default:
110
+ * throw error;
111
+ * }
112
+ * }
113
+ * }
114
+ * ```
115
+ */
116
+ var DaytonaSandboxError = class DaytonaSandboxError extends Error {
117
+ /** Error name for instanceof checks and logging */
118
+ name = "DaytonaSandboxError";
119
+ /**
120
+ * Creates a new DaytonaSandboxError.
121
+ *
122
+ * @param message - Human-readable error description
123
+ * @param code - Structured error code for programmatic handling
124
+ * @param cause - Original error that caused this error (for debugging)
125
+ */
126
+ constructor(message, code, cause) {
127
+ super(message);
128
+ this.code = code;
129
+ this.cause = cause;
130
+ Object.setPrototypeOf(this, DaytonaSandboxError.prototype);
131
+ }
132
+ };
133
+
134
+ //#endregion
135
+ //#region src/sandbox.ts
136
+ /**
137
+ * Daytona Sandbox implementation of the SandboxBackendProtocol.
138
+ *
139
+ * This module provides a Daytona Sandbox backend for deepagents, enabling agents
140
+ * to execute commands, read/write files, and manage isolated sandbox environments
141
+ * using Daytona's infrastructure.
142
+ *
143
+ * @packageDocumentation
144
+ */
145
+ /**
146
+ * Daytona Sandbox backend for deepagents.
147
+ *
148
+ * Extends `BaseSandbox` to provide command execution, file operations, and
149
+ * sandbox lifecycle management using Daytona's SDK.
150
+ *
151
+ * ## Basic Usage
152
+ *
153
+ * ```typescript
154
+ * import { DaytonaSandbox } from "@langchain/daytona";
155
+ *
156
+ * // Create and initialize a sandbox
157
+ * const sandbox = await DaytonaSandbox.create({
158
+ * language: "typescript",
159
+ * timeout: 300,
160
+ * });
161
+ *
162
+ * try {
163
+ * // Execute commands
164
+ * const result = await sandbox.execute("node --version");
165
+ * console.log(result.output);
166
+ * } finally {
167
+ * // Always cleanup
168
+ * await sandbox.close();
169
+ * }
170
+ * ```
171
+ *
172
+ * ## Using with DeepAgent
173
+ *
174
+ * ```typescript
175
+ * import { createDeepAgent } from "deepagents";
176
+ * import { DaytonaSandbox } from "@langchain/daytona";
177
+ *
178
+ * const sandbox = await DaytonaSandbox.create();
179
+ *
180
+ * const agent = createDeepAgent({
181
+ * model: new ChatAnthropic({ model: "claude-sonnet-4-20250514" }),
182
+ * systemPrompt: "You are a coding assistant with sandbox access.",
183
+ * backend: sandbox,
184
+ * });
185
+ * ```
186
+ */
187
+ var DaytonaSandbox = class DaytonaSandbox extends deepagents.BaseSandbox {
188
+ /** Private reference to the Daytona client */
189
+ #daytona = null;
190
+ /** Private reference to the underlying Daytona Sandbox instance */
191
+ #sandbox = null;
192
+ /** Configuration options for this sandbox */
193
+ #options;
194
+ /** Unique identifier for this sandbox instance */
195
+ #id;
196
+ /** Default timeout for command execution in seconds */
197
+ #timeout;
198
+ /**
199
+ * Get the unique identifier for this sandbox.
200
+ *
201
+ * Before initialization, returns a temporary ID.
202
+ * After initialization, returns the actual Daytona sandbox ID.
203
+ */
204
+ get id() {
205
+ return this.#id;
206
+ }
207
+ /**
208
+ * Get the underlying Daytona Sandbox instance.
209
+ *
210
+ * @throws {DaytonaSandboxError} If the sandbox is not initialized
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * const sandbox = await DaytonaSandbox.create();
215
+ * const daytonaSdk = sandbox.sandbox; // Access the raw SDK
216
+ * ```
217
+ */
218
+ get sandbox() {
219
+ if (!this.#sandbox) throw new DaytonaSandboxError("Sandbox not initialized. Call initialize() or use DaytonaSandbox.create()", "NOT_INITIALIZED");
220
+ return this.#sandbox;
221
+ }
222
+ /**
223
+ * Check if the sandbox is initialized and running.
224
+ */
225
+ get isRunning() {
226
+ return this.#sandbox !== null;
227
+ }
228
+ /**
229
+ * Create a new DaytonaSandbox instance.
230
+ *
231
+ * Note: This only creates the instance. Call `initialize()` to actually
232
+ * create the Daytona Sandbox, or use the static `DaytonaSandbox.create()` method.
233
+ *
234
+ * @param options - Configuration options for the sandbox
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * // Two-step initialization
239
+ * const sandbox = new DaytonaSandbox({ language: "typescript" });
240
+ * await sandbox.initialize();
241
+ *
242
+ * // Or use the factory method
243
+ * const sandbox = await DaytonaSandbox.create({ language: "typescript" });
244
+ * ```
245
+ */
246
+ constructor(options = {}) {
247
+ super();
248
+ this.#options = {
249
+ language: "typescript",
250
+ timeout: 300,
251
+ ...options
252
+ };
253
+ this.#timeout = this.#options.timeout ?? 300;
254
+ this.#id = `daytona-sandbox-${Date.now()}`;
255
+ }
256
+ /**
257
+ * Initialize the sandbox by creating a new Daytona Sandbox instance.
258
+ *
259
+ * This method authenticates with Daytona and provisions a new sandbox.
260
+ * After initialization, the `id` property will reflect the actual sandbox ID.
261
+ *
262
+ * @throws {DaytonaSandboxError} If already initialized (`ALREADY_INITIALIZED`)
263
+ * @throws {DaytonaSandboxError} If authentication fails (`AUTHENTICATION_FAILED`)
264
+ * @throws {DaytonaSandboxError} If sandbox creation fails (`SANDBOX_CREATION_FAILED`)
265
+ *
266
+ * @example
267
+ * ```typescript
268
+ * const sandbox = new DaytonaSandbox();
269
+ * await sandbox.initialize();
270
+ * console.log(`Sandbox ID: ${sandbox.id}`);
271
+ * ```
272
+ */
273
+ async initialize() {
274
+ if (this.#sandbox) throw new DaytonaSandboxError("Sandbox is already initialized. Each DaytonaSandbox instance can only be initialized once.", "ALREADY_INITIALIZED");
275
+ let credentials;
276
+ try {
277
+ credentials = getAuthCredentials(this.#options.auth, this.#options.target);
278
+ } catch (error) {
279
+ throw new DaytonaSandboxError("Failed to authenticate with Daytona. Check your API key configuration.", "AUTHENTICATION_FAILED", error instanceof Error ? error : void 0);
280
+ }
281
+ try {
282
+ this.#daytona = new _daytonaio_sdk.Daytona({
283
+ apiKey: credentials.apiKey,
284
+ apiUrl: credentials.apiUrl,
285
+ target: credentials.target
286
+ });
287
+ if (this.#options.image) {
288
+ const createOptions = {
289
+ image: this.#options.image,
290
+ language: this.#options.language ?? "typescript"
291
+ };
292
+ if (this.#options.envVars) createOptions.envVars = this.#options.envVars;
293
+ if (this.#options.autoStopInterval !== void 0) createOptions.autoStopInterval = this.#options.autoStopInterval;
294
+ if (this.#options.labels) createOptions.labels = this.#options.labels;
295
+ if (this.#options.resources) createOptions.resources = this.#options.resources;
296
+ this.#sandbox = await this.#daytona.create(createOptions);
297
+ } else {
298
+ const createOptions = { language: this.#options.language ?? "typescript" };
299
+ if (this.#options.snapshot) createOptions.snapshot = this.#options.snapshot;
300
+ if (this.#options.envVars) createOptions.envVars = this.#options.envVars;
301
+ if (this.#options.autoStopInterval !== void 0) createOptions.autoStopInterval = this.#options.autoStopInterval;
302
+ if (this.#options.labels) createOptions.labels = this.#options.labels;
303
+ this.#sandbox = await this.#daytona.create(createOptions);
304
+ }
305
+ this.#id = this.#sandbox.id;
306
+ if (this.#options.initialFiles) await this.#uploadInitialFiles(this.#options.initialFiles);
307
+ } catch (error) {
308
+ throw new DaytonaSandboxError(`Failed to create Daytona Sandbox: ${error instanceof Error ? error.message : String(error)}`, "SANDBOX_CREATION_FAILED", error instanceof Error ? error : void 0);
309
+ }
310
+ }
311
+ /**
312
+ * Upload initial files to the sandbox.
313
+ *
314
+ * @param files - A map of file paths to their string contents
315
+ */
316
+ async #uploadInitialFiles(files) {
317
+ const encoder = new TextEncoder();
318
+ const fileEntries = Object.entries(files).map(([path, content]) => [path, encoder.encode(content)]);
319
+ const errors = (await this.uploadFiles(fileEntries)).filter((r) => r.error !== null);
320
+ if (errors.length > 0) throw new DaytonaSandboxError(`Failed to upload initial files: ${errors.map((e) => `${e.path}: ${e.error}`).join(", ")}`, "FILE_OPERATION_FAILED");
321
+ }
322
+ /**
323
+ * Execute a command in the sandbox.
324
+ *
325
+ * Commands are run using the sandbox's shell.
326
+ *
327
+ * @param command - The shell command to execute
328
+ * @returns Execution result with output, exit code, and truncation flag
329
+ * @throws {DaytonaSandboxError} If the sandbox is not initialized
330
+ *
331
+ * @example
332
+ * ```typescript
333
+ * const result = await sandbox.execute("echo 'Hello World'");
334
+ * console.log(result.output); // "Hello World\n"
335
+ * console.log(result.exitCode); // 0
336
+ * ```
337
+ */
338
+ async execute(command) {
339
+ const sandbox = this.sandbox;
340
+ try {
341
+ const response = await sandbox.process.executeCommand(command, void 0, void 0, this.#timeout);
342
+ return {
343
+ output: response.result ?? "",
344
+ exitCode: response.exitCode ?? 0,
345
+ truncated: false
346
+ };
347
+ } catch (error) {
348
+ if (error instanceof Error && error.message.includes("timeout")) throw new DaytonaSandboxError(`Command timed out: ${command}`, "COMMAND_TIMEOUT", error);
349
+ throw new DaytonaSandboxError(`Command execution failed: ${error instanceof Error ? error.message : String(error)}`, "COMMAND_FAILED", error instanceof Error ? error : void 0);
350
+ }
351
+ }
352
+ /**
353
+ * Upload files to the sandbox.
354
+ *
355
+ * Files are written to the sandbox filesystem. Parent directories are
356
+ * created automatically if they don't exist.
357
+ *
358
+ * @param files - Array of [path, content] tuples to upload
359
+ * @returns Upload result for each file, with success or error status
360
+ *
361
+ * @example
362
+ * ```typescript
363
+ * const encoder = new TextEncoder();
364
+ * const results = await sandbox.uploadFiles([
365
+ * ["src/index.js", encoder.encode("console.log('Hello')")],
366
+ * ["package.json", encoder.encode('{"name": "test"}')],
367
+ * ]);
368
+ * ```
369
+ */
370
+ async uploadFiles(files) {
371
+ const sandbox = this.sandbox;
372
+ const results = [];
373
+ for (const [path, content] of files) try {
374
+ const parentDir = path.substring(0, path.lastIndexOf("/"));
375
+ if (parentDir) await sandbox.fs.createFolder(parentDir, "755");
376
+ const buffer = Buffer.from(content);
377
+ await sandbox.fs.uploadFile(buffer, path);
378
+ results.push({
379
+ path,
380
+ error: null
381
+ });
382
+ } catch (error) {
383
+ results.push({
384
+ path,
385
+ error: this.#mapError(error)
386
+ });
387
+ }
388
+ return results;
389
+ }
390
+ /**
391
+ * Download files from the sandbox.
392
+ *
393
+ * Each file is read individually, allowing partial success when some
394
+ * files exist and others don't.
395
+ *
396
+ * @param paths - Array of file paths to download
397
+ * @returns Download result for each file, with content or error
398
+ *
399
+ * @example
400
+ * ```typescript
401
+ * const results = await sandbox.downloadFiles(["src/index.js", "missing.txt"]);
402
+ * for (const result of results) {
403
+ * if (result.content) {
404
+ * console.log(new TextDecoder().decode(result.content));
405
+ * } else {
406
+ * console.error(`Error: ${result.error}`);
407
+ * }
408
+ * }
409
+ * ```
410
+ */
411
+ async downloadFiles(paths) {
412
+ const sandbox = this.sandbox;
413
+ const results = [];
414
+ for (const path of paths) try {
415
+ const buffer = await sandbox.fs.downloadFile(path);
416
+ results.push({
417
+ path,
418
+ content: new Uint8Array(buffer),
419
+ error: null
420
+ });
421
+ } catch (error) {
422
+ results.push({
423
+ path,
424
+ content: null,
425
+ error: this.#mapError(error)
426
+ });
427
+ }
428
+ return results;
429
+ }
430
+ /**
431
+ * Close the sandbox and release all resources.
432
+ *
433
+ * After closing, the sandbox cannot be used again. The sandbox is deleted
434
+ * from Daytona's infrastructure.
435
+ *
436
+ * @example
437
+ * ```typescript
438
+ * try {
439
+ * await sandbox.execute("npm run build");
440
+ * } finally {
441
+ * await sandbox.close();
442
+ * }
443
+ * ```
444
+ */
445
+ async close() {
446
+ if (this.#sandbox) try {
447
+ await this.#sandbox.delete();
448
+ } finally {
449
+ this.#sandbox = null;
450
+ this.#daytona = null;
451
+ }
452
+ }
453
+ /**
454
+ * Stop the sandbox without deleting it.
455
+ *
456
+ * The sandbox can be restarted later using `start()`.
457
+ *
458
+ * @example
459
+ * ```typescript
460
+ * await sandbox.stop();
461
+ * // Later...
462
+ * await sandbox.start();
463
+ * ```
464
+ */
465
+ async stop() {
466
+ if (this.#sandbox) await this.#sandbox.stop();
467
+ }
468
+ /**
469
+ * Start a stopped sandbox.
470
+ *
471
+ * @param timeout - Maximum time to wait in seconds (default: 60)
472
+ *
473
+ * @example
474
+ * ```typescript
475
+ * await sandbox.start();
476
+ * console.log("Sandbox is now running");
477
+ * ```
478
+ */
479
+ async start(timeout = 60) {
480
+ if (this.#sandbox) await this.#sandbox.start(timeout);
481
+ }
482
+ /**
483
+ * Forcefully terminate and delete the sandbox.
484
+ *
485
+ * Use this when you need to immediately stop the sandbox.
486
+ *
487
+ * @example
488
+ * ```typescript
489
+ * await sandbox.kill();
490
+ * ```
491
+ */
492
+ async kill() {
493
+ await this.close();
494
+ }
495
+ /**
496
+ * Get the working directory path inside the sandbox.
497
+ *
498
+ * @returns The absolute path to the sandbox working directory
499
+ *
500
+ * @example
501
+ * ```typescript
502
+ * const workDir = await sandbox.getWorkDir();
503
+ * console.log(`Working directory: ${workDir}`);
504
+ * ```
505
+ */
506
+ async getWorkDir() {
507
+ return await this.sandbox.getWorkDir() ?? "/home/daytona";
508
+ }
509
+ /**
510
+ * Get the user's home directory path inside the sandbox.
511
+ *
512
+ * @returns The absolute path to the user's home directory
513
+ *
514
+ * @example
515
+ * ```typescript
516
+ * const homeDir = await sandbox.getUserHomeDir();
517
+ * console.log(`Home directory: ${homeDir}`);
518
+ * ```
519
+ */
520
+ async getUserHomeDir() {
521
+ return await this.sandbox.getUserHomeDir() ?? "/home/daytona";
522
+ }
523
+ /**
524
+ * Set the sandbox from an existing Daytona Sandbox instance.
525
+ * Used internally by the static `connect()` method.
526
+ */
527
+ #setFromExisting(daytona, existingSandbox, sandboxId) {
528
+ this.#daytona = daytona;
529
+ this.#sandbox = existingSandbox;
530
+ this.#id = sandboxId;
531
+ }
532
+ /**
533
+ * Map Daytona SDK errors to standardized FileOperationError codes.
534
+ *
535
+ * @param error - The error from the Daytona SDK
536
+ * @returns A standardized error code
537
+ */
538
+ #mapError(error) {
539
+ if (error instanceof Error) {
540
+ const msg = error.message.toLowerCase();
541
+ if (msg.includes("not found") || msg.includes("enoent")) return "file_not_found";
542
+ if (msg.includes("permission") || msg.includes("eacces")) return "permission_denied";
543
+ if (msg.includes("directory") || msg.includes("eisdir")) return "is_directory";
544
+ }
545
+ return "invalid_path";
546
+ }
547
+ /**
548
+ * Create and initialize a new DaytonaSandbox in one step.
549
+ *
550
+ * This is the recommended way to create a sandbox. It combines
551
+ * construction and initialization into a single async operation.
552
+ *
553
+ * @param options - Configuration options for the sandbox
554
+ * @returns An initialized and ready-to-use sandbox
555
+ *
556
+ * @example
557
+ * ```typescript
558
+ * const sandbox = await DaytonaSandbox.create({
559
+ * language: "typescript",
560
+ * cpu: 2,
561
+ * memory: 4,
562
+ * });
563
+ * ```
564
+ */
565
+ static async create(options) {
566
+ const sandbox = new DaytonaSandbox(options);
567
+ await sandbox.initialize();
568
+ return sandbox;
569
+ }
570
+ /**
571
+ * Connect to an existing sandbox by ID.
572
+ *
573
+ * This allows you to resume working with a sandbox that was created
574
+ * earlier or that is still running.
575
+ *
576
+ * @param sandboxId - The ID of the sandbox to connect to
577
+ * @param options - Optional auth configuration (for API key)
578
+ * @returns A connected sandbox instance
579
+ *
580
+ * @example
581
+ * ```typescript
582
+ * // Resume a sandbox from a stored ID
583
+ * const sandbox = await DaytonaSandbox.connect("sandbox-abc123");
584
+ * const result = await sandbox.execute("ls -la");
585
+ * ```
586
+ */
587
+ static async connect(sandboxId, options) {
588
+ let credentials;
589
+ try {
590
+ credentials = getAuthCredentials(options?.auth, options?.target);
591
+ } catch (error) {
592
+ throw new DaytonaSandboxError("Failed to authenticate with Daytona. Check your API key configuration.", "AUTHENTICATION_FAILED", error instanceof Error ? error : void 0);
593
+ }
594
+ try {
595
+ const daytona = new _daytonaio_sdk.Daytona({
596
+ apiKey: credentials.apiKey,
597
+ apiUrl: credentials.apiUrl,
598
+ target: credentials.target
599
+ });
600
+ const existingSandbox = await daytona.get(sandboxId);
601
+ const daytonaSandbox = new DaytonaSandbox(options);
602
+ daytonaSandbox.#setFromExisting(daytona, existingSandbox, sandboxId);
603
+ return daytonaSandbox;
604
+ } catch (error) {
605
+ throw new DaytonaSandboxError(`Sandbox not found: ${sandboxId}`, "SANDBOX_NOT_FOUND", error instanceof Error ? error : void 0);
606
+ }
607
+ }
608
+ };
609
+ /**
610
+ * Create an async factory function that creates a new Daytona Sandbox per invocation.
611
+ *
612
+ * Each call to the factory will create and initialize a new sandbox.
613
+ * This is useful when you want fresh, isolated environments for each
614
+ * agent invocation.
615
+ *
616
+ * **Important**: This returns an async factory. For use with middleware that
617
+ * requires synchronous BackendFactory, use `createDaytonaSandboxFactoryFromSandbox()`
618
+ * with a pre-created sandbox instead.
619
+ *
620
+ * @param options - Optional configuration for sandbox creation
621
+ * @returns An async factory function that creates new sandboxes
622
+ *
623
+ * @example
624
+ * ```typescript
625
+ * import { DaytonaSandbox, createDaytonaSandboxFactory } from "@langchain/daytona";
626
+ *
627
+ * // Create a factory for new sandboxes
628
+ * const factory = createDaytonaSandboxFactory({ language: "typescript" });
629
+ *
630
+ * // Each call creates a new sandbox
631
+ * const sandbox1 = await factory();
632
+ * const sandbox2 = await factory();
633
+ *
634
+ * try {
635
+ * // Use sandboxes...
636
+ * } finally {
637
+ * await sandbox1.close();
638
+ * await sandbox2.close();
639
+ * }
640
+ * ```
641
+ */
642
+ function createDaytonaSandboxFactory(options) {
643
+ return async () => {
644
+ return await DaytonaSandbox.create(options);
645
+ };
646
+ }
647
+ /**
648
+ * Create a backend factory that reuses an existing Daytona Sandbox.
649
+ *
650
+ * This allows multiple agent invocations to share the same sandbox,
651
+ * avoiding the startup overhead of creating new sandboxes.
652
+ *
653
+ * Important: You are responsible for managing the sandbox lifecycle
654
+ * (calling `close()` when done).
655
+ *
656
+ * @param sandbox - An existing DaytonaSandbox instance (must be initialized)
657
+ * @returns A BackendFactory that returns the provided sandbox
658
+ *
659
+ * @example
660
+ * ```typescript
661
+ * import { createDeepAgent, createFilesystemMiddleware } from "deepagents";
662
+ * import { DaytonaSandbox, createDaytonaSandboxFactoryFromSandbox } from "@langchain/daytona";
663
+ *
664
+ * // Create and initialize a sandbox
665
+ * const sandbox = await DaytonaSandbox.create({ language: "typescript" });
666
+ *
667
+ * try {
668
+ * const agent = createDeepAgent({
669
+ * model: new ChatAnthropic({ model: "claude-sonnet-4-20250514" }),
670
+ * systemPrompt: "You are a coding assistant.",
671
+ * middlewares: [
672
+ * createFilesystemMiddleware({
673
+ * backend: createDaytonaSandboxFactoryFromSandbox(sandbox),
674
+ * }),
675
+ * ],
676
+ * });
677
+ *
678
+ * await agent.invoke({ messages: [...] });
679
+ * } finally {
680
+ * await sandbox.close();
681
+ * }
682
+ * ```
683
+ */
684
+ function createDaytonaSandboxFactoryFromSandbox(sandbox) {
685
+ return () => sandbox;
686
+ }
687
+
688
+ //#endregion
689
+ exports.DaytonaSandbox = DaytonaSandbox;
690
+ exports.DaytonaSandboxError = DaytonaSandboxError;
691
+ exports.createDaytonaSandboxFactory = createDaytonaSandboxFactory;
692
+ exports.createDaytonaSandboxFactoryFromSandbox = createDaytonaSandboxFactoryFromSandbox;
693
+ exports.getAuthApiKey = getAuthApiKey;
694
+ exports.getAuthApiUrl = getAuthApiUrl;
695
+ exports.getAuthCredentials = getAuthCredentials;
696
+ //# sourceMappingURL=index.cjs.map