zeitlich 0.2.13 → 0.2.15

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 (135) hide show
  1. package/README.md +61 -50
  2. package/dist/adapters/sandbox/daytona/index.cjs +205 -0
  3. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -0
  4. package/dist/adapters/sandbox/daytona/index.d.cts +86 -0
  5. package/dist/adapters/sandbox/daytona/index.d.ts +86 -0
  6. package/dist/adapters/sandbox/daytona/index.js +202 -0
  7. package/dist/adapters/sandbox/daytona/index.js.map +1 -0
  8. package/dist/adapters/sandbox/inmemory/index.cjs +174 -0
  9. package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -0
  10. package/dist/adapters/sandbox/inmemory/index.d.cts +28 -0
  11. package/dist/adapters/sandbox/inmemory/index.d.ts +28 -0
  12. package/dist/adapters/sandbox/inmemory/index.js +172 -0
  13. package/dist/adapters/sandbox/inmemory/index.js.map +1 -0
  14. package/dist/adapters/sandbox/virtual/index.cjs +405 -0
  15. package/dist/adapters/sandbox/virtual/index.cjs.map +1 -0
  16. package/dist/adapters/sandbox/virtual/index.d.cts +85 -0
  17. package/dist/adapters/sandbox/virtual/index.d.ts +85 -0
  18. package/dist/adapters/sandbox/virtual/index.js +400 -0
  19. package/dist/adapters/sandbox/virtual/index.js.map +1 -0
  20. package/dist/adapters/thread/google-genai/index.cjs +306 -0
  21. package/dist/adapters/thread/google-genai/index.cjs.map +1 -0
  22. package/dist/adapters/thread/google-genai/index.d.cts +145 -0
  23. package/dist/adapters/thread/google-genai/index.d.ts +145 -0
  24. package/dist/adapters/thread/google-genai/index.js +300 -0
  25. package/dist/adapters/thread/google-genai/index.js.map +1 -0
  26. package/dist/adapters/{langchain → thread/langchain}/index.cjs +29 -9
  27. package/dist/adapters/thread/langchain/index.cjs.map +1 -0
  28. package/dist/adapters/{langchain → thread/langchain}/index.d.cts +17 -21
  29. package/dist/adapters/{langchain → thread/langchain}/index.d.ts +17 -21
  30. package/dist/adapters/{langchain → thread/langchain}/index.js +29 -9
  31. package/dist/adapters/thread/langchain/index.js.map +1 -0
  32. package/dist/index.cjs +866 -567
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +235 -74
  35. package/dist/index.d.ts +235 -74
  36. package/dist/index.js +854 -562
  37. package/dist/index.js.map +1 -1
  38. package/dist/{thread-manager-qc0g5Rvd.d.cts → types-35POpVfa.d.cts} +7 -6
  39. package/dist/{thread-manager-qc0g5Rvd.d.ts → types-35POpVfa.d.ts} +7 -6
  40. package/dist/types-BMXzv7TN.d.cts +476 -0
  41. package/dist/types-BMXzv7TN.d.ts +476 -0
  42. package/dist/types-BVP87m_W.d.cts +121 -0
  43. package/dist/types-BWvIYK28.d.ts +391 -0
  44. package/dist/types-CDubRtad.d.cts +115 -0
  45. package/dist/types-CDubRtad.d.ts +115 -0
  46. package/dist/types-CwwgQ_9H.d.ts +121 -0
  47. package/dist/types-Dje1TdH6.d.cts +391 -0
  48. package/dist/workflow.cjs +460 -321
  49. package/dist/workflow.cjs.map +1 -1
  50. package/dist/workflow.d.cts +271 -222
  51. package/dist/workflow.d.ts +271 -222
  52. package/dist/workflow.js +456 -319
  53. package/dist/workflow.js.map +1 -1
  54. package/package.json +65 -8
  55. package/src/adapters/sandbox/daytona/filesystem.ts +136 -0
  56. package/src/adapters/sandbox/daytona/index.ts +149 -0
  57. package/src/adapters/sandbox/daytona/types.ts +34 -0
  58. package/src/adapters/sandbox/inmemory/index.ts +213 -0
  59. package/src/adapters/sandbox/virtual/filesystem.ts +345 -0
  60. package/src/adapters/sandbox/virtual/index.ts +88 -0
  61. package/src/adapters/sandbox/virtual/mutations.ts +38 -0
  62. package/src/adapters/sandbox/virtual/provider.ts +101 -0
  63. package/src/adapters/sandbox/virtual/tree.ts +82 -0
  64. package/src/adapters/sandbox/virtual/types.ts +127 -0
  65. package/src/adapters/sandbox/virtual/virtual-sandbox.test.ts +523 -0
  66. package/src/adapters/sandbox/virtual/with-virtual-sandbox.ts +91 -0
  67. package/src/adapters/thread/google-genai/activities.ts +132 -0
  68. package/src/adapters/thread/google-genai/index.ts +41 -0
  69. package/src/adapters/thread/google-genai/model-invoker.ts +154 -0
  70. package/src/adapters/thread/google-genai/thread-manager.ts +169 -0
  71. package/src/adapters/{langchain → thread/langchain}/activities.ts +22 -15
  72. package/src/adapters/{langchain → thread/langchain}/index.ts +1 -1
  73. package/src/adapters/{langchain → thread/langchain}/model-invoker.ts +15 -18
  74. package/src/adapters/{langchain → thread/langchain}/thread-manager.ts +1 -1
  75. package/src/index.ts +32 -24
  76. package/src/lib/activity.ts +87 -0
  77. package/src/lib/hooks/index.ts +11 -0
  78. package/src/lib/hooks/types.ts +98 -0
  79. package/src/lib/model/helpers.ts +6 -0
  80. package/src/lib/model/index.ts +13 -0
  81. package/src/lib/{model-invoker.ts → model/types.ts} +18 -1
  82. package/src/lib/sandbox/index.ts +19 -0
  83. package/src/lib/sandbox/manager.ts +76 -0
  84. package/src/lib/sandbox/sandbox.test.ts +158 -0
  85. package/src/lib/{fs.ts → sandbox/tree.ts} +6 -6
  86. package/src/lib/sandbox/types.ts +164 -0
  87. package/src/lib/session/index.ts +11 -0
  88. package/src/lib/{session.ts → session/session.ts} +83 -50
  89. package/src/lib/session/types.ts +95 -0
  90. package/src/lib/skills/fs-provider.ts +16 -15
  91. package/src/lib/skills/handler.ts +31 -0
  92. package/src/lib/skills/index.ts +5 -1
  93. package/src/lib/skills/register.ts +20 -0
  94. package/src/lib/skills/tool.ts +47 -0
  95. package/src/lib/state/index.ts +9 -0
  96. package/src/lib/{state-manager.ts → state/manager.ts} +10 -147
  97. package/src/lib/state/types.ts +134 -0
  98. package/src/lib/subagent/define.ts +71 -0
  99. package/src/lib/subagent/handler.ts +99 -0
  100. package/src/lib/subagent/index.ts +13 -0
  101. package/src/lib/subagent/register.ts +68 -0
  102. package/src/lib/subagent/tool.ts +80 -0
  103. package/src/lib/subagent/types.ts +92 -0
  104. package/src/lib/thread/index.ts +7 -0
  105. package/src/lib/{thread-manager.ts → thread/manager.ts} +20 -33
  106. package/src/lib/thread/types.ts +39 -0
  107. package/src/lib/tool-router/auto-append.ts +55 -0
  108. package/src/lib/tool-router/index.ts +41 -0
  109. package/src/lib/tool-router/router.ts +462 -0
  110. package/src/lib/tool-router/types.ts +478 -0
  111. package/src/lib/tool-router/with-sandbox.ts +70 -0
  112. package/src/lib/types.ts +5 -382
  113. package/src/tools/bash/bash.test.ts +53 -55
  114. package/src/tools/bash/handler.ts +23 -51
  115. package/src/tools/edit/handler.ts +67 -81
  116. package/src/tools/glob/handler.ts +60 -17
  117. package/src/tools/read-file/handler.ts +67 -0
  118. package/src/tools/read-skill/handler.ts +1 -31
  119. package/src/tools/read-skill/tool.ts +5 -47
  120. package/src/tools/subagent/handler.ts +1 -100
  121. package/src/tools/subagent/tool.ts +5 -93
  122. package/src/tools/task-create/handler.ts +1 -1
  123. package/src/tools/task-get/handler.ts +1 -1
  124. package/src/tools/task-list/handler.ts +1 -1
  125. package/src/tools/task-update/handler.ts +1 -1
  126. package/src/tools/write-file/handler.ts +47 -0
  127. package/src/workflow.ts +88 -47
  128. package/tsup.config.ts +8 -1
  129. package/dist/adapters/langchain/index.cjs.map +0 -1
  130. package/dist/adapters/langchain/index.js.map +0 -1
  131. package/dist/model-invoker-y_zlyMqu.d.cts +0 -892
  132. package/dist/model-invoker-y_zlyMqu.d.ts +0 -892
  133. package/src/lib/tool-router.ts +0 -977
  134. package/src/lib/workflow-helpers.ts +0 -50
  135. /package/src/lib/{thread-id.ts → thread/id.ts} +0 -0
package/dist/index.js CHANGED
@@ -1,152 +1,10 @@
1
1
  import { uuid4, setHandler, defineUpdate, ApplicationFailure, condition, proxyActivities, defineQuery, workflowInfo, executeChild } from '@temporalio/workflow';
2
2
  import z14, { z } from 'zod';
3
- import { Context } from '@temporalio/activity';
4
- import { Bash } from 'just-bash';
5
- import { readFile, readdir } from 'fs/promises';
3
+ import { ApplicationFailure as ApplicationFailure$1 } from '@temporalio/common';
6
4
  import { join } from 'path';
