zeitlich 0.2.22 → 0.2.23

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 (101) hide show
  1. package/README.md +242 -59
  2. package/dist/adapters/sandbox/daytona/index.cjs +4 -1
  3. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  4. package/dist/adapters/sandbox/daytona/index.d.cts +2 -1
  5. package/dist/adapters/sandbox/daytona/index.d.ts +2 -1
  6. package/dist/adapters/sandbox/daytona/index.js +4 -1
  7. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  8. package/dist/adapters/sandbox/daytona/workflow.cjs +1 -0
  9. package/dist/adapters/sandbox/daytona/workflow.cjs.map +1 -1
  10. package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
  11. package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
  12. package/dist/adapters/sandbox/daytona/workflow.js +1 -0
  13. package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
  14. package/dist/adapters/sandbox/inmemory/index.cjs +16 -2
  15. package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
  16. package/dist/adapters/sandbox/inmemory/index.d.cts +3 -2
  17. package/dist/adapters/sandbox/inmemory/index.d.ts +3 -2
  18. package/dist/adapters/sandbox/inmemory/index.js +16 -2
  19. package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
  20. package/dist/adapters/sandbox/inmemory/workflow.cjs +1 -0
  21. package/dist/adapters/sandbox/inmemory/workflow.cjs.map +1 -1
  22. package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
  23. package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
  24. package/dist/adapters/sandbox/inmemory/workflow.js +1 -0
  25. package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
  26. package/dist/adapters/sandbox/virtual/index.cjs +33 -9
  27. package/dist/adapters/sandbox/virtual/index.cjs.map +1 -1
  28. package/dist/adapters/sandbox/virtual/index.d.cts +6 -5
  29. package/dist/adapters/sandbox/virtual/index.d.ts +6 -5
  30. package/dist/adapters/sandbox/virtual/index.js +33 -9
  31. package/dist/adapters/sandbox/virtual/index.js.map +1 -1
  32. package/dist/adapters/sandbox/virtual/workflow.cjs +1 -0
  33. package/dist/adapters/sandbox/virtual/workflow.cjs.map +1 -1
  34. package/dist/adapters/sandbox/virtual/workflow.d.cts +3 -3
  35. package/dist/adapters/sandbox/virtual/workflow.d.ts +3 -3
  36. package/dist/adapters/sandbox/virtual/workflow.js +1 -0
  37. package/dist/adapters/sandbox/virtual/workflow.js.map +1 -1
  38. package/dist/adapters/thread/google-genai/index.d.cts +3 -3
  39. package/dist/adapters/thread/google-genai/index.d.ts +3 -3
  40. package/dist/adapters/thread/google-genai/workflow.d.cts +3 -3
  41. package/dist/adapters/thread/google-genai/workflow.d.ts +3 -3
  42. package/dist/adapters/thread/langchain/index.d.cts +3 -3
  43. package/dist/adapters/thread/langchain/index.d.ts +3 -3
  44. package/dist/adapters/thread/langchain/workflow.d.cts +3 -3
  45. package/dist/adapters/thread/langchain/workflow.d.ts +3 -3
  46. package/dist/index.cjs +247 -57
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.cts +9 -8
  49. package/dist/index.d.ts +9 -8
  50. package/dist/index.js +245 -55
  51. package/dist/index.js.map +1 -1
  52. package/dist/{queries-Bw6WEPMw.d.cts → queries-DModcWRy.d.cts} +1 -1
  53. package/dist/{queries-C27raDaB.d.ts → queries-byD0jr1Y.d.ts} +1 -1
  54. package/dist/{types-ClsHhtwL.d.cts → types-B50pBPEV.d.ts} +159 -35
  55. package/dist/{types-YbL7JpEA.d.cts → types-Bll19FZJ.d.cts} +7 -0
  56. package/dist/{types-YbL7JpEA.d.ts → types-Bll19FZJ.d.ts} +7 -0
  57. package/dist/{types-BJ8itUAl.d.cts → types-BuXdFhaZ.d.cts} +6 -6
  58. package/dist/{types-HBosetv3.d.cts → types-ChAMwU3q.d.cts} +2 -0
  59. package/dist/{types-HBosetv3.d.ts → types-ChAMwU3q.d.ts} +2 -0
  60. package/dist/{types-C5bkx6kQ.d.ts → types-DQW8l7pY.d.cts} +159 -35
  61. package/dist/{types-ENYCKFBk.d.ts → types-GZ76HZSj.d.ts} +6 -6
  62. package/dist/workflow.cjs +241 -57
  63. package/dist/workflow.cjs.map +1 -1
  64. package/dist/workflow.d.cts +49 -32
  65. package/dist/workflow.d.ts +49 -32
  66. package/dist/workflow.js +239 -55
  67. package/dist/workflow.js.map +1 -1
  68. package/package.json +2 -2
  69. package/src/adapters/sandbox/daytona/filesystem.ts +1 -1
  70. package/src/adapters/sandbox/daytona/index.ts +4 -0
  71. package/src/adapters/sandbox/daytona/proxy.ts +4 -3
  72. package/src/adapters/sandbox/e2b/index.ts +5 -0
  73. package/src/adapters/sandbox/inmemory/index.ts +24 -4
  74. package/src/adapters/sandbox/inmemory/proxy.ts +2 -2
  75. package/src/adapters/sandbox/virtual/filesystem.ts +41 -17
  76. package/src/adapters/sandbox/virtual/provider.ts +4 -0
  77. package/src/adapters/sandbox/virtual/proxy.ts +1 -0
  78. package/src/adapters/sandbox/virtual/types.ts +9 -4
  79. package/src/lib/lifecycle.ts +57 -0
  80. package/src/lib/sandbox/manager.ts +13 -1
  81. package/src/lib/sandbox/types.ts +13 -4
  82. package/src/lib/session/index.ts +1 -0
  83. package/src/lib/session/session-edge-cases.integration.test.ts +447 -33
  84. package/src/lib/session/session.integration.test.ts +52 -32
  85. package/src/lib/session/session.ts +107 -33
  86. package/src/lib/session/types.ts +55 -16
  87. package/src/lib/subagent/define.ts +5 -4
  88. package/src/lib/subagent/handler.ts +139 -14
  89. package/src/lib/subagent/index.ts +3 -0
  90. package/src/lib/subagent/register.ts +10 -3
  91. package/src/lib/subagent/signals.ts +8 -0
  92. package/src/lib/subagent/subagent.integration.test.ts +853 -150
  93. package/src/lib/subagent/tool.ts +2 -2
  94. package/src/lib/subagent/types.ts +77 -19
  95. package/src/lib/subagent/workflow.ts +83 -12
  96. package/src/lib/tool-router/router.integration.test.ts +137 -4
  97. package/src/lib/tool-router/router.ts +13 -3
  98. package/src/lib/tool-router/types.ts +7 -0
  99. package/src/lib/workflow.test.ts +89 -21
  100. package/src/lib/workflow.ts +33 -18
  101. package/src/workflow.ts +6 -1
package/README.md CHANGED
@@ -28,20 +28,41 @@ Temporal solves these problems for workflows. Zeitlich brings these guarantees t
28
28
  - **Type-safe tools** — Define tools with Zod schemas, get full TypeScript inference
29
29
  - **Lifecycle hooks** — Pre/post tool execution, session start/end
30
30
  - **Subagent support** — Spawn child agents as Temporal child workflows
