zeitlich 0.2.36 → 0.2.37
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/README.md +146 -92
- package/dist/{activities-BVI2lTwr.d.ts → activities-Bb-nAjwQ.d.ts} +2 -2
- package/dist/{activities-hd4aNnZE.d.cts → activities-vkI4_3CC.d.cts} +2 -2
- package/dist/adapters/sandbox/bedrock/index.cjs +14 -11
- package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/index.d.cts +4 -3
- package/dist/adapters/sandbox/bedrock/index.d.ts +4 -3
- package/dist/adapters/sandbox/bedrock/index.js +14 -11
- package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.cjs +2 -0
- package/dist/adapters/sandbox/bedrock/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.d.cts +2 -2
- package/dist/adapters/sandbox/bedrock/workflow.d.ts +2 -2
- package/dist/adapters/sandbox/bedrock/workflow.js +2 -0
- package/dist/adapters/sandbox/bedrock/workflow.js.map +1 -1
- package/dist/adapters/sandbox/daytona/index.cjs +8 -0
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +2 -1
- package/dist/adapters/sandbox/daytona/index.d.ts +2 -1
- package/dist/adapters/sandbox/daytona/index.js +8 -0
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.cjs +2 -0
- package/dist/adapters/sandbox/daytona/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/daytona/workflow.js +2 -0
- package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
- package/dist/adapters/sandbox/e2b/index.cjs +59 -10
- package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +5 -3
- package/dist/adapters/sandbox/e2b/index.d.ts +5 -3
- package/dist/adapters/sandbox/e2b/index.js +59 -10
- package/dist/adapters/sandbox/e2b/index.js.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.cjs +2 -0
- package/dist/adapters/sandbox/e2b/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/e2b/workflow.js +2 -0
- package/dist/adapters/sandbox/e2b/workflow.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.cjs +5 -0
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +2 -1
- package/dist/adapters/sandbox/inmemory/index.d.ts +2 -1
- package/dist/adapters/sandbox/inmemory/index.js +5 -0
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.cjs +2 -0
- package/dist/adapters/sandbox/inmemory/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.js +2 -0
- package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
- package/dist/adapters/thread/anthropic/index.cjs +71 -36
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +5 -5
- package/dist/adapters/thread/anthropic/index.d.ts +5 -5
- package/dist/adapters/thread/anthropic/index.js +71 -36
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +5 -1
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +5 -5
- package/dist/adapters/thread/anthropic/workflow.d.ts +5 -5
- package/dist/adapters/thread/anthropic/workflow.js +5 -1
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +50 -25
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +5 -5
- package/dist/adapters/thread/google-genai/index.d.ts +5 -5
- package/dist/adapters/thread/google-genai/index.js +50 -25
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +5 -1
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +5 -5
- package/dist/adapters/thread/google-genai/workflow.d.ts +5 -5
- package/dist/adapters/thread/google-genai/workflow.js +5 -1
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +34 -7
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +5 -5
- package/dist/adapters/thread/langchain/index.d.ts +5 -5
- package/dist/adapters/thread/langchain/index.js +34 -7
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +5 -1
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +5 -5
- package/dist/adapters/thread/langchain/workflow.d.ts +5 -5
- package/dist/adapters/thread/langchain/workflow.js +5 -1
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +206 -120
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -11
- package/dist/index.d.ts +17 -11
- package/dist/index.js +207 -121
- package/dist/index.js.map +1 -1
- package/dist/{proxy-BjdFGPTm.d.ts → proxy-0smGKvx8.d.ts} +1 -1
- package/dist/{proxy-7RnVaPdJ.d.cts → proxy-DEtowJyd.d.cts} +1 -1
- package/dist/{thread-manager-DjN5JYul.d.ts → thread-manager-3fszQih4.d.ts} +2 -2
- package/dist/{thread-manager-CbpiGq1L.d.ts → thread-manager-C-C4pI2z.d.ts} +2 -2
- package/dist/{thread-manager-BBzNgQWH.d.cts → thread-manager-CzYln2OC.d.cts} +2 -2
- package/dist/{thread-manager-DzXm9eeI.d.cts → thread-manager-D4vgzYrh.d.cts} +2 -2
- package/dist/{types-yiXmqedU.d.ts → types-B37hKoWA.d.ts} +1 -1
- package/dist/{types-DQ1l_gXL.d.cts → types-BO7Yju20.d.cts} +63 -14
- package/dist/{types-wiGLvxWf.d.ts → types-CNuWnvy9.d.ts} +1 -1
- package/dist/{types-CADc5V_P.d.ts → types-CPKDl-y_.d.ts} +63 -14
- package/dist/{types-Mc_4BCfT.d.cts → types-D08CXPh8.d.cts} +1 -1
- package/dist/{types-CBH54cwr.d.cts → types-DWEUmYAJ.d.cts} +1 -1
- package/dist/{types-DxCpFNv_.d.cts → types-tQL9njTu.d.cts} +25 -0
- package/dist/{types-DxCpFNv_.d.ts → types-tQL9njTu.d.ts} +25 -0
- package/dist/{workflow-P2pTSfKu.d.ts → workflow-CjXHbZZc.d.ts} +2 -2
- package/dist/{workflow-DhtWRovz.d.cts → workflow-Do_lzJpT.d.cts} +2 -2
- package/dist/workflow.cjs +182 -114
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +3 -3
- package/dist/workflow.d.ts +3 -3
- package/dist/workflow.js +183 -115
- package/dist/workflow.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/sandbox/bedrock/filesystem.ts +6 -12
- package/src/adapters/sandbox/bedrock/index.ts +10 -8
- package/src/adapters/sandbox/bedrock/proxy.ts +2 -0
- package/src/adapters/sandbox/daytona/index.ts +6 -0
- package/src/adapters/sandbox/daytona/proxy.ts +2 -0
- package/src/adapters/sandbox/e2b/filesystem.ts +5 -4
- package/src/adapters/sandbox/e2b/index.ts +63 -12
- package/src/adapters/sandbox/e2b/proxy.ts +2 -0
- package/src/adapters/sandbox/inmemory/index.ts +5 -0
- package/src/adapters/sandbox/inmemory/proxy.ts +2 -0
- package/src/adapters/thread/anthropic/activities.ts +49 -26
- package/src/adapters/thread/anthropic/model-invoker.ts +15 -6
- package/src/adapters/thread/anthropic/proxy.ts +6 -2
- package/src/adapters/thread/anthropic/thread-manager.test.ts +26 -7
- package/src/adapters/thread/anthropic/thread-manager.ts +60 -46
- package/src/adapters/thread/google-genai/activities.ts +7 -2
- package/src/adapters/thread/google-genai/model-invoker.ts +26 -8
- package/src/adapters/thread/google-genai/proxy.ts +6 -2
- package/src/adapters/thread/google-genai/thread-manager.test.ts +13 -3
- package/src/adapters/thread/google-genai/thread-manager.ts +54 -33
- package/src/adapters/thread/langchain/activities.ts +46 -24
- package/src/adapters/thread/langchain/hooks.test.ts +36 -49
- package/src/adapters/thread/langchain/hooks.ts +18 -5
- package/src/adapters/thread/langchain/model-invoker.ts +3 -3
- package/src/adapters/thread/langchain/proxy.ts +6 -2
- package/src/adapters/thread/langchain/thread-manager.test.ts +5 -1
- package/src/adapters/thread/langchain/thread-manager.ts +20 -9
- package/src/index.ts +4 -1
- package/src/lib/activity.ts +16 -6
- package/src/lib/hooks/types.ts +6 -6
- package/src/lib/lifecycle.ts +9 -1
- package/src/lib/model/proxy.ts +2 -2
- package/src/lib/observability/hooks.ts +4 -5
- package/src/lib/observability/index.ts +1 -4
- package/src/lib/sandbox/manager.ts +21 -4
- package/src/lib/sandbox/node-fs.ts +3 -6
- package/src/lib/sandbox/sandbox.test.ts +36 -3
- package/src/lib/sandbox/tree.integration.test.ts +10 -3
- package/src/lib/sandbox/types.ts +35 -1
- package/src/lib/session/session-edge-cases.integration.test.ts +51 -13
- package/src/lib/session/session.integration.test.ts +139 -0
- package/src/lib/session/session.ts +50 -19
- package/src/lib/session/types.ts +13 -5
- package/src/lib/skills/fs-provider.ts +12 -8
- package/src/lib/skills/handler.ts +1 -1
- package/src/lib/skills/parse.ts +3 -1
- package/src/lib/skills/register.ts +1 -3
- package/src/lib/skills/skills.integration.test.ts +25 -15
- package/src/lib/state/manager.integration.test.ts +12 -2
- package/src/lib/subagent/define.ts +1 -1
- package/src/lib/subagent/handler.ts +186 -71
- package/src/lib/subagent/index.ts +1 -5
- package/src/lib/subagent/register.ts +3 -2
- package/src/lib/subagent/signals.ts +1 -10
- package/src/lib/subagent/subagent.integration.test.ts +438 -156
- package/src/lib/subagent/tool.ts +4 -3
- package/src/lib/subagent/types.ts +50 -20
- package/src/lib/subagent/workflow.ts +9 -49
- package/src/lib/thread/id.test.ts +1 -1
- package/src/lib/thread/id.ts +1 -2
- package/src/lib/thread/proxy.ts +3 -4
- package/src/lib/thread/types.ts +11 -3
- package/src/lib/tool-router/index.ts +1 -5
- package/src/lib/tool-router/router-edge-cases.integration.test.ts +1 -1
- package/src/lib/tool-router/router.ts +3 -2
- package/src/lib/tool-router/types.ts +11 -3
- package/src/lib/tool-router/with-sandbox.ts +19 -5
- package/src/lib/virtual-fs/filesystem.ts +1 -1
- package/src/lib/virtual-fs/index.ts +5 -1
- package/src/lib/virtual-fs/mutations.ts +2 -4
- package/src/lib/virtual-fs/queries.ts +9 -5
- package/src/lib/virtual-fs/types.ts +4 -1
- package/src/lib/virtual-fs/virtual-fs.test.ts +9 -11
- package/src/lib/workflow.test.ts +7 -4
- package/src/lib/workflow.ts +1 -5
- package/src/tools/ask-user-question/tool.ts +1 -3
- package/src/tools/glob/handler.ts +1 -4
- package/src/tools/task-get/handler.ts +4 -5
- package/src/tools/task-list/handler.ts +1 -4
- package/src/tools/task-update/handler.ts +4 -5
- package/src/workflow.ts +20 -7
- package/tsup.config.ts +9 -6
- package/src/lib/.env +0 -1
- package/src/tools/bash/.env +0 -1
package/README.md
CHANGED
|
@@ -39,15 +39,16 @@ Zeitlich's core is framework-agnostic — it defines generic interfaces (`ModelI
|
|
|
39
39
|
### Thread Adapters
|
|
40
40
|
|
|
41
41
|
A thread adapter bundles two concerns:
|
|
42
|
+
|
|
42
43
|
1. **Thread management** — Storing and retrieving conversation messages in Redis
|
|
43
44
|
2. **Model invocation** — Calling the LLM with the conversation history and tools
|
|
44
45
|
|
|
45
46
|
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
|
|
|
47
|
-
| Adapter
|
|
48
|
-
|
|
49
|
-
| LangChain
|
|
50
|
-
| Google GenAI | `zeitlich/adapters/thread/google-genai` | `@google/genai`
|
|
48
|
+
| Adapter | Import | SDK |
|
|
49
|
+
| ------------ | --------------------------------------- | ---------------------------------------- |
|
|
50
|
+
| LangChain | `zeitlich/adapters/thread/langchain` | `@langchain/core` + any provider package |
|
|
51
|
+
| Google GenAI | `zeitlich/adapters/thread/google-genai` | `@google/genai` |
|
|
51
52
|
|
|
52
53
|
Vercel AI SDK and other provider-specific adapters can be built by implementing the `ThreadOps` and `ModelInvoker` interfaces.
|
|
53
54
|
|
|
@@ -55,13 +56,13 @@ Vercel AI SDK and other provider-specific adapters can be built by implementing
|
|
|
55
56
|
|
|
56
57
|
A sandbox adapter provides filesystem access for tools like `Bash`, `Read`, `Write`, and `Edit`:
|
|
57
58
|
|
|
58
|
-
| Adapter
|
|
59
|
-
|
|
60
|
-
| In-memory
|
|
61
|
-
| Virtual FS | `zeitlich` / `zeitlich/workflow`
|
|
62
|
-
| Daytona
|
|
63
|
-
| E2B
|
|
64
|
-
| Bedrock
|
|
59
|
+
| Adapter | Import | Use case |
|
|
60
|
+
| ---------- | ------------------------------------ | ------------------------------------------------- |
|
|
61
|
+
| In-memory | `zeitlich/adapters/sandbox/inmemory` | Tests and lightweight agents |
|
|
62
|
+
| Virtual FS | `zeitlich` / `zeitlich/workflow` | Built-in virtual filesystem with custom resolvers |
|
|
63
|
+
| Daytona | `zeitlich/adapters/sandbox/daytona` | Remote Daytona workspaces |
|
|
64
|
+
| E2B | `zeitlich/adapters/sandbox/e2b` | E2B cloud sandboxes |
|
|
65
|
+
| Bedrock | `zeitlich/adapters/sandbox/bedrock` | AWS Bedrock AgentCore Code Interpreter |
|
|
65
66
|
|
|
66
67
|
### Example: LangChain Adapter
|
|
67
68
|
|
|
@@ -442,13 +443,15 @@ export const researcherWorkflow = defineSubagentWorkflow(
|
|
|
442
443
|
buildContextMessage: () => [{ type: "text", text: prompt }],
|
|
443
444
|
});
|
|
444
445
|
|
|
445
|
-
const { finalMessage, threadId } = await session.runSession({
|
|
446
|
+
const { finalMessage, threadId } = await session.runSession({
|
|
447
|
+
stateManager,
|
|
448
|
+
});
|
|
446
449
|
return {
|
|
447
450
|
toolResponse: finalMessage ? extractText(finalMessage) : "No response",
|
|
448
451
|
data: null,
|
|
449
452
|
threadId,
|
|
450
453
|
};
|
|
451
|
-
}
|
|
454
|
+
}
|
|
452
455
|
);
|
|
453
456
|
```
|
|
454
457
|
|
|
@@ -510,6 +513,7 @@ license: MIT
|
|
|
510
513
|
## Instructions
|
|
511
514
|
|
|
512
515
|
When reviewing code, follow these steps:
|
|
516
|
+
|
|
513
517
|
1. Read the diff with `Bash`
|
|
514
518
|
2. Search for related tests with `Grep`
|
|
515
519
|
3. Read the checklist from `resources/checklist.md`
|
|
@@ -591,7 +595,7 @@ For advanced use cases, you can construct the tool and handler independently:
|
|
|
591
595
|
```typescript
|
|
592
596
|
import { createReadSkillTool, createReadSkillHandler } from "zeitlich/workflow";
|
|
593
597
|
|
|
594
|
-
const tool = createReadSkillTool(skills);
|
|
598
|
+
const tool = createReadSkillTool(skills); // ToolDefinition with enum schema
|
|
595
599
|
const handler = createReadSkillHandler(skills); // Returns skill instructions
|
|
596
600
|
```
|
|
597
601
|
|
|
@@ -603,11 +607,11 @@ Every session has a **thread** (conversation history) and an optional **sandbox*
|
|
|
603
607
|
|
|
604
608
|
The `thread` field on `SessionConfig` (and `WorkflowInput`) accepts one of three modes:
|
|
605
609
|
|
|
606
|
-
| Mode
|
|
607
|
-
|
|
608
|
-
| `{ mode: "new" }`
|
|
609
|
-
| `{ mode: "fork", threadId }`
|
|
610
|
-
| `{ mode: "continue", threadId }` | Append directly to an existing thread in-place.
|
|
610
|
+
| Mode | Description |
|
|
611
|
+
| -------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
612
|
+
| `{ mode: "new" }` | Start a fresh thread (default). Optionally pass `threadId` to choose the ID. |
|
|
613
|
+
| `{ mode: "fork", threadId }` | Copy all messages from an existing thread into a new one and continue there. The original is never mutated. |
|
|
614
|
+
| `{ mode: "continue", threadId }` | Append directly to an existing thread in-place. |
|
|
611
615
|
|
|
612
616
|
```typescript
|
|
613
617
|
import { createSession } from "zeitlich/workflow";
|
|
@@ -637,22 +641,24 @@ const continuedSession = await createSession({
|
|
|
637
641
|
|
|
638
642
|
The `sandbox` field controls how a sandbox is created or reused:
|
|
639
643
|
|
|
640
|
-
| Mode
|
|
641
|
-
|
|
642
|
-
| `{ mode: "new" }`
|
|
643
|
-
| `{ mode: "continue", sandboxId }`
|
|
644
|
-
| `{ mode: "fork", sandboxId }`
|
|
645
|
-
| `{ mode: "
|
|
644
|
+
| Mode | Description |
|
|
645
|
+
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
646
|
+
| `{ mode: "new" }` | Create a fresh sandbox (default when `sandboxOps` is provided). |
|
|
647
|
+
| `{ mode: "continue", sandboxId }` | Take ownership of an existing sandbox (paused or running). Paused sandboxes are automatically resumed. |
|
|
648
|
+
| `{ mode: "fork", sandboxId }` | Fork from an existing sandbox. A new sandbox is created and owned by this session. |
|
|
649
|
+
| `{ mode: "from-snapshot", snapshot }` | Restore a fresh sandbox from a previously captured `SandboxSnapshot`. The new sandbox is owned by this session. |
|
|
650
|
+
| `{ mode: "inherit", sandboxId }` | Use a sandbox owned by someone else (e.g. a parent agent). Shutdown policy is ignored. |
|
|
646
651
|
|
|
647
652
|
#### Sandbox Shutdown (`SandboxShutdown`)
|
|
648
653
|
|
|
649
654
|
The `sandboxShutdown` field controls what happens to the sandbox when the session exits:
|
|
650
655
|
|
|
651
|
-
| Value
|
|
652
|
-
|
|
653
|
-
| `"destroy"`
|
|
654
|
-
| `"pause"`
|
|
655
|
-
| `"keep"`
|
|
656
|
+
| Value | Description |
|
|
657
|
+
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
658
|
+
| `"destroy"` | Tear down the sandbox entirely (default). |
|
|
659
|
+
| `"pause"` | Pause the sandbox so it can be resumed later. |
|
|
660
|
+
| `"keep"` | Leave the sandbox running (no-op on exit). |
|
|
661
|
+
| `"snapshot"` | Capture a snapshot, then destroy the sandbox. The snapshot is surfaced on the session result as `snapshot` (plus `baseSnapshot` when the sandbox was freshly created). |
|
|
656
662
|
|
|
657
663
|
Subagents also support two additional shutdown modes:
|
|
658
664
|
|
|
@@ -692,6 +698,47 @@ export const codeRunnerSubagent = defineSubagent(codeRunnerWorkflow, {
|
|
|
692
698
|
});
|
|
693
699
|
```
|
|
694
700
|
|
|
701
|
+
##### Snapshot-driven continuation (E2B only)
|
|
702
|
+
|
|
703
|
+
`continuation: "snapshot"` avoids keeping a sandbox paused between invocations. Instead, each call boots a fresh sandbox from a stored snapshot, captures a new snapshot on exit, and destroys the sandbox inline:
|
|
704
|
+
|
|
705
|
+
```typescript
|
|
706
|
+
export const analystSubagent = defineSubagent(analystWorkflow, {
|
|
707
|
+
thread: "continue",
|
|
708
|
+
sandbox: { source: "own", init: "once", continuation: "snapshot" },
|
|
709
|
+
});
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
How it works:
|
|
713
|
+
|
|
714
|
+
- **First call** for a thread: session creates a fresh sandbox, snapshots it right after seeding (the **base snapshot**, kept per-agent with `init: "once"`), runs the agent, snapshots again on exit (the **thread snapshot**), and destroys the sandbox.
|
|
715
|
+
- **Same-thread follow-up**: session restores the thread's latest snapshot into a new sandbox, runs, snapshots on exit, destroys. The superseded snapshot is deleted eagerly.
|
|
716
|
+
- **New thread, same agent** (`init: "once"`): session restores from the base snapshot, skipping re-seeding.
|
|
717
|
+
- `thread: "fork"` preserves the source thread's snapshot (the fork writes to a new key) so the source can still be continued later.
|
|
718
|
+
|
|
719
|
+
Snapshots are cleaned up by the **child workflow that produced them**, not by the parent. Each snapshot-producing subagent stays alive after signalling its result back to the parent, and waits for a `cleanupSnapshots` signal. When the parent session exits, it fans that signal out to every pending snapshot-owner child; each child deletes its own snapshots via its own `sandboxOps` and terminates.
|
|
720
|
+
|
|
721
|
+
This means heterogeneous providers "just work" — the parent doesn't need to know (or even have) `sandboxOps` for the provider the child used. The child wraps its `deleteSnapshots` callback via `session.runSession()` and the workflow wrapper does the rest:
|
|
722
|
+
|
|
723
|
+
```typescript
|
|
724
|
+
export const analystWorkflow = defineSubagentWorkflow(
|
|
725
|
+
{ name: "analyst", description: "...", sandboxShutdown: "snapshot" },
|
|
726
|
+
async (prompt, sessionInput) => {
|
|
727
|
+
const session = await createSession({
|
|
728
|
+
...sessionInput,
|
|
729
|
+
sandboxOps,
|
|
730
|
+
runAgent,
|
|
731
|
+
threadOps,
|
|
732
|
+
buildContextMessage: () => prompt,
|
|
733
|
+
});
|
|
734
|
+
const result = await session.runSession({ stateManager });
|
|
735
|
+
return result; // result.deleteSnapshots is forwarded automatically
|
|
736
|
+
}
|
|
737
|
+
);
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
Trade-off: cleanup is deferred to parent close (no eager GC of superseded thread snapshots). Extra cost is a few snapshot IDs held for the parent's lifetime — much cheaper than keeping sandboxes paused. Currently implemented for the E2B adapter. The in-memory adapter treats snapshots as opaque caller-held data (delete is a no-op), and Daytona/Bedrock throw `SandboxNotSupportedError` for snapshot operations.
|
|
741
|
+
|
|
695
742
|
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.
|
|
696
743
|
|
|
697
744
|
The `sandbox` field accepts `"none"` (default) or an object with `source`, `continuation`, and optional `init`/`shutdown` fields:
|
|
@@ -714,9 +761,11 @@ export const researcherWorkflow = defineSubagentWorkflow(
|
|
|
714
761
|
// ... other config
|
|
715
762
|
});
|
|
716
763
|
|
|
717
|
-
const { threadId, finalMessage } = await session.runSession({
|
|
764
|
+
const { threadId, finalMessage } = await session.runSession({
|
|
765
|
+
stateManager,
|
|
766
|
+
});
|
|
718
767
|
return { toolResponse: extractText(finalMessage), data: null, threadId };
|
|
719
|
-
}
|
|
768
|
+
}
|
|
720
769
|
);
|
|
721
770
|
```
|
|
722
771
|
|
|
@@ -790,10 +839,15 @@ Each `fs` instance also exposes `workspaceBase`, which is the base used for rela
|
|
|
790
839
|
```typescript
|
|
791
840
|
import { VirtualFileSystem } from "zeitlich";
|
|
792
841
|
|
|
793
|
-
const virtualFs = new VirtualFileSystem(
|
|
842
|
+
const virtualFs = new VirtualFileSystem(
|
|
843
|
+
fileTree,
|
|
844
|
+
resolver,
|
|
845
|
+
{ projectId: "p1" },
|
|
846
|
+
"/repo"
|
|
847
|
+
);
|
|
794
848
|
console.log(virtualFs.workspaceBase); // "/repo"
|
|
795
849
|
|
|
796
|
-
await virtualFs.writeFile("src/index.ts",
|
|
850
|
+
await virtualFs.writeFile("src/index.ts", "export const ok = true;\n");
|
|
797
851
|
const content = await virtualFs.readFile("src/index.ts"); // reads /repo/src/index.ts
|
|
798
852
|
```
|
|
799
853
|
|
|
@@ -879,80 +933,80 @@ const session = await createSession({
|
|
|
879
933
|
|
|
880
934
|
Safe for use in Temporal workflow files:
|
|
881
935
|
|
|
882
|
-
| Export
|
|
883
|
-
|
|
|
884
|
-
| `createSession`
|
|
885
|
-
| `createAgentStateManager`
|
|
886
|
-
| `createToolRouter`
|
|
887
|
-
| `defineTool`
|
|
888
|
-
| `defineSubagentWorkflow`
|
|
889
|
-
| `defineSubagent`
|
|
890
|
-
| `proxyRunAgent`
|
|
891
|
-
| `getShortId`
|
|
892
|
-
| Tool definitions
|
|
893
|
-
| Task tools
|
|
894
|
-
| Skill utilities
|
|
895
|
-
| `defineWorkflow`
|
|
896
|
-
| Lifecycle types
|
|
897
|
-
| Types
|
|
936
|
+
| Export | Description |
|
|
937
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
938
|
+
| `createSession` | Creates an agent session with tools, prompts, subagents, and hooks |
|
|
939
|
+
| `createAgentStateManager` | Creates a state manager for workflow state with query/update handlers |
|
|
940
|
+
| `createToolRouter` | Creates a tool router (used internally by session, or for advanced use) |
|
|
941
|
+
| `defineTool` | Identity function for type-safe tool definition with handler and hooks |
|
|
942
|
+
| `defineSubagentWorkflow` | Defines a subagent workflow with embedded name, description, and optional resultSchema |
|
|
943
|
+
| `defineSubagent` | Creates a `SubagentConfig` from a `SubagentDefinition` with optional parent-specific overrides |
|
|
944
|
+
| `proxyRunAgent` | Workflow-safe proxy for `runAgent` activities with LLM-optimised defaults (heartbeat, timeouts, retries) |
|
|
945
|
+
| `getShortId` | Generate a compact, workflow-deterministic identifier (base-62, 12 chars) |
|
|
946
|
+
| Tool definitions | `askUserQuestionTool`, `globTool`, `grepTool`, `readFileTool`, `writeFileTool`, `editTool`, `bashTool` |
|
|
947
|
+
| Task tools | `taskCreateTool`, `taskGetTool`, `taskListTool`, `taskUpdateTool` for workflow task management |
|
|
948
|
+
| Skill utilities | `parseSkillFile`, `createReadSkillTool`, `createReadSkillHandler` |
|
|
949
|
+
| `defineWorkflow` | Wraps a main workflow function, translating `WorkflowInput` into session-compatible fields |
|
|
950
|
+
| Lifecycle types | `ThreadInit`, `SandboxInit`, `SandboxShutdown`, `SubagentSandboxShutdown`, `SubagentSandboxConfig` |
|
|
951
|
+
| Types | `Skill`, `SkillMetadata`, `SkillProvider`, `SubagentDefinition`, `SubagentConfig`, `ToolDefinition`, `ToolWithHandler`, `RouterContext`, `SessionConfig`, `WorkflowConfig`, `WorkflowInput`, etc. |
|
|
898
952
|
|
|
899
953
|
### Activity Entry Point (`zeitlich`)
|
|
900
954
|
|
|
901
955
|
Framework-agnostic utilities for activities, worker setup, and Node.js code:
|
|
902
956
|
|
|
903
|
-
| Export | Description
|
|
904
|
-
| ------------------------- |
|
|
905
|
-
| `createRunAgentActivity` | Wraps a handler into a scope-prefixed `RunAgentActivity` with auto-fetched parent workflow state
|
|
906
|
-
| `withParentWorkflowState`
|
|
907
|
-
| `createThreadManager` | Generic Redis-backed thread manager factory
|
|
908
|
-
| `toTree` | Generate file tree string from an `IFileSystem` instance
|
|
909
|
-
| `withSandbox` | Wraps a handler to auto-resolve sandbox from context (pairs with `withAutoAppend`)
|
|
910
|
-
| `NodeFsSandboxFileSystem`
|
|
911
|
-
| `FileSystemSkillProvider`
|
|
957
|
+
| Export | Description |
|
|
958
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
959
|
+
| `createRunAgentActivity` | Wraps a handler into a scope-prefixed `RunAgentActivity` with auto-fetched parent workflow state |
|
|
960
|
+
| `withParentWorkflowState` | Wraps a tool handler into an `ActivityToolHandler` with auto-fetched parent workflow state |
|
|
961
|
+
| `createThreadManager` | Generic Redis-backed thread manager factory |
|
|
962
|
+
| `toTree` | Generate file tree string from an `IFileSystem` instance |
|
|
963
|
+
| `withSandbox` | Wraps a handler to auto-resolve sandbox from context (pairs with `withAutoAppend`) |
|
|
964
|
+
| `NodeFsSandboxFileSystem` | `node:fs` adapter for `SandboxFileSystem` — read skills from the worker's local disk |
|
|
965
|
+
| `FileSystemSkillProvider` | Load skills from a directory following the agentskills.io layout |
|
|
912
966
|
| Tool handlers | `bashHandler`, `editHandler`, `globHandler`, `readFileHandler`, `writeFileHandler`, `createAskUserQuestionHandler` |
|
|
913
967
|
|
|
914
968
|
### Thread Adapter Entry Points
|
|
915
969
|
|
|
916
970
|
**LangChain** (`zeitlich/adapters/thread/langchain`):
|
|
917
971
|
|
|
918
|
-
| Export
|
|
919
|
-
|
|
|
920
|
-
| `createLangChainAdapter`
|
|
921
|
-
| `createLangChainModelInvoker`
|
|
922
|
-
| `invokeLangChainModel`
|
|
923
|
-
| `createLangChainThreadManager`
|
|
972
|
+
| Export | Description |
|
|
973
|
+
| ------------------------------ | ----------------------------------------------------------------------------- |
|
|
974
|
+
| `createLangChainAdapter` | Unified adapter returning `createActivities`, `invoker`, `createModelInvoker` |
|
|
975
|
+
| `createLangChainModelInvoker` | Factory that returns a `ModelInvoker` backed by a LangChain chat model |
|
|
976
|
+
| `invokeLangChainModel` | One-shot model invocation convenience function |
|
|
977
|
+
| `createLangChainThreadManager` | Thread manager with LangChain `StoredMessage` helpers |
|
|
924
978
|
|
|
925
979
|
**Google GenAI** (`zeitlich/adapters/thread/google-genai`):
|
|
926
980
|
|
|
927
|
-
| Export
|
|
928
|
-
|
|
|
929
|
-
| `createGoogleGenAIAdapter`
|
|
930
|
-
| `createGoogleGenAIModelInvoker`
|
|
931
|
-
| `invokeGoogleGenAIModel`
|
|
932
|
-
| `createGoogleGenAIThreadManager`
|
|
981
|
+
| Export | Description |
|
|
982
|
+
| -------------------------------- | ----------------------------------------------------------------------------- |
|
|
983
|
+
| `createGoogleGenAIAdapter` | Unified adapter returning `createActivities`, `invoker`, `createModelInvoker` |
|
|
984
|
+
| `createGoogleGenAIModelInvoker` | Factory that returns a `ModelInvoker` backed by the `@google/genai` SDK |
|
|
985
|
+
| `invokeGoogleGenAIModel` | One-shot model invocation convenience function |
|
|
986
|
+
| `createGoogleGenAIThreadManager` | Thread manager with Google GenAI `Content` helpers |
|
|
933
987
|
|
|
934
988
|
### Types
|
|
935
989
|
|
|
936
|
-
| Export
|
|
937
|
-
|
|
|
938
|
-
| `AgentStatus`
|
|
939
|
-
| `MessageContent`
|
|
940
|
-
| `ToolMessageContent`
|
|
941
|
-
| `ModelInvoker`
|
|
942
|
-
| `ModelInvokerConfig`
|
|
943
|
-
| `ToolDefinition`
|
|
944
|
-
| `ToolWithHandler`
|
|
945
|
-
| `RouterContext`
|
|
946
|
-
| `Hooks`
|
|
947
|
-
| `ToolRouterHooks`
|
|
948
|
-
| `ThreadInit`
|
|
949
|
-
| `SandboxInit`
|
|
950
|
-
| `SandboxShutdown`
|
|
951
|
-
| `SubagentSandboxShutdown` | Extended shutdown with `"pause-until-parent-close"`
|
|
952
|
-
| `SubagentSandboxConfig`
|
|
953
|
-
| `SubagentDefinition`
|
|
954
|
-
| `SubagentConfig`
|
|
955
|
-
| `AgentState`
|
|
990
|
+
| Export | Description |
|
|
991
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
992
|
+
| `AgentStatus` | `"RUNNING" \| "WAITING_FOR_INPUT" \| "COMPLETED" \| "FAILED" \| "CANCELLED"` |
|
|
993
|
+
| `MessageContent` | Framework-agnostic message content (`string \| ContentPart[]`) |
|
|
994
|
+
| `ToolMessageContent` | Content returned by a tool handler (`string`) |
|
|
995
|
+
| `ModelInvoker` | Generic model invocation contract |
|
|
996
|
+
| `ModelInvokerConfig` | Configuration passed to a model invoker |
|
|
997
|
+
| `ToolDefinition` | Tool definition with name, description, and Zod schema |
|
|
998
|
+
| `ToolWithHandler` | Tool definition combined with its handler |
|
|
999
|
+
| `RouterContext` | Base context every tool handler receives (`threadId`, `toolCallId`, `toolName`, `sandboxId?`) |
|
|
1000
|
+
| `Hooks` | Combined session lifecycle + tool execution hooks |
|
|
1001
|
+
| `ToolRouterHooks` | Narrowed hook interface for tool execution only (pre/post/failure) |
|
|
1002
|
+
| `ThreadInit` | Thread initialization strategy: `"new"`, `"continue"`, or `"fork"` |
|
|
1003
|
+
| `SandboxInit` | Sandbox initialization strategy: `"new"`, `"continue"`, `"fork"`, `"from-snapshot"`, or `"inherit"` |
|
|
1004
|
+
| `SandboxShutdown` | Sandbox exit policy: `"destroy" \| "pause" \| "keep" \| "snapshot"` |
|
|
1005
|
+
| `SubagentSandboxShutdown` | Extended shutdown with `"pause-until-parent-close"` |
|
|
1006
|
+
| `SubagentSandboxConfig` | Subagent sandbox strategy: `"none" \| "inherit" \| "own"` with `continuation: "continue" \| "fork" \| "snapshot"` |
|
|
1007
|
+
| `SubagentDefinition` | Callable subagent workflow with embedded metadata (from `defineSubagentWorkflow`) |
|
|
1008
|
+
| `SubagentConfig` | Resolved subagent configuration consumed by `createSession` |
|
|
1009
|
+
| `AgentState` | Generic agent state type |
|
|
956
1010
|
|
|
957
1011
|
## Architecture
|
|
958
1012
|
|
|
@@ -1069,7 +1123,7 @@ const sinks: InjectedSinks<ZeitlichObservabilitySinks> = {
|
|
|
1069
1123
|
},
|
|
1070
1124
|
};
|
|
1071
1125
|
|
|
1072
|
-
const worker = await Worker.create({ sinks
|
|
1126
|
+
const worker = await Worker.create({ sinks /* ... */ });
|
|
1073
1127
|
```
|
|
1074
1128
|
|
|
1075
1129
|
**2. Wire hooks in your workflow:**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Redis from 'ioredis';
|
|
2
2
|
import { Part, Content, GoogleGenAI } from '@google/genai';
|
|
3
|
-
import { a as ModelInvoker, P as PrefixedThreadOps, S as ScopedPrefix, R as RouterContext, b as ToolHandlerResponse, c as ActivityToolHandler } from './types-
|
|
4
|
-
import { T as ThreadManagerHooks, P as ProviderThreadManager } from './types-
|
|
3
|
+
import { a as ModelInvoker, P as PrefixedThreadOps, S as ScopedPrefix, R as RouterContext, b as ToolHandlerResponse, c as ActivityToolHandler } from './types-CPKDl-y_.js';
|
|
4
|
+
import { T as ThreadManagerHooks, P as ProviderThreadManager } from './types-B37hKoWA.js';
|
|
5
5
|
|
|
6
6
|
/** SDK-native content type for Google GenAI human messages */
|
|
7
7
|
type GoogleGenAIContent = string | Part[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Redis from 'ioredis';
|
|
2
2
|
import { Part, Content, GoogleGenAI } from '@google/genai';
|
|
3
|
-
import { a as ModelInvoker, P as PrefixedThreadOps, S as ScopedPrefix, R as RouterContext, b as ToolHandlerResponse, c as ActivityToolHandler } from './types-
|
|
4
|
-
import { T as ThreadManagerHooks, P as ProviderThreadManager } from './types-
|
|
3
|
+
import { a as ModelInvoker, P as PrefixedThreadOps, S as ScopedPrefix, R as RouterContext, b as ToolHandlerResponse, c as ActivityToolHandler } from './types-BO7Yju20.cjs';
|
|
4
|
+
import { T as ThreadManagerHooks, P as ProviderThreadManager } from './types-D08CXPh8.cjs';
|
|
5
5
|
|
|
6
6
|
/** SDK-native content type for Google GenAI human messages */
|
|
7
7
|
type GoogleGenAIContent = string | Part[];
|
|
@@ -29,9 +29,7 @@ async function consumeStream(stream) {
|
|
|
29
29
|
event.resourceNotFoundException.message ?? "Resource not found"
|
|
30
30
|
);
|
|
31
31
|
if ("validationException" in event && event.validationException)
|
|
32
|
-
throw new Error(
|
|
33
|
-
event.validationException.message ?? "Validation error"
|
|
34
|
-
);
|
|
32
|
+
throw new Error(event.validationException.message ?? "Validation error");
|
|
35
33
|
if ("internalServerException" in event && event.internalServerException)
|
|
36
34
|
throw new Error(
|
|
37
35
|
event.internalServerException.message ?? "Internal server error"
|
|
@@ -54,6 +52,9 @@ var BedrockSandboxFileSystem = class {
|
|
|
54
52
|
this.sessionId = sessionId;
|
|
55
53
|
this.workspaceBase = path.posix.resolve("/", workspaceBase);
|
|
56
54
|
}
|
|
55
|
+
client;
|
|
56
|
+
codeInterpreterIdentifier;
|
|
57
|
+
sessionId;
|
|
57
58
|
workspaceBase;
|
|
58
59
|
/**
|
|
59
60
|
* Resolve a caller-supplied path to an absolute path within the workspace.
|
|
@@ -181,9 +182,7 @@ var BedrockSandboxFileSystem = class {
|
|
|
181
182
|
async mkdir(path, options) {
|
|
182
183
|
const norm = this.normalisePath(path);
|
|
183
184
|
const flag = options?.recursive ? "-p " : "";
|
|
184
|
-
const { exitCode, stderr } = await this.execShell(
|
|
185
|
-
`mkdir ${flag}"${norm}"`
|
|
186
|
-
);
|
|
185
|
+
const { exitCode, stderr } = await this.execShell(`mkdir ${flag}"${norm}"`);
|
|
187
186
|
if (exitCode !== 0) throw new Error(`mkdir failed: ${stderr}`);
|
|
188
187
|
}
|
|
189
188
|
async readdir(path) {
|
|
@@ -290,9 +289,7 @@ async function consumeExecStream(stream) {
|
|
|
290
289
|
event.resourceNotFoundException.message ?? "Resource not found"
|
|
291
290
|
);
|
|
292
291
|
if ("validationException" in event && event.validationException)
|
|
293
|
-
throw new Error(
|
|
294
|
-
event.validationException.message ?? "Validation error"
|
|
295
|
-
);
|
|
292
|
+
throw new Error(event.validationException.message ?? "Validation error");
|
|
296
293
|
if ("internalServerException" in event && event.internalServerException)
|
|
297
294
|
throw new Error(
|
|
298
295
|
event.internalServerException.message ?? "Internal server error"
|
|
@@ -321,6 +318,10 @@ var BedrockSandboxImpl = class {
|
|
|
321
318
|
workspaceBase
|
|
322
319
|
);
|
|
323
320
|
}
|
|
321
|
+
id;
|
|
322
|
+
client;
|
|
323
|
+
codeInterpreterIdentifier;
|
|
324
|
+
sessionId;
|
|
324
325
|
capabilities = {
|
|
325
326
|
filesystem: true,
|
|
326
327
|
execution: true,
|
|
@@ -342,8 +343,7 @@ var BedrockSandboxImpl = class {
|
|
|
342
343
|
arguments: { command: cmd }
|
|
343
344
|
})
|
|
344
345
|
);
|
|
345
|
-
if (!resp.stream)
|
|
346
|
-
throw new Error("No stream in code interpreter response");
|
|
346
|
+
if (!resp.stream) throw new Error("No stream in code interpreter response");
|
|
347
347
|
return consumeExecStream(resp.stream);
|
|
348
348
|
}
|
|
349
349
|
async destroy() {
|
|
@@ -446,6 +446,9 @@ var BedrockSandboxProvider = class {
|
|
|
446
446
|
async fork(_sandboxId) {
|
|
447
447
|
throw new SandboxNotSupportedError("fork");
|
|
448
448
|
}
|
|
449
|
+
async deleteSnapshot(_snapshot) {
|
|
450
|
+
throw new SandboxNotSupportedError("deleteSnapshot");
|
|
451
|
+
}
|
|
449
452
|
};
|
|
450
453
|
|
|
451
454
|
exports.BedrockSandboxFileSystem = BedrockSandboxFileSystem;
|