zeitlich 0.2.38 → 0.2.39
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 +18 -0
- package/dist/{activities-BKhMtKDd.d.ts → activities-Bmu7XnaG.d.ts} +4 -6
- package/dist/{activities-CDcwkRZs.d.cts → activities-ByBFLvm2.d.cts} +4 -6
- package/dist/adapter-id-BB-mmrts.d.cts +17 -0
- package/dist/adapter-id-BB-mmrts.d.ts +17 -0
- package/dist/adapter-id-CMwVrVqv.d.cts +17 -0
- package/dist/adapter-id-CMwVrVqv.d.ts +17 -0
- package/dist/adapter-id-CbY2zeSt.d.cts +17 -0
- package/dist/adapter-id-CbY2zeSt.d.ts +17 -0
- package/dist/adapters/thread/anthropic/index.cjs +140 -23
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +8 -7
- package/dist/adapters/thread/anthropic/index.d.ts +8 -7
- package/dist/adapters/thread/anthropic/index.js +140 -24
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +8 -3
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +5 -4
- package/dist/adapters/thread/anthropic/workflow.d.ts +5 -4
- package/dist/adapters/thread/anthropic/workflow.js +8 -4
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +140 -23
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +5 -4
- package/dist/adapters/thread/google-genai/index.d.ts +5 -4
- package/dist/adapters/thread/google-genai/index.js +140 -24
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +8 -3
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +5 -4
- package/dist/adapters/thread/google-genai/workflow.d.ts +5 -4
- package/dist/adapters/thread/google-genai/workflow.js +8 -4
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/index.cjs +16 -0
- package/dist/adapters/thread/index.cjs.map +1 -0
- package/dist/adapters/thread/index.d.cts +34 -0
- package/dist/adapters/thread/index.d.ts +34 -0
- package/dist/adapters/thread/index.js +12 -0
- package/dist/adapters/thread/index.js.map +1 -0
- package/dist/adapters/thread/langchain/index.cjs +139 -24
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +8 -7
- package/dist/adapters/thread/langchain/index.d.ts +8 -7
- package/dist/adapters/thread/langchain/index.js +139 -25
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +8 -3
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +5 -4
- package/dist/adapters/thread/langchain/workflow.d.ts +5 -4
- package/dist/adapters/thread/langchain/workflow.js +8 -4
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +266 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +263 -49
- package/dist/index.js.map +1 -1
- package/dist/{proxy-D_3x7RN4.d.cts → proxy-BAKzNGRq.d.cts} +1 -1
- package/dist/{proxy-CUlKSvZS.d.ts → proxy-DO_MXbY4.d.ts} +1 -1
- package/dist/{thread-manager-CVu7o2cs.d.ts → thread-manager-CcRXasqs.d.ts} +2 -4
- package/dist/{thread-manager-HSwyh28L.d.cts → thread-manager-ClwSaUnj.d.cts} +2 -4
- package/dist/{thread-manager-c1gPopAG.d.ts → thread-manager-D-7lp1JK.d.ts} +2 -4
- package/dist/{thread-manager-wGi-LqIP.d.cts → thread-manager-Y8Ucf0Tf.d.cts} +2 -4
- package/dist/{types-C06FwR96.d.cts → types-Bcbiq8iv.d.cts} +162 -44
- package/dist/{types-BH_IRryz.d.ts → types-DpHTX-iO.d.ts} +54 -6
- package/dist/{types-DNr31FzL.d.ts → types-Dt8-HBBT.d.ts} +162 -44
- package/dist/{types-BaOw4hKI.d.cts → types-hFFi-Zd9.d.cts} +54 -6
- package/dist/{workflow-CSCkpwAL.d.ts → workflow-Bmf9EtDW.d.ts} +82 -2
- package/dist/{workflow-DuvMZ8Vm.d.cts → workflow-Bx9utBwb.d.cts} +82 -2
- package/dist/workflow.cjs +188 -37
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +2 -2
- package/dist/workflow.d.ts +2 -2
- package/dist/workflow.js +185 -38
- package/dist/workflow.js.map +1 -1
- package/package.json +11 -1
- package/src/adapters/thread/adapter-id.test.ts +42 -0
- package/src/adapters/thread/anthropic/activities.ts +33 -7
- package/src/adapters/thread/anthropic/adapter-id.ts +16 -0
- package/src/adapters/thread/anthropic/fork-transform.test.ts +291 -0
- package/src/adapters/thread/anthropic/index.ts +3 -0
- package/src/adapters/thread/anthropic/model-invoker.ts +8 -4
- package/src/adapters/thread/anthropic/proxy.ts +3 -2
- package/src/adapters/thread/anthropic/thread-manager.ts +27 -4
- package/src/adapters/thread/google-genai/activities.ts +33 -7
- package/src/adapters/thread/google-genai/adapter-id.ts +16 -0
- package/src/adapters/thread/google-genai/fork-transform.test.ts +149 -0
- package/src/adapters/thread/google-genai/index.ts +3 -0
- package/src/adapters/thread/google-genai/model-invoker.ts +7 -3
- package/src/adapters/thread/google-genai/proxy.ts +3 -2
- package/src/adapters/thread/google-genai/thread-manager.ts +27 -4
- package/src/adapters/thread/index.ts +39 -0
- package/src/adapters/thread/langchain/activities.ts +33 -7
- package/src/adapters/thread/langchain/adapter-id.ts +16 -0
- package/src/adapters/thread/langchain/fork-transform.test.ts +142 -0
- package/src/adapters/thread/langchain/index.ts +3 -0
- package/src/adapters/thread/langchain/model-invoker.ts +8 -3
- package/src/adapters/thread/langchain/proxy.ts +3 -2
- package/src/adapters/thread/langchain/thread-manager.ts +27 -4
- package/src/lib/lifecycle.ts +3 -1
- package/src/lib/model/types.ts +7 -10
- package/src/lib/session/session-edge-cases.integration.test.ts +131 -63
- package/src/lib/session/session.integration.test.ts +174 -5
- package/src/lib/session/session.ts +68 -28
- package/src/lib/session/types.ts +60 -9
- package/src/lib/state/index.ts +1 -0
- package/src/lib/state/manager.integration.test.ts +109 -0
- package/src/lib/state/manager.ts +38 -8
- package/src/lib/state/types.ts +25 -0
- package/src/lib/subagent/handler.ts +124 -11
- package/src/lib/subagent/index.ts +5 -1
- package/src/lib/subagent/subagent.integration.test.ts +528 -0
- package/src/lib/subagent/types.ts +63 -14
- package/src/lib/subagent/workflow.ts +29 -2
- package/src/lib/thread/index.ts +5 -0
- package/src/lib/thread/keys.test.ts +101 -0
- package/src/lib/thread/keys.ts +94 -0
- package/src/lib/thread/manager.test.ts +139 -0
- package/src/lib/thread/manager.ts +92 -14
- package/src/lib/thread/proxy.ts +2 -0
- package/src/lib/thread/types.ts +60 -6
- package/src/lib/tool-router/types.ts +16 -8
- package/src/lib/types.ts +12 -0
- package/src/workflow.ts +12 -1
- package/tsup.config.ts +1 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { as as ToolMap, a1 as SessionConfig, aD as ZeitlichSession, $ as SandboxShutdown, ak as ThreadInit, _ as SandboxInit, u as JsonSerializable, B as BaseAgentState, p as AgentStateManager, aF as ToolRouterOptions, av as ToolRouter, R as RouterContext, J as JsonValue, ax as ToolWithHandler, w as ParsedToolCallUnion, at as ToolNames, aa as SubagentDefinition, ad as SubagentHooks, ae as SubagentSandboxConfig, a9 as SubagentConfig, af as SubagentSandboxShutdown, ag as SubagentSessionInput, ab as SubagentFnResult, a6 as SessionStartHook, a2 as SessionEndHook, E as PostToolUseHook, z as PostToolUseFailureHook, a4 as SessionExitReason, al as TokenUsage, f as RunAgentConfig, A as AgentResponse, F as FileEntryMetadata, az as VirtualFileTree, k as TreeMutation, s as FileEntry, aA as VirtualFsOps, h as SkillMetadata, i as Skill, c as ToolHandlerResponse, aq as ToolHandler, aC as WorkflowTask, d as ActivityToolHandler } from './types-Bcbiq8iv.cjs';
|
|
2
2
|
import { g as SandboxOps } from './types-yx0LzPGn.cjs';
|
|
3
3
|
import z$1, { z } from 'zod';
|
|
4
4
|
import { Sinks, proxyActivities } from '@temporalio/workflow';
|
|
@@ -97,6 +97,68 @@ declare function defineWorkflow<TInput, TResult>(config: WorkflowConfig, fn: (in
|
|
|
97
97
|
*/
|
|
98
98
|
declare function getShortId(length?: number): string;
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Public helpers for zeitlich's Redis thread storage layout.
|
|
102
|
+
*
|
|
103
|
+
* These are the exact string-building primitives zeitlich's internal thread
|
|
104
|
+
* manager uses for every adapter. Downstream consumers that need to read a
|
|
105
|
+
* persisted thread (for evaluation, observability, admin tooling, etc.)
|
|
106
|
+
* should use these helpers rather than reconstructing the key layout by
|
|
107
|
+
* hand — the layout is versioned with this module, so upgrading zeitlich
|
|
108
|
+
* keeps the consumer in sync.
|
|
109
|
+
*
|
|
110
|
+
* The layout is adapter-agnostic: every thread adapter stores messages the
|
|
111
|
+
* same way.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* import {
|
|
116
|
+
* getThreadListKey,
|
|
117
|
+
* getThreadMetaKey,
|
|
118
|
+
* THREAD_TTL_SECONDS,
|
|
119
|
+
* } from 'zeitlich';
|
|
120
|
+
*
|
|
121
|
+
* const listKey = getThreadListKey('messages', threadId);
|
|
122
|
+
* const metaKey = getThreadMetaKey('messages', threadId);
|
|
123
|
+
* const ttl = await redis.ttl(listKey); // <= THREAD_TTL_SECONDS
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
/**
|
|
127
|
+
* TTL (in seconds) applied to every thread list and thread meta key that
|
|
128
|
+
* zeitlich's {@link createThreadManager} writes. Exposed so downstream
|
|
129
|
+
* consumers can size their Redis retention / query windows to match.
|
|
130
|
+
*
|
|
131
|
+
* Current value: 90 days.
|
|
132
|
+
*/
|
|
133
|
+
declare const THREAD_TTL_SECONDS: number;
|
|
134
|
+
/**
|
|
135
|
+
* Build the Redis list key that holds a thread's serialized messages.
|
|
136
|
+
*
|
|
137
|
+
* Mirrors the exact key used internally by zeitlich's thread manager,
|
|
138
|
+
* so a consumer calling `redis.lrange(getThreadListKey(key, id), 0, -1)`
|
|
139
|
+
* sees the same data the writer wrote.
|
|
140
|
+
*
|
|
141
|
+
* @param threadKey - Thread key (defaults to `"messages"` inside the
|
|
142
|
+
* thread manager, but downstream adapters may pass
|
|
143
|
+
* their own value).
|
|
144
|
+
* @param threadId - Thread id as provided to the thread manager.
|
|
145
|
+
*/
|
|
146
|
+
declare function getThreadListKey(threadKey: string, threadId: string): string;
|
|
147
|
+
/**
|
|
148
|
+
* Build the Redis key that stores a thread's existence marker / metadata.
|
|
149
|
+
*
|
|
150
|
+
* Zeitlich treats the presence of this key as "thread has been
|
|
151
|
+
* initialized"; append/load/fork/truncate operations fail when it is
|
|
152
|
+
* missing. Consumers can use it as a cheap existence probe without
|
|
153
|
+
* scanning the message list.
|
|
154
|
+
*
|
|
155
|
+
* @param threadKey - Thread key (defaults to `"messages"` inside the
|
|
156
|
+
* thread manager, but downstream adapters may pass
|
|
157
|
+
* their own value).
|
|
158
|
+
* @param threadId - Thread id as provided to the thread manager.
|
|
159
|
+
*/
|
|
160
|
+
declare function getThreadMetaKey(threadKey: string, threadId: string): string;
|
|
161
|
+
|
|
100
162
|
/**
|
|
101
163
|
* Creates an agent state manager for tracking workflow state.
|
|
102
164
|
* Automatically registers Temporal query and update handlers for the agent.
|
|
@@ -194,6 +256,22 @@ type SubagentArgs = {
|
|
|
194
256
|
threadId?: string | null;
|
|
195
257
|
};
|
|
196
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Default `workflowRunTimeout` applied to every subagent child workflow
|
|
261
|
+
* unless overridden via `SubagentConfig.workflowOptions.workflowRunTimeout`.
|
|
262
|
+
*
|
|
263
|
+
* Chosen as a safety bound: Temporal retries failing workflow tasks forever
|
|
264
|
+
* by default, so a child that fails to initialize (e.g. missing workflow
|
|
265
|
+
* export) or is otherwise broken will never reach a terminal state on its
|
|
266
|
+
* own and the parent's `Subagent` tool call would hang indefinitely. A
|
|
267
|
+
* bounded run timeout guarantees the child is eventually terminated and the
|
|
268
|
+
* parent receives a structured `ChildWorkflowFailure` it can surface to the
|
|
269
|
+
* agent. One hour is generous enough for realistic agent sessions while
|
|
270
|
+
* still catching hangs; agents that legitimately need longer should set an
|
|
271
|
+
* explicit `workflowOptions.workflowRunTimeout`.
|
|
272
|
+
*/
|
|
273
|
+
declare const DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT = "1h";
|
|
274
|
+
|
|
197
275
|
/**
|
|
198
276
|
* Creates a `SubagentConfig` from a `SubagentDefinition` (returned by `defineSubagentWorkflow`).
|
|
199
277
|
* Metadata (name, description, resultSchema) is read from the definition — only configure
|
|
@@ -264,6 +342,8 @@ declare function defineSubagent<TResult extends z.ZodType = z.ZodType, TContext
|
|
|
264
342
|
* });
|
|
265
343
|
*
|
|
266
344
|
* const { finalMessage, threadId } = await session.runSession({ stateManager });
|
|
345
|
+
* // `sandboxId`, `snapshot`, and `baseSnapshot` are auto-forwarded
|
|
346
|
+
* // from the session — no need to thread them through manually.
|
|
267
347
|
* return { toolResponse: finalMessage ?? "No response", data: null, threadId };
|
|
268
348
|
* },
|
|
269
349
|
* );
|
|
@@ -775,4 +855,4 @@ declare const createAskUserQuestionHandler: () => ActivityToolHandler<AskUserQue
|
|
|
775
855
|
}[];
|
|
776
856
|
}>;
|
|
777
857
|
|
|
778
|
-
export {
|
|
858
|
+
export { hasDirectory as $, type AskUserQuestionArgs as A, type BashArgs as B, createTaskGetHandler as C, DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT as D, createTaskListHandler as E, type FileEditArgs as F, type GlobArgs as G, createTaskUpdateHandler as H, createToolRouter as I, defineSubagent as J, defineSubagentWorkflow as K, defineTool as L, defineWorkflow as M, editTool as N, type ObservabilityHooks as O, filesWithMimeType as P, formatVirtualFileTree as Q, type ReadSkillArgs as R, type SessionEndedEvent as S, THREAD_TTL_SECONDS as T, getShortId as U, getThreadListKey as V, type WorkflowConfig as W, getThreadMetaKey as X, globTool as Y, type ZeitlichObservabilitySinks as Z, grepTool as _, type FileReadArgs as a, hasFileWithMimeType as a0, hasNoOtherToolCalls as a1, parseSkillFile as a2, proxyRunAgent as a3, proxyVirtualFsOps as a4, readFileTool as a5, taskCreateTool as a6, taskGetTool as a7, taskListTool as a8, taskUpdateTool as a9, writeFileTool as aa, type FileWriteArgs as b, type FileTreeAccessor as c, type GrepArgs as d, type SessionStartedEvent as e, type SubagentArgs as f, type TaskCreateArgs as g, type TaskGetArgs as h, type TaskListArgs as i, type TaskUpdateArgs as j, type ToolExecutedEvent as k, type TurnCompletedEvent as l, type WorkflowInput as m, type WorkflowSessionInput as n, applyVirtualTreeMutations as o, askUserQuestionTool as p, bashTool as q, composeHooks as r, createAgentStateManager as s, createAskUserQuestionHandler as t, createBashToolDescription as u, createObservabilityHooks as v, createReadSkillHandler as w, createReadSkillTool as x, createSession as y, createTaskCreateHandler as z };
|
package/dist/workflow.cjs
CHANGED
|
@@ -440,6 +440,7 @@ function createSubagentTool(subagents) {
|
|
|
440
440
|
var childSandboxReadySignal = workflow.defineSignal("childSandboxReady");
|
|
441
441
|
|
|
442
442
|
// src/lib/subagent/handler.ts
|
|
443
|
+
var DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT = "1h";
|
|
443
444
|
function resolveSandboxConfig(config) {
|
|
444
445
|
if (!config || config === "none") {
|
|
445
446
|
return { source: "none", init: "per-call", continuation: "fork" };
|
|
@@ -471,17 +472,28 @@ function createSubagentHandler(subagents) {
|
|
|
471
472
|
const threadSandboxes = /* @__PURE__ */ new Map();
|
|
472
473
|
const persistentSandboxes = /* @__PURE__ */ new Map();
|
|
473
474
|
const persistentSandboxCreating = /* @__PURE__ */ new Set();
|
|
475
|
+
const persistentSandboxCreationError = /* @__PURE__ */ new Map();
|
|
474
476
|
const lazyCreatorAgent = /* @__PURE__ */ new Map();
|
|
477
|
+
const snapshotBaseCreatorAgent = /* @__PURE__ */ new Map();
|
|
475
478
|
const threadSnapshots = /* @__PURE__ */ new Map();
|
|
476
479
|
const persistentBaseSnapshot = /* @__PURE__ */ new Map();
|
|
477
480
|
const persistentBaseSnapshotCreating = /* @__PURE__ */ new Set();
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
lazyCreatorAgent.
|
|
481
|
+
const persistentBaseSnapshotCreationError = /* @__PURE__ */ new Map();
|
|
482
|
+
workflow.setHandler(
|
|
483
|
+
childSandboxReadySignal,
|
|
484
|
+
({ childWorkflowId, sandboxId, baseSnapshot }) => {
|
|
485
|
+
const lazyAgent = lazyCreatorAgent.get(childWorkflowId);
|
|
486
|
+
if (lazyAgent && !persistentSandboxes.has(lazyAgent)) {
|
|
487
|
+
persistentSandboxes.set(lazyAgent, sandboxId);
|
|
488
|
+
lazyCreatorAgent.delete(childWorkflowId);
|
|
489
|
+
}
|
|
490
|
+
const snapAgent = snapshotBaseCreatorAgent.get(childWorkflowId);
|
|
491
|
+
if (snapAgent && baseSnapshot && !persistentBaseSnapshot.has(snapAgent)) {
|
|
492
|
+
persistentBaseSnapshot.set(snapAgent, baseSnapshot);
|
|
493
|
+
snapshotBaseCreatorAgent.delete(childWorkflowId);
|
|
494
|
+
}
|
|
483
495
|
}
|
|
484
|
-
|
|
496
|
+
);
|
|
485
497
|
const handler = async (args, context) => {
|
|
486
498
|
const config = subagents.find((s) => s.agentName === args.subagent);
|
|
487
499
|
if (!config) {
|
|
@@ -537,8 +549,20 @@ function createSubagentHandler(subagents) {
|
|
|
537
549
|
baseSnap = persistentBaseSnapshot.get(config.agentName);
|
|
538
550
|
if (!baseSnap) {
|
|
539
551
|
if (persistentBaseSnapshotCreating.has(config.agentName)) {
|
|
540
|
-
await workflow.condition(
|
|
552
|
+
await workflow.condition(
|
|
553
|
+
() => persistentBaseSnapshot.has(config.agentName) || persistentBaseSnapshotCreationError.has(config.agentName) || !persistentBaseSnapshotCreating.has(config.agentName)
|
|
554
|
+
);
|
|
555
|
+
const creatorErr = persistentBaseSnapshotCreationError.get(
|
|
556
|
+
config.agentName
|
|
557
|
+
);
|
|
558
|
+
if (creatorErr !== void 0) {
|
|
559
|
+
throw creatorErr;
|
|
560
|
+
}
|
|
541
561
|
baseSnap = persistentBaseSnapshot.get(config.agentName);
|
|
562
|
+
if (!baseSnap) {
|
|
563
|
+
persistentBaseSnapshotCreating.add(config.agentName);
|
|
564
|
+
isSnapshotBaseCreator = true;
|
|
565
|
+
}
|
|
542
566
|
} else {
|
|
543
567
|
persistentBaseSnapshotCreating.add(config.agentName);
|
|
544
568
|
isSnapshotBaseCreator = true;
|
|
@@ -556,8 +580,20 @@ function createSubagentHandler(subagents) {
|
|
|
556
580
|
baseSandboxId = persistentSandboxes.get(config.agentName);
|
|
557
581
|
if (!baseSandboxId) {
|
|
558
582
|
if (persistentSandboxCreating.has(config.agentName)) {
|
|
559
|
-
await workflow.condition(
|
|
583
|
+
await workflow.condition(
|
|
584
|
+
() => persistentSandboxes.has(config.agentName) || persistentSandboxCreationError.has(config.agentName) || !persistentSandboxCreating.has(config.agentName)
|
|
585
|
+
);
|
|
586
|
+
const creatorErr = persistentSandboxCreationError.get(
|
|
587
|
+
config.agentName
|
|
588
|
+
);
|
|
589
|
+
if (creatorErr !== void 0) {
|
|
590
|
+
throw creatorErr;
|
|
591
|
+
}
|
|
560
592
|
baseSandboxId = persistentSandboxes.get(config.agentName);
|
|
593
|
+
if (!baseSandboxId) {
|
|
594
|
+
persistentSandboxCreating.add(config.agentName);
|
|
595
|
+
isLazyCreator = true;
|
|
596
|
+
}
|
|
561
597
|
} else {
|
|
562
598
|
persistentSandboxCreating.add(config.agentName);
|
|
563
599
|
isLazyCreator = true;
|
|
@@ -586,6 +622,12 @@ function createSubagentHandler(subagents) {
|
|
|
586
622
|
};
|
|
587
623
|
const resolvedContext = config.context === void 0 ? void 0 : typeof config.context === "function" ? config.context() : config.context;
|
|
588
624
|
const childOpts = {
|
|
625
|
+
// Apply a bounded run timeout by default so a child workflow that
|
|
626
|
+
// fails to initialize or otherwise never reaches a terminal state
|
|
627
|
+
// cannot hang the parent's `Subagent` tool call forever. Callers can
|
|
628
|
+
// raise, lower, or disable it via `workflowOptions.workflowRunTimeout`.
|
|
629
|
+
workflowRunTimeout: DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT,
|
|
630
|
+
...config.workflowOptions ?? {},
|
|
589
631
|
workflowId: childWorkflowId,
|
|
590
632
|
args: resolvedContext === void 0 ? [args.prompt, workflowInput] : [args.prompt, workflowInput, resolvedContext],
|
|
591
633
|
taskQueue: config.taskQueue ?? parentTaskQueue
|
|
@@ -593,13 +635,39 @@ function createSubagentHandler(subagents) {
|
|
|
593
635
|
if (isLazyCreator) {
|
|
594
636
|
lazyCreatorAgent.set(childWorkflowId, config.agentName);
|
|
595
637
|
}
|
|
638
|
+
if (isSnapshotBaseCreator) {
|
|
639
|
+
snapshotBaseCreatorAgent.set(childWorkflowId, config.agentName);
|
|
640
|
+
}
|
|
596
641
|
workflow.log.info("subagent spawned", {
|
|
597
642
|
subagent: config.agentName,
|
|
598
643
|
childWorkflowId,
|
|
599
644
|
threadMode,
|
|
600
645
|
sandboxSource: sandboxCfg.source
|
|
601
646
|
});
|
|
602
|
-
|
|
647
|
+
let childResult;
|
|
648
|
+
try {
|
|
649
|
+
childResult = await workflow.executeChild(
|
|
650
|
+
config.workflow,
|
|
651
|
+
childOpts
|
|
652
|
+
);
|
|
653
|
+
} catch (err) {
|
|
654
|
+
workflow.log.warn("subagent failed", {
|
|
655
|
+
subagent: config.agentName,
|
|
656
|
+
childWorkflowId,
|
|
657
|
+
error: err instanceof Error ? err.message : String(err)
|
|
658
|
+
});
|
|
659
|
+
if (isLazyCreator) {
|
|
660
|
+
persistentSandboxCreating.delete(config.agentName);
|
|
661
|
+
persistentSandboxCreationError.set(config.agentName, err);
|
|
662
|
+
lazyCreatorAgent.delete(childWorkflowId);
|
|
663
|
+
}
|
|
664
|
+
if (isSnapshotBaseCreator) {
|
|
665
|
+
persistentBaseSnapshotCreating.delete(config.agentName);
|
|
666
|
+
persistentBaseSnapshotCreationError.set(config.agentName, err);
|
|
667
|
+
snapshotBaseCreatorAgent.delete(childWorkflowId);
|
|
668
|
+
}
|
|
669
|
+
throw err;
|
|
670
|
+
}
|
|
603
671
|
const effectiveShutdown = sandboxShutdownOverride ?? sandboxCfg.shutdown ?? "destroy";
|
|
604
672
|
workflow.log.info("subagent completed", {
|
|
605
673
|
subagent: config.agentName,
|
|
@@ -643,10 +711,13 @@ function createSubagentHandler(subagents) {
|
|
|
643
711
|
}
|
|
644
712
|
if (isLazyCreator) {
|
|
645
713
|
persistentSandboxCreating.delete(config.agentName);
|
|
714
|
+
persistentSandboxCreationError.delete(config.agentName);
|
|
646
715
|
lazyCreatorAgent.delete(childWorkflowId);
|
|
647
716
|
}
|
|
648
717
|
if (isSnapshotBaseCreator) {
|
|
649
718
|
persistentBaseSnapshotCreating.delete(config.agentName);
|
|
719
|
+
persistentBaseSnapshotCreationError.delete(config.agentName);
|
|
720
|
+
snapshotBaseCreatorAgent.delete(childWorkflowId);
|
|
650
721
|
}
|
|
651
722
|
if (!toolResponse) {
|
|
652
723
|
return {
|
|
@@ -889,6 +960,7 @@ async function createSession({
|
|
|
889
960
|
sandbox: sandboxInit,
|
|
890
961
|
sandboxShutdown = "destroy",
|
|
891
962
|
onSandboxReady,
|
|
963
|
+
onSessionExit,
|
|
892
964
|
virtualFs: virtualFsConfig,
|
|
893
965
|
virtualFsOps
|
|
894
966
|
}) {
|
|
@@ -914,7 +986,8 @@ async function createSession({
|
|
|
914
986
|
appendSystemMessage,
|
|
915
987
|
appendAgentMessage,
|
|
916
988
|
forkThread,
|
|
917
|
-
|
|
989
|
+
loadThreadState,
|
|
990
|
+
saveThreadState
|
|
918
991
|
} = threadOps;
|
|
919
992
|
const plugins = [];
|
|
920
993
|
let destroySubagentSandboxes;
|
|
@@ -1042,7 +1115,10 @@ async function createSession({
|
|
|
1042
1115
|
baseSnapshot = await sandboxOps.snapshotSandbox(sandboxId);
|
|
1043
1116
|
}
|
|
1044
1117
|
if (sandboxId && sandboxOwned && onSandboxReady) {
|
|
1045
|
-
onSandboxReady(
|
|
1118
|
+
onSandboxReady({
|
|
1119
|
+
sandboxId,
|
|
1120
|
+
...baseSnapshot && { baseSnapshot }
|
|
1121
|
+
});
|
|
1046
1122
|
}
|
|
1047
1123
|
if (virtualFsConfig) {
|
|
1048
1124
|
if (!virtualFsOps) {
|
|
@@ -1085,9 +1161,20 @@ async function createSession({
|
|
|
1085
1161
|
});
|
|
1086
1162
|
const sessionStartMs = Date.now();
|
|
1087
1163
|
const systemPrompt = stateManager.getSystemPrompt();
|
|
1164
|
+
const rehydrateFromSlice = (slice) => {
|
|
1165
|
+
stateManager.mergeUpdate({
|
|
1166
|
+
tasks: new Map(slice.tasks),
|
|
1167
|
+
...slice.custom
|
|
1168
|
+
});
|
|
1169
|
+
};
|
|
1088
1170
|
if (threadMode === "fork" && sourceThreadId) {
|
|
1089
1171
|
await forkThread(sourceThreadId, threadId, threadKey);
|
|
1090
|
-
|
|
1172
|
+
const forkedSlice = await loadThreadState(threadId, threadKey);
|
|
1173
|
+
if (forkedSlice) rehydrateFromSlice(forkedSlice);
|
|
1174
|
+
} else if (threadMode === "continue") {
|
|
1175
|
+
const continuedSlice = await loadThreadState(threadId, threadKey);
|
|
1176
|
+
if (continuedSlice) rehydrateFromSlice(continuedSlice);
|
|
1177
|
+
} else {
|
|
1091
1178
|
if (appendSystemPrompt) {
|
|
1092
1179
|
if (systemPrompt == null || typeof systemPrompt === "string" && systemPrompt.trim() === "") {
|
|
1093
1180
|
throw workflow.ApplicationFailure.create({
|
|
@@ -1109,24 +1196,21 @@ async function createSession({
|
|
|
1109
1196
|
let exitReason = "completed";
|
|
1110
1197
|
let finalMessage = null;
|
|
1111
1198
|
try {
|
|
1199
|
+
let assistantId;
|
|
1112
1200
|
while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
|
|
1113
1201
|
stateManager.incrementTurns();
|
|
1114
1202
|
const currentTurn = stateManager.getTurns();
|
|
1115
1203
|
workflow.log.debug("turn started", { agentName, threadId, turn: currentTurn });
|
|
1116
1204
|
stateManager.setTools(toolRouter.getToolDefinitions());
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
rawToolCalls,
|
|
1120
|
-
usage,
|
|
1121
|
-
threadLengthAtCall
|
|
1122
|
-
} = await runAgent({
|
|
1205
|
+
assistantId ??= workflow.uuid4();
|
|
1206
|
+
const { message, rawToolCalls, usage } = await runAgent({
|
|
1123
1207
|
threadId,
|
|
1124
1208
|
threadKey,
|
|
1125
1209
|
agentName,
|
|
1126
|
-
metadata
|
|
1210
|
+
metadata,
|
|
1211
|
+
assistantMessageId: assistantId
|
|
1127
1212
|
});
|
|
1128
|
-
|
|
1129
|
-
await appendAgentMessage(threadId, workflow.uuid4(), message, threadKey);
|
|
1213
|
+
await appendAgentMessage(threadId, assistantId, message, threadKey);
|
|
1130
1214
|
if (usage) {
|
|
1131
1215
|
stateManager.updateUsage(usage);
|
|
1132
1216
|
}
|
|
@@ -1180,15 +1264,9 @@ async function createSession({
|
|
|
1180
1264
|
toolCallId: rewind.toolCallId,
|
|
1181
1265
|
toolName: rewind.toolName
|
|
1182
1266
|
});
|
|
1183
|
-
if (preAssistantLength === void 0) {
|
|
1184
|
-
throw workflow.ApplicationFailure.create({
|
|
1185
|
-
message: "Rewind requested but runAgent did not report `threadLengthAtCall`; the adapter must populate it to support rewinds.",
|
|
1186
|
-
nonRetryable: true
|
|
1187
|
-
});
|
|
1188
|
-
}
|
|
1189
|
-
await truncateThread(threadId, preAssistantLength, threadKey);
|
|
1190
1267
|
continue;
|
|
1191
1268
|
}
|
|
1269
|
+
assistantId = void 0;
|
|
1192
1270
|
if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
|
|
1193
1271
|
const conditionMet = await workflow.condition(
|
|
1194
1272
|
() => stateManager.getStatus() === "RUNNING",
|
|
@@ -1221,6 +1299,19 @@ async function createSession({
|
|
|
1221
1299
|
});
|
|
1222
1300
|
throw workflow.ApplicationFailure.fromError(error);
|
|
1223
1301
|
} finally {
|
|
1302
|
+
try {
|
|
1303
|
+
await saveThreadState(
|
|
1304
|
+
threadId,
|
|
1305
|
+
stateManager.getPersistedSlice(),
|
|
1306
|
+
threadKey
|
|
1307
|
+
);
|
|
1308
|
+
} catch (persistError) {
|
|
1309
|
+
workflow.log.warn("failed to persist thread state", {
|
|
1310
|
+
agentName,
|
|
1311
|
+
threadId,
|
|
1312
|
+
error: persistError instanceof Error ? persistError.message : String(persistError)
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1224
1315
|
await callSessionEnd(exitReason, stateManager.getTurns());
|
|
1225
1316
|
if (sandboxOwned && sandboxId && sandboxOps) {
|
|
1226
1317
|
switch (sandboxShutdown) {
|
|
@@ -1257,6 +1348,12 @@ async function createSession({
|
|
|
1257
1348
|
...baseSnapshot && { hasBaseSnapshot: true },
|
|
1258
1349
|
...exitSnapshot && { hasExitSnapshot: true }
|
|
1259
1350
|
});
|
|
1351
|
+
if (onSessionExit) {
|
|
1352
|
+
onSessionExit({
|
|
1353
|
+
...sandboxId && { sandboxId },
|
|
1354
|
+
...exitSnapshot && { snapshot: exitSnapshot }
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1260
1357
|
return {
|
|
1261
1358
|
threadId,
|
|
1262
1359
|
finalMessage,
|
|
@@ -1285,6 +1382,15 @@ function defineWorkflow(config, fn) {
|
|
|
1285
1382
|
return workflow;
|
|
1286
1383
|
}
|
|
1287
1384
|
|
|
1385
|
+
// src/lib/thread/keys.ts
|
|
1386
|
+
var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
|
|
1387
|
+
function getThreadListKey(threadKey, threadId) {
|
|
1388
|
+
return `${threadKey}:thread:${threadId}`;
|
|
1389
|
+
}
|
|
1390
|
+
function getThreadMetaKey(threadKey, threadId) {
|
|
1391
|
+
return `${threadKey}:meta:thread:${threadId}`;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1288
1394
|
// src/lib/types.ts
|
|
1289
1395
|
function isTerminalStatus(status) {
|
|
1290
1396
|
return status === "COMPLETED" || status === "FAILED" || status === "CANCELLED";
|
|
@@ -1304,11 +1410,19 @@ function createAgentStateManager({
|
|
|
1304
1410
|
let systemPrompt = initialState?.systemPrompt;
|
|
1305
1411
|
const tasks = new Map(initialState?.tasks);
|
|
1306
1412
|
const {
|
|
1307
|
-
status:
|
|
1308
|
-
version:
|
|
1309
|
-
turns:
|
|
1310
|
-
tasks:
|
|
1311
|
-
tools:
|
|
1413
|
+
status: _status,
|
|
1414
|
+
version: _version,
|
|
1415
|
+
turns: _turns,
|
|
1416
|
+
tasks: _tasks,
|
|
1417
|
+
tools: _tools,
|
|
1418
|
+
systemPrompt: _systemPrompt,
|
|
1419
|
+
fileTree: _fileTree,
|
|
1420
|
+
inlineFiles: _inlineFiles,
|
|
1421
|
+
virtualFsCtx: _virtualFsCtx,
|
|
1422
|
+
totalInputTokens: _totalInputTokens,
|
|
1423
|
+
totalOutputTokens: _totalOutputTokens,
|
|
1424
|
+
cachedWriteTokens: _cachedWriteTokens,
|
|
1425
|
+
cachedReadTokens: _cachedReadTokens,
|
|
1312
1426
|
...custom
|
|
1313
1427
|
} = initialState ?? {};
|
|
1314
1428
|
const customState = custom;
|
|
@@ -1388,7 +1502,14 @@ function createAgentStateManager({
|
|
|
1388
1502
|
version++;
|
|
1389
1503
|
},
|
|
1390
1504
|
mergeUpdate(update) {
|
|
1391
|
-
|
|
1505
|
+
const { tasks: nextTasks, ...rest } = update;
|
|
1506
|
+
if (nextTasks) {
|
|
1507
|
+
tasks.clear();
|
|
1508
|
+
for (const [id, task] of nextTasks) {
|
|
1509
|
+
tasks.set(id, task);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
Object.assign(customState, rest);
|
|
1392
1513
|
version++;
|
|
1393
1514
|
},
|
|
1394
1515
|
getCurrentState() {
|
|
@@ -1426,6 +1547,12 @@ function createAgentStateManager({
|
|
|
1426
1547
|
}
|
|
1427
1548
|
return deleted;
|
|
1428
1549
|
},
|
|
1550
|
+
getPersistedSlice() {
|
|
1551
|
+
return {
|
|
1552
|
+
tasks: Array.from(tasks.entries()),
|
|
1553
|
+
custom: { ...customState }
|
|
1554
|
+
};
|
|
1555
|
+
},
|
|
1429
1556
|
updateUsage(usage) {
|
|
1430
1557
|
totalInputTokens += usage.inputTokens ?? 0;
|
|
1431
1558
|
totalOutputTokens += usage.outputTokens ?? 0;
|
|
@@ -1469,22 +1596,42 @@ function defineSubagentWorkflow(config, fn) {
|
|
|
1469
1596
|
});
|
|
1470
1597
|
}
|
|
1471
1598
|
const parentHandle = workflow.getExternalWorkflowHandle(parent.workflowId);
|
|
1599
|
+
let capturedSandboxId;
|
|
1600
|
+
let capturedSnapshot;
|
|
1601
|
+
let capturedBaseSnapshot;
|
|
1602
|
+
let capturedThreadId;
|
|
1472
1603
|
const sessionInput = {
|
|
1473
1604
|
agentName: config.name,
|
|
1474
1605
|
sandboxShutdown: effectiveShutdown,
|
|
1475
1606
|
...workflowInput.thread && { thread: workflowInput.thread },
|
|
1476
1607
|
...workflowInput.sandbox && { sandbox: workflowInput.sandbox },
|
|
1477
|
-
onSandboxReady: (sandboxId) => {
|
|
1608
|
+
onSandboxReady: ({ sandboxId, baseSnapshot }) => {
|
|
1609
|
+
capturedBaseSnapshot = baseSnapshot;
|
|
1478
1610
|
const isReuse = workflowInput.sandbox?.mode === "continue";
|
|
1479
1611
|
if (!isReuse) {
|
|
1480
1612
|
void parentHandle.signal(childSandboxReadySignal, {
|
|
1481
1613
|
childWorkflowId: workflow.workflowInfo().workflowId,
|
|
1482
|
-
sandboxId
|
|
1614
|
+
sandboxId,
|
|
1615
|
+
...baseSnapshot && { baseSnapshot }
|
|
1483
1616
|
});
|
|
1484
1617
|
}
|
|
1618
|
+
},
|
|
1619
|
+
onSessionExit: ({ sandboxId, snapshot, threadId }) => {
|
|
1620
|
+
capturedSandboxId = sandboxId;
|
|
1621
|
+
capturedSnapshot = snapshot;
|
|
1622
|
+
capturedThreadId = threadId;
|
|
1623
|
+
}
|
|
1624
|
+
};
|
|
1625
|
+
const result = await fn(prompt, sessionInput, context ?? {});
|
|
1626
|
+
return {
|
|
1627
|
+
...result,
|
|
1628
|
+
...capturedThreadId !== void 0 && { threadId: capturedThreadId },
|
|
1629
|
+
...capturedSandboxId !== void 0 && { sandboxId: capturedSandboxId },
|
|
1630
|
+
...capturedSnapshot !== void 0 && { snapshot: capturedSnapshot },
|
|
1631
|
+
...capturedBaseSnapshot !== void 0 && {
|
|
1632
|
+
baseSnapshot: capturedBaseSnapshot
|
|
1485
1633
|
}
|
|
1486
1634
|
};
|
|
1487
|
-
return fn(prompt, sessionInput, context ?? {});
|
|
1488
1635
|
};
|
|
1489
1636
|
Object.defineProperty(workflow$1, "name", { value: config.name });
|
|
1490
1637
|
return Object.assign(workflow$1, {
|
|
@@ -2143,8 +2290,10 @@ var createAskUserQuestionHandler = () => async (args) => {
|
|
|
2143
2290
|
};
|
|
2144
2291
|
};
|
|
2145
2292
|
|
|
2293
|
+
exports.DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT = DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT;
|
|
2146
2294
|
exports.SandboxNotFoundError = SandboxNotFoundError;
|
|
2147
2295
|
exports.SandboxNotSupportedError = SandboxNotSupportedError;
|
|
2296
|
+
exports.THREAD_TTL_SECONDS = THREAD_TTL_SECONDS;
|
|
2148
2297
|
exports.applyVirtualTreeMutations = applyVirtualTreeMutations;
|
|
2149
2298
|
exports.askUserQuestionTool = askUserQuestionTool;
|
|
2150
2299
|
exports.bashTool = bashTool;
|
|
@@ -2169,6 +2318,8 @@ exports.editTool = editTool;
|
|
|
2169
2318
|
exports.filesWithMimeType = filesWithMimeType;
|
|
2170
2319
|
exports.formatVirtualFileTree = formatVirtualFileTree;
|
|
2171
2320
|
exports.getShortId = getShortId;
|
|
2321
|
+
exports.getThreadListKey = getThreadListKey;
|
|
2322
|
+
exports.getThreadMetaKey = getThreadMetaKey;
|
|
2172
2323
|
exports.globTool = globTool;
|
|
2173
2324
|
exports.grepTool = grepTool;
|
|
2174
2325
|
exports.hasDirectory = hasDirectory;
|