31
+ - **Skills** — First-class [agentskills.io](https://agentskills.io) support with progressive disclosure
31
32
  - **Filesystem utilities** — In-memory or custom providers for file operations
32
- - **Model flexibility** — Framework-agnostic model invocation with adapters for LangChain (and more coming)
33
+ - **Model flexibility** — Framework-agnostic model invocation with adapters for LangChain, Vercel AI SDK, or provider-specific SDKs
33
34
 
34
35
  ## LLM Integration
35
36
 
36
- Zeitlich's core is framework-agnostic — it defines generic interfaces (`ModelInvoker`, `ThreadOps`, `MessageContent`) that work with any LLM SDK. Concrete implementations are provided via adapter packages.
37
+ Zeitlich's core is framework-agnostic — it defines generic interfaces (`ModelInvoker`, `ThreadOps`, `MessageContent`) that work with any LLM SDK. You choose a **thread adapter** (for conversation storage and model invocation) and a **sandbox adapter** (for filesystem operations), then wire them together.
37
38
 
38
- ### LangChain Adapter (`zeitlich/adapters/thread/langchain`)
39
+ ### Thread Adapters
39
40
 
40
- The built-in LangChain adapter gives you:
41
+ A thread adapter bundles two concerns:
42
+ 1. **Thread management** — Storing and retrieving conversation messages in Redis
43
+ 2. **Model invocation** — Calling the LLM with the conversation history and tools
41
44
 
42
- - **Provider flexibility** Use Anthropic, OpenAI, Google, Azure, AWS Bedrock, or any LangChain-supported provider
43
- - **Consistent interface** — Same tool calling and message format regardless of provider
44
- - **Easy model swapping** Change models without rewriting agent logic
45
+ Each adapter exposes the same shape: `createActivities(scope)` for Temporal worker registration, and an `invoker` for model calls. Pick the one matching your preferred SDK:
46
+
47
+ | Adapter | Import | SDK |
48
+ |---------|--------|-----|
49
+ | LangChain | `zeitlich/adapters/thread/langchain` | `@langchain/core` + any provider package |
50
+ | Google GenAI | `zeitlich/adapters/thread/google-genai` | `@google/genai` |
51
+
52
+ Vercel AI SDK and other provider-specific adapters can be built by implementing the `ThreadOps` and `ModelInvoker` interfaces.
53
+
54
+ ### Sandbox Adapters
55
+
56
+ A sandbox adapter provides filesystem access for tools like `Bash`, `Read`, `Write`, and `Edit`:
57
+
58
+ | Adapter | Import | Use case |
59
+ |---------|--------|----------|
60
+ | In-memory | `zeitlich/adapters/sandbox/inmemory` | Tests and lightweight agents |
61
+ | Virtual | `zeitlich/adapters/sandbox/virtual` | Custom resolvers with path-only ops |
62
+ | Daytona | `zeitlich/adapters/sandbox/daytona` | Remote Daytona workspaces |
63
+ | E2B | `zeitlich/adapters/sandbox/e2b` | E2B cloud sandboxes |
64
+
65
+ ### Example: LangChain Adapter
45
66
 
46
67
  ```typescript
47
68
  import { ChatAnthropic } from "@langchain/anthropic";
@@ -55,20 +76,13 @@ const adapter = createLangChainAdapter({
55
76
 
56
77
  export function createActivities(client: WorkflowClient) {
57
78
  return {
58
- // scope must match the workflow name (used by the proxy to resolve activity names)
59
79
  ...adapter.createActivities("myAgentWorkflow"),
60
80
  runAgent: createRunAgentActivity(client, adapter.invoker),
61
81
  };
62
82
  }
63
83
  ```
64
84
 
65
- Install the LangChain package for your chosen provider:
66
-
67
- ```bash
68
- npm install @langchain/core @langchain/anthropic # Anthropic
69
- npm install @langchain/core @langchain/openai # OpenAI
70
- npm install @langchain/core @langchain/google-genai # Google
71
- ```
85
+ All adapters follow the same pattern — `createActivities(scope)` for worker registration and `invoker` for model calls.
72
86
 
73
87
  ## Installation
74
88
 
@@ -79,7 +93,8 @@ npm install zeitlich ioredis
79
93
  **Peer dependencies:**
80
94
 
81
95
  - `ioredis` >= 5.0.0
82
- - `@langchain/core` >= 1.0.0 (optional — only needed when using `zeitlich/adapters/thread/langchain`)
96
+ - `@langchain/core` >= 1.0.0 (optional — only when using the LangChain adapter)
97
+ - `@google/genai` >= 1.0.0 (optional — only when using the Google GenAI adapter)
83
98
 
84
99
  **Required infrastructure:**
85
100
 
@@ -91,7 +106,7 @@ npm install zeitlich ioredis
91
106
  Zeitlich uses separate entry points for workflow-side and activity-side code:
92
107
 
93
108
  ```typescript
94
- // In workflow files — no external dependencies (Redis, LangChain, etc.)
109
+ // In workflow files — no external dependencies (Redis, LLM SDKs, etc.)
95
110
  import {
96
111
  createSession,
97
112
  createAgentStateManager,
@@ -99,7 +114,7 @@ import {
99
114
  bashTool,
100
115
  } from "zeitlich/workflow";
101
116
 
102
- // Adapter-specific workflow proxies (auto-scoped to current workflow)
117
+ // Adapter workflow proxies (auto-scoped to current workflow)
103
118
  import { proxyLangChainThreadOps } from "zeitlich/adapters/thread/langchain/workflow";
104
119
  import { proxyInMemorySandboxOps } from "zeitlich/adapters/sandbox/inmemory/workflow";
105
120
 
@@ -111,7 +126,7 @@ import {
111
126
  bashHandler,
112
127
  } from "zeitlich";
113
128
 
114
- // LangChain adapter — activity-side (thread management + model invocation)
129
+ // Thread adapter — activity-side
115
130
  import { createLangChainAdapter } from "zeitlich/adapters/thread/langchain";
116
131
  ```
117
132
 
@@ -146,7 +161,7 @@ export const searchTool: ToolDefinition<"Search", typeof searchSchema> = {
146
161
 
147
162
  ### 2. Create the Workflow
148
163
 
149
- The system prompt is set via `createAgentStateManager`'s `initialState`, and agent config fields (`agentName`, `maxTurns`, etc.) are spread into `createSession`.
164
+ The workflow wires together a **thread adapter** (for conversation storage / model calls) and a **sandbox adapter** (for filesystem tools). Both are pluggable swap the proxy import to switch providers.
150
165
 
151
166
  ```typescript
152
167
  import { proxyActivities, workflowInfo } from "@temporalio/workflow";
@@ -158,10 +173,12 @@ import {
158
173
  bashTool,
159
174
  defineTool,
160
175
  } from "zeitlich/workflow";
161
- import { proxyLangChainThreadOps } from "zeitlich/adapters/thread/langchain/workflow";
162
176
  import { searchTool } from "./tools";
163
177
  import type { MyActivities } from "./activities";
164
178
 
179
+ import { proxyLangChainThreadOps } from "zeitlich/adapters/thread/langchain/workflow";
180
+ import { proxyInMemorySandboxOps } from "zeitlich/adapters/sandbox/inmemory/workflow";
181
+
165
182
  const {
166
183
  runAgentActivity,
167
184
  searchHandlerActivity,
@@ -190,12 +207,12 @@ export const myAgentWorkflow = defineWorkflow(
190
207
  agentName: "my-agent",
191
208
  });
192
209
 
193
- // threadOps auto-scopes to "myAgentWorkflow" via workflowInfo().workflowType
194
210
  const session = await createSession({
195
211
  agentName: "my-agent",
196
212
  maxTurns: 20,
197
- threadId: runId,
213
+ thread: { mode: "new", threadId: runId },
198
214
  threadOps: proxyLangChainThreadOps(),
215
+ sandboxOps: proxyInMemorySandboxOps(),
199
216
  runAgent: runAgentActivity,
200
217
  buildContextMessage: () => [{ type: "text", text: prompt }],
201
218
  tools: {
@@ -228,20 +245,26 @@ export const myAgentWorkflow = defineWorkflow(
228
245
 
229
246
  ### 3. Create Activities
230
247
 
231
- Activities are factory functions that receive infrastructure dependencies (`redis`, `client`). Each returns an object of activity functions registered with the Temporal worker.
248
+ Activities are factory functions that receive infrastructure dependencies (`redis`, `client`). The thread adapter and sandbox provider are configured here swap imports to change LLM or sandbox backend.
232
249
 
233
250
  ```typescript
234
251
  import type Redis from "ioredis";
235
252
  import type { WorkflowClient } from "@temporalio/client";
236
253
  import { ChatAnthropic } from "@langchain/anthropic";
237
254
  import {
255
+ SandboxManager,
238
256
  withSandbox,
239
257
  bashHandler,
240
258
  createAskUserQuestionHandler,
241
259
  createRunAgentActivity,
242
260
  } from "zeitlich";
261
+ import { InMemorySandboxProvider } from "zeitlich/adapters/sandbox/inmemory";
262
+
243
263
  import { createLangChainAdapter } from "zeitlich/adapters/thread/langchain";
244
264
 
265
+ const sandboxProvider = new InMemorySandboxProvider();
266
+ const sandboxManager = new SandboxManager(sandboxProvider);
267
+
245
268
  export const createActivities = ({
246
269
  redis,
247
270
  client,
@@ -258,8 +281,8 @@ export const createActivities = ({
258
281
  });
259
282
 
260
283
  return {
261
- // "myAgentWorkflow" must match the workflow name in defineWorkflow()
262
284
  ...adapter.createActivities("myAgentWorkflow"),
285
+ ...sandboxManager.createActivities("myAgentWorkflow"),
263
286
  runAgentActivity: createRunAgentActivity(client, adapter.invoker),
264
287
  searchHandlerActivity: async (args: { query: string }) => ({
265
288
  toolResponse: JSON.stringify(await performSearch(args.query)),
@@ -411,7 +434,7 @@ export const researcherWorkflow = defineSubagentWorkflow(
411
434
  });
412
435
 
413
436
  const session = await createSession({
414
- ...sessionInput, // spreads agentName, threadId, continueThread, sandboxId
437
+ ...sessionInput, // spreads agentName, thread, sandbox, sandboxShutdown
415
438
  threadOps: proxyLangChainThreadOps(), // auto-scoped to "Researcher"
416
439
  runAgent: runResearcherActivity,
417
440
  buildContextMessage: () => [{ type: "text", text: prompt }],
@@ -439,7 +462,7 @@ export const researcherSubagent = defineSubagent(researcherWorkflow);
439
462
 
440
463
  // Optionally override parent-specific config
441
464
  export const researcherSubagent = defineSubagent(researcherWorkflow, {
442
- allowThreadContinuation: true,
465
+ thread: "fork",
443
466
  sandbox: "own",
444
467
  hooks: {
445
468
  onPostExecution: ({ result }) => console.log("researcher done", result),
@@ -454,39 +477,186 @@ const session = await createSession({
454
477
 
455
478
  The `Subagent` tool is automatically added when subagents are configured, allowing the LLM to spawn child workflows.
456
479
 
457
- ### Thread Continuation
480
+ ### Skills
481
+
482
+ Zeitlich has first-class support for the [agentskills.io](https://agentskills.io) specification. Skills are reusable instruction sets that an agent can load on-demand via the built-in `ReadSkill` tool — progressive disclosure keeps token usage low while giving agents access to rich, domain-specific guidance.
483
+
484
+ #### Defining a Skill
485
+
486
+ Each skill lives in its own directory as a `SKILL.md` file with YAML frontmatter:
487
+
488
+ ```
489
+ skills/
490
+ ├── code-review/
491
+ │ └── SKILL.md
492
+ ├── pdf-processing/
493
+ │ └── SKILL.md
494
+ ```
495
+
496
+ ```markdown
497
+ ---
498
+ name: code-review
499
+ description: Review pull requests for correctness, style, and security issues
500
+ allowed-tools: Bash Grep Read
501
+ license: MIT
502
+ ---
503
+
504
+ ## Instructions
505
+
506
+ When reviewing code, follow these steps:
507
+ 1. Read the diff with `Bash`
508
+ 2. Search for related tests with `Grep`
509
+ 3. ...
510
+ ```
511
+
512
+ Required fields: `name` and `description`. Optional: `license`, `compatibility`, `allowed-tools` (space-delimited), `metadata` (key-value map).
458
513
 
459
- By default, each session initializes a fresh thread. To continue from an existing thread (e.g., resuming a conversation after a workflow completes), pass `continueThread: true` along with the previous `threadId`:
514
+ #### Loading Skills
515
+
516
+ Use `FileSystemSkillProvider` to load skills from a directory (works with any sandbox filesystem):
517
+
518
+ ```typescript
519
+ import { FileSystemSkillProvider } from "zeitlich";
520
+ import { InMemorySandboxProvider } from "zeitlich/adapters/sandbox/inmemory";
521
+
522
+ const provider = new InMemorySandboxProvider();
523
+ const { sandbox } = await provider.create({});
524
+
525
+ const skillProvider = new FileSystemSkillProvider(sandbox.fs, "/skills");
526
+ const skills = await skillProvider.loadAll();
527
+ ```
528
+
529
+ Or parse a single file directly:
530
+
531
+ ```typescript
532
+ import { parseSkillFile } from "zeitlich/workflow";
533
+
534
+ const { frontmatter, body } = parseSkillFile(rawMarkdown);
535
+ // frontmatter: SkillMetadata, body: instruction text
536
+ ```
537
+
538
+ #### Passing Skills to a Session
539
+
540
+ Pass loaded skills to `createSession`. Zeitlich automatically registers a `ReadSkill` tool whose description lists all available skills — the agent discovers them through the tool definition and loads instructions on demand:
460
541
 
461
542
  ```typescript
462
543
  import { createSession } from "zeitlich/workflow";
463
544
 
464
- // First run — threadId defaults to getShortId() if omitted
465
545
  const session = await createSession({
466
- // threadId is optional, auto-generated if not provided
467
546
  // ... other config
547
+ skills, // Skill[] — loaded via FileSystemSkillProvider or manually
468
548
  });
549
+ ```
550
+
551
+ The `ReadSkill` tool accepts a `skill_name` parameter (constrained to an enum of available names) and returns the full instruction body. The handler runs directly in the workflow — no activity needed.
552
+
553
+ #### Building Skills Manually
554
+
555
+ For advanced use cases, you can construct the tool and handler independently:
556
+
557
+ ```typescript
558
+ import { createReadSkillTool, createReadSkillHandler } from "zeitlich/workflow";
559
+
560
+ const tool = createReadSkillTool(skills); // ToolDefinition with enum schema
561
+ const handler = createReadSkillHandler(skills); // Returns skill instructions
562
+ ```
563
+
564
+ ### Thread & Sandbox Lifecycle
565
+
566
+ Every session has a **thread** (conversation history) and an optional **sandbox** (filesystem environment). Both are configured with explicit lifecycle types that control how they are initialized and torn down.
567
+
568
+ #### Thread Initialization (`ThreadInit`)
569
+
570
+ The `thread` field on `SessionConfig` (and `WorkflowInput`) accepts one of three modes:
571
+
572
+ | Mode | Description |
573
+ |------|-------------|
574
+ | `{ mode: "new" }` | Start a fresh thread (default). Optionally pass `threadId` to choose the ID. |
575
+ | `{ mode: "fork", threadId }` | Copy all messages from an existing thread into a new one and continue there. The original is never mutated. |
576
+ | `{ mode: "continue", threadId }` | Append directly to an existing thread in-place. |
469
577
 
470
- // Later — new workflow forks the previous thread
578
+ ```typescript
579
+ import { createSession } from "zeitlich/workflow";
580
+
581
+ // First run — fresh thread
582
+ const session = await createSession({
583
+ thread: { mode: "new" },
584
+ // ... other config
585
+ });
586
+
587
+ // Later — fork the previous conversation
471
588
  const resumedSession = await createSession({
472
- threadId: savedThreadId, // the thread to continue from
473
- continueThread: true, // fork into a new thread with the old messages
589
+ thread: { mode: "fork", threadId: savedThreadId },
474
590
  // ... other config
475
591
  });
476
- ```
477
592
 
478
- When `continueThread` is true the session **forks** the provided thread — it copies all messages into a new thread and operates on the copy. The original thread is never mutated, so multiple sessions can safely continue from the same thread in parallel.
593
+ // Or append directly to the existing thread
594
+ const continuedSession = await createSession({
595
+ thread: { mode: "continue", threadId: savedThreadId },
596
+ // ... other config
597
+ });
598
+ ```
479
599
 
480
600
  `getShortId()` produces compact, workflow-deterministic IDs (~12 base-62 chars) that are more token-efficient than UUIDs.
481
601
 
482
- #### Subagent Thread Continuation
602
+ #### Sandbox Initialization (`SandboxInit`)
603
+
604
+ The `sandbox` field controls how a sandbox is created or reused:
605
+
606
+ | Mode | Description |
607
+ |------|-------------|
608
+ | `{ mode: "new" }` | Create a fresh sandbox (default when `sandboxOps` is provided). |
609
+ | `{ mode: "continue", sandboxId }` | Resume a previously-paused sandbox. This session takes ownership. |
610
+ | `{ mode: "fork", sandboxId }` | Fork from an existing sandbox. A new sandbox is created and owned by this session. |
611
+ | `{ mode: "inherit", sandboxId }` | Use a sandbox owned by someone else (e.g. a parent agent). Shutdown policy is ignored. |
483
612
 
484
- Subagents can opt in to thread continuation via `allowThreadContinuation`. When enabled, the parent agent can pass a `threadId` to resume a previous subagent conversation:
613
+ #### Sandbox Shutdown (`SandboxShutdown`)
614
+
615
+ The `sandboxShutdown` field controls what happens to the sandbox when the session exits:
616
+
617
+ | Value | Description |
618
+ |-------|-------------|
619
+ | `"destroy"` | Tear down the sandbox entirely (default). |
620
+ | `"pause"` | Pause the sandbox so it can be resumed later. |
621
+ | `"keep"` | Leave the sandbox running (no-op on exit). |
622
+
623
+ Subagents also support `"pause-until-parent-close"` — pause on exit, then wait for the parent workflow to signal when to destroy it.
624
+
625
+ #### Subagent Thread & Sandbox Config
626
+
627
+ Subagents configure thread and sandbox strategies via `defineSubagent`:
485
628
 
486
629
  ```typescript
487
- import { defineSubagentWorkflow, defineSubagent, createSession } from "zeitlich/workflow";
488
- import { proxyLangChainThreadOps } from "zeitlich/adapters/thread/langchain/workflow";
630
+ import { defineSubagent } from "zeitlich/workflow";
631
+ import { researcherWorkflow } from "./researcher.workflow";
632
+
633
+ // Fresh thread each time, no sandbox (defaults)
634
+ export const researcherSubagent = defineSubagent(researcherWorkflow);
635
+
636
+ // Allow the parent to continue a previous conversation via fork
637
+ export const researcherSubagent = defineSubagent(researcherWorkflow, {
638
+ thread: "fork",
639
+ });
489
640
 
641
+ // Own sandbox with pause-on-exit
642
+ export const researcherSubagent = defineSubagent(researcherWorkflow, {
643
+ thread: "fork",
644
+ sandbox: { source: "own", shutdown: "pause" },
645
+ });
646
+
647
+ // Inherit the parent's sandbox
648
+ export const researcherSubagent = defineSubagent(researcherWorkflow, {
649
+ sandbox: "inherit",
650
+ });
651
+ ```
652
+
653
+ The `thread` field accepts `"new"` (default), `"fork"`, or `"continue"`. When set to `"fork"` or `"continue"`, the parent agent can pass a `threadId` in a subsequent `Task` tool call to resume the conversation. The subagent returns its `threadId` in the response (surfaced as `[Thread ID: ...]`), which the parent can use for continuation.
654
+
655
+ The `sandbox` field accepts `"none"` (default), `"inherit"`, `"own"`, or `{ source: "own", shutdown }` for explicit shutdown policy.
656
+
657
+ The subagent workflow receives lifecycle fields via `sessionInput`:
658
+
659
+ ```typescript
490
660
  export const researcherWorkflow = defineSubagentWorkflow(
491
661
  {
492
662
  name: "Researcher",
@@ -494,28 +664,17 @@ export const researcherWorkflow = defineSubagentWorkflow(
494
664
  },
495
665
  async (prompt, sessionInput) => {
496
666
  const session = await createSession({
497
- ...sessionInput, // threadId/continueThread are provided by parent when resuming
667
+ ...sessionInput, // spreads agentName, thread, sandbox, sandboxShutdown
498
668
  threadOps: proxyLangChainThreadOps(),
499
669
  // ... other config
500
670
  });
501
671
 
502
672
  const { threadId, finalMessage } = await session.runSession({ stateManager });
503
- return {
504
- toolResponse: finalMessage ? extractText(finalMessage) : "No response",
505
- data: null,
506
- threadId,
507
- };
673
+ return { toolResponse: extractText(finalMessage), data: null, threadId };
508
674
  },
509
675
  );
510
-
511
- // Enable thread continuation in the parent registration
512
- export const researcherSubagent = defineSubagent(researcherWorkflow, {
513
- allowThreadContinuation: true,
514
- });
515
676
  ```
516
677
 
517
- The subagent returns its `threadId` in the response, which the handler surfaces to the parent LLM as `[Thread ID: ...]`. The parent can then pass that ID back in a subsequent `Subagent` tool call to continue the conversation.
518
-
519
678
  ### Filesystem Utilities
520
679
 
521
680
  Built-in support for file operations with in-memory or custom filesystem providers (e.g. from [`just-bash`](https://github.com/nicholasgasior/just-bash)).
@@ -632,6 +791,7 @@ Zeitlich provides ready-to-use tool definitions and handlers for common agent op
632
791
  | `Grep` | Search file contents with regex patterns |
633
792
  | `Bash` | Execute shell commands |
634
793
  | `AskUserQuestion` | Ask the user questions during execution with structured options |
794
+ | `ReadSkill` | Load skill instructions on demand (see [Skills](#skills)) |
635
795
  | `Task` | Launch subagents as child workflows (see [Subagents](#subagents)) |
636
796
 
637
797
  ```typescript
@@ -691,7 +851,10 @@ Safe for use in Temporal workflow files:
691
851
  | `getShortId` | Generate a compact, workflow-deterministic identifier (base-62, 12 chars) |
692
852
  | Tool definitions | `askUserQuestionTool`, `globTool`, `grepTool`, `readFileTool`, `writeFileTool`, `editTool`, `bashTool` |
693
853
  | Task tools | `taskCreateTool`, `taskGetTool`, `taskListTool`, `taskUpdateTool` for workflow task management |
694
- | Types | `SubagentDefinition`, `SubagentConfig`, `ToolDefinition`, `ToolWithHandler`, `RouterContext`, `SessionConfig`, etc. |
854
+ | Skill utilities | `parseSkillFile`, `createReadSkillTool`, `createReadSkillHandler` |
855
+ | `defineWorkflow` | Wraps a main workflow function, translating `WorkflowInput` into session-compatible fields |
856
+ | Lifecycle types | `ThreadInit`, `SandboxInit`, `SandboxShutdown`, `SubagentSandboxShutdown`, `SubagentSandboxConfig` |
857
+ | Types | `Skill`, `SkillMetadata`, `SkillProvider`, `SubagentDefinition`, `SubagentConfig`, `ToolDefinition`, `ToolWithHandler`, `RouterContext`, `SessionConfig`, `WorkflowConfig`, `WorkflowInput`, etc. |
695
858
 
696
859
  ### Activity Entry Point (`zeitlich`)
697
860
 
@@ -704,11 +867,12 @@ Framework-agnostic utilities for activities, worker setup, and Node.js code:
704
867
  | `createThreadManager` | Generic Redis-backed thread manager factory |
705
868
  | `toTree` | Generate file tree string from an `IFileSystem` instance |
706
869
  | `withSandbox` | Wraps a handler to auto-resolve sandbox from context (pairs with `withAutoAppend`) |
870
+ | `FileSystemSkillProvider` | Load skills from a directory following the agentskills.io layout |
707
871
  | Tool handlers | `bashHandler`, `editHandler`, `globHandler`, `readFileHandler`, `writeFileHandler`, `createAskUserQuestionHandler` |
708
872
 
709
- ### LangChain Adapter Entry Point (`zeitlich/adapters/thread/langchain`)
873
+ ### Thread Adapter Entry Points
710
874
 
711
- LangChain-specific implementations:
875
+ **LangChain** (`zeitlich/adapters/thread/langchain`):
712
876
 
713
877
  | Export | Description |
714
878
  | ----------------------------------- | ---------------------------------------------------------------------- |
@@ -717,6 +881,15 @@ LangChain-specific implementations:
717
881
  | `invokeLangChainModel` | One-shot model invocation convenience function |
718
882
  | `createLangChainThreadManager` | Thread manager with LangChain `StoredMessage` helpers |
719
883
 
884
+ **Google GenAI** (`zeitlich/adapters/thread/google-genai`):
885
+
886
+ | Export | Description |
887
+ | ----------------------------------- | ---------------------------------------------------------------------- |
888
+ | `createGoogleGenAIAdapter` | Unified adapter returning `createActivities`, `invoker`, `createModelInvoker` |
889
+ | `createGoogleGenAIModelInvoker` | Factory that returns a `ModelInvoker` backed by the `@google/genai` SDK |
890
+ | `invokeGoogleGenAIModel` | One-shot model invocation convenience function |
891
+ | `createGoogleGenAIThreadManager` | Thread manager with Google GenAI `Content` helpers |
892
+
720
893
  ### Types
721
894
 
722
895
  | Export | Description |
@@ -731,6 +904,11 @@ LangChain-specific implementations:
731
904
  | `RouterContext` | Base context every tool handler receives (`threadId`, `toolCallId`, `toolName`, `sandboxId?`) |
732
905
  | `Hooks` | Combined session lifecycle + tool execution hooks |
733
906
  | `ToolRouterHooks` | Narrowed hook interface for tool execution only (pre/post/failure) |
907
+ | `ThreadInit` | Thread initialization strategy: `"new"`, `"continue"`, or `"fork"` |
908
+ | `SandboxInit` | Sandbox initialization strategy: `"new"`, `"continue"`, `"fork"`, or `"inherit"` |
909
+ | `SandboxShutdown` | Sandbox exit policy: `"destroy" \| "pause" \| "keep"` |
910
+ | `SubagentSandboxShutdown` | Extended shutdown with `"pause-until-parent-close"` |
911
+ | `SubagentSandboxConfig` | Subagent sandbox strategy: `"none" \| "inherit" \| "own" \| { source, shutdown }` |
734
912
  | `SubagentDefinition` | Callable subagent workflow with embedded metadata (from `defineSubagentWorkflow`) |
735
913
  | `SubagentConfig` | Resolved subagent configuration consumed by `createSession` |
736
914
  | `AgentState` | Generic agent state type |
@@ -758,9 +936,14 @@ LangChain-specific implementations:
758
936
  │ └──────────────────────────────────────────────────────────┘ │
759
937
  │ │ │
760
938
  │ ┌──────────────────────────────────────────────────────────┐ │
761
- │ │ LLM Adapter (zeitlich/adapters/thread/langchain) │ │
762
- │ │ • createLangChainAdapter (thread ops + model invoker) │ │
763
- │ │ • createLangChainThreadManager (message helpers) │ │
939
+ │ │ Thread Adapter (zeitlich/adapters/thread/*) │ │
940
+ │ │ • LangChain, Google GenAI, or custom │ │
941
+ │ │ • Thread ops (message storage) + model invoker │ │
942
+ │ └──────────────────────────────────────────────────────────┘ │
943
+ │ ┌──────────────────────────────────────────────────────────┐ │
944
+ │ │ Sandbox Adapter (zeitlich/adapters/sandbox/*) │ │
945
+ │ │ • In-memory, Virtual, Daytona, E2B, or custom │ │
946
+ │ │ • Filesystem ops for agent tools │ │
764
947
  │ └──────────────────────────────────────────────────────────┘ │
765
948
  └─────────────────────────────────────────────────────────────────┘
766
949
 
@@ -47,7 +47,7 @@ var DaytonaSandboxFileSystem = class {
47
47
  await this.sandbox.fs.uploadFiles(
48
48
  files.map((f) => ({
49
49
  source: Buffer.from(f.content),
50
- destination: f.path
50
+ destination: this.normalisePath(f.path)
51
51
  }))
52
52
  );
53
53
  }
@@ -231,6 +231,9 @@ var DaytonaSandboxProvider = class {
231
231
  } catch {
232
232
  }
233
233
  }
234
+ async pause(_sandboxId, _ttlSeconds) {
235
+ throw new SandboxNotSupportedError("pause");
236
+ }
234
237
  async fork(_sandboxId) {
235
238
  throw new Error("Not implemented");
236
239
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/sandbox/types.ts","../../../../src/adapters/sandbox/daytona/filesystem.ts","../../../../src/adapters/sandbox/daytona/index.ts"],"names":["ApplicationFailure","posix","path","Daytona"],"mappings":"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","file":"index.cjs","sourcesContent":["// ============================================================================\n// Sandbox Filesystem\n// ============================================================================\n\nexport interface DirentEntry {\n name: string;\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n}\n\nexport interface FileStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n size: number;\n mtime: Date;\n}\n\n/**\n * Provider-agnostic filesystem interface.\n *\n * Implementations that don't support a method should throw\n * {@link SandboxNotSupportedError}.\n */\nexport interface SandboxFileSystem {\n /** Base directory used when resolving relative paths. */\n readonly workspaceBase: string;\n readFile(path: string): Promise<string>;\n readFileBuffer(path: string): Promise<Uint8Array>;\n writeFile(path: string, content: string | Uint8Array): Promise<void>;\n appendFile(path: string, content: string | Uint8Array): Promise<void>;\n exists(path: string): Promise<boolean>;\n stat(path: string): Promise<FileStat>;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n readdir(path: string): Promise<string[]>;\n readdirWithFileTypes(path: string): Promise<DirentEntry[]>;\n rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>;\n cp(src: string, dest: string, options?: { recursive?: boolean }): Promise<void>;\n mv(src: string, dest: string): Promise<void>;\n readlink(path: string): Promise<string>;\n resolvePath(base: string, path: string): string;\n}\n\n// ============================================================================\n// Execution\n// ============================================================================\n\nexport interface ExecOptions {\n timeout?: number;\n cwd?: string;\n env?: Record<string, string>;\n}\n\nexport interface ExecResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\n// ============================================================================\n// Capabilities\n// ============================================================================\n\nexport interface SandboxCapabilities {\n /** Sandbox supports filesystem operations */\n filesystem: boolean;\n /** Sandbox supports shell/command execution */\n execution: boolean;\n /** Sandbox state can be persisted and restored */\n persistence: boolean;\n}\n\n// ============================================================================\n// Sandbox\n// ============================================================================\n\nexport interface Sandbox {\n readonly id: string;\n readonly capabilities: SandboxCapabilities;\n readonly fs: SandboxFileSystem;\n\n exec(command: string, options?: ExecOptions): Promise<ExecResult>;\n destroy(): Promise<void>;\n}\n\n// ============================================================================\n// Snapshots\n// ============================================================================\n\nexport interface SandboxSnapshot {\n sandboxId: string;\n providerId: string;\n /** Provider-specific serialised state */\n data: unknown;\n createdAt: string;\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport interface SandboxCreateOptions {\n /** Preferred sandbox ID (provider may ignore) */\n id?: string;\n /** Seed the filesystem with these files */\n initialFiles?: Record<string, string | Uint8Array>;\n /** Environment variables available inside the sandbox */\n env?: Record<string, string>;\n}\n\nexport interface SandboxCreateResult {\n sandbox: Sandbox;\n /** Optional state to merge into the workflow's `AgentState` via the session. */\n stateUpdate?: Record<string, unknown>;\n}\n\nexport interface SandboxProvider<\n TOptions extends SandboxCreateOptions = SandboxCreateOptions,\n TSandbox extends Sandbox = Sandbox,\n> {\n readonly id: string;\n readonly capabilities: SandboxCapabilities;\n\n create(options?: TOptions): Promise<SandboxCreateResult>;\n get(sandboxId: string): Promise<TSandbox>;\n destroy(sandboxId: string): Promise<void>;\n snapshot(sandboxId: string): Promise<SandboxSnapshot>;\n restore(snapshot: SandboxSnapshot): Promise<Sandbox>;\n fork(sandboxId: string): Promise<Sandbox>;\n}\n\n// ============================================================================\n// SandboxOps — workflow-side activity interface (like ThreadOps)\n// ============================================================================\n\nexport interface SandboxOps<\n TOptions extends SandboxCreateOptions = SandboxCreateOptions,\n> {\n createSandbox(\n options?: TOptions,\n ): Promise<{ sandboxId: string; stateUpdate?: Record<string, unknown> }>;\n destroySandbox(sandboxId: string): Promise<void>;\n snapshotSandbox(sandboxId: string): Promise<SandboxSnapshot>;\n forkSandbox(sandboxId: string): Promise<string>;\n}\n\n/**\n * Maps generic {@link SandboxOps} method names to adapter-prefixed names.\n *\n * @example\n * ```typescript\n * type InMemOps = PrefixedSandboxOps<\"inMemory\">;\n * // → { inMemoryCreateSandbox, inMemoryDestroySandbox, inMemorySnapshotSandbox }\n * ```\n */\nexport type PrefixedSandboxOps<\n TPrefix extends string,\n TOptions extends SandboxCreateOptions = SandboxCreateOptions,\n> = {\n [K in keyof SandboxOps<TOptions> as `${TPrefix}${Capitalize<K & string>}`]: SandboxOps<TOptions>[K];\n};\n\n// ============================================================================\n// Errors\n// ============================================================================\n\nimport { ApplicationFailure } from \"@temporalio/common\";\n\nexport class SandboxNotSupportedError extends ApplicationFailure {\n constructor(operation: string) {\n super(\n `Sandbox does not support: ${operation}`,\n \"SandboxNotSupportedError\",\n true,\n );\n }\n}\n\nexport class SandboxNotFoundError extends ApplicationFailure {\n constructor(sandboxId: string) {\n super(`Sandbox not found: ${sandboxId}`, \"SandboxNotFoundError\", true);\n }\n}\n","import type { Sandbox as DaytonaSdkSandbox } from \"@daytonaio/sdk\";\nimport type {\n SandboxFileSystem,\n DirentEntry,\n FileStat,\n} from \"../../../lib/sandbox/types\";\nimport { SandboxNotSupportedError } from \"../../../lib/sandbox/types\";\nimport { posix } from \"node:path\";\n\n/**\n * {@link SandboxFileSystem} backed by a Daytona SDK sandbox.\n *\n * Maps zeitlich's filesystem interface to Daytona's `sandbox.fs` and\n * `sandbox.process` APIs. Operations that have no direct Daytona equivalent\n * (e.g. `appendFile`, `cp`) are composed from primitives.\n */\nexport class DaytonaSandboxFileSystem implements SandboxFileSystem {\n readonly workspaceBase: string;\n\n constructor(\n private sandbox: DaytonaSdkSandbox,\n workspaceBase = \"/home/daytona\"\n ) {\n this.workspaceBase = posix.resolve(\"/\", workspaceBase);\n }\n\n private normalisePath(path: string): string {\n return posix.resolve(this.workspaceBase, path);\n }\n\n async readFile(path: string): Promise<string> {\n const norm = this.normalisePath(path);\n const buf = await this.sandbox.fs.downloadFile(norm);\n return buf.toString(\"utf-8\");\n }\n\n async readFileBuffer(path: string): Promise<Uint8Array> {\n const norm = this.normalisePath(path);\n const buf = await this.sandbox.fs.downloadFile(norm);\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n }\n\n async writeFile(path: string, content: string | Uint8Array): Promise<void> {\n const norm = this.normalisePath(path);\n const buf =\n typeof content === \"string\"\n ? Buffer.from(content, \"utf-8\")\n : Buffer.from(content);\n await this.sandbox.fs.uploadFile(buf, norm);\n }\n\n async writeFiles(\n files: { path: string; content: string | Uint8Array }[]\n ): Promise<void> {\n await this.sandbox.fs.uploadFiles(\n files.map((f) => ({\n source: Buffer.from(f.content),\n destination: f.path,\n }))\n );\n }\n\n async appendFile(path: string, content: string | Uint8Array): Promise<void> {\n const norm = this.normalisePath(path);\n let existing: Buffer;\n try {\n existing = await this.sandbox.fs.downloadFile(norm);\n } catch {\n return this.writeFile(norm, content);\n }\n\n const addition =\n typeof content === \"string\" ? Buffer.from(content, \"utf-8\") : content;\n const merged = Buffer.concat([existing, Buffer.from(addition)]);\n await this.sandbox.fs.uploadFile(merged, norm);\n }\n\n async exists(path: string): Promise<boolean> {\n const norm = this.normalisePath(path);\n try {\n await this.sandbox.fs.getFileDetails(norm);\n return true;\n } catch {\n return false;\n }\n }\n\n async stat(path: string): Promise<FileStat> {\n const norm = this.normalisePath(path);\n const info = await this.sandbox.fs.getFileDetails(norm);\n return {\n isFile: !info.isDir,\n isDirectory: info.isDir,\n isSymbolicLink: false,\n size: info.size,\n mtime: new Date(info.modTime),\n };\n }\n\n async mkdir(path: string, _options?: { recursive?: boolean }): Promise<void> {\n const norm = this.normalisePath(path);\n await this.sandbox.fs.createFolder(norm, \"755\");\n }\n\n async readdir(path: string): Promise<string[]> {\n const norm = this.normalisePath(path);\n const entries = await this.sandbox.fs.listFiles(norm);\n return entries.map((e) => e.name);\n }\n\n async readdirWithFileTypes(path: string): Promise<DirentEntry[]> {\n const norm = this.normalisePath(path);\n const entries = await this.sandbox.fs.listFiles(norm);\n return entries.map((e) => ({\n name: e.name,\n isFile: !e.isDir,\n isDirectory: e.isDir,\n isSymbolicLink: false,\n }));\n }\n\n async rm(\n path: string,\n options?: { recursive?: boolean; force?: boolean }\n ): Promise<void> {\n const norm = this.normalisePath(path);\n try {\n await this.sandbox.fs.deleteFile(norm, options?.recursive);\n } catch (err) {\n if (!options?.force) throw err;\n }\n }\n\n async cp(\n src: string,\n dest: string,\n options?: { recursive?: boolean }\n ): Promise<void> {\n const normSrc = this.normalisePath(src);\n const normDest = this.normalisePath(dest);\n const info = await this.sandbox.fs.getFileDetails(normSrc);\n if (info.isDir) {\n if (!options?.recursive) {\n throw new Error(`EISDIR: is a directory (use recursive): ${src}`);\n }\n await this.sandbox.process.executeCommand(\n `cp -r \"${normSrc}\" \"${normDest}\"`\n );\n } else {\n await this.sandbox.process.executeCommand(\n `cp \"${normSrc}\" \"${normDest}\"`\n );\n }\n }\n\n async mv(src: string, dest: string): Promise<void> {\n const normSrc = this.normalisePath(src);\n const normDest = this.normalisePath(dest);\n await this.sandbox.fs.moveFiles(normSrc, normDest);\n }\n\n async readlink(_path: string): Promise<string> {\n throw new SandboxNotSupportedError(\"readlink\");\n }\n\n resolvePath(base: string, path: string): string {\n return posix.resolve(this.normalisePath(base), path);\n }\n}\n","import { Daytona, type Sandbox as DaytonaSdkSandbox } from \"@daytonaio/sdk\";\nimport type {\n Sandbox,\n SandboxCapabilities,\n SandboxCreateResult,\n SandboxProvider,\n SandboxSnapshot,\n ExecOptions,\n ExecResult,\n} from \"../../../lib/sandbox/types\";\nimport {\n SandboxNotFoundError,\n SandboxNotSupportedError,\n} from \"../../../lib/sandbox/types\";\nimport { DaytonaSandboxFileSystem } from \"./filesystem\";\nimport type {\n DaytonaSandbox,\n DaytonaSandboxConfig,\n DaytonaSandboxCreateOptions,\n} from \"./types\";\n\n// ============================================================================\n// DaytonaSandbox\n// ============================================================================\n\nclass DaytonaSandboxImpl implements Sandbox {\n readonly capabilities: SandboxCapabilities = {\n filesystem: true,\n execution: true,\n persistence: false,\n };\n\n readonly fs: DaytonaSandboxFileSystem;\n\n constructor(\n readonly id: string,\n private sdkSandbox: DaytonaSdkSandbox,\n workspaceBase = \"/home/daytona\"\n ) {\n this.fs = new DaytonaSandboxFileSystem(sdkSandbox, workspaceBase);\n }\n\n async exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n const response = await this.sdkSandbox.process.executeCommand(\n command,\n options?.cwd,\n options?.env,\n options?.timeout\n );\n\n return {\n exitCode: response.exitCode ?? 0,\n stdout: response.result ?? \"\",\n stderr: \"\",\n };\n }\n\n async destroy(): Promise<void> {\n await this.sdkSandbox.delete(60);\n }\n}\n\n// ============================================================================\n// DaytonaSandboxProvider\n// ============================================================================\n\nexport class DaytonaSandboxProvider implements SandboxProvider<\n DaytonaSandboxCreateOptions,\n DaytonaSandbox\n> {\n readonly id = \"daytona\";\n readonly capabilities: SandboxCapabilities = {\n filesystem: true,\n execution: true,\n persistence: false,\n };\n\n private client: Daytona;\n private readonly defaultWorkspaceBase: string;\n\n constructor(config?: DaytonaSandboxConfig) {\n this.client = new Daytona(config);\n this.defaultWorkspaceBase = config?.workspaceBase ?? \"/home/daytona\";\n }\n\n async create(\n options?: DaytonaSandboxCreateOptions\n ): Promise<SandboxCreateResult> {\n const sdkSandbox = await this.client.create(\n {\n language: options?.language,\n snapshot: options?.snapshot,\n envVars: options?.env,\n labels: options?.labels,\n autoStopInterval: options?.autoStopInterval,\n autoArchiveInterval: options?.autoArchiveInterval,\n autoDeleteInterval: options?.autoDeleteInterval,\n },\n { timeout: options?.timeout ?? 60 }\n );\n\n const workspaceBase = options?.workspaceBase ?? this.defaultWorkspaceBase;\n\n const sandbox = new DaytonaSandboxImpl(\n sdkSandbox.id,\n sdkSandbox,\n workspaceBase\n );\n\n if (options?.initialFiles) {\n await sandbox.fs.writeFiles(\n Object.entries(options.initialFiles).map(([path, content]) => ({\n path,\n content,\n }))\n );\n }\n\n return { sandbox };\n }\n\n async get(sandboxId: string): Promise<DaytonaSandbox> {\n try {\n const sdkSandbox = await this.client.get(sandboxId);\n return new DaytonaSandboxImpl(\n sdkSandbox.id,\n sdkSandbox,\n this.defaultWorkspaceBase\n );\n } catch {\n throw new SandboxNotFoundError(sandboxId);\n }\n }\n\n async destroy(sandboxId: string): Promise<void> {\n try {\n const sdkSandbox = await this.client.get(sandboxId);\n await this.client.delete(sdkSandbox);\n } catch {\n // Already gone\n }\n }\n\n async fork(_sandboxId: string): Promise<Sandbox> {\n throw new Error(\"Not implemented\");\n }\n\n async snapshot(_sandboxId: string): Promise<SandboxSnapshot> {\n throw new SandboxNotSupportedError(\n \"snapshot (use Daytona's native snapshot API directly)\"\n );\n }\n\n async restore(_snapshot: SandboxSnapshot): Promise<never> {\n throw new SandboxNotSupportedError(\n \"restore (use Daytona's native snapshot API directly)\"\n );\n }\n}\n\n// Re-exports\nexport { DaytonaSandboxFileSystem } from \"./filesystem\";\nexport type {\n DaytonaSandbox,\n DaytonaSandboxConfig,\n DaytonaSandboxCreateOptions,\n} from \"./types\";\n"]}
1
+ {"version":3,"sources":["../../../../src/lib/sandbox/types.ts","../../../../src/adapters/sandbox/daytona/filesystem.ts","../../../../src/adapters/sandbox/daytona/index.ts"],"names":["ApplicationFailure","posix","path","Daytona"],"mappings":"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","file":"index.cjs","sourcesContent":["// ============================================================================\n// Sandbox Filesystem\n// ============================================================================\n\nexport interface DirentEntry {\n name: string;\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n}\n\nexport interface FileStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n size: number;\n mtime: Date;\n}\n\n/**\n * Provider-agnostic filesystem interface.\n *\n * Implementations that don't support a method should throw\n * {@link SandboxNotSupportedError}.\n */\nexport interface SandboxFileSystem {\n /** Base directory used when resolving relative paths. */\n readonly workspaceBase: string;\n readFile(path: string): Promise<string>;\n readFileBuffer(path: string): Promise<Uint8Array>;\n writeFile(path: string, content: string | Uint8Array): Promise<void>;\n appendFile(path: string, content: string | Uint8Array): Promise<void>;\n exists(path: string): Promise<boolean>;\n stat(path: string): Promise<FileStat>;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n readdir(path: string): Promise<string[]>;\n readdirWithFileTypes(path: string): Promise<DirentEntry[]>;\n rm(\n path: string,\n options?: { recursive?: boolean; force?: boolean }\n ): Promise<void>;\n cp(\n src: string,\n dest: string,\n options?: { recursive?: boolean }\n ): Promise<void>;\n mv(src: string, dest: string): Promise<void>;\n readlink(path: string): Promise<string>;\n resolvePath(base: string, path: string): string;\n}\n\n// ============================================================================\n// Execution\n// ============================================================================\n\nexport interface ExecOptions {\n timeout?: number;\n cwd?: string;\n env?: Record<string, string>;\n}\n\nexport interface ExecResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\n// ============================================================================\n// Capabilities\n// ============================================================================\n\nexport interface SandboxCapabilities {\n /** Sandbox supports filesystem operations */\n filesystem: boolean;\n /** Sandbox supports shell/command execution */\n execution: boolean;\n /** Sandbox state can be persisted and restored */\n persistence: boolean;\n}\n\n// ============================================================================\n// Sandbox\n// ============================================================================\n\nexport interface Sandbox {\n readonly id: string;\n readonly capabilities: SandboxCapabilities;\n readonly fs: SandboxFileSystem;\n\n exec(command: string, options?: ExecOptions): Promise<ExecResult>;\n destroy(): Promise<void>;\n}\n\n// ============================================================================\n// Snapshots\n// ============================================================================\n\nexport interface SandboxSnapshot {\n sandboxId: string;\n providerId: string;\n /** Provider-specific serialised state */\n data: unknown;\n createdAt: string;\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport interface SandboxCreateOptions {\n /** Preferred sandbox ID (provider may ignore) */\n id?: string;\n /** Seed the filesystem with these files */\n initialFiles?: Record<string, string | Uint8Array>;\n /** Environment variables available inside the sandbox */\n env?: Record<string, string>;\n}\n\nexport interface SandboxCreateResult {\n sandbox: Sandbox;\n /** Optional state to merge into the workflow's `AgentState` via the session. */\n stateUpdate?: Record<string, unknown>;\n}\n\nexport interface SandboxProvider<\n TOptions extends SandboxCreateOptions = SandboxCreateOptions,\n TSandbox extends Sandbox = Sandbox,\n> {\n readonly id: string;\n readonly capabilities: SandboxCapabilities;\n\n create(options?: TOptions): Promise<SandboxCreateResult>;\n get(sandboxId: string): Promise<TSandbox>;\n destroy(sandboxId: string): Promise<void>;\n pause(sandboxId: string, ttlSeconds?: number): Promise<void>;\n snapshot(sandboxId: string): Promise<SandboxSnapshot>;\n restore(snapshot: SandboxSnapshot): Promise<Sandbox>;\n fork(sandboxId: string): Promise<Sandbox>;\n}\n\n// ============================================================================\n// SandboxOps — workflow-side activity interface (like ThreadOps)\n// ============================================================================\n\nexport interface SandboxOps<\n TOptions extends SandboxCreateOptions = SandboxCreateOptions,\n> {\n createSandbox(\n options?: TOptions\n ): Promise<{ sandboxId: string; stateUpdate?: Record<string, unknown> }>;\n destroySandbox(sandboxId: string): Promise<void>;\n pauseSandbox(sandboxId: string): Promise<void>;\n snapshotSandbox(sandboxId: string): Promise<SandboxSnapshot>;\n forkSandbox(sandboxId: string): Promise<string>;\n}\n\n/**\n * Maps generic {@link SandboxOps} method names to adapter-prefixed names.\n *\n * @example\n * ```typescript\n * type InMemOps = PrefixedSandboxOps<\"inMemory\">;\n * // → { inMemoryCreateSandbox, inMemoryDestroySandbox, inMemorySnapshotSandbox }\n * ```\n */\nexport type PrefixedSandboxOps<\n TPrefix extends string,\n TOptions extends SandboxCreateOptions = SandboxCreateOptions,\n> = {\n [K in keyof SandboxOps<TOptions> as `${TPrefix}${Capitalize<K & string>}`]: SandboxOps<TOptions>[K];\n};\n\n// ============================================================================\n// Errors\n// ============================================================================\n\nimport { ApplicationFailure } from \"@temporalio/common\";\n\nexport class SandboxNotSupportedError extends ApplicationFailure {\n constructor(operation: string) {\n super(\n `Sandbox does not support: ${operation}`,\n \"SandboxNotSupportedError\",\n true\n );\n }\n}\n\nexport class SandboxNotFoundError extends ApplicationFailure {\n constructor(sandboxId: string) {\n super(`Sandbox not found: ${sandboxId}`, \"SandboxNotFoundError\", true);\n }\n}\n","import type { Sandbox as DaytonaSdkSandbox } from \"@daytonaio/sdk\";\nimport type {\n SandboxFileSystem,\n DirentEntry,\n FileStat,\n} from \"../../../lib/sandbox/types\";\nimport { SandboxNotSupportedError } from \"../../../lib/sandbox/types\";\nimport { posix } from \"node:path\";\n\n/**\n * {@link SandboxFileSystem} backed by a Daytona SDK sandbox.\n *\n * Maps zeitlich's filesystem interface to Daytona's `sandbox.fs` and\n * `sandbox.process` APIs. Operations that have no direct Daytona equivalent\n * (e.g. `appendFile`, `cp`) are composed from primitives.\n */\nexport class DaytonaSandboxFileSystem implements SandboxFileSystem {\n readonly workspaceBase: string;\n\n constructor(\n private sandbox: DaytonaSdkSandbox,\n workspaceBase = \"/home/daytona\"\n ) {\n this.workspaceBase = posix.resolve(\"/\", workspaceBase);\n }\n\n private normalisePath(path: string): string {\n return posix.resolve(this.workspaceBase, path);\n }\n\n async readFile(path: string): Promise<string> {\n const norm = this.normalisePath(path);\n const buf = await this.sandbox.fs.downloadFile(norm);\n return buf.toString(\"utf-8\");\n }\n\n async readFileBuffer(path: string): Promise<Uint8Array> {\n const norm = this.normalisePath(path);\n const buf = await this.sandbox.fs.downloadFile(norm);\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n }\n\n async writeFile(path: string, content: string | Uint8Array): Promise<void> {\n const norm = this.normalisePath(path);\n const buf =\n typeof content === \"string\"\n ? Buffer.from(content, \"utf-8\")\n : Buffer.from(content);\n await this.sandbox.fs.uploadFile(buf, norm);\n }\n\n async writeFiles(\n files: { path: string; content: string | Uint8Array }[]\n ): Promise<void> {\n await this.sandbox.fs.uploadFiles(\n files.map((f) => ({\n source: Buffer.from(f.content),\n destination: this.normalisePath(f.path),\n }))\n );\n }\n\n async appendFile(path: string, content: string | Uint8Array): Promise<void> {\n const norm = this.normalisePath(path);\n let existing: Buffer;\n try {\n existing = await this.sandbox.fs.downloadFile(norm);\n } catch {\n return this.writeFile(norm, content);\n }\n\n const addition =\n typeof content === \"string\" ? Buffer.from(content, \"utf-8\") : content;\n const merged = Buffer.concat([existing, Buffer.from(addition)]);\n await this.sandbox.fs.uploadFile(merged, norm);\n }\n\n async exists(path: string): Promise<boolean> {\n const norm = this.normalisePath(path);\n try {\n await this.sandbox.fs.getFileDetails(norm);\n return true;\n } catch {\n return false;\n }\n }\n\n async stat(path: string): Promise<FileStat> {\n const norm = this.normalisePath(path);\n const info = await this.sandbox.fs.getFileDetails(norm);\n return {\n isFile: !info.isDir,\n isDirectory: info.isDir,\n isSymbolicLink: false,\n size: info.size,\n mtime: new Date(info.modTime),\n };\n }\n\n async mkdir(path: string, _options?: { recursive?: boolean }): Promise<void> {\n const norm = this.normalisePath(path);\n await this.sandbox.fs.createFolder(norm, \"755\");\n }\n\n async readdir(path: string): Promise<string[]> {\n const norm = this.normalisePath(path);\n const entries = await this.sandbox.fs.listFiles(norm);\n return entries.map((e) => e.name);\n }\n\n async readdirWithFileTypes(path: string): Promise<DirentEntry[]> {\n const norm = this.normalisePath(path);\n const entries = await this.sandbox.fs.listFiles(norm);\n return entries.map((e) => ({\n name: e.name,\n isFile: !e.isDir,\n isDirectory: e.isDir,\n isSymbolicLink: false,\n }));\n }\n\n async rm(\n path: string,\n options?: { recursive?: boolean; force?: boolean }\n ): Promise<void> {\n const norm = this.normalisePath(path);\n try {\n await this.sandbox.fs.deleteFile(norm, options?.recursive);\n } catch (err) {\n if (!options?.force) throw err;\n }\n }\n\n async cp(\n src: string,\n dest: string,\n options?: { recursive?: boolean }\n ): Promise<void> {\n const normSrc = this.normalisePath(src);\n const normDest = this.normalisePath(dest);\n const info = await this.sandbox.fs.getFileDetails(normSrc);\n if (info.isDir) {\n if (!options?.recursive) {\n throw new Error(`EISDIR: is a directory (use recursive): ${src}`);\n }\n await this.sandbox.process.executeCommand(\n `cp -r \"${normSrc}\" \"${normDest}\"`\n );\n } else {\n await this.sandbox.process.executeCommand(\n `cp \"${normSrc}\" \"${normDest}\"`\n );\n }\n }\n\n async mv(src: string, dest: string): Promise<void> {\n const normSrc = this.normalisePath(src);\n const normDest = this.normalisePath(dest);\n await this.sandbox.fs.moveFiles(normSrc, normDest);\n }\n\n async readlink(_path: string): Promise<string> {\n throw new SandboxNotSupportedError(\"readlink\");\n }\n\n resolvePath(base: string, path: string): string {\n return posix.resolve(this.normalisePath(base), path);\n }\n}\n","import { Daytona, type Sandbox as DaytonaSdkSandbox } from \"@daytonaio/sdk\";\nimport type {\n Sandbox,\n SandboxCapabilities,\n SandboxCreateResult,\n SandboxProvider,\n SandboxSnapshot,\n ExecOptions,\n ExecResult,\n} from \"../../../lib/sandbox/types\";\nimport {\n SandboxNotFoundError,\n SandboxNotSupportedError,\n} from \"../../../lib/sandbox/types\";\nimport { DaytonaSandboxFileSystem } from \"./filesystem\";\nimport type {\n DaytonaSandbox,\n DaytonaSandboxConfig,\n DaytonaSandboxCreateOptions,\n} from \"./types\";\n\n// ============================================================================\n// DaytonaSandbox\n// ============================================================================\n\nclass DaytonaSandboxImpl implements Sandbox {\n readonly capabilities: SandboxCapabilities = {\n filesystem: true,\n execution: true,\n persistence: false,\n };\n\n readonly fs: DaytonaSandboxFileSystem;\n\n constructor(\n readonly id: string,\n private sdkSandbox: DaytonaSdkSandbox,\n workspaceBase = \"/home/daytona\"\n ) {\n this.fs = new DaytonaSandboxFileSystem(sdkSandbox, workspaceBase);\n }\n\n async exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n const response = await this.sdkSandbox.process.executeCommand(\n command,\n options?.cwd,\n options?.env,\n options?.timeout\n );\n\n return {\n exitCode: response.exitCode ?? 0,\n stdout: response.result ?? \"\",\n stderr: \"\",\n };\n }\n\n async destroy(): Promise<void> {\n await this.sdkSandbox.delete(60);\n }\n}\n\n// ============================================================================\n// DaytonaSandboxProvider\n// ============================================================================\n\nexport class DaytonaSandboxProvider implements SandboxProvider<\n DaytonaSandboxCreateOptions,\n DaytonaSandbox\n> {\n readonly id = \"daytona\";\n readonly capabilities: SandboxCapabilities = {\n filesystem: true,\n execution: true,\n persistence: false,\n };\n\n private client: Daytona;\n private readonly defaultWorkspaceBase: string;\n\n constructor(config?: DaytonaSandboxConfig) {\n this.client = new Daytona(config);\n this.defaultWorkspaceBase = config?.workspaceBase ?? \"/home/daytona\";\n }\n\n async create(\n options?: DaytonaSandboxCreateOptions\n ): Promise<SandboxCreateResult> {\n const sdkSandbox = await this.client.create(\n {\n language: options?.language,\n snapshot: options?.snapshot,\n envVars: options?.env,\n labels: options?.labels,\n autoStopInterval: options?.autoStopInterval,\n autoArchiveInterval: options?.autoArchiveInterval,\n autoDeleteInterval: options?.autoDeleteInterval,\n },\n { timeout: options?.timeout ?? 60 }\n );\n\n const workspaceBase = options?.workspaceBase ?? this.defaultWorkspaceBase;\n\n const sandbox = new DaytonaSandboxImpl(\n sdkSandbox.id,\n sdkSandbox,\n workspaceBase\n );\n\n if (options?.initialFiles) {\n await sandbox.fs.writeFiles(\n Object.entries(options.initialFiles).map(([path, content]) => ({\n path,\n content,\n }))\n );\n }\n\n return { sandbox };\n }\n\n async get(sandboxId: string): Promise<DaytonaSandbox> {\n try {\n const sdkSandbox = await this.client.get(sandboxId);\n return new DaytonaSandboxImpl(\n sdkSandbox.id,\n sdkSandbox,\n this.defaultWorkspaceBase\n );\n } catch {\n throw new SandboxNotFoundError(sandboxId);\n }\n }\n\n async destroy(sandboxId: string): Promise<void> {\n try {\n const sdkSandbox = await this.client.get(sandboxId);\n await this.client.delete(sdkSandbox);\n } catch {\n // Already gone\n }\n }\n\n async pause(_sandboxId: string, _ttlSeconds?: number): Promise<void> {\n throw new SandboxNotSupportedError(\"pause\");\n }\n\n async fork(_sandboxId: string): Promise<Sandbox> {\n throw new Error(\"Not implemented\");\n }\n\n async snapshot(_sandboxId: string): Promise<SandboxSnapshot> {\n throw new SandboxNotSupportedError(\n \"snapshot (use Daytona's native snapshot API directly)\"\n );\n }\n\n async restore(_snapshot: SandboxSnapshot): Promise<never> {\n throw new SandboxNotSupportedError(\n \"restore (use Daytona's native snapshot API directly)\"\n );\n }\n}\n\n// Re-exports\nexport { DaytonaSandboxFileSystem } from \"./filesystem\";\nexport type {\n DaytonaSandbox,\n DaytonaSandboxConfig,\n DaytonaSandboxCreateOptions,\n} from \"./types\";\n"]}