zeitlich 0.2.11 → 0.2.13

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 (46) hide show
  1. package/README.md +313 -126
  2. package/dist/adapters/langchain/index.cjs +270 -0
  3. package/dist/adapters/langchain/index.cjs.map +1 -0
  4. package/dist/adapters/langchain/index.d.cts +132 -0
  5. package/dist/adapters/langchain/index.d.ts +132 -0
  6. package/dist/adapters/langchain/index.js +265 -0
  7. package/dist/adapters/langchain/index.js.map +1 -0
  8. package/dist/index.cjs +89 -209
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +62 -46
  11. package/dist/index.d.ts +62 -46
  12. package/dist/index.js +88 -208
  13. package/dist/index.js.map +1 -1
  14. package/dist/{workflow-BhjsEQc1.d.cts → model-invoker-y_zlyMqu.d.cts} +45 -482
  15. package/dist/{workflow-BhjsEQc1.d.ts → model-invoker-y_zlyMqu.d.ts} +45 -482
  16. package/dist/thread-manager-qc0g5Rvd.d.cts +39 -0
  17. package/dist/thread-manager-qc0g5Rvd.d.ts +39 -0
  18. package/dist/workflow.cjs +59 -27
  19. package/dist/workflow.cjs.map +1 -1
  20. package/dist/workflow.d.cts +459 -6
  21. package/dist/workflow.d.ts +459 -6
  22. package/dist/workflow.js +60 -29
  23. package/dist/workflow.js.map +1 -1
  24. package/package.json +17 -2
  25. package/src/adapters/langchain/activities.ts +120 -0
  26. package/src/adapters/langchain/index.ts +38 -0
  27. package/src/adapters/langchain/model-invoker.ts +102 -0
  28. package/src/adapters/langchain/thread-manager.ts +142 -0
  29. package/src/index.ts +24 -23
  30. package/src/lib/fs.ts +25 -0
  31. package/src/lib/model-invoker.ts +15 -75
  32. package/src/lib/session.ts +52 -21
  33. package/src/lib/state-manager.ts +23 -5
  34. package/src/lib/thread-id.ts +25 -0
  35. package/src/lib/thread-manager.ts +18 -142
  36. package/src/lib/tool-router.ts +12 -18
  37. package/src/lib/types.ts +26 -10
  38. package/src/lib/workflow-helpers.ts +50 -0
  39. package/src/tools/ask-user-question/handler.ts +25 -1
  40. package/src/tools/bash/handler.ts +13 -0
  41. package/src/tools/subagent/handler.ts +16 -5
  42. package/src/tools/subagent/tool.ts +34 -15
  43. package/src/workflow.ts +26 -7
  44. package/tsup.config.ts +1 -0
  45. package/src/activities.ts +0 -91
  46. package/src/plugin.ts +0 -28
package/README.md CHANGED
@@ -29,39 +29,44 @@ Temporal solves these problems for workflows. Zeitlich brings these guarantees t
29
29
  - **Lifecycle hooks** — Pre/post tool execution, session start/end
30
30
  - **Subagent support** — Spawn child agents as Temporal child workflows
31
31
  - **Filesystem utilities** — In-memory or custom providers for file operations
32
- - **Model flexibility** — Use any LLM provider via LangChain
32
+ - **Model flexibility** — Framework-agnostic model invocation with adapters for LangChain (and more coming)
33
33
 
34
34
  ## LLM Integration
35
35
 