5
+ import { Context } from '@temporalio/activity';
7
6
 
8
- // src/lib/session.ts
9
- var SUBAGENT_TOOL_NAME = "Subagent";
10
- function buildSubagentDescription(subagents) {
11
- const subagentList = subagents.map((s) => {
12
- const continuation = s.allowThreadContinuation ? "\n*(Supports thread continuation \u2014 pass a threadId to resume a previous conversation)*" : "";
13
- return `## ${s.agentName}
14
- ${s.description}${continuation}`;
15
- }).join("\n\n");
16
- return `The ${SUBAGENT_TOOL_NAME} tool launches specialized agents (subagents) that autonomously handle complex work. Each agent type has specific capabilities and tools available to it.
17
-
18
- # Available subagents:
19
- ${subagentList}
20
- `;
21
- }
22
- function createSubagentTool(subagents) {
23
- if (subagents.length === 0) {
24
- throw new Error("createTaskTool requires at least one subagent");
25
- }
26
- const names = subagents.map((s) => s.agentName);
27
- const hasThreadContinuation = subagents.some(
28
- (s) => s.allowThreadContinuation
29
- );
30
- const baseFields = {
31
- subagent: z14.enum(names).describe("The type of subagent to launch"),
32
- description: z14.string().describe("A short (3-5 word) description of the task"),
33
- prompt: z14.string().describe("The task for the agent to perform")
34
- };
35
- const schema = hasThreadContinuation ? z14.object({
36
- ...baseFields,
37
- threadId: z14.string().nullable().describe(
38
- "Thread ID to continue an existing conversation, or null to start a new one"
39
- )
40
- }) : z14.object(baseFields);
41
- return {
42
- name: SUBAGENT_TOOL_NAME,
43
- description: buildSubagentDescription(subagents),
44
- schema
45
- };
46
- }
47
- var BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
48
- function getShortId(length = 12) {
49
- const hex = uuid4().replace(/-/g, "");
50
- let result = "";
51
- for (let i = 0; i < length; i++) {
52
- const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
53
- result += BASE62[byte % BASE62.length];
54
- }
55
- return result;
56
- }
57
-
58
- // src/tools/subagent/handler.ts
59
- function createSubagentHandler(subagents) {
60
- const { taskQueue: parentTaskQueue } = workflowInfo();
61
- return async (args) => {
62
- const config = subagents.find((s) => s.agentName === args.subagent);
63
- if (!config) {
64
- throw new Error(
65
- `Unknown subagent: ${args.subagent}. Available: ${subagents.map((s) => s.agentName).join(", ")}`
66
- );
67
- }
68
- const childWorkflowId = `${args.subagent}-${getShortId()}`;
69
- const input = {
70
- prompt: args.prompt,
71
- ...config.context && { context: config.context },
72
- ...args.threadId && config.allowThreadContinuation && { threadId: args.threadId }
73
- };
74
- const childOpts = {
75
- workflowId: childWorkflowId,
76
- args: [input],
77
- taskQueue: config.taskQueue ?? parentTaskQueue
78
- };
79
- const { toolResponse, data, usage, threadId: childThreadId } = typeof config.workflow === "string" ? await executeChild(config.workflow, childOpts) : await executeChild(config.workflow, childOpts);
80
- if (!toolResponse) {
81
- return {
82
- toolResponse: "Subagent workflow returned no response",
83
- data: null,
84
- ...usage && { usage }
85
- };
86
- }
87
- const validated = config.resultSchema ? config.resultSchema.safeParse(data) : null;
88
- if (validated && !validated.success) {
89
- return {
90
- toolResponse: `Subagent workflow returned invalid data: ${validated.error.message}`,
91
- data: null,
92
- ...usage && { usage }
93
- };
94
- }
95
- let finalToolResponse = toolResponse;
96
- if (config.allowThreadContinuation && childThreadId) {
97
- finalToolResponse = typeof toolResponse === "string" ? `${toolResponse}
98
-
99
- [Thread ID: ${childThreadId}]` : toolResponse;
100
- }
101
- return {
102
- toolResponse: finalToolResponse,
103
- data: validated ? validated.data : data,
104
- ...usage && { usage }
105
- };
106
- };
107
- }
108
- var READ_SKILL_TOOL_NAME = "ReadSkill";
109
- function buildReadSkillDescription(skills) {
110
- const skillList = skills.map((s) => `- **${s.name}**: ${s.description}`).join("\n");
111
- return `Load the full instructions for a skill. Read the skill before following its instructions.
112
-
113
- # Available skills:
114
- ${skillList}
115
- `;
116
- }
117
- function createReadSkillTool(skills) {
118
- if (skills.length === 0) {
119
- throw new Error("createReadSkillTool requires at least one skill");
120
- }
121
- const names = skills.map((s) => s.name);
122
- return {
123
- name: READ_SKILL_TOOL_NAME,
124
- description: buildReadSkillDescription(skills),
125
- schema: z14.object({
126
- skill_name: z14.enum(names).describe("The name of the skill to load")
127
- })
128
- };
129
- }
130
-
131
- // src/tools/read-skill/handler.ts
132
- function createReadSkillHandler(skills) {
133
- const skillMap = new Map(skills.map((s) => [s.name, s]));
134
- return (args) => {
135
- const skill = skillMap.get(args.skill_name);
136
- if (!skill) {
137
- return {
138
- toolResponse: JSON.stringify({
139
- error: `Skill "${args.skill_name}" not found`
140
- }),
141
- data: null
142
- };
143
- }
144
- return {
145
- toolResponse: skill.instructions,
146
- data: null
147
- };
148
- };
149
- }
7
+ // src/lib/session/session.ts
150
8
  function createToolRouter(options) {
151
9
  const { appendToolResult } = options;
152
10
  const toolMap = /* @__PURE__ */ new Map();
@@ -154,45 +12,12 @@ function createToolRouter(options) {
154
12
  toolMap.set(tool.name, tool);
155
13
  }
156
14
  const isEnabled = (tool) => tool.enabled ?? true;
157
- if (options.subagents) {
158
- if (options.subagents.length > 0) {
159
- const subagentHooksMap = /* @__PURE__ */ new Map();
160
- for (const s of options.subagents) {
161
- if (s.hooks) subagentHooksMap.set(s.agentName, s.hooks);
162
- }
163
- const resolveSubagentName = (args) => args.subagent;
164
- toolMap.set(SUBAGENT_TOOL_NAME, {
165
- ...createSubagentTool(options.subagents),
166
- handler: createSubagentHandler(options.subagents),
167
- ...subagentHooksMap.size > 0 && {
168
- hooks: {
169
- onPreToolUse: async (ctx) => {
170
- const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
171
- return hooks?.onPreExecution?.(ctx) ?? {};
172
- },
173
- onPostToolUse: async (ctx) => {
174
- const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
175
- await hooks?.onPostExecution?.(ctx);
176
- },
177
- onPostToolUseFailure: async (ctx) => {
178
- const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
179
- return hooks?.onExecutionFailure?.(ctx) ?? {};
180
- }
181
- }
182
- }
183
- });
15
+ if (options.plugins) {
16
+ for (const plugin of options.plugins) {
17
+ toolMap.set(plugin.name, plugin);
184
18
  }
185
19
  }
186
- if (options.skills && options.skills.length > 0) {
187
- toolMap.set(READ_SKILL_TOOL_NAME, {
188
- ...createReadSkillTool(options.skills),
189
- handler: createReadSkillHandler(options.skills)
190
- });
191
- }
192
- async function processToolCall(toolCall, turn, handlerContext) {
193
- const startTime = Date.now();
194
- const tool = toolMap.get(toolCall.name);
195
- const toolHooks = tool?.hooks;
20
+ async function runPreHooks(toolCall, tool, turn) {
196
21
  let effectiveArgs = toolCall.args;
197
22
  if (options.hooks?.onPreToolUse) {
198
23
  const preResult = await options.hooks.onPreToolUse({
@@ -200,58 +25,105 @@ function createToolRouter(options) {
200
25
  threadId: options.threadId,
201
26
  turn
202
27
  });
203
- if (preResult?.skip) {
204
- await appendToolResult({
205
- threadId: options.threadId,
206
- toolCallId: toolCall.id,
207
- toolName: toolCall.name,
208
- content: JSON.stringify({
209
- skipped: true,
210
- reason: "Skipped by PreToolUse hook"
211
- })
212
- });
213
- return null;
214
- }
215
- if (preResult?.modifiedArgs !== void 0) {
28
+ if (preResult?.skip) return { skip: true };
29
+ if (preResult?.modifiedArgs !== void 0)
216
30
  effectiveArgs = preResult.modifiedArgs;
217
- }
218
31
  }
219
- if (toolHooks?.onPreToolUse) {
220
- const preResult = await toolHooks.onPreToolUse({
32
+ if (tool?.hooks?.onPreToolUse) {
33
+ const preResult = await tool.hooks.onPreToolUse({
221
34
  args: effectiveArgs,
222
35
  threadId: options.threadId,
223
36
  turn
224
37
  });
225
- if (preResult?.skip) {
226
- await appendToolResult({
227
- threadId: options.threadId,
228
- toolCallId: toolCall.id,
229
- toolName: toolCall.name,
230
- content: JSON.stringify({
231
- skipped: true,
232
- reason: "Skipped by tool PreToolUse hook"
233
- })
234
- });
235
- return null;
236
- }
237
- if (preResult?.modifiedArgs !== void 0) {
38
+ if (preResult?.skip) return { skip: true };
39
+ if (preResult?.modifiedArgs !== void 0)
238
40
  effectiveArgs = preResult.modifiedArgs;
239
- }
240
41
  }
42
+ return { skip: false, args: effectiveArgs };
43
+ }
44
+ async function runFailureHooks(toolCall, tool, error, effectiveArgs, turn) {
45
+ const err = error instanceof Error ? error : new Error(String(error));
46
+ const errorStr = String(error);
47
+ if (tool?.hooks?.onPostToolUseFailure) {
48
+ const r = await tool.hooks.onPostToolUseFailure({
49
+ args: effectiveArgs,
50
+ error: err,
51
+ threadId: options.threadId,
52
+ turn
53
+ });
54
+ if (r?.fallbackContent !== void 0)
55
+ return { content: r.fallbackContent, result: { error: errorStr, recovered: true } };
56
+ if (r?.suppress)
57
+ return {
58
+ content: JSON.stringify({ error: errorStr, suppressed: true }),
59
+ result: { error: errorStr, suppressed: true }
60
+ };
61
+ }
62
+ if (options.hooks?.onPostToolUseFailure) {
63
+ const r = await options.hooks.onPostToolUseFailure({
64
+ toolCall,
65
+ error: err,
66
+ threadId: options.threadId,
67
+ turn
68
+ });
69
+ if (r?.fallbackContent !== void 0)
70
+ return { content: r.fallbackContent, result: { error: errorStr, recovered: true } };
71
+ if (r?.suppress)
72
+ return {
73
+ content: JSON.stringify({ error: errorStr, suppressed: true }),
74
+ result: { error: errorStr, suppressed: true }
75
+ };
76
+ }
77
+ throw ApplicationFailure.fromError(error, { nonRetryable: true });
78
+ }
79
+ async function runPostHooks(toolCall, tool, toolResult, effectiveArgs, turn, durationMs) {
80
+ if (tool?.hooks?.onPostToolUse) {
81
+ await tool.hooks.onPostToolUse({
82
+ args: effectiveArgs,
83
+ result: toolResult.data,
84
+ threadId: options.threadId,
85
+ turn,
86
+ durationMs
87
+ });
88
+ }
89
+ if (options.hooks?.onPostToolUse) {
90
+ await options.hooks.onPostToolUse({
91
+ toolCall,
92
+ result: toolResult,
93
+ threadId: options.threadId,
94
+ turn,
95
+ durationMs
96
+ });
97
+ }
98
+ }
99
+ async function processToolCall(toolCall, turn, sandboxId) {
100
+ const startTime = Date.now();
101
+ const tool = toolMap.get(toolCall.name);
102
+ const preResult = await runPreHooks(toolCall, tool, turn);
103
+ if (preResult.skip) {
104
+ await appendToolResult({
105
+ threadId: options.threadId,
106
+ toolCallId: toolCall.id,
107
+ toolName: toolCall.name,
108
+ content: JSON.stringify({ skipped: true, reason: "Skipped by PreToolUse hook" })
109
+ });
110
+ return null;
111
+ }
112
+ const effectiveArgs = preResult.args;
241
113
  let result;
242
114
  let content;
243
115
  let resultAppended = false;
244
116
  try {
245
117
  if (tool) {
246
- const enrichedContext = {
247
- ...handlerContext ?? {},
118
+ const routerContext = {
248
119
  threadId: options.threadId,
249
120
  toolCallId: toolCall.id,
250
- toolName: toolCall.name
121
+ toolName: toolCall.name,
122
+ ...sandboxId !== void 0 && { sandboxId }
251
123
  };
252
124
  const response = await tool.handler(
253
125
  effectiveArgs,
254
- enrichedContext
126
+ routerContext
255
127
  );
256
128
  result = response.data;
257
129
  content = response.toolResponse;
@@ -261,47 +133,9 @@ function createToolRouter(options) {
261
133
  content = JSON.stringify(result, null, 2);
262
134
  }
263
135
  } catch (error) {
264
- const err = error instanceof Error ? error : new Error(String(error));
265
- let recovered = false;
266
- if (toolHooks?.onPostToolUseFailure) {
267
- const failureResult = await toolHooks.onPostToolUseFailure({
268
- args: effectiveArgs,
269
- error: err,
270
- threadId: options.threadId,
271
- turn
272
- });
273
- if (failureResult?.fallbackContent !== void 0) {
274
- content = failureResult.fallbackContent;
275
- result = { error: String(error), recovered: true };
276
- recovered = true;
277
- } else if (failureResult?.suppress) {
278
- content = JSON.stringify({ error: String(error), suppressed: true });
279
- result = { error: String(error), suppressed: true };
280
- recovered = true;
281
- }
282
- }
283
- if (!recovered && options.hooks?.onPostToolUseFailure) {
284
- const failureResult = await options.hooks.onPostToolUseFailure({
285
- toolCall,
286
- error: err,
287
- threadId: options.threadId,
288
- turn
289
- });
290
- if (failureResult?.fallbackContent !== void 0) {
291
- content = failureResult.fallbackContent;
292
- result = { error: String(error), recovered: true };
293
- recovered = true;
294
- } else if (failureResult?.suppress) {
295
- content = JSON.stringify({ error: String(error), suppressed: true });
296
- result = { error: String(error), suppressed: true };
297
- recovered = true;
298
- }
299
- }
300
- if (!recovered) {
301
- throw ApplicationFailure.fromError(error, {
302
- nonRetryable: true
303
- });
304
- }
136
+ const recovery = await runFailureHooks(toolCall, tool, error, effectiveArgs, turn);
137
+ result = recovery.result;
138
+ content = recovery.content;
305
139
  }
306
140
  if (!resultAppended) {
307
141
  await appendToolResult({
@@ -316,29 +150,10 @@ function createToolRouter(options) {
316
150
  name: toolCall.name,
317
151
  data: result
318
152
  };
319
- const durationMs = Date.now() - startTime;
320
- if (toolHooks?.onPostToolUse) {
321
- await toolHooks.onPostToolUse({
322
- args: effectiveArgs,
323
- result,
324
- threadId: options.threadId,
325
- turn,
326
- durationMs
327
- });
328
- }
329
- if (options.hooks?.onPostToolUse) {
330
- await options.hooks.onPostToolUse({
331
- toolCall,
332
- result: toolResult,
333
- threadId: options.threadId,
334
- turn,
335
- durationMs
336
- });
337
- }
153
+ await runPostHooks(toolCall, tool, toolResult, effectiveArgs, turn, Date.now() - startTime);
338
154
  return toolResult;
339
155
  }
340
156
  return {
341
- // --- Methods from registry ---
342
157
  hasTools() {
343
158
  return Array.from(toolMap.values()).some(isEnabled);
344
159
  },
@@ -362,32 +177,25 @@ function createToolRouter(options) {
362
177
  return Array.from(toolMap.entries()).filter(([, tool]) => isEnabled(tool)).map(([name]) => name);
363
178
  },
364
179
  getToolDefinitions() {
365
- const activeSubagents = options.subagents?.filter((subagent) => isEnabled(subagent)) ?? [];
366
- const activeSkills = options.skills ?? [];
367
- return [
368
- ...Array.from(toolMap).filter(
369
- ([, tool]) => isEnabled(tool) && tool.name !== SUBAGENT_TOOL_NAME && tool.name !== READ_SKILL_TOOL_NAME
370
- ).map(([name, tool]) => ({
371
- name,
372
- description: tool.description,
373
- schema: tool.schema,
374
- strict: tool.strict,
375
- max_uses: tool.max_uses
376
- })),
377
- ...activeSubagents.length > 0 ? [createSubagentTool(activeSubagents)] : [],
378
- ...activeSkills.length > 0 ? [createReadSkillTool(activeSkills)] : []
379
- ];
180
+ return Array.from(toolMap).filter(([, tool]) => isEnabled(tool)).map(([name, tool]) => ({
181
+ name,
182
+ description: tool.description,
183
+ schema: tool.schema,
184
+ strict: tool.strict,
185
+ max_uses: tool.max_uses
186
+ }));
380
187
  },
381
- // --- Methods for processing tool calls ---
382
188
  async processToolCalls(toolCalls, context) {
383
189
  if (toolCalls.length === 0) {
384
190
  return [];
385
191
  }
386
192
  const turn = context?.turn ?? 0;
387
- const handlerContext = context?.handlerContext;
193
+ const sandboxId = context?.sandboxId;
388
194
  if (options.parallel) {
389
195
  const results2 = await Promise.all(
390
- toolCalls.map((tc) => processToolCall(tc, turn, handlerContext))
196
+ toolCalls.map(
197
+ (tc) => processToolCall(tc, turn, sandboxId)
198
+ )
391
199
  );
392
200
  return results2.filter(
393
201
  (r) => r !== null
@@ -395,7 +203,11 @@ function createToolRouter(options) {
395
203
  }
396
204
  const results = [];
397
205
  for (const toolCall of toolCalls) {
398
- const result = await processToolCall(toolCall, turn, handlerContext);
206
+ const result = await processToolCall(
207
+ toolCall,
208
+ turn,
209
+ sandboxId
210
+ );
399
211
  if (result !== null) {
400
212
  results.push(result);
401
213
  }
@@ -407,17 +219,16 @@ function createToolRouter(options) {
407
219
  if (matchingCalls.length === 0) {
408
220
  return [];
409
221
  }
410
- const handlerContext = context?.handlerContext ?? {};
411
222
  const processOne = async (toolCall) => {
412
- const enrichedContext = {
413
- ...handlerContext ?? {},
223
+ const routerContext = {
414
224
  threadId: options.threadId,
415
225
  toolCallId: toolCall.id,
416
- toolName: toolCall.name
226
+ toolName: toolCall.name,
227
+ ...context?.sandboxId !== void 0 && { sandboxId: context.sandboxId }
417
228
  };
418
229
  const response = await handler(
419
230
  toolCall.args,
420
- enrichedContext
231
+ routerContext
421
232
  );
422
233
  if (!response.resultAppended) {
423
234
  await appendToolResult({
@@ -433,59 +244,232 @@ function createToolRouter(options) {
433
244
  data: response.data
434
245
  };
435
246
  };
436
- if (options.parallel) {
437
- return Promise.all(matchingCalls.map(processOne));
438
- }
439
- const results = [];
440
- for (const toolCall of matchingCalls) {
441
- results.push(await processOne(toolCall));
442
- }
443
- return results;
247
+ if (options.parallel) {
248
+ return Promise.all(matchingCalls.map(processOne));
249
+ }
250
+ const results = [];
251
+ for (const toolCall of matchingCalls) {
252
+ results.push(await processOne(toolCall));
253
+ }
254
+ return results;
255
+ },
256
+ filterByName(toolCalls, name) {
257
+ return toolCalls.filter(
258
+ (tc) => tc.name === name
259
+ );
260
+ },
261
+ hasToolCall(toolCalls, name) {
262
+ return toolCalls.some((tc) => tc.name === name);
263
+ },
264
+ getResultsByName(results, name) {
265
+ return results.filter((r) => r.name === name);
266
+ }
267
+ };
268
+ }
269
+ function defineTool(tool) {
270
+ return tool;
271
+ }
272
+ function hasNoOtherToolCalls(toolCalls, excludeName) {
273
+ return toolCalls.filter((tc) => tc.name !== excludeName).length === 0;
274
+ }
275
+ var BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
276
+ function getShortId(length = 12) {
277
+ const hex = uuid4().replace(/-/g, "");
278
+ let result = "";
279
+ for (let i = 0; i < length; i++) {
280
+ const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
281
+ result += BASE62[byte % BASE62.length];
282
+ }
283
+ return result;
284
+ }
285
+ var SUBAGENT_TOOL_NAME = "Subagent";
286
+ function buildSubagentDescription(subagents) {
287
+ const subagentList = subagents.map((s) => {
288
+ const continuation = s.allowThreadContinuation ? "\n*(Supports thread continuation \u2014 pass a threadId to resume a previous conversation)*" : "";
289
+ return `## ${s.agentName}
290
+ ${s.description}${continuation}`;
291
+ }).join("\n\n");
292
+ return `The ${SUBAGENT_TOOL_NAME} tool launches specialized agents (subagents) that autonomously handle complex work. Each agent type has specific capabilities and tools available to it.
293
+
294
+ # Available subagents:
295
+ ${subagentList}
296
+ `;
297
+ }
298
+ function createSubagentTool(subagents) {
299
+ if (subagents.length === 0) {
300
+ throw new Error("createSubagentTool requires at least one subagent");
301
+ }
302
+ const names = subagents.map((s) => s.agentName);
303
+ const hasThreadContinuation = subagents.some(
304
+ (s) => s.allowThreadContinuation
305
+ );
306
+ const baseFields = {
307
+ subagent: z14.enum(names).describe("The type of subagent to launch"),
308
+ description: z14.string().describe("A short (3-5 word) description of the task"),
309
+ prompt: z14.string().describe("The task for the agent to perform")
310
+ };
311
+ const schema = hasThreadContinuation ? z14.object({
312
+ ...baseFields,
313
+ threadId: z14.string().nullable().describe(
314
+ "Thread ID to continue an existing conversation, or null to start a new one"
315
+ )
316
+ }) : z14.object(baseFields);
317
+ return {
318
+ name: SUBAGENT_TOOL_NAME,
319
+ description: buildSubagentDescription(subagents),
320
+ schema
321
+ };
322
+ }
323
+ function createSubagentHandler(subagents) {
324
+ const { taskQueue: parentTaskQueue } = workflowInfo();
325
+ return async (args, context) => {
326
+ const config = subagents.find((s) => s.agentName === args.subagent);
327
+ if (!config) {
328
+ throw new Error(
329
+ `Unknown subagent: ${args.subagent}. Available: ${subagents.map((s) => s.agentName).join(", ")}`
330
+ );
331
+ }
332
+ const childWorkflowId = `${args.subagent}-${getShortId()}`;
333
+ const { sandboxId: parentSandboxId } = context;
334
+ const inheritSandbox = config.sandbox !== "own" && !!parentSandboxId;
335
+ const input = {
336
+ prompt: args.prompt,
337
+ ...config.context && { context: config.context },
338
+ ...args.threadId && args.threadId !== null && config.allowThreadContinuation && { previousThreadId: args.threadId },
339
+ ...inheritSandbox && { sandboxId: parentSandboxId }
340
+ };
341
+ const childOpts = {
342
+ workflowId: childWorkflowId,
343
+ args: [input],
344
+ taskQueue: config.taskQueue ?? parentTaskQueue
345
+ };
346
+ const {
347
+ toolResponse,
348
+ data,
349
+ usage,
350
+ threadId: childThreadId
351
+ } = typeof config.workflow === "string" ? await executeChild(config.workflow, childOpts) : await executeChild(config.workflow, childOpts);
352
+ if (!toolResponse) {
353
+ return {
354
+ toolResponse: "Subagent workflow returned no response",
355
+ data: null,
356
+ ...usage && { usage }
357
+ };
358
+ }
359
+ const validated = config.resultSchema ? config.resultSchema.safeParse(data) : null;
360
+ if (validated && !validated.success) {
361
+ return {
362
+ toolResponse: `Subagent workflow returned invalid data: ${validated.error.message}`,
363
+ data: null,
364
+ ...usage && { usage }
365
+ };
366
+ }
367
+ let finalToolResponse = toolResponse;
368
+ if (config.allowThreadContinuation && childThreadId) {
369
+ finalToolResponse = typeof toolResponse === "string" ? `${toolResponse}
370
+
371
+ [Thread ID: ${childThreadId}]` : toolResponse;
372
+ }
373
+ return {
374
+ toolResponse: finalToolResponse,
375
+ data: validated ? validated.data : data,
376
+ ...usage && { usage }
377
+ };
378
+ };
379
+ }
380
+
381
+ // src/lib/subagent/register.ts
382
+ function buildSubagentRegistration(subagents) {
383
+ if (subagents.length === 0) return null;
384
+ const getEnabled = () => subagents.filter((s) => s.enabled ?? true);
385
+ const subagentHooksMap = /* @__PURE__ */ new Map();
386
+ for (const s of subagents) {
387
+ if (s.hooks) subagentHooksMap.set(s.agentName, s.hooks);
388
+ }
389
+ const resolveSubagentName = (args) => args.subagent;
390
+ return {
391
+ name: SUBAGENT_TOOL_NAME,
392
+ get enabled() {
393
+ return getEnabled().length > 0;
444
394
  },
445
- // --- Utility methods ---
446
- filterByName(toolCalls, name) {
447
- return toolCalls.filter(
448
- (tc) => tc.name === name
449
- );
395
+ get description() {
396
+ return createSubagentTool(getEnabled()).description;
450
397
  },
451
- hasToolCall(toolCalls, name) {
452
- return toolCalls.some((tc) => tc.name === name);
398
+ get schema() {
399
+ return createSubagentTool(getEnabled()).schema;
453
400
  },
454
- getResultsByName(results, name) {
455
- return results.filter((r) => r.name === name);
401
+ handler: createSubagentHandler(subagents),
402
+ ...subagentHooksMap.size > 0 && {
403
+ hooks: {
404
+ onPreToolUse: async (ctx) => {
405
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
406
+ return hooks?.onPreExecution?.(ctx) ?? {};
407
+ },
408
+ onPostToolUse: async (ctx) => {
409
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
410
+ await hooks?.onPostExecution?.(ctx);
411
+ },
412
+ onPostToolUseFailure: async (ctx) => {
413
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
414
+ return hooks?.onExecutionFailure?.(ctx) ?? {};
415
+ }
416
+ }
456
417
  }
457
418
  };
458
419
  }
459
- function withAutoAppend(threadHandler, handler) {
460
- return async (args, context) => {
461
- const response = await handler(args, context);
462
- const threadId = context.threadId;
463
- const toolCallId = context.toolCallId;
464
- const toolName = context.toolName;
465
- await threadHandler({
466
- threadId,
467
- toolCallId,
468
- toolName,
469
- content: response.toolResponse
470
- });
420
+ var READ_SKILL_TOOL_NAME = "ReadSkill";
421
+ function buildReadSkillDescription(skills) {
422
+ const skillList = skills.map((s) => `- **${s.name}**: ${s.description}`).join("\n");
423
+ return `Load the full instructions for a skill. Read the skill before following its instructions.
424
+
425
+ # Available skills:
426
+ ${skillList}
427
+ `;
428
+ }
429
+ function createReadSkillTool(skills) {
430
+ if (skills.length === 0) {
431
+ throw new Error("createReadSkillTool requires at least one skill");
432
+ }
433
+ const names = skills.map((s) => s.name);
434
+ return {
435
+ name: READ_SKILL_TOOL_NAME,
436
+ description: buildReadSkillDescription(skills),
437
+ schema: z14.object({
438
+ skill_name: z14.enum(names).describe("The name of the skill to load")
439
+ })
440
+ };
441
+ }
442
+
443
+ // src/lib/skills/handler.ts
444
+ function createReadSkillHandler(skills) {
445
+ const skillMap = new Map(skills.map((s) => [s.name, s]));
446
+ return (args) => {
447
+ const skill = skillMap.get(args.skill_name);
448
+ if (!skill) {
449
+ return {
450
+ toolResponse: JSON.stringify({
451
+ error: `Skill "${args.skill_name}" not found`
452
+ }),
453
+ data: null
454
+ };
455
+ }
471
456
  return {
472
- toolResponse: "Response appended via withAutoAppend",
473
- data: response.data,
474
- resultAppended: true
457
+ toolResponse: skill.instructions,
458
+ data: null
475
459
  };
476
460
  };
477
461
  }
478
- function defineTool(tool) {
479
- return tool;
480
- }
481
- function defineSubagent(config) {
482
- return config;
483
- }
484
- function hasNoOtherToolCalls(toolCalls, excludeName) {
485
- return toolCalls.filter((tc) => tc.name !== excludeName).length === 0;
462
+
463
+ // src/lib/skills/register.ts
464
+ function buildSkillRegistration(skills) {
465
+ if (skills.length === 0) return null;
466
+ return {
467
+ ...createReadSkillTool(skills),
468
+ handler: createReadSkillHandler(skills)
469
+ };
486
470
  }
487
471
 
488
- // src/lib/session.ts
472
+ // src/lib/session/session.ts
489
473
  var createSession = async ({
490
474
  threadId: providedThreadId,
491
475
  agentName,
@@ -501,22 +485,34 @@ var createSession = async ({
501
485
  hooks = {},
502
486
  appendSystemPrompt = true,
503
487
  continueThread = false,
504
- waitForInputTimeout = "48h"
488
+ waitForInputTimeout = "48h",
489
+ sandbox: sandboxOps,
490
+ sandboxId: inheritedSandboxId
505
491
  }) => {
506
- const threadId = providedThreadId ?? getShortId();
492
+ const sourceThreadId = continueThread ? providedThreadId : void 0;
493
+ const threadId = continueThread && providedThreadId ? getShortId() : providedThreadId ?? getShortId();
507
494
  const {
508
495
  appendToolResult,
509
496
  appendHumanMessage,
510
497
  initializeThread,
511
- appendSystemMessage
498
+ appendSystemMessage,
499
+ forkThread
512
500
  } = threadOps ?? proxyDefaultThreadOps();
501
+ const plugins = [];
502
+ if (subagents) {
503
+ const reg = buildSubagentRegistration(subagents);
504
+ if (reg) plugins.push(reg);
505
+ }
506
+ if (skills) {
507
+ const reg = buildSkillRegistration(skills);
508
+ if (reg) plugins.push(reg);
509
+ }
513
510
  const toolRouter = createToolRouter({
514
511
  tools,
515
512
  appendToolResult,
516
513
  threadId,
517
514
  hooks,
518
- subagents,
519
- skills,
515
+ plugins,
520
516
  parallel: processToolsInParallel
521
517
  });
522
518
  const callSessionEnd = async (exitReason, turns) => {
@@ -553,6 +549,17 @@ var createSession = async ({
553
549
  stateManager.run();
554
550
  }
555
551
  );
552
+ let sandboxId = inheritedSandboxId;
553
+ const ownsSandbox = !sandboxId && !!sandboxOps;
554
+ if (ownsSandbox) {
555
+ const result = await sandboxOps.createSandbox({ id: threadId });
556
+ sandboxId = result.sandboxId;
557
+ if (result.stateUpdate) {
558
+ stateManager.mergeUpdate(
559
+ result.stateUpdate
560
+ );
561
+ }
562
+ }
556
563
  if (hooks.onSessionStart) {
557
564
  await hooks.onSessionStart({
558
565
  threadId,
@@ -561,7 +568,9 @@ var createSession = async ({
561
568
  });
562
569
  }
563
570
  const systemPrompt = stateManager.getSystemPrompt();
564
- if (!continueThread) {
571
+ if (continueThread && sourceThreadId) {
572
+ await forkThread(sourceThreadId, threadId);
573
+ } else {
565
574
  if (appendSystemPrompt) {
566
575
  if (!systemPrompt || systemPrompt.trim() === "") {
567
576
  throw ApplicationFailure.create({
@@ -593,6 +602,7 @@ var createSession = async ({
593
602
  stateManager.complete();
594
603
  exitReason = "completed";
595
604
  return {
605
+ threadId,
596
606
  finalMessage: message,
597
607
  exitReason,
598
608
  usage: stateManager.getTotalUsage()
@@ -616,7 +626,8 @@ var createSession = async ({
616
626
  const toolCallResults = await toolRouter.processToolCalls(
617
627
  parsedToolCalls,
618
628
  {
619
- turn: currentTurn
629
+ turn: currentTurn,
630
+ ...sandboxId !== void 0 && { sandboxId }
620
631
  }
621
632
  );
622
633
  for (const result of toolCallResults) {
@@ -644,8 +655,12 @@ var createSession = async ({
644
655
  throw ApplicationFailure.fromError(error);
645
656
  } finally {
646
657
  await callSessionEnd(exitReason, stateManager.getTurns());
658
+ if (ownsSandbox && sandboxId && sandboxOps) {
659
+ await sandboxOps.destroySandbox(sandboxId);
660
+ }
647
661
  }
648
662
  return {
663
+ threadId,
649
664
  finalMessage: null,
650
665
  exitReason,
651
666
  usage: stateManager.getTotalUsage()
@@ -666,16 +681,109 @@ function proxyDefaultThreadOps(options) {
666
681
  }
667
682
  );
668
683
  }
684
+ function proxySandboxOps(options) {
685
+ return proxyActivities(
686
+ options ?? {
687
+ startToCloseTimeout: "30s",
688
+ retry: {
689
+ maximumAttempts: 3,
690
+ initialInterval: "2s",
691
+ maximumInterval: "30s",
692
+ backoffCoefficient: 2
693
+ }
694
+ }
695
+ );
696
+ }
697
+
698
+ // src/lib/thread/manager.ts
699
+ var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
700
+ var APPEND_IDEMPOTENT_SCRIPT = `
701
+ if redis.call('EXISTS', KEYS[1]) == 1 then
702
+ return 0
703
+ end
704
+ for i = 2, #ARGV do
705
+ redis.call('RPUSH', KEYS[2], ARGV[i])
706
+ end
707
+ redis.call('EXPIRE', KEYS[2], tonumber(ARGV[1]))
708
+ redis.call('SET', KEYS[1], '1', 'EX', tonumber(ARGV[1]))
709
+ return 1
710
+ `;
711
+ function getThreadKey(threadId, key) {
712
+ return `thread:${threadId}:${key}`;
713
+ }
714
+ function createThreadManager(config) {
715
+ const {
716
+ redis,
717
+ threadId,
718
+ key = "messages",
719
+ serialize = (m) => JSON.stringify(m),
720
+ deserialize = (raw) => JSON.parse(raw),
721
+ idOf
722
+ } = config;
723
+ const redisKey = getThreadKey(threadId, key);
724
+ const metaKey = getThreadKey(threadId, `${key}:meta`);
725
+ async function assertThreadExists() {
726
+ const exists = await redis.exists(metaKey);
727
+ if (!exists) {
728
+ throw new Error(`Thread "${threadId}" (key: ${key}) does not exist`);
729
+ }
730
+ }
731
+ return {
732
+ async initialize() {
733
+ await redis.del(redisKey);
734
+ await redis.set(metaKey, "1", "EX", THREAD_TTL_SECONDS);
735
+ },
736
+ async load() {
737
+ await assertThreadExists();
738
+ const data = await redis.lrange(redisKey, 0, -1);
739
+ return data.map(deserialize);
740
+ },
741
+ async append(messages) {
742
+ if (messages.length === 0) return;
743
+ await assertThreadExists();
744
+ if (idOf) {
745
+ const dedupId = messages.map(idOf).join(":");
746
+ const dedupKey = getThreadKey(threadId, `dedup:${dedupId}`);
747
+ await redis.eval(
748
+ APPEND_IDEMPOTENT_SCRIPT,
749
+ 2,
750
+ dedupKey,
751
+ redisKey,
752
+ String(THREAD_TTL_SECONDS),
753
+ ...messages.map(serialize)
754
+ );
755
+ } else {
756
+ await redis.rpush(redisKey, ...messages.map(serialize));
757
+ await redis.expire(redisKey, THREAD_TTL_SECONDS);
758
+ }
759
+ },
760
+ async fork(newThreadId) {
761
+ await assertThreadExists();
762
+ const data = await redis.lrange(redisKey, 0, -1);
763
+ const forked = createThreadManager({
764
+ ...config,
765
+ threadId: newThreadId
766
+ });
767
+ await forked.initialize();
768
+ if (data.length > 0) {
769
+ const newKey = getThreadKey(newThreadId, key);
770
+ await redis.rpush(newKey, ...data);
771
+ await redis.expire(newKey, THREAD_TTL_SECONDS);
772
+ }
773
+ return forked;
774
+ },
775
+ async delete() {
776
+ await redis.del(redisKey, metaKey);
777
+ }
778
+ };
779
+ }
669
780
 
670
781
  // src/lib/types.ts
671
- var agentQueryName = (agentName) => `get${agentName}State`;
672
- var agentStateChangeUpdateName = (agentName) => `waitFor${agentName}StateChange`;
673
782
  function isTerminalStatus(status) {
674
783
  return status === "COMPLETED" || status === "FAILED" || status === "CANCELLED";
675
784
  }
676
785
  function createAgentStateManager({
677
- initialState,
678
- agentName
786
+ initialState
679
787
  }) {
680
788
  let status = initialState?.status ?? "RUNNING";
681
789
  let version = initialState?.version ?? 0;
@@ -706,11 +814,9 @@ function createAgentStateManager({
706
814
  ...customState
707
815
  };
708
816
  }
709
- const stateQuery = defineQuery(
710
- agentQueryName(agentName)
711
- );
817
+ const stateQuery = defineQuery("getAgentState");
712
818
  const stateChangeUpdate = defineUpdate(
713
- agentStateChangeUpdateName(agentName)
819
+ "waitForAgentStateChange"
714
820
  );
715
821
  setHandler(stateQuery, () => buildState());
716
822
  setHandler(stateChangeUpdate, async (lastKnownVersion) => {
@@ -774,6 +880,10 @@ function createAgentStateManager({
774
880
  customState[key] = value;
775
881
  version++;
776
882
  },
883
+ mergeUpdate(update) {
884
+ Object.assign(customState, update);
885
+ version++;
886
+ },
777
887
  getCurrentState() {
778
888
  return buildState();
779
889
  },
@@ -829,6 +939,127 @@ function createAgentStateManager({
829
939
  };
830
940
  }
831
941
 
942
+ // src/lib/tool-router/auto-append.ts
943
+ function withAutoAppend(threadHandler, handler) {
944
+ return async (args, context) => {
945
+ const response = await handler(args, context);
946
+ await threadHandler({
947
+ threadId: context.threadId,
948
+ toolCallId: context.toolCallId,
949
+ toolName: context.toolName,
950
+ content: response.toolResponse
951
+ });
952
+ return {
953
+ toolResponse: "Response appended via withAutoAppend",
954
+ data: response.data,
955
+ resultAppended: true
956
+ };
957
+ };
958
+ }
959
+
960
+ // src/lib/tool-router/with-sandbox.ts
961
+ function withSandbox(manager, handler) {
962
+ return async (args, context) => {
963
+ if (!context.sandboxId) {
964
+ return {
965
+ toolResponse: `Error: No sandbox configured for this agent. The ${context.toolName} tool requires a sandbox.`,
966
+ data: null
967
+ };
968
+ }
969
+ const sandbox = await manager.getSandbox(context.sandboxId);
970
+ return handler(args, { ...context, sandbox, sandboxId: context.sandboxId });
971
+ };
972
+ }
973
+
974
+ // src/lib/subagent/define.ts
975
+ function defineSubagent(config) {
976
+ return config;
977
+ }
978
+ var SandboxNotSupportedError = class extends ApplicationFailure$1 {
979
+ constructor(operation) {
980
+ super(
981
+ `Sandbox does not support: ${operation}`,
982
+ "SandboxNotSupportedError",
983
+ true
984
+ );
985
+ }
986
+ };
987
+ var SandboxNotFoundError = class extends ApplicationFailure$1 {
988
+ constructor(sandboxId) {
989
+ super(`Sandbox not found: ${sandboxId}`, "SandboxNotFoundError", true);
990
+ }
991
+ };
992
+
993
+ // src/adapters/sandbox/virtual/mutations.ts
994
+ function applyVirtualTreeMutations(stateManager, mutations) {
995
+ let tree = [...stateManager.get("fileTree")];
996
+ for (const m of mutations) {
997
+ switch (m.type) {
998
+ case "add":
999
+ tree.push(m.entry);
1000
+ break;
1001
+ case "remove":
1002
+ tree = tree.filter((e) => e.path !== m.path);
1003
+ break;
1004
+ case "update":
1005
+ tree = tree.map(
1006
+ (e) => e.path === m.path ? { ...e, ...m.entry } : e
1007
+ );
1008
+ break;
1009
+ }
1010
+ }
1011
+ stateManager.set("fileTree", tree);
1012
+ return tree;
1013
+ }
1014
+
1015
+ // src/adapters/sandbox/virtual/tree.ts
1016
+ var buildTree = (entries) => {
1017
+ const root = { name: "/", children: /* @__PURE__ */ new Map(), isFile: false };
1018
+ for (const entry of entries) {
1019
+ const parts = entry.path.split("/").filter(Boolean);
1020
+ let current = root;
1021
+ for (const part of parts) {
1022
+ let child = current.children.get(part);
1023
+ if (!child) {
1024
+ child = { name: part, children: /* @__PURE__ */ new Map(), isFile: false };
1025
+ current.children.set(part, child);
1026
+ }
1027
+ current = child;
1028
+ }
1029
+ current.isFile = current.children.size === 0;
1030
+ }
1031
+ return root;
1032
+ };
1033
+ var printNode = (node, tab, sort) => {
1034
+ const entries = [...node.children.values()];
1035
+ if (sort) {
1036
+ entries.sort((a, b) => {
1037
+ if (!a.isFile && !b.isFile) return a.name.localeCompare(b.name);
1038
+ if (!a.isFile) return -1;
1039
+ if (!b.isFile) return 1;
1040
+ return a.name.localeCompare(b.name);
1041
+ });
1042
+ }
1043
+ let str = "";
1044
+ for (const [i, entry] of entries.entries()) {
1045
+ const isLast = i === entries.length - 1;
1046
+ const branch = isLast ? "\u2514\u2500" : "\u251C\u2500";
1047
+ const childTab = tab + (isLast ? " " : "\u2502 ");
1048
+ if (entry.isFile) {
1049
+ str += "\n" + tab + branch + " " + entry.name;
1050
+ } else {
1051
+ const subtree = printNode(entry, childTab, sort);
1052
+ str += "\n" + tab + branch + " " + entry.name + "/" + subtree;
1053
+ }
1054
+ }
1055
+ return str;
1056
+ };
1057
+ function formatVirtualFileTree(entries, opts = {}) {
1058
+ const sort = opts.sort ?? true;
1059
+ const root = buildTree(entries);
1060
+ return "/" + printNode(root, "", sort);
1061
+ }
1062
+
832
1063
  // src/lib/skills/parse.ts
833
1064
  function parseSkillFile(raw) {
834
1065
  const trimmed = raw.replace(/^\uFEFF/, "");
@@ -1250,197 +1481,313 @@ var createAskUserQuestionHandler = () => async (args) => {
1250
1481
  data: { questions: args.questions }
1251
1482
  };
1252
1483
  };
1253
-
1254
- // src/lib/thread-manager.ts
1255
- var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
1256
- var APPEND_IDEMPOTENT_SCRIPT = `
1257
- if redis.call('EXISTS', KEYS[1]) == 1 then
1258
- return 0
1259
- end
1260
- for i = 2, #ARGV do
1261
- redis.call('RPUSH', KEYS[2], ARGV[i])
1262
- end
1263
- redis.call('EXPIRE', KEYS[2], tonumber(ARGV[1]))
1264
- redis.call('SET', KEYS[1], '1', 'EX', tonumber(ARGV[1]))
1265
- return 1
1266
- `;
1267
- function getThreadKey(threadId, key) {
1268
- return `thread:${threadId}:${key}`;
1269
- }
1270
- function createThreadManager(config) {
1271
- const {
1272
- redis,
1273
- threadId,
1274
- key = "messages",
1275
- serialize = (m) => JSON.stringify(m),
1276
- deserialize = (raw) => JSON.parse(raw),
1277
- idOf
1278
- } = config;
1279
- const redisKey = getThreadKey(threadId, key);
1280
- const metaKey = getThreadKey(threadId, `${key}:meta`);
1281
- async function assertThreadExists() {
1282
- const exists = await redis.exists(metaKey);
1283
- if (!exists) {
1284
- throw new Error(`Thread "${threadId}" (key: ${key}) does not exist`);
1484
+ var FileSystemSkillProvider = class {
1485
+ constructor(fs, baseDir) {
1486
+ this.fs = fs;
1487
+ this.baseDir = baseDir;
1488
+ }
1489
+ async listSkills() {
1490
+ const dirs = await this.discoverSkillDirs();
1491
+ const skills = [];
1492
+ for (const dir of dirs) {
1493
+ const raw = await this.fs.readFile(join(this.baseDir, dir, "SKILL.md"));
1494
+ const { frontmatter } = parseSkillFile(raw);
1495
+ skills.push(frontmatter);
1285
1496
  }
1497
+ return skills;
1286
1498
  }
1287
- return {
1288
- async initialize() {
1289
- await redis.del(redisKey);
1290
- await redis.set(metaKey, "1", "EX", THREAD_TTL_SECONDS);
1291
- },
1292
- async load() {
1293
- await assertThreadExists();
1294
- const data = await redis.lrange(redisKey, 0, -1);
1295
- return data.map(deserialize);
1296
- },
1297
- async append(messages) {
1298
- if (messages.length === 0) return;
1299
- await assertThreadExists();
1300
- if (idOf) {
1301
- const dedupId = messages.map(idOf).join(":");
1302
- const dedupKey = getThreadKey(threadId, `dedup:${dedupId}`);
1303
- await redis.eval(
1304
- APPEND_IDEMPOTENT_SCRIPT,
1305
- 2,
1306
- dedupKey,
1307
- redisKey,
1308
- String(THREAD_TTL_SECONDS),
1309
- ...messages.map(serialize)
1310
- );
1311
- } else {
1312
- await redis.rpush(redisKey, ...messages.map(serialize));
1313
- await redis.expire(redisKey, THREAD_TTL_SECONDS);
1499
+ async getSkill(name) {
1500
+ const raw = await this.fs.readFile(
1501
+ join(this.baseDir, name, "SKILL.md")
1502
+ );
1503
+ const { frontmatter, body } = parseSkillFile(raw);
1504
+ if (frontmatter.name !== name) {
1505
+ throw new Error(
1506
+ `Skill directory "${name}" contains SKILL.md with mismatched name "${frontmatter.name}"`
1507
+ );
1508
+ }
1509
+ return { ...frontmatter, instructions: body };
1510
+ }
1511
+ /**
1512
+ * Convenience method to load all skills with full instructions.
1513
+ * Returns `Skill[]` ready to pass into a workflow.
1514
+ */
1515
+ async loadAll() {
1516
+ const dirs = await this.discoverSkillDirs();
1517
+ const skills = [];
1518
+ for (const dir of dirs) {
1519
+ const raw = await this.fs.readFile(join(this.baseDir, dir, "SKILL.md"));
1520
+ const { frontmatter, body } = parseSkillFile(raw);
1521
+ skills.push({ ...frontmatter, instructions: body });
1522
+ }
1523
+ return skills;
1524
+ }
1525
+ async discoverSkillDirs() {
1526
+ const entries = await this.fs.readdirWithFileTypes(this.baseDir);
1527
+ const dirs = [];
1528
+ for (const entry of entries) {
1529
+ if (!entry.isDirectory) continue;
1530
+ const skillPath = join(this.baseDir, entry.name, "SKILL.md");
1531
+ if (await this.fs.exists(skillPath)) {
1532
+ dirs.push(entry.name);
1314
1533
  }
1315
- },
1316
- async delete() {
1317
- await redis.del(redisKey, metaKey);
1318
1534
  }
1319
- };
1320
- }
1321
- async function queryParentWorkflowState(client, queryName) {
1535
+ return dirs;
1536
+ }
1537
+ };
1538
+ async function queryParentWorkflowState(client) {
1322
1539
  const { workflowExecution } = Context.current().info;
1323
1540
  const handle = client.getHandle(
1324
1541
  workflowExecution.workflowId,
1325
1542
  workflowExecution.runId
1326
1543
  );
1327
- return handle.query(queryName);
1544
+ return handle.query("getAgentState");
1328
1545
  }
1329
- function createRunAgentActivity(client, invoker) {
1546
+ function createRunAgentActivity(client, handler) {
1330
1547
  return async (config) => {
1331
- const state = await queryParentWorkflowState(
1332
- client,
1333
- agentQueryName(config.agentName)
1334
- );
1335
- return invoker({ ...config, state });
1548
+ const state = await queryParentWorkflowState(client);
1549
+ return handler({ ...config, state });
1336
1550
  };
1337
1551
  }
1338
- function createGlobHandler(fs) {
1339
- return async (_args) => {
1340
- new Bash({ fs });
1341
- return {
1342
- toolResponse: "Hello, world!",
1343
- data: { files: [] }
1344
- };
1552
+ function withParentWorkflowState(client, handler) {
1553
+ return async (args, context) => {
1554
+ const state = await queryParentWorkflowState(client);
1555
+ return handler(args, { ...context, state });
1345
1556
  };
1346
1557
  }
1347
1558
 
1559
+ // src/lib/sandbox/manager.ts
1560
+ var SandboxManager = class {
1561
+ constructor(provider) {
1562
+ this.provider = provider;
1563
+ }
1564
+ async create(options) {
1565
+ const { sandbox, stateUpdate } = await this.provider.create(options);
1566
+ return { sandboxId: sandbox.id, ...stateUpdate && { stateUpdate } };
1567
+ }
1568
+ async getSandbox(id) {
1569
+ return this.provider.get(id);
1570
+ }
1571
+ async destroy(id) {
1572
+ await this.provider.destroy(id);
1573
+ }
1574
+ async snapshot(id) {
1575
+ return this.provider.snapshot(id);
1576
+ }
1577
+ async restore(snapshot) {
1578
+ const sandbox = await this.provider.restore(snapshot);
1579
+ return sandbox.id;
1580
+ }
1581
+ /**
1582
+ * Returns Temporal activity functions matching {@link SandboxOps}.
1583
+ * Spread these into your worker's activity map.
1584
+ */
1585
+ createActivities() {
1586
+ return {
1587
+ createSandbox: async (options) => {
1588
+ return this.create(options);
1589
+ },
1590
+ destroySandbox: async (sandboxId) => {
1591
+ await this.destroy(sandboxId);
1592
+ },
1593
+ snapshotSandbox: async (sandboxId) => {
1594
+ return this.snapshot(sandboxId);
1595
+ }
1596
+ };
1597
+ }
1598
+ };
1599
+
1600
+ // src/tools/bash/handler.ts
1601
+ var bashHandler = async (args, { sandbox }) => {
1602
+ try {
1603
+ const result = await sandbox.exec(args.command);
1604
+ return {
1605
+ toolResponse: `Exit code: ${result.exitCode}
1606
+
1607
+ stdout:
1608
+ ${result.stdout}
1609
+
1610
+ stderr:
1611
+ ${result.stderr}`,
1612
+ data: result
1613
+ };
1614
+ } catch (error) {
1615
+ const err = error instanceof Error ? error : new Error("Unknown error");
1616
+ return {
1617
+ toolResponse: `Error executing bash command: ${err.message}`,
1618
+ data: null
1619
+ };
1620
+ }
1621
+ };
1622
+
1348
1623
  // src/tools/edit/handler.ts
1349
1624
  function escapeRegExp(str) {
1350
1625
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1351
1626
  }
1352
- function createEditHandler(fs) {
1353
- return async (args) => {
1354
- const { file_path, old_string, new_string, replace_all = false } = args;
1355
- if (old_string === new_string) {
1627
+ var editHandler = async (args, { sandbox }) => {
1628
+ const { fs } = sandbox;
1629
+ const { file_path, old_string, new_string, replace_all = false } = args;
1630
+ if (old_string === new_string) {
1631
+ return {
1632
+ toolResponse: `Error: old_string and new_string must be different.`,
1633
+ data: { path: file_path, success: false, replacements: 0 }
1634
+ };
1635
+ }
1636
+ try {
1637
+ const exists = await fs.exists(file_path);
1638
+ if (!exists) {
1356
1639
  return {
1357
- toolResponse: `Error: old_string and new_string must be different.`,
1640
+ toolResponse: `Error: File "${file_path}" does not exist.`,
1358
1641
  data: { path: file_path, success: false, replacements: 0 }
1359
1642
  };
1360
1643
  }
1361
- try {
1362
- const exists = await fs.exists(file_path);
1363
- if (!exists) {
1364
- return {
1365
- toolResponse: `Error: File "${file_path}" does not exist.`,
1366
- data: { path: file_path, success: false, replacements: 0 }
1367
- };
1368
- }
1369
- const content = await fs.readFile(file_path);
1370
- if (!content.includes(old_string)) {
1371
- return {
1372
- toolResponse: `Error: Could not find the specified text in "${file_path}". Make sure old_string matches exactly (whitespace-sensitive).`,
1373
- data: { path: file_path, success: false, replacements: 0 }
1374
- };
1375
- }
1376
- const escapedOldString = escapeRegExp(old_string);
1377
- const globalRegex = new RegExp(escapedOldString, "g");
1378
- const occurrences = (content.match(globalRegex) || []).length;
1379
- if (!replace_all && occurrences > 1) {
1380
- return {
1381
- toolResponse: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
1382
- data: { path: file_path, success: false, replacements: 0 }
1383
- };
1384
- }
1385
- let newContent;
1386
- let replacements;
1387
- if (replace_all) {
1388
- newContent = content.split(old_string).join(new_string);
1389
- replacements = occurrences;
1390
- } else {
1391
- const index = content.indexOf(old_string);
1392
- newContent = content.slice(0, index) + new_string + content.slice(index + old_string.length);
1393
- replacements = 1;
1394
- }
1395
- await fs.writeFile(file_path, newContent);
1396
- const summary = replace_all ? `Replaced ${replacements} occurrence(s)` : `Replaced 1 occurrence`;
1644
+ const content = await fs.readFile(file_path);
1645
+ if (!content.includes(old_string)) {
1397
1646
  return {
1398
- toolResponse: `${summary} in ${file_path}`,
1399
- data: { path: file_path, success: true, replacements }
1647
+ toolResponse: `Error: Could not find the specified text in "${file_path}". Make sure old_string matches exactly (whitespace-sensitive).`,
1648
+ data: { path: file_path, success: false, replacements: 0 }
1400
1649
  };
1401
- } catch (error) {
1402
- const message = error instanceof Error ? error.message : "Unknown error";
1650
+ }
1651
+ const escapedOldString = escapeRegExp(old_string);
1652
+ const globalRegex = new RegExp(escapedOldString, "g");
1653
+ const occurrences = (content.match(globalRegex) || []).length;
1654
+ if (!replace_all && occurrences > 1) {
1403
1655
  return {
1404
- toolResponse: `Error editing file "${file_path}": ${message}`,
1656
+ toolResponse: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
1405
1657
  data: { path: file_path, success: false, replacements: 0 }
1406
1658
  };
1407
1659
  }
1408
- };
1660
+ let newContent;
1661
+ let replacements;
1662
+ if (replace_all) {
1663
+ newContent = content.split(old_string).join(new_string);
1664
+ replacements = occurrences;
1665
+ } else {
1666
+ const index = content.indexOf(old_string);
1667
+ newContent = content.slice(0, index) + new_string + content.slice(index + old_string.length);
1668
+ replacements = 1;
1669
+ }
1670
+ await fs.writeFile(file_path, newContent);
1671
+ const summary = replace_all ? `Replaced ${replacements} occurrence(s)` : `Replaced 1 occurrence`;
1672
+ return {
1673
+ toolResponse: `${summary} in ${file_path}`,
1674
+ data: { path: file_path, success: true, replacements }
1675
+ };
1676
+ } catch (error) {
1677
+ const message = error instanceof Error ? error.message : "Unknown error";
1678
+ return {
1679
+ toolResponse: `Error editing file "${file_path}": ${message}`,
1680
+ data: { path: file_path, success: false, replacements: 0 }
1681
+ };
1682
+ }
1683
+ };
1684
+
1685
+ // src/tools/glob/handler.ts
1686
+ function matchGlob(pattern, path) {
1687
+ const regex = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
1688
+ return new RegExp(`^${regex}$`).test(path);
1409
1689
  }
1410
- var createBashHandler = (bashOptions) => async (args, _context) => {
1411
- const { command } = args;
1412
- const mergedOptions = {
1413
- ...bashOptions,
1414
- executionLimits: {
1415
- maxStringLength: 52428800,
1416
- // 50MB default
1417
- ...bashOptions.executionLimits
1690
+ async function walk(fs, dir) {
1691
+ const results = [];
1692
+ const entries = await fs.readdirWithFileTypes(dir);
1693
+ for (const entry of entries) {
1694
+ const full = dir === "/" ? `/${entry.name}` : `${dir}/${entry.name}`;
1695
+ if (entry.isDirectory) {
1696
+ results.push(...await walk(fs, full));
1697
+ } else {
1698
+ results.push(full);
1418
1699
  }
1419
- };
1420
- const bash = new Bash(mergedOptions);
1700
+ }
1701
+ return results;
1702
+ }
1703
+ var globHandler = async (args, { sandbox }) => {
1704
+ const { fs } = sandbox;
1705
+ const { pattern, root = "/" } = args;
1421
1706
  try {
1422
- const { exitCode, stderr, stdout } = await bash.exec(command);
1423
- const bashExecOut = { exitCode, stderr, stdout };
1707
+ const allFiles = await walk(fs, root);
1708
+ const relativeTo = root.endsWith("/") ? root : `${root}/`;
1709
+ const matched = allFiles.map((f) => f.startsWith(relativeTo) ? f.slice(relativeTo.length) : f).filter((f) => matchGlob(pattern, f));
1424
1710
  return {
1425
- toolResponse: `Exit code: ${exitCode}
1426
-
1427
- stdout:
1428
- ${stdout}
1711
+ toolResponse: matched.length > 0 ? `Found ${matched.length} file(s):
1712
+ ${matched.join("\n")}` : `No files matched pattern "${pattern}"`,
1713
+ data: { files: matched }
1714
+ };
1715
+ } catch (error) {
1716
+ const message = error instanceof Error ? error.message : "Unknown error";
1717
+ return {
1718
+ toolResponse: `Error running glob: ${message}`,
1719
+ data: { files: [] }
1720
+ };
1721
+ }
1722
+ };
1429
1723
 
1430
- stderr:
1431
- ${stderr}`,
1432
- data: bashExecOut
1724
+ // src/tools/read-file/handler.ts
1725
+ var readFileHandler = async (args, { sandbox }) => {
1726
+ const { fs } = sandbox;
1727
+ const { path, offset, limit } = args;
1728
+ try {
1729
+ const exists = await fs.exists(path);
1730
+ if (!exists) {
1731
+ return {
1732
+ toolResponse: `Error: File "${path}" does not exist.`,
1733
+ data: null
1734
+ };
1735
+ }
1736
+ const raw = await fs.readFile(path);
1737
+ const lines = raw.split("\n");
1738
+ const totalLines = lines.length;
1739
+ if (offset !== void 0 || limit !== void 0) {
1740
+ const start = Math.max(0, (offset ?? 1) - 1);
1741
+ const end = limit !== void 0 ? start + limit : lines.length;
1742
+ const slice = lines.slice(start, end);
1743
+ const numbered2 = slice.map((line, i) => `${String(start + i + 1).padStart(6)}|${line}`).join("\n");
1744
+ return {
1745
+ toolResponse: numbered2,
1746
+ data: { path, content: numbered2, totalLines }
1747
+ };
1748
+ }
1749
+ const numbered = lines.map((line, i) => `${String(i + 1).padStart(6)}|${line}`).join("\n");
1750
+ return {
1751
+ toolResponse: numbered,
1752
+ data: { path, content: numbered, totalLines }
1433
1753
  };
1434
1754
  } catch (error) {
1435
- const err = error instanceof Error ? error : new Error("Unknown error");
1755
+ const message = error instanceof Error ? error.message : "Unknown error";
1436
1756
  return {
1437
- toolResponse: `Error executing bash command: ${err.message}`,
1757
+ toolResponse: `Error reading file "${path}": ${message}`,
1438
1758
  data: null
1439
1759
  };
1440
1760
  }
1441
1761
  };
1442
1762
 
1443
- // src/lib/fs.ts
1763
+ // src/tools/write-file/handler.ts
1764
+ var writeFileHandler = async (args, { sandbox }) => {
1765
+ const { fs } = sandbox;
1766
+ const { file_path, content } = args;
1767
+ try {
1768
+ const lastSlash = file_path.lastIndexOf("/");
1769
+ if (lastSlash > 0) {
1770
+ const dir = file_path.slice(0, lastSlash);
1771
+ const dirExists = await fs.exists(dir);
1772
+ if (!dirExists) {
1773
+ await fs.mkdir(dir, { recursive: true });
1774
+ }
1775
+ }
1776
+ await fs.writeFile(file_path, content);
1777
+ return {
1778
+ toolResponse: `Successfully wrote to ${file_path}`,
1779
+ data: { path: file_path, success: true }
1780
+ };
1781
+ } catch (error) {
1782
+ const message = error instanceof Error ? error.message : "Unknown error";
1783
+ return {
1784
+ toolResponse: `Error writing file "${file_path}": ${message}`,
1785
+ data: { path: file_path, success: false }
1786
+ };
1787
+ }
1788
+ };
1789
+
1790
+ // src/lib/sandbox/tree.ts
1444
1791
  var basename = (path, separator) => {
1445
1792
  if (path[path.length - 1] === separator) path = path.slice(0, -1);
1446
1793
  const lastSlashIndex = path.lastIndexOf(separator);
@@ -1469,7 +1816,7 @@ var toTree = async (fs, opts = {}) => {
1469
1816
  const sort = opts.sort ?? true;
1470
1817
  let subtree = " (...)";
1471
1818
  if (depth > 0) {
1472
- const list = await fs.readdirWithFileTypes?.(dir) || [];
1819
+ const list = await fs.readdirWithFileTypes(dir);
1473
1820
  if (sort) {
1474
1821
  list.sort((a, b) => {
1475
1822
  if (a.isDirectory && b.isDirectory) {
@@ -1503,62 +1850,7 @@ var toTree = async (fs, opts = {}) => {
1503
1850
  const base = basename(dir, separator) + separator;
1504
1851
  return base + subtree;
1505
1852
  };
1506
- var FileSystemSkillProvider = class {
1507
- constructor(baseDir) {
1508
- this.baseDir = baseDir;
1509
- }
1510
- async listSkills() {
1511
- const dirs = await this.discoverSkillDirs();
1512
- const skills = [];
1513
- for (const dir of dirs) {
1514
- const raw = await readFile(join(this.baseDir, dir, "SKILL.md"), "utf-8");
1515
- const { frontmatter } = parseSkillFile(raw);
1516
- skills.push(frontmatter);
1517
- }
1518
- return skills;
1519
- }
1520
- async getSkill(name) {
1521
- const raw = await readFile(
1522
- join(this.baseDir, name, "SKILL.md"),
1523
- "utf-8"
1524
- );
1525
- const { frontmatter, body } = parseSkillFile(raw);
1526
- if (frontmatter.name !== name) {
1527
- throw new Error(
1528
- `Skill directory "${name}" contains SKILL.md with mismatched name "${frontmatter.name}"`
1529
- );
1530
- }
1531
- return { ...frontmatter, instructions: body };
1532
- }
1533
- /**
1534
- * Convenience method to load all skills with full instructions.
1535
- * Returns `Skill[]` ready to pass into a workflow.
1536
- */
1537
- async loadAll() {
1538
- const dirs = await this.discoverSkillDirs();
1539
- const skills = [];
1540
- for (const dir of dirs) {
1541
- const raw = await readFile(join(this.baseDir, dir, "SKILL.md"), "utf-8");
1542
- const { frontmatter, body } = parseSkillFile(raw);
1543
- skills.push({ ...frontmatter, instructions: body });
1544
- }
1545
- return skills;
1546
- }
1547
- async discoverSkillDirs() {
1548
- const entries = await readdir(this.baseDir, { withFileTypes: true });
1549
- const dirs = [];
1550
- for (const entry of entries) {
1551
- if (!entry.isDirectory()) continue;
1552
- try {
1553
- await readFile(join(this.baseDir, entry.name, "SKILL.md"), "utf-8");
1554
- dirs.push(entry.name);
1555
- } catch {
1556
- }
1557
- }
1558
- return dirs;
1559
- }
1560
- };
1561
1853
 
1562
- export { FileSystemSkillProvider, agentQueryName, agentStateChangeUpdateName, askUserQuestionTool, bashTool, createAgentStateManager, createAskUserQuestionHandler, createBashHandler, createBashToolDescription, createEditHandler, createGlobHandler, createReadSkillHandler, createReadSkillTool, createRunAgentActivity, createSession, createSubagentTool, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskUpdateHandler, createThreadManager, createToolRouter, defineSubagent, defineTool, editTool, getShortId, globTool, grepTool, hasNoOtherToolCalls, isTerminalStatus, parseSkillFile, proxyDefaultThreadOps, queryParentWorkflowState, readFileTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, withAutoAppend, writeFileTool };
1854
+ export { FileSystemSkillProvider, SandboxManager, SandboxNotFoundError, SandboxNotSupportedError, applyVirtualTreeMutations, askUserQuestionTool, bashHandler, bashTool, createAgentStateManager, createAskUserQuestionHandler, createBashToolDescription, createReadSkillHandler, createReadSkillTool, createRunAgentActivity, createSession, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskUpdateHandler, createThreadManager, createToolRouter, defineSubagent, defineTool, editHandler, editTool, formatVirtualFileTree, getShortId, globHandler, globTool, grepTool, hasNoOtherToolCalls, isTerminalStatus, parseSkillFile, proxyDefaultThreadOps, proxySandboxOps, queryParentWorkflowState, readFileHandler, readFileTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, withAutoAppend, withParentWorkflowState, withSandbox, writeFileHandler, writeFileTool };
1563
1855
  //# sourceMappingURL=index.js.map
1564
1856
  //# sourceMappingURL=index.js.map