36
- Zeitlich uses [LangChain](https://js.langchain.com/) as the abstraction layer for LLM execution. This gives you:
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
+
38
+ ### LangChain Adapter (`zeitlich/adapters/langchain`)
39
+
40
+ The built-in LangChain adapter gives you:
37
41
 
38
42
  - **Provider flexibility** — Use Anthropic, OpenAI, Google, Azure, AWS Bedrock, or any LangChain-supported provider
39
43
  - **Consistent interface** — Same tool calling and message format regardless of provider
40
44
  - **Easy model swapping** — Change models without rewriting agent logic
41
- - **Soon** — Support native provider SDKs directly
42
45
 
43
46
  ```typescript
44
47
  import { ChatAnthropic } from "@langchain/anthropic";
45
- import { ChatOpenAI } from "@langchain/openai";
46
- import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
48
+ import { createLangChainAdapter } from "zeitlich/adapters/langchain";
49
+ import { createRunAgentActivity } from "zeitlich";
47
50
 
48
- // Use any LangChain chat model
49
- const anthropic = new ChatAnthropic({ model: "claude-sonnet-4-20250514" });
50
- const openai = new ChatOpenAI({ model: "gpt-4o" });
51
- const google = new ChatGoogleGenerativeAI({ model: "gemini-1.5-pro" });
51
+ const adapter = createLangChainAdapter({
52
+ redis,
53
+ model: new ChatAnthropic({ model: "claude-sonnet-4-20250514" }),
54
+ });
52
55
 
53
- // Pass to invokeModel in your activity
54
- return {
55
- runAgent: (config) => invokeModel({ config, model: anthropic, redis, client }),
56
- };
56
+ export function createActivities(client: WorkflowClient) {
57
+ return {
58
+ ...adapter.threadOps,
59
+ runAgent: createRunAgentActivity(client, adapter.invoker),
60
+ };
61
+ }
57
62
  ```
58
63
 
59
64
  Install the LangChain package for your chosen provider:
60
65
 
61
66
  ```bash
62
- npm install @langchain/anthropic # Anthropic
63
- npm install @langchain/openai # OpenAI
64
- npm install @langchain/google-genai # Google
67
+ npm install @langchain/core @langchain/anthropic # Anthropic
68
+ npm install @langchain/core @langchain/openai # OpenAI
69
+ npm install @langchain/core @langchain/google-genai # Google
65
70
  ```
66
71
 
67
72
  ## Installation
@@ -73,6 +78,7 @@ npm install zeitlich ioredis
73
78
  **Peer dependencies:**
74
79
 
75
80
  - `ioredis` >= 5.0.0
81
+ - `@langchain/core` >= 1.0.0 (optional — only needed when using `zeitlich/adapters/langchain`)
76
82
 
77
83
  **Required infrastructure:**
78
84
 
@@ -81,21 +87,37 @@ npm install zeitlich ioredis
81
87
 
82
88
  ## Import Paths
83
89
 
84
- Zeitlich provides two entry points to work with Temporal's workflow sandboxing:
90
+ Zeitlich provides three entry points:
85
91
 
86
92
  ```typescript
87
- // In workflow files - no external dependencies (Redis, LangChain, etc.)
93
+ // In workflow files no external dependencies (Redis, LangChain, etc.)
88
94
  import {
89
95
  createSession,
90
96
  createAgentStateManager,
91
97
  askUserQuestionTool,
98
+ bashTool,
99
+ defineTool,
100
+ type SubagentWorkflow,
101
+ type ModelInvoker,
92
102
  } from "zeitlich/workflow";
93
103
 
94
- // In activity files and worker setup - full functionality
95
- import { ZeitlichPlugin, invokeModel, toTree } from "zeitlich";
104
+ // In activity files and worker setup — framework-agnostic core
105
+ import {
106
+ createRunAgentActivity,
107
+ createBashHandler,
108
+ createAskUserQuestionHandler,
109
+ toTree,
110
+ } from "zeitlich";
111
+
112
+ // LangChain adapter — unified adapter for LLM invocation and thread management
113
+ import { createLangChainAdapter } from "zeitlich/adapters/langchain";
96
114
  ```
97
115
 
98
- **Why?** Temporal workflows run in an isolated V8 sandbox that cannot import modules with Node.js APIs or external dependencies. The `/workflow` entry point contains only pure TypeScript code safe for workflow use.
116
+ **Why three entry points?**
117
+
118
+ - `zeitlich/workflow` — Pure TypeScript, safe for Temporal's V8 sandbox
119
+ - `zeitlich` — Activity-side utilities (Redis, filesystem), framework-agnostic
120
+ - `zeitlich/adapters/langchain` — LangChain-specific adapter (model invocation + thread management)
99
121
 
100
122
  ## Examples
101
123
 
@@ -118,54 +140,28 @@ export const searchTool: ToolDefinition<"Search", typeof searchSchema> = {
118
140
  };
119
141
  ```
120
142
 
121
- ### 2. Create Activities
143
+ ### 2. Create the Workflow
122
144
 
123
- ```typescript
124
- import type Redis from "ioredis";
125
- import type { WorkflowClient } from "@temporalio/client";
126
- import { ChatAnthropic } from "@langchain/anthropic";
127
- import { invokeModel, type InvokeModelConfig } from "zeitlich";
128
-
129
- export const createActivities = ({
130
- redis,
131
- client,
132
- }: {
133
- redis: Redis;
134
- client: WorkflowClient;
135
- }) => {
136
- const model = new ChatAnthropic({
137
- model: "claude-sonnet-4-20250514",
138
- maxTokens: 4096,
139
- });
140
-
141
- return {
142
- runAgent: (config: InvokeModelConfig) =>
143
- invokeModel({ config, model, redis, client }),
144
-
145
- handleSearchResult: async ({ args }) => {
146
- const results = await performSearch(args.query);
147
- return { result: { results } };
148
- },
149
- };
150
- };
151
-
152
- export type MyActivities = ReturnType<typeof createActivities>;
153
- ```
154
-
155
- ### 3. Create the Workflow
145
+ The system prompt is set via `createAgentStateManager`'s `initialState`, and agent config fields (`agentName`, `maxTurns`, etc.) are spread into `createSession`.
156
146
 
157
147
  ```typescript
158
148
  import { proxyActivities, workflowInfo } from "@temporalio/workflow";
159
149
  import {
160
150
  createAgentStateManager,
161
151
  createSession,
152
+ askUserQuestionTool,
153
+ bashTool,
162
154
  defineTool,
163
- proxyDefaultThreadOps,
164
155
  } from "zeitlich/workflow";
165
156
  import { searchTool } from "./tools";
166
157
  import type { MyActivities } from "./activities";
167
158
 
168
- const { runAgent, handleSearchResult } = proxyActivities<MyActivities>({
159
+ const {
160
+ runAgentActivity,
161
+ searchHandlerActivity,
162
+ bashHandlerActivity,
163
+ askUserQuestionHandlerActivity,
164
+ } = proxyActivities<MyActivities>({
169
165
  startToCloseTimeout: "30m",
170
166
  retry: {
171
167
  maximumAttempts: 6,
@@ -179,51 +175,109 @@ const { runAgent, handleSearchResult } = proxyActivities<MyActivities>({
179
175
  export async function myAgentWorkflow({ prompt }: { prompt: string }) {
180
176
  const { runId } = workflowInfo();
181
177
 
182
- const stateManager = createAgentStateManager({});
178
+ const stateManager = createAgentStateManager({
179
+ initialState: {
180
+ systemPrompt: "You are a helpful assistant.",
181
+ },
182
+ agentName: "my-agent",
183
+ });
183
184
 
184
185
  const session = await createSession({
185
- threadId: runId,
186
186
  agentName: "my-agent",
187
187
  maxTurns: 20,
188
- systemPrompt: "You are a helpful assistant.",
189
- runAgent,
190
- threadOps: proxyDefaultThreadOps(),
188
+ threadId: runId,
189
+ runAgent: runAgentActivity,
191
190
  buildContextMessage: () => [{ type: "text", text: prompt }],
192
191
  tools: {
193
192
  Search: defineTool({
194
193
  ...searchTool,
195
- handler: handleSearchResult,
194
+ handler: searchHandlerActivity,
195
+ }),
196
+ AskUserQuestion: defineTool({
197
+ ...askUserQuestionTool,
198
+ handler: askUserQuestionHandlerActivity,
199
+ hooks: {
200
+ onPostToolUse: () => {
201
+ stateManager.waitForInput();
202
+ },
203
+ },
204
+ }),
205
+ Bash: defineTool({
206
+ ...bashTool,
207
+ handler: bashHandlerActivity,
196
208
  }),
197
209
  },
198
210
  });
199
211
 
200
- await session.runSession({ stateManager });
201
- return stateManager.getCurrentState();
212
+ const result = await session.runSession({ stateManager });
213
+ return result;
202
214
  }
203
215
  ```
204
216
 
217
+ ### 3. Create Activities
218
+
219
+ Activities are factory functions that receive infrastructure dependencies (`redis`, `client`). Each returns an object of activity functions registered with the Temporal worker.
220
+
221
+ ```typescript
222
+ import type Redis from "ioredis";
223
+ import type { WorkflowClient } from "@temporalio/client";
224
+ import { ChatAnthropic } from "@langchain/anthropic";
225
+ import {
226
+ createBashHandler,
227
+ createAskUserQuestionHandler,
228
+ createRunAgentActivity,
229
+ } from "zeitlich";
230
+ import { createLangChainAdapter } from "zeitlich/adapters/langchain";
231
+
232
+ export const createActivities = ({
233
+ redis,
234
+ client,
235
+ }: {
236
+ redis: Redis;
237
+ client: WorkflowClient;
238
+ }) => {
239
+ const { threadOps, invoker } = createLangChainAdapter({
240
+ redis,
241
+ model: new ChatAnthropic({
242
+ model: "claude-sonnet-4-20250514",
243
+ maxTokens: 4096,
244
+ }),
245
+ });
246
+
247
+ return {
248
+ ...threadOps,
249
+ runAgentActivity: createRunAgentActivity(client, invoker),
250
+ searchHandlerActivity: async (args: { query: string }) => ({
251
+ toolResponse: JSON.stringify(await performSearch(args.query)),
252
+ data: null,
253
+ }),
254
+ bashHandlerActivity: createBashHandler({ fs: inMemoryFileSystem }),
255
+ askUserQuestionHandlerActivity: createAskUserQuestionHandler(),
256
+ };
257
+ };
258
+
259
+ export type MyActivities = ReturnType<typeof createActivities>;
260
+ ```
261
+
205
262
  ### 4. Set Up the Worker
206
263
 
207
264
  ```typescript
208
265
  import { Worker, NativeConnection } from "@temporalio/worker";
209
- import { Client } from "@temporalio/client";
210
- import { ZeitlichPlugin } from "zeitlich";
211
266
  import Redis from "ioredis";
267
+ import { fileURLToPath } from "node:url";
212
268
  import { createActivities } from "./activities";
213
269
 
214
270
  async function run() {
215
271
  const connection = await NativeConnection.connect({
216
272
  address: "localhost:7233",
217
273
  });
218
- const client = new Client({ connection });
219
274
  const redis = new Redis({ host: "localhost", port: 6379 });
220
275
 
221
276
  const worker = await Worker.create({
222
- plugins: [new ZeitlichPlugin({ redis })],
223
277
  connection,
224
278
  taskQueue: "my-agent",
225
- workflowsPath: require.resolve("./workflows"),
226
- activities: createActivities({ redis, client: client.workflow }),
279
+ workflowsPath: fileURLToPath(new URL("./workflows.ts", import.meta.url)),
280
+ activities: createActivities({ redis, client }),
227
281
  });
228
282
 
229
283
  await worker.run();
@@ -234,13 +288,17 @@ async function run() {
234
288
 
235
289
  ### Agent State Manager
236
290
 
237
- Manages workflow state with automatic versioning and status tracking:
291
+ Manages workflow state with automatic versioning and status tracking. Requires `agentName` to register Temporal query/update handlers, and accepts an optional `initialState` for system prompt and custom fields:
238
292
 
239
293
  ```typescript
240
294
  import { createAgentStateManager } from "zeitlich/workflow";
241
295
 
242
296
  const stateManager = createAgentStateManager({
243
- customField: "value",
297
+ initialState: {
298
+ systemPrompt: "You are a helpful assistant.",
299
+ customField: "value",
300
+ },
301
+ agentName: "my-agent",
244
302
  });
245
303
 
246
304
  // State operations
@@ -310,63 +368,174 @@ const session = await createSession({
310
368
 
311
369
  ### Subagents
312
370
 
313
- Spawn child agents as Temporal child workflows:
371
+ Spawn child agents as Temporal child workflows. Each subagent is a workflow typed with `SubagentWorkflow` that returns `{ toolResponse, data }`:
314
372
 
315
373
  ```typescript
316
- // Define subagent workflows (each is a Temporal workflow that returns string | null)
374
+ import { proxyActivities, workflowInfo } from "@temporalio/workflow";
375
+ import {
376
+ createAgentStateManager,
377
+ createSession,
378
+ type SubagentWorkflow,
379
+ } from "zeitlich/workflow";
380
+ import { agentConfig } from "./config";
381
+ import type { createResearcherActivities } from "./activities";
382
+
383
+ const { runResearcherActivity } = proxyActivities<
384
+ ReturnType<typeof createResearcherActivities>
385
+ >({ startToCloseTimeout: "30m", heartbeatTimeout: "5m" });
386
+
387
+ // Subagent workflow typed as SubagentWorkflow
388
+ export const researcherSubagentWorkflow: SubagentWorkflow = async ({
389
+ prompt,
390
+ }) => {
391
+ const { runId } = workflowInfo();
392
+
393
+ const stateManager = createAgentStateManager({
394
+ initialState: { systemPrompt: agentConfig.systemPrompt },
395
+ agentName: agentConfig.agentName,
396
+ });
397
+
398
+ const session = await createSession({
399
+ ...agentConfig,
400
+ threadId: runId,
401
+ runAgent: runResearcherActivity,
402
+ buildContextMessage: () => [{ type: "text", text: prompt }],
403
+ });
404
+
405
+ const { finalMessage } = await session.runSession({ stateManager });
406
+ return {
407
+ toolResponse: finalMessage ? extractText(finalMessage) : "No response",
408
+ data: null,
409
+ };
410
+ };
411
+
412
+ // Register the subagent for the parent workflow
317
413
  export const researcherSubagent = {
318
- name: "researcher",
319
- description: "Researches topics and returns findings",
320
- workflow: researcherWorkflow,
414
+ agentName: agentConfig.agentName,
415
+ description: agentConfig.description,
416
+ workflow: researcherSubagentWorkflow,
321
417
  };
418
+ ```
419
+
420
+ In the parent workflow, pass subagents to `createSession`:
322
421
 
323
- // In the main agent workflow
422
+ ```typescript
324
423
  const session = await createSession({
325
424
  // ... other config
326
425
  subagents: [researcherSubagent, codeReviewerSubagent],
327
426
  });
328
427
  ```
329
428
 
330
- The `Task` tool is automatically added when subagents are configured, allowing the agent to spawn child workflows.
429
+ The `Subagent` tool is automatically added when subagents are configured, allowing the LLM to spawn child workflows.
331
430
 
332
- ### Filesystem Utilities
431
+ ### Thread Continuation
333
432
 
334
- Built-in support for file operations. Use `buildFileTree` to generate a file tree string that's included in the agent's context:
433
+ By default, each session initializes a fresh thread. To continue an existing thread (e.g., resuming a conversation after a workflow completes), pass `continueThread: true` along with the previous `threadId`:
335
434
 
336
435
  ```typescript
337
- // In activities
338
- export const createActivities = () => ({
339
- generateFileTree: async (): Promise<string> => {
340
- // Return a formatted file tree string
341
- return toTree("/path/to/workspace");
342
- },
343
- });
436
+ import { createSession } from "zeitlich/workflow";
344
437
 
345
- // In workflow
438
+ // First run — threadId defaults to getShortId() if omitted
346
439
  const session = await createSession({
440
+ // threadId is optional, auto-generated if not provided
441
+ // ... other config
442
+ });
443
+
444
+ // Later — new workflow picks up the same thread
445
+ const resumedSession = await createSession({
446
+ threadId: savedThreadId, // pass the ID from the first run
447
+ continueThread: true, // skip thread init + system prompt
347
448
  // ... other config
348
- buildFileTree: generateFileTree, // Called at session start
349
449
  });
350
450
  ```
351
451
 
352
- For more advanced file operations, use the built-in tool handler factories:
452
+ `getShortId()` produces compact, workflow-deterministic IDs (~12 base-62 chars) that are more token-efficient than UUIDs.
453
+
454
+ #### Subagent Thread Continuation
455
+
456
+ Subagents can opt in to thread continuation via `allowThreadContinuation`. When enabled, the parent agent can pass a `threadId` to resume a previous subagent conversation:
353
457
 
354
458
  ```typescript
355
- import { createGlobHandler, createEditHandler, toTree } from "zeitlich";
459
+ import { getShortId, type SubagentWorkflow } from "zeitlich/workflow";
356
460
 
357
- export const createActivities = () => ({
358
- generateFileTree: () => toTree("/workspace"),
359
- globHandlerActivity: createGlobHandler("/workspace"),
360
- editHandlerActivity: createEditHandler("/workspace"),
361
- });
461
+ // Subagent workflow that supports continuation
462
+ export const researcherWorkflow: SubagentWorkflow = async ({
463
+ prompt,
464
+ threadId,
465
+ }) => {
466
+ const effectiveThreadId = threadId ?? getShortId();
467
+
468
+ const session = await createSession({
469
+ threadId: effectiveThreadId,
470
+ continueThread: !!threadId,
471
+ // ... other config
472
+ });
473
+
474
+ const { finalMessage } = await session.runSession({ stateManager });
475
+ return {
476
+ toolResponse: finalMessage ? extractText(finalMessage) : "No response",
477
+ data: null,
478
+ threadId: effectiveThreadId,
479
+ };
480
+ };
481
+
482
+ // Register with allowThreadContinuation
483
+ export const researcherSubagent = {
484
+ agentName: "Researcher",
485
+ description: "Researches topics and gathers information",
486
+ workflow: researcherWorkflow,
487
+ allowThreadContinuation: true,
488
+ };
362
489
  ```
363
490
 
364
- `toTree` also accepts an in-memory filesystem object (e.g. from [`just-bash`](https://github.com/nicholasgasior/just-bash)):
491
+ 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.
492
+
493
+ ### Filesystem Utilities
494
+
495
+ Built-in support for file operations with in-memory or custom filesystem providers (e.g. from [`just-bash`](https://github.com/nicholasgasior/just-bash)).
496
+
497
+ `toTree` generates a file tree string from an `IFileSystem` instance:
365
498
 
366
499
  ```typescript
367
500
  import { toTree } from "zeitlich";
368
501
 
369
- const fileTree = toTree(inMemoryFileSystem);
502
+ // In activities - generate a file tree string for agent context
503
+ export const createActivities = ({ redis, client }) => ({
504
+ generateFileTreeActivity: async () => toTree(inMemoryFileSystem),
505
+ // ...
506
+ });
507
+ ```
508
+
509
+ Use the tree in `buildContextMessage` to give the agent filesystem awareness:
510
+
511
+ ```typescript
512
+ // In workflow
513
+ const fileTree = await generateFileTreeActivity();
514
+
515
+ const session = await createSession({
516
+ // ... other config
517
+ buildContextMessage: () => [
518
+ { type: "text", text: `Files in the filesystem: ${fileTree}` },
519
+ { type: "text", text: prompt },
520
+ ],
521
+ });
522
+ ```
523
+
524
+ For file operations, use the built-in tool handler factories. All handlers accept an `IFileSystem`:
525
+
526
+ ```typescript
527
+ import {
528
+ createGlobHandler,
529
+ createEditHandler,
530
+ createBashHandler,
531
+ } from "zeitlich";
532
+
533
+ export const createActivities = ({ redis, client }) => ({
534
+ generateFileTreeActivity: async () => toTree(inMemoryFileSystem),
535
+ globHandlerActivity: createGlobHandler(inMemoryFileSystem),
536
+ editHandlerActivity: createEditHandler(inMemoryFileSystem),
537
+ bashHandlerActivity: createBashHandler({ fs: inMemoryFileSystem }),
538
+ });
370
539
  ```
371
540
 
372
541
  ### Built-in Tools
@@ -429,33 +598,50 @@ const session = await createSession({
429
598
 
430
599
  Safe for use in Temporal workflow files:
431
600
 
432
- | Export | Description |
433
- | ------------------------- | ---------------------------------------------------------------------------------------------- |
434
- | `createSession` | Creates an agent session with tools, prompts, subagents, and hooks |
435
- | `createAgentStateManager` | Creates a state manager for workflow state |
436
- | `createToolRouter` | Creates a tool router (used internally by session, or for advanced use) |
437
- | `createTaskTool` | Creates the Task tool for subagent support |
438
- | Tool definitions | `askUserQuestionTool`, `globTool`, `grepTool`, `readTool`, `writeTool`, `editTool`, `bashTool` |
439
- | Task tools | `taskCreateTool`, `taskGetTool`, `taskListTool`, `taskUpdateTool` for workflow task management |
440
- | Types | All TypeScript types and interfaces |
601
+ | Export | Description |
602
+ | ------------------------- | ------------------------------------------------------------------------------------------------------ |
603
+ | `createSession` | Creates an agent session with tools, prompts, subagents, and hooks |
604
+ | `createAgentStateManager` | Creates a state manager for workflow state with query/update handlers |
605
+ | `createToolRouter` | Creates a tool router (used internally by session, or for advanced use) |
606
+ | `defineTool` | Identity function for type-safe tool definition with handler and hooks |
607
+ | `defineSubagent` | Identity function for type-safe subagent configuration |
608
+ | `getShortId` | Generate a compact, workflow-deterministic identifier (base-62, 12 chars) |
609
+ | `createSubagentTool` | Creates the Subagent tool for spawning child workflows |
610
+ | Tool definitions | `askUserQuestionTool`, `globTool`, `grepTool`, `readFileTool`, `writeFileTool`, `editTool`, `bashTool` |
611
+ | Task tools | `taskCreateTool`, `taskGetTool`, `taskListTool`, `taskUpdateTool` for workflow task management |
612
+ | Types | `SubagentWorkflow`, `ToolDefinition`, `ToolWithHandler`, `AgentConfig`, `SessionConfig`, etc. |
441
613
 
442
614
  ### Activity Entry Point (`zeitlich`)
443
615
 
444
- For use in activities, worker setup, and Node.js code:
616
+ Framework-agnostic utilities for activities, worker setup, and Node.js code:
617
+
618
+ | Export | Description |
619
+ | ------------------------- | --------------------------------------------------------------------------------------------- |
620
+ | `createRunAgentActivity` | Wraps a `ModelInvoker` into a `RunAgentActivity` with automatic tool loading |
621
+ | `createThreadManager` | Generic Redis-backed thread manager factory |
622
+ | `toTree` | Generate file tree string from an `IFileSystem` instance |
623
+ | Tool handlers | `createGlobHandler`, `createEditHandler`, `createBashHandler`, `createAskUserQuestionHandler` |
624
+
625
+ ### LangChain Adapter Entry Point (`zeitlich/adapters/langchain`)
445
626
 
446
- | Export | Description |
447
- | ------------------------ | --------------------------------------------------------------------------------- |
448
- | `ZeitlichPlugin` | Temporal worker plugin that registers shared activities |
449
- | `createSharedActivities` | Creates thread management activities |
450
- | `invokeModel` | Core LLM invocation utility (requires Redis + LangChain) |
451
- | `toTree` | Generate file tree string from a directory path |
452
- | Tool handlers | `createGlobHandler`, `createEditHandler`, `createBashHandler`, `createAskUserQuestionHandler` |
627
+ LangChain-specific implementations:
628
+
629
+ | Export | Description |
630
+ | ----------------------------------- | ---------------------------------------------------------------------- |
631
+ | `createLangChainAdapter` | Unified adapter returning `threadOps`, `invoker`, `createModelInvoker` |
632
+ | `createLangChainModelInvoker` | Factory that returns a `ModelInvoker` backed by a LangChain chat model |
633
+ | `invokeLangChainModel` | One-shot model invocation convenience function |
634
+ | `createLangChainThreadManager` | Thread manager with LangChain `StoredMessage` helpers |
453
635
 
454
636
  ### Types
455
637
 
456
638
  | Export | Description |
457
639
  | ----------------------- | ---------------------------------------------------------------------------- |
458
640
  | `AgentStatus` | `"RUNNING" \| "WAITING_FOR_INPUT" \| "COMPLETED" \| "FAILED" \| "CANCELLED"` |
641
+ | `MessageContent` | Framework-agnostic message content (`string \| ContentPart[]`) |
642
+ | `ToolMessageContent` | Content returned by a tool handler (`string`) |
643
+ | `ModelInvoker` | Generic model invocation contract |
644
+ | `ModelInvokerConfig` | Configuration passed to a model invoker |
459
645
  | `ToolDefinition` | Tool definition with name, description, and Zod schema |
460
646
  | `ToolWithHandler` | Tool definition combined with its handler |
461
647
  | `SubagentConfig` | Configuration for subagent workflows |
@@ -468,25 +654,26 @@ For use in activities, worker setup, and Node.js code:
468
654
  ┌─────────────────────────────────────────────────────────────────┐
469
655
  │ Temporal Worker │
470
656
  │ ┌──────────────────────────────────────────────────────────┐ │
471
- │ │ ZeitlichPlugin │ │
472
- │ │ • Registers shared activities (thread management) │ │
473
- │ └──────────────────────────────────────────────────────────┘ │
474
- │ │ │
475
- │ ┌──────────────────────────────────────────────────────────┐ │
476
- │ │ Workflow │ │
657
+ │ │ Workflow (zeitlich/workflow) │ │
477
658
  │ │ ┌────────────────┐ ┌───────────────────────────────┐ │ │
478
659
  │ │ │ State Manager │ │ Session │ │ │
479
660
  │ │ │ • Status │ │ • Agent loop │ │ │
480
661
  │ │ │ • Turns │ │ • Tool routing & hooks │ │ │
481
662
  │ │ │ • Custom state │ │ • Prompts (system, context) │ │ │
482
663
  │ │ └────────────────┘ │ • Subagent coordination │ │ │
483
- │ │ └───────────────────────────────────┘ │ │
664
+ │ │ └───────────────────────────────┘ │ │
484
665
  │ └──────────────────────────────────────────────────────────┘ │
485
666
  │ │ │
486
667
  │ ┌──────────────────────────────────────────────────────────┐ │
487
- │ │ Activities │ │
488
- │ │ • runAgent (LLM invocation) │ │
668
+ │ │ Activities (zeitlich) │ │
489
669
  │ │ • Tool handlers (search, file ops, bash, etc.) │ │
670
+ │ │ • Generic thread manager (BaseThreadManager<T>) │ │
671
+ │ └──────────────────────────────────────────────────────────┘ │
672
+ │ │ │
673
+ │ ┌──────────────────────────────────────────────────────────┐ │
674
+ │ │ LLM Adapter (zeitlich/adapters/langchain) │ │
675
+ │ │ • createLangChainAdapter (thread ops + model invoker) │ │
676
+ │ │ • createLangChainThreadManager (message helpers) │ │
490
677
  │ └──────────────────────────────────────────────────────────┘ │
491
678
  └─────────────────────────────────────────────────────────────────┘
492
679