@botbotgo/agent-harness 0.0.475 → 0.0.476

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 (227) hide show
  1. package/README.md +3 -1234
  2. package/README.zh.md +3 -1191
  3. package/dist/acp.js +1 -1
  4. package/dist/api.js +1 -404
  5. package/dist/benchmark/checkpoint-resume-cost-benchmark.js +1 -55
  6. package/dist/benchmark/deepagent-local-model-benchmark.js +2 -35
  7. package/dist/benchmark/upstream-runtime-ab-benchmark.js +1 -179
  8. package/dist/cli/chat-interactive.js +25 -244
  9. package/dist/cli/chat-rendering.js +6 -100
  10. package/dist/cli/chat-stream.js +23 -512
  11. package/dist/cli/chat-ui.js +21 -199
  12. package/dist/cli/chat-workspace.js +2 -210
  13. package/dist/cli/main.js +21 -428
  14. package/dist/cli/managed-service-commands.js +9 -63
  15. package/dist/cli/managed-service.js +2 -137
  16. package/dist/cli/options-init-chat.js +1 -108
  17. package/dist/cli/options-runtime.js +1 -158
  18. package/dist/cli/options-serve.js +1 -282
  19. package/dist/cli/options.js +2 -19
  20. package/dist/cli/process-guards.js +1 -139
  21. package/dist/cli/request-tree.js +7 -296
  22. package/dist/cli/runtime-commands.js +12 -258
  23. package/dist/cli/runtime-output.js +16 -155
  24. package/dist/cli/server-commands.js +16 -270
  25. package/dist/cli/workspace.js +1 -67
  26. package/dist/cli.js +1 -7
  27. package/dist/client/acp.js +1 -1
  28. package/dist/client/in-process.js +1 -67
  29. package/dist/client/index.js +1 -2
  30. package/dist/client/types.js +0 -1
  31. package/dist/client.js +1 -1
  32. package/dist/contracts/core.js +1 -1
  33. package/dist/contracts/runtime-evaluation.js +0 -1
  34. package/dist/contracts/runtime-memory.js +0 -1
  35. package/dist/contracts/runtime-observability.js +0 -1
  36. package/dist/contracts/runtime-requests.js +0 -1
  37. package/dist/contracts/runtime-scheduling.js +0 -1
  38. package/dist/contracts/runtime.js +1 -27
  39. package/dist/contracts/types.js +1 -3
  40. package/dist/contracts/workspace.js +0 -1
  41. package/dist/flow/build-flow-graph.js +1 -50
  42. package/dist/flow/export-mermaid.js +2 -464
  43. package/dist/flow/export-sequence-mermaid.js +2 -325
  44. package/dist/flow/flow-graph-normalization.js +1 -214
  45. package/dist/flow/flow-graph-runtime.js +1 -107
  46. package/dist/flow/flow-graph-upstream.js +1 -494
  47. package/dist/flow/index.js +1 -3
  48. package/dist/flow/types.js +0 -1
  49. package/dist/index.js +1 -5
  50. package/dist/init-project.js +1 -1
  51. package/dist/knowledge/config.js +1 -32
  52. package/dist/knowledge/contracts.js +0 -1
  53. package/dist/knowledge/index.js +1 -2
  54. package/dist/knowledge/module.js +12 -909
  55. package/dist/knowledge/procedural/config.js +1 -125
  56. package/dist/knowledge/procedural/index.js +1 -2
  57. package/dist/knowledge/procedural/manager.js +9 -345
  58. package/dist/mcp.js +1 -2
  59. package/dist/package-version.d.ts +1 -1
  60. package/dist/package-version.js +1 -2
  61. package/dist/persistence/file-store.js +3 -758
  62. package/dist/persistence/sqlite-request-context-store.js +5 -54
  63. package/dist/persistence/sqlite-request-queue-store.js +10 -108
  64. package/dist/persistence/sqlite-runtime.js +1 -86
  65. package/dist/persistence/sqlite-store.js +62 -810
  66. package/dist/persistence/types.js +0 -1
  67. package/dist/projections/presentation.js +37 -206
  68. package/dist/projections/request-events.js +2 -502
  69. package/dist/projections/upstream-events.js +1 -201
  70. package/dist/protocol/a2a/http-discovery.js +1 -178
  71. package/dist/protocol/a2a/http-rpc.js +6 -622
  72. package/dist/protocol/a2a/http.js +1 -138
  73. package/dist/protocol/a2a/task-state.js +3 -317
  74. package/dist/protocol/acp/client.js +8 -294
  75. package/dist/protocol/acp/harness-client.js +1 -218
  76. package/dist/protocol/acp/http.js +5 -130
  77. package/dist/protocol/acp/server.js +1 -310
  78. package/dist/protocol/acp/stdio.js +2 -69
  79. package/dist/protocol/ag-ui/http.js +3 -378
  80. package/dist/protocol/mcp/server.js +1 -428
  81. package/dist/resource/backend/workspace-scoped-backend.js +1 -319
  82. package/dist/resource/isolation.js +1 -237
  83. package/dist/resource/mcp/tool-support.js +3 -296
  84. package/dist/resource/mcp-tool-support.js +1 -2
  85. package/dist/resource/providers/resource-provider.js +1 -215
  86. package/dist/resource/resource-impl.js +1 -3
  87. package/dist/resource/resource-types.js +0 -1
  88. package/dist/resource/resource.js +1 -1
  89. package/dist/resource/sources.js +1 -247
  90. package/dist/resource/tools/function-tool-resolver.js +2 -272
  91. package/dist/runtime/adapter/compat/deepagent-compat.js +1 -29
  92. package/dist/runtime/adapter/compat/openai-compatible.js +1 -55
  93. package/dist/runtime/adapter/direct-builtin-utility.js +2 -90
  94. package/dist/runtime/adapter/flow/execution-context.js +1 -71
  95. package/dist/runtime/adapter/flow/invocation-flow.js +8 -425
  96. package/dist/runtime/adapter/flow/invoke-runtime.js +1 -20
  97. package/dist/runtime/adapter/flow/stream-runtime.js +11 -1395
  98. package/dist/runtime/adapter/invocation-result.js +2 -473
  99. package/dist/runtime/adapter/local-tool-invocation.js +6 -638
  100. package/dist/runtime/adapter/middleware/context-hygiene.js +1 -83
  101. package/dist/runtime/adapter/middleware-assembly.js +5 -477
  102. package/dist/runtime/adapter/model/invocation-request.js +3 -183
  103. package/dist/runtime/adapter/model/message-assembly.js +1 -28
  104. package/dist/runtime/adapter/model/model-providers.js +23 -1115
  105. package/dist/runtime/adapter/model/prompted-json-tool-call-capture.js +1 -40
  106. package/dist/runtime/adapter/model/prompted-json-tool-policy.js +1 -22
  107. package/dist/runtime/adapter/resilience.js +1 -104
  108. package/dist/runtime/adapter/runtime-adapter-support.js +3 -141
  109. package/dist/runtime/adapter/runtime-shell.js +5 -166
  110. package/dist/runtime/adapter/stream-event-projection.js +2 -622
  111. package/dist/runtime/adapter/stream-text-consumption.js +1 -18
  112. package/dist/runtime/adapter/terminal-status.js +2 -67
  113. package/dist/runtime/adapter/tool/builtin-middleware-tools.js +6 -627
  114. package/dist/runtime/adapter/tool/declared-middleware.js +1 -154
  115. package/dist/runtime/adapter/tool/interrupt-policy.js +1 -34
  116. package/dist/runtime/adapter/tool/provider-tool.js +1 -25
  117. package/dist/runtime/adapter/tool/resolved-tool.js +1 -225
  118. package/dist/runtime/adapter/tool/tool-arguments.js +3 -486
  119. package/dist/runtime/adapter/tool/tool-hitl.js +1 -346
  120. package/dist/runtime/adapter/tool/tool-name-mapping.js +1 -128
  121. package/dist/runtime/adapter/tool/tool-output-artifacts.js +2 -88
  122. package/dist/runtime/adapter/tool/tool-replay.js +1 -37
  123. package/dist/runtime/adapter/tool-resolution.js +1 -86
  124. package/dist/runtime/adapter/upstream-configurable-keys.js +1 -2
  125. package/dist/runtime/agent-runtime-adapter.js +60 -2338
  126. package/dist/runtime/agent-runtime-assembly.js +7 -249
  127. package/dist/runtime/env/runtime-env.js +1 -62
  128. package/dist/runtime/harness/background-runtime.js +1 -8
  129. package/dist/runtime/harness/bindings.js +1 -58
  130. package/dist/runtime/harness/events/event-bus.js +1 -16
  131. package/dist/runtime/harness/events/event-sink.js +1 -61
  132. package/dist/runtime/harness/events/events.js +1 -80
  133. package/dist/runtime/harness/events/listener-runtime.js +1 -13
  134. package/dist/runtime/harness/events/runtime-event-operations.js +1 -9
  135. package/dist/runtime/harness/events/streaming.js +1 -100
  136. package/dist/runtime/harness/events/timeline.js +1 -52
  137. package/dist/runtime/harness/public-shapes.js +1 -186
  138. package/dist/runtime/harness/run/artifact-paths.js +1 -15
  139. package/dist/runtime/harness/run/governance.js +1 -295
  140. package/dist/runtime/harness/run/helpers.js +1 -71
  141. package/dist/runtime/harness/run/inspection.js +1 -409
  142. package/dist/runtime/harness/run/operator-overview.js +1 -80
  143. package/dist/runtime/harness/run/queue-diagnostics.js +1 -15
  144. package/dist/runtime/harness/run/recovery.js +1 -162
  145. package/dist/runtime/harness/run/resources.js +1 -60
  146. package/dist/runtime/harness/run/resume.js +1 -56
  147. package/dist/runtime/harness/run/routing.js +1 -48
  148. package/dist/runtime/harness/run/run-lifecycle.js +1 -66
  149. package/dist/runtime/harness/run/run-operations.js +1 -217
  150. package/dist/runtime/harness/run/run-queue.js +1 -43
  151. package/dist/runtime/harness/run/run-slot-acquisition.js +1 -157
  152. package/dist/runtime/harness/run/session-records.js +1 -97
  153. package/dist/runtime/harness/run/start-run.js +1 -120
  154. package/dist/runtime/harness/run/startup-runtime.js +1 -69
  155. package/dist/runtime/harness/run/stream-run.js +8 -1418
  156. package/dist/runtime/harness/run/surface-semantics.js +1 -79
  157. package/dist/runtime/harness/runtime-defaults.js +1 -39
  158. package/dist/runtime/harness/system/boundary-analysis.js +1 -234
  159. package/dist/runtime/harness/system/health-monitor.js +1 -258
  160. package/dist/runtime/harness/system/inventory.js +1 -129
  161. package/dist/runtime/harness/system/mem0-ingestion-sync.js +5 -345
  162. package/dist/runtime/harness/system/policy-engine.js +1 -175
  163. package/dist/runtime/harness/system/runtime-memory-candidates.js +4 -110
  164. package/dist/runtime/harness/system/runtime-memory-consolidation.js +1 -51
  165. package/dist/runtime/harness/system/runtime-memory-manager.js +10 -693
  166. package/dist/runtime/harness/system/runtime-memory-policy.js +1 -155
  167. package/dist/runtime/harness/system/runtime-memory-records.js +11 -577
  168. package/dist/runtime/harness/system/runtime-memory-sync.js +5 -206
  169. package/dist/runtime/harness/system/session-memory-sync.js +3 -113
  170. package/dist/runtime/harness/system/skill-requirements.js +1 -112
  171. package/dist/runtime/harness/system/store.js +9 -365
  172. package/dist/runtime/harness/tool-gateway/index.js +1 -2
  173. package/dist/runtime/harness/tool-gateway/policy.js +1 -45
  174. package/dist/runtime/harness/tool-gateway/validation.js +1 -176
  175. package/dist/runtime/harness/tool-schema.js +1 -3
  176. package/dist/runtime/harness.js +3 -1490
  177. package/dist/runtime/index.js +1 -3
  178. package/dist/runtime/layout/runtime-layout.js +1 -31
  179. package/dist/runtime/maintenance/checkpoint-maintenance.js +2 -178
  180. package/dist/runtime/maintenance/file-checkpoint-saver.js +1 -106
  181. package/dist/runtime/maintenance/runtime-record-maintenance.js +2 -169
  182. package/dist/runtime/maintenance/sqlite-checkpoint-saver.js +4 -289
  183. package/dist/runtime/parsing/output-content.js +10 -550
  184. package/dist/runtime/parsing/output-parsing.js +1 -4
  185. package/dist/runtime/parsing/output-recovery.js +3 -213
  186. package/dist/runtime/parsing/output-tool-args.js +7 -663
  187. package/dist/runtime/parsing/stream-event-parsing.js +3 -362
  188. package/dist/runtime/prompts/runtime-prompts.js +4 -73
  189. package/dist/runtime/scheduling/system-schedule-manager.js +11 -532
  190. package/dist/runtime/skills/skill-metadata.js +1 -197
  191. package/dist/runtime/startup-tracing.js +2 -37
  192. package/dist/runtime/support/compiled-binding.js +1 -290
  193. package/dist/runtime/support/embedding-models.js +1 -118
  194. package/dist/runtime/support/harness-support.js +5 -137
  195. package/dist/runtime/support/llamaindex.js +1 -108
  196. package/dist/runtime/support/runtime-adapter-options.js +1 -29
  197. package/dist/runtime/support/runtime-factories.js +1 -51
  198. package/dist/runtime/support/vector-stores.js +9 -270
  199. package/dist/scaffold/init-project.js +54 -233
  200. package/dist/tooling/extensions.js +1 -311
  201. package/dist/tooling/module-loader.js +1 -55
  202. package/dist/tools.js +1 -176
  203. package/dist/utils/agent-display.js +1 -18
  204. package/dist/utils/bundled-text.js +4 -39
  205. package/dist/utils/compiled-binding.js +1 -33
  206. package/dist/utils/fs.js +2 -45
  207. package/dist/utils/id.js +1 -9
  208. package/dist/utils/message-content.js +1 -30
  209. package/dist/utils/object.js +1 -6
  210. package/dist/workspace/agent-binding-compiler.js +3 -613
  211. package/dist/workspace/compile.js +1 -472
  212. package/dist/workspace/framework-contract-validation.js +2 -322
  213. package/dist/workspace/index.js +1 -1
  214. package/dist/workspace/object-loader-paths.js +1 -71
  215. package/dist/workspace/object-loader-readers.js +1 -187
  216. package/dist/workspace/object-loader.js +1 -754
  217. package/dist/workspace/resource-compilers.js +1 -374
  218. package/dist/workspace/support/agent-capabilities.js +1 -37
  219. package/dist/workspace/support/agent-execution-config.js +1 -44
  220. package/dist/workspace/support/discovery.js +1 -147
  221. package/dist/workspace/support/source-collectors.js +1 -30
  222. package/dist/workspace/support/source-protocols.js +2 -192
  223. package/dist/workspace/support/workspace-ref-utils.js +1 -362
  224. package/dist/workspace/tool-hydration.js +1 -280
  225. package/dist/workspace/validate.js +1 -99
  226. package/dist/workspace/yaml-object-reader.js +1 -285
  227. package/package.json +7 -3
@@ -1,627 +1,6 @@
1
- import path from "node:path";
2
- import { z } from "zod";
3
- import { isSandboxBackend } from "deepagents";
4
- import { isRecord } from "../../../utils/object.js";
5
- import { formatBuiltinTodoSnapshot, summarizeBuiltinWriteTodosArgs, truncateLines } from "../runtime-adapter-support.js";
6
- import { maybePersistLargeToolOutput, resolveToolRuntimeContext } from "./tool-output-artifacts.js";
7
- function buildTaskToolDescription(subagents) {
8
- const lines = [
9
- "Delegate a bounded task to the subagent whose declared description best matches the task.",
10
- "Use this only when a subagent is a better fit than the current agent. Set subagent_type to exactly one listed subagent name.",
11
- ];
12
- const available = (subagents ?? [])
13
- .filter((subagent) => subagent.name.trim().length > 0)
14
- .map((subagent) => {
15
- const description = subagent.description.trim() || "No description provided.";
16
- return `- ${subagent.name}: ${description}`;
17
- });
18
- return available.length > 0
19
- ? [...lines, "", "Available subagents:", ...available].join("\n")
20
- : lines.join(" ");
21
- }
22
- function buildTaskToolSchema(subagents) {
23
- const names = (subagents ?? [])
24
- .map((subagent) => subagent.name.trim())
25
- .filter((name) => name.length > 0);
26
- const subagentTypeSchema = names.length > 0
27
- ? z.enum(names)
28
- : z.string();
29
- return z.object({
30
- description: z.string().describe("Concrete bounded task for the selected subagent to perform."),
31
- subagent_type: subagentTypeSchema.describe("Exact name of the selected subagent."),
32
- }).passthrough();
33
- }
34
- export const BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS = [
35
- { name: "write_todos", description: "Create and update the runtime todo board for multi-step work." },
36
- { name: "read_todos", description: "Read the current runtime todo board." },
37
- { name: "ls", description: "List files in a directory." },
38
- { name: "read_file", description: "Read a file from the workspace filesystem." },
39
- { name: "write_file", description: "Write a file in the workspace filesystem." },
40
- { name: "edit_file", description: "Replace exact text inside a workspace file." },
41
- { name: "glob", description: "Find files matching a glob pattern." },
42
- { name: "grep", description: "Search for text across workspace files." },
43
- { name: "execute", description: "Run a shell command in the workspace sandbox." },
44
- { name: "fetch_url", description: "Fetch a URL and return the response body." },
45
- { name: "http_request", description: "Send a structured HTTP request." },
46
- { name: "send_message", description: "Send a message through the configured backend." },
47
- { name: "request_approval", description: "Request an approval decision from the runtime." },
48
- { name: "schedule_task", description: "Create, inspect, update, list, and delete system-level scheduled tasks." },
49
- { name: "task", description: "Delegate a bounded task to a subagent." },
50
- ];
51
- export function filterBuiltinMiddlewareToolDescriptors(options) {
52
- const modelExposedNames = new Set([
53
- "fetch_url",
54
- "http_request",
55
- "send_message",
56
- "request_approval",
57
- "schedule_task",
58
- ]);
59
- const allowedModelExposedNames = Array.isArray(options?.modelExposed)
60
- ? new Set(options.modelExposed)
61
- : undefined;
62
- return BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS.filter((descriptor) => {
63
- if (options?.todos === false
64
- && (descriptor.name === "write_todos" || descriptor.name === "read_todos")) {
65
- return false;
66
- }
67
- if (options?.filesystem === false
68
- && [
69
- "ls",
70
- "read_file",
71
- "write_file",
72
- "edit_file",
73
- "glob",
74
- "grep",
75
- "execute",
76
- ].includes(descriptor.name)) {
77
- return false;
78
- }
79
- if (modelExposedNames.has(descriptor.name)) {
80
- if (options?.modelExposed === false) {
81
- return false;
82
- }
83
- if (allowedModelExposedNames && !allowedModelExposedNames.has(descriptor.name)) {
84
- return false;
85
- }
86
- }
87
- return true;
88
- }).map((descriptor) => ({ ...descriptor }));
89
- }
90
- function toDisplayContent(content) {
91
- if (typeof content === "string") {
92
- return content;
93
- }
94
- if (content instanceof Uint8Array) {
95
- return new TextDecoder().decode(content);
96
- }
97
- return "";
98
- }
99
- function notAvailable(toolName, capability) {
100
- return `Error: ${toolName} is not available. This backend does not support ${capability}.`;
101
- }
102
- function shellQuote(value) {
103
- return `'${value.replace(/'/g, `'\"'\"'`)}'`;
104
- }
105
- async function tryExecuteShallowDirectoryListing(backend, targetPath) {
106
- if (typeof backend.execute !== "function" || process.platform === "win32") {
107
- return undefined;
108
- }
109
- const quotedPath = shellQuote(targetPath);
110
- const command = [
111
- "set -f",
112
- `dir=${quotedPath}`,
113
- 'if [ ! -d "$dir" ]; then exit 0; fi',
114
- "count=0",
115
- 'for entry in "$dir"/* "$dir"/.[!.]* "$dir"/..?*; do',
116
- ' [ -e "$entry" ] || continue',
117
- ' if [ -d "$entry" ]; then',
118
- ' printf \'%s (directory)\\n\' \"$entry\"',
119
- " else",
120
- ' printf \'%s\\n\' \"$entry\"',
121
- " fi",
122
- " count=$((count + 1))",
123
- ' if [ "$count" -ge 400 ]; then',
124
- " printf '...[truncated]\\n'",
125
- " break",
126
- " fi",
127
- "done",
128
- ].join("; ");
129
- try {
130
- const result = await Promise.resolve(backend.execute(command));
131
- const output = typeof result?.output === "string" ? result.output.trim() : "";
132
- if (!output) {
133
- return undefined;
134
- }
135
- return output;
136
- }
137
- catch {
138
- return undefined;
139
- }
140
- }
141
- function resolveWorkspaceRoot(backend) {
142
- const typed = backend;
143
- if (typeof typed.rootDir === "string" && typed.rootDir.trim().length > 0) {
144
- return typed.rootDir.trim();
145
- }
146
- if (typeof typed.root === "string" && typed.root.trim().length > 0) {
147
- return typed.root.trim();
148
- }
149
- if (typeof typed.cwd === "string" && typed.cwd.trim().length > 0) {
150
- return typed.cwd.trim();
151
- }
152
- return undefined;
153
- }
154
- function normalizeWorkspacePathOrThrow(backend, inputPath) {
155
- if (!inputPath) {
156
- return inputPath;
157
- }
158
- const workspaceRoot = resolveWorkspaceRoot(backend);
159
- if (!workspaceRoot || !path.isAbsolute(inputPath)) {
160
- return inputPath;
161
- }
162
- if (inputPath.startsWith("/large_tool_results/")) {
163
- throw new Error(`Path '${inputPath}' is an internal runtime spill path, not a workspace file. Do not read internal runtime spill files such as '/large_tool_results/...'. Use the preview already in context, rerun the producing tool with narrower output, or write the needed data to a workspace-relative file instead.`);
164
- }
165
- const normalizedWorkspaceRoot = path.resolve(workspaceRoot);
166
- const normalizedInputPath = path.resolve(inputPath);
167
- if (normalizedInputPath === normalizedWorkspaceRoot || normalizedInputPath.startsWith(`${normalizedWorkspaceRoot}${path.sep}`)) {
168
- return path.relative(normalizedWorkspaceRoot, normalizedInputPath) || ".";
169
- }
170
- throw new Error(`Path '${inputPath}' is outside the workspace root '${normalizedWorkspaceRoot}'. Use a workspace-relative path instead.`);
171
- }
172
- function formatHttpResponse(result) {
173
- if (result?.error) {
174
- return result.error;
175
- }
176
- const content = toDisplayContent(result?.body ?? result?.content);
177
- const status = typeof result?.status === "number" ? `${result.status}${result.statusText ? ` ${result.statusText}` : ""}` : null;
178
- const headerLines = result?.headers ? Object.entries(result.headers).map(([key, value]) => `${key}: ${value}`) : [];
179
- const lines = [
180
- ...(status ? [`Status: ${status}`] : []),
181
- ...(headerLines.length > 0 ? ["Headers:", ...headerLines] : []),
182
- ...(content ? ["Body:", content] : []),
183
- ];
184
- return lines.length > 0 ? lines.join("\n") : "Request completed.";
185
- }
186
- async function fetchUrlWithRuntimeFallback(backend, url) {
187
- if (typeof backend.fetchUrl === "function") {
188
- try {
189
- const result = await Promise.resolve(backend.fetchUrl(url));
190
- if (typeof result === "string") {
191
- return result;
192
- }
193
- return formatHttpResponse(result);
194
- }
195
- catch {
196
- // Fall through to the runtime-owned network fetch below.
197
- }
198
- }
199
- const response = await fetch(url);
200
- return formatHttpResponse({
201
- status: response.status,
202
- statusText: response.statusText,
203
- headers: Object.fromEntries(response.headers.entries()),
204
- body: await response.text(),
205
- });
206
- }
207
- function parseScheduleWhen(value) {
208
- const normalized = value.trim().toLowerCase();
209
- if (!normalized) {
210
- return undefined;
211
- }
212
- const intervalMatch = /^every\s+(\d+)\s*(minute|minutes|min|mins|hour|hours|hr|hrs)$/u.exec(normalized);
213
- if (intervalMatch) {
214
- const quantity = Number.parseInt(intervalMatch[1], 10);
215
- const unit = intervalMatch[2];
216
- return {
217
- type: "interval",
218
- everyMinutes: unit.startsWith("h") ? quantity * 60 : quantity,
219
- };
220
- }
221
- if (normalized === "hourly" || normalized === "every hour") {
222
- return {
223
- type: "interval",
224
- everyMinutes: 60,
225
- };
226
- }
227
- return {
228
- type: "cron",
229
- expression: value,
230
- };
231
- }
232
- export async function createBuiltinMiddlewareTools(backend, options) {
233
- const tools = new Map();
234
- const pathScopedBackend = options.workspaceRoot
235
- ? { ...backend, rootDir: options.workspaceRoot }
236
- : backend;
237
- let todoSnapshot = {
238
- items: [],
239
- summary: {
240
- total: 0,
241
- pending: 0,
242
- inProgress: 0,
243
- completed: 0,
244
- failed: 0,
245
- cancelled: 0,
246
- },
247
- };
248
- const finalizeOutput = async (toolName, output, toolConfig) => maybePersistLargeToolOutput({
249
- toolName,
250
- output,
251
- toolRuntimeContext: resolveToolRuntimeContext(toolConfig, options.toolRuntimeContext),
252
- });
253
- tools.set("write_todos", {
254
- name: "write_todos",
255
- description: "Create and update the runtime todo board for multi-step work.",
256
- schema: z.object({
257
- todos: z.array(z.object({
258
- id: z.union([z.string(), z.number()]).optional(),
259
- content: z.string().optional(),
260
- description: z.string().optional(),
261
- title: z.string().optional(),
262
- name: z.string().optional(),
263
- text: z.string().optional(),
264
- status: z.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
265
- ownerAgentId: z.string().optional(),
266
- startedAt: z.string().optional(),
267
- endedAt: z.string().optional(),
268
- result: z.unknown().optional(),
269
- metadata: z.record(z.string(), z.unknown()).optional(),
270
- }).passthrough()).optional(),
271
- }).passthrough(),
272
- invoke: async (input) => {
273
- const args = isRecord(input) ? input : {};
274
- const summary = summarizeBuiltinWriteTodosArgs(args);
275
- todoSnapshot = summary;
276
- return {
277
- ok: true,
278
- tool: "write_todos",
279
- message: `Tracked ${summary.summary.total} todo item(s).`,
280
- summary,
281
- };
282
- },
283
- });
284
- tools.set("read_todos", {
285
- name: "read_todos",
286
- description: "Read the current runtime todo board.",
287
- schema: z.object({}).passthrough(),
288
- invoke: async () => ({
289
- ok: true,
290
- tool: "read_todos",
291
- message: formatBuiltinTodoSnapshot(todoSnapshot),
292
- summary: todoSnapshot,
293
- }),
294
- });
295
- tools.set("ls", {
296
- name: "ls",
297
- description: "List files in a directory.",
298
- schema: z.object({ path: z.string().optional().default("/") }).passthrough(),
299
- invoke: async (input, toolConfig) => {
300
- const targetPath = normalizeWorkspacePathOrThrow(pathScopedBackend, isRecord(input) && typeof input.path === "string" ? input.path : "/");
301
- const shallowListing = await tryExecuteShallowDirectoryListing(pathScopedBackend, targetPath);
302
- if (typeof shallowListing === "string") {
303
- return finalizeOutput("ls", shallowListing.length > 0 ? shallowListing : `No files found in ${targetPath}`, toolConfig);
304
- }
305
- const legacyInfos = (await Promise.resolve(backend.lsInfo?.(targetPath))) ?? [];
306
- const infos = legacyInfos.length > 0
307
- ? legacyInfos
308
- : ((await Promise.resolve(backend.ls?.(targetPath)))?.files ?? []).map((info) => ({
309
- path: info.path,
310
- is_dir: info.isDir,
311
- size: info.size,
312
- }));
313
- if (infos.length === 0) {
314
- return `No files found in ${targetPath}`;
315
- }
316
- return finalizeOutput("ls", truncateLines(infos.map((info) => info.is_dir ? `${info.path} (directory)` : `${info.path}${info.size ? ` (${info.size} bytes)` : ""}`)), toolConfig);
317
- },
318
- });
319
- tools.set("read_file", {
320
- name: "read_file",
321
- description: "Read a file from the workspace filesystem.",
322
- schema: z.object({
323
- file_path: z.string(),
324
- offset: z.number().optional(),
325
- limit: z.number().optional(),
326
- }).passthrough(),
327
- invoke: async (input) => {
328
- const typed = isRecord(input) ? input : {};
329
- const filePath = normalizeWorkspacePathOrThrow(pathScopedBackend, typeof typed.file_path === "string" ? typed.file_path : "");
330
- const offset = typeof typed.offset === "number" ? typed.offset : 0;
331
- const limit = typeof typed.limit === "number" ? typed.limit : 500;
332
- const result = await Promise.resolve(backend.read?.(filePath, offset, limit));
333
- if (typeof result === "string") {
334
- return result;
335
- }
336
- return result?.error ?? toDisplayContent(result?.content);
337
- },
338
- });
339
- tools.set("write_file", {
340
- name: "write_file",
341
- description: "Write a file in the workspace filesystem.",
342
- schema: z.object({ file_path: z.string(), content: z.string().optional() }).passthrough(),
343
- invoke: async (input) => {
344
- const typed = isRecord(input) ? input : {};
345
- const filePath = normalizeWorkspacePathOrThrow(pathScopedBackend, typeof typed.file_path === "string" ? typed.file_path : "");
346
- const result = await Promise.resolve(backend.write?.(filePath, typeof typed.content === "string" ? typed.content : ""));
347
- return result?.error ?? `Successfully wrote to '${result?.path ?? filePath}'`;
348
- },
349
- });
350
- tools.set("edit_file", {
351
- name: "edit_file",
352
- description: "Replace exact text inside a workspace file.",
353
- schema: z.object({
354
- file_path: z.string(),
355
- old_string: z.string(),
356
- new_string: z.string(),
357
- replace_all: z.boolean().optional(),
358
- }).passthrough(),
359
- invoke: async (input) => {
360
- const typed = isRecord(input) ? input : {};
361
- const filePath = normalizeWorkspacePathOrThrow(pathScopedBackend, typeof typed.file_path === "string" ? typed.file_path : "");
362
- const result = await Promise.resolve(backend.edit?.(filePath, typeof typed.old_string === "string" ? typed.old_string : "", typeof typed.new_string === "string" ? typed.new_string : "", typed.replace_all === true));
363
- return result?.error ?? `Successfully replaced ${result?.occurrences ?? 0} occurrence(s) in '${result?.path ?? filePath}'`;
364
- },
365
- });
366
- tools.set("glob", {
367
- name: "glob",
368
- description: "Find files matching a glob pattern.",
369
- schema: z.object({ pattern: z.string(), path: z.string().optional().default("/") }).passthrough(),
370
- invoke: async (input) => {
371
- const typed = isRecord(input) ? input : {};
372
- const pattern = typeof typed.pattern === "string" ? typed.pattern : "";
373
- const targetPath = normalizeWorkspacePathOrThrow(pathScopedBackend, typeof typed.path === "string" ? typed.path : "/");
374
- const legacyInfos = (await Promise.resolve(backend.globInfo?.(pattern, targetPath))) ?? [];
375
- const infos = legacyInfos.length > 0
376
- ? legacyInfos
377
- : ((await Promise.resolve(backend.glob?.(pattern, targetPath)))?.files ?? []);
378
- if (infos.length === 0) {
379
- return `No files found matching pattern '${pattern}'`;
380
- }
381
- return truncateLines(infos.map((info) => info.path));
382
- },
383
- });
384
- tools.set("grep", {
385
- name: "grep",
386
- description: "Search for text across workspace files.",
387
- schema: z.object({
388
- pattern: z.string(),
389
- path: z.string().optional().default("/"),
390
- glob: z.string().nullable().optional(),
391
- }).passthrough(),
392
- invoke: async (input) => {
393
- const typed = isRecord(input) ? input : {};
394
- const targetPath = normalizeWorkspacePathOrThrow(pathScopedBackend, typeof typed.path === "string" ? typed.path : "/");
395
- const legacyResult = await Promise.resolve(backend.grepRaw?.(typeof typed.pattern === "string" ? typed.pattern : "", targetPath, typeof typed.glob === "string" ? typed.glob : null));
396
- const structuredResult = await Promise.resolve(backend.grep?.(typeof typed.pattern === "string" ? typed.pattern : "", targetPath, typeof typed.glob === "string" ? typed.glob : null));
397
- const normalizedStructuredMatches = structuredResult?.matches?.map((match) => ({
398
- path: match.path,
399
- line: match.lineNumber ?? match.line_number ?? match.line ?? 0,
400
- text: match.content ?? match.text ?? "",
401
- }));
402
- const normalizedResult = legacyResult ?? normalizedStructuredMatches;
403
- if (typeof normalizedResult === "string") {
404
- return normalizedResult;
405
- }
406
- if (!normalizedResult || normalizedResult.length === 0) {
407
- return `No matches found for pattern '${typeof typed.pattern === "string" ? typed.pattern : ""}'`;
408
- }
409
- const lines = [];
410
- let currentFile = "";
411
- for (const match of normalizedResult) {
412
- if (match.path !== currentFile) {
413
- currentFile = match.path;
414
- lines.push(`\n${currentFile}:`);
415
- }
416
- lines.push(` ${match.line}: ${match.text}`);
417
- }
418
- return truncateLines(lines);
419
- },
420
- });
421
- tools.set("execute", {
422
- name: "execute",
423
- description: "Run a shell command in the workspace sandbox.",
424
- schema: z.object({ command: z.string() }).passthrough(),
425
- invoke: async (input, toolConfig) => {
426
- if (!isSandboxBackend(backend) || typeof backend.execute !== "function") {
427
- return "Error: Execution not available. This agent's backend does not support command execution (SandboxBackendProtocol).";
428
- }
429
- const typed = isRecord(input) ? input : {};
430
- const result = await Promise.resolve(backend.execute(typeof typed.command === "string" ? typed.command : ""));
431
- const parts = [result.output];
432
- if (result.exitCode !== null) {
433
- parts.push(`\n[Command ${result.exitCode === 0 ? "succeeded" : "failed"} with exit code ${result.exitCode}]`);
434
- }
435
- if (result.truncated) {
436
- parts.push("\n[Output was truncated due to size limits]");
437
- }
438
- return finalizeOutput("execute", parts.join(""), toolConfig);
439
- },
440
- });
441
- tools.set("fetch_url", {
442
- name: "fetch_url",
443
- description: "Fetch a URL and return the response body.",
444
- schema: z.object({ url: z.string() }).passthrough(),
445
- invoke: async (input, toolConfig) => {
446
- const typed = isRecord(input) ? input : {};
447
- return finalizeOutput("fetch_url", await fetchUrlWithRuntimeFallback(backend, typeof typed.url === "string" ? typed.url : ""), toolConfig);
448
- },
449
- });
450
- tools.set("http_request", {
451
- name: "http_request",
452
- description: "Send a structured HTTP request.",
453
- schema: z.object({
454
- url: z.string(),
455
- method: z.string().optional(),
456
- headers: z.record(z.string(), z.string()).optional(),
457
- body: z.string().optional(),
458
- }).passthrough(),
459
- invoke: async (input, toolConfig) => {
460
- if (typeof backend.httpRequest !== "function") {
461
- return notAvailable("http_request", "structured HTTP requests");
462
- }
463
- const typed = isRecord(input) ? input : {};
464
- const result = await Promise.resolve(backend.httpRequest({
465
- url: typeof typed.url === "string" ? typed.url : "",
466
- method: typeof typed.method === "string" ? typed.method : undefined,
467
- headers: typed.headers && typeof typed.headers === "object" && !Array.isArray(typed.headers)
468
- ? Object.fromEntries(Object.entries(typed.headers).filter(([, value]) => typeof value === "string"))
469
- : undefined,
470
- body: typeof typed.body === "string" ? typed.body : undefined,
471
- }));
472
- if (typeof result === "string") {
473
- return finalizeOutput("http_request", result, toolConfig);
474
- }
475
- return finalizeOutput("http_request", formatHttpResponse(result), toolConfig);
476
- },
477
- });
478
- tools.set("send_message", {
479
- name: "send_message",
480
- description: "Send a message through the configured backend.",
481
- schema: z.object({
482
- destination: z.string(),
483
- message: z.string(),
484
- subject: z.string().optional(),
485
- metadata: z.record(z.string(), z.unknown()).optional(),
486
- }).passthrough(),
487
- invoke: async (input) => {
488
- if (typeof backend.sendMessage !== "function") {
489
- return notAvailable("send_message", "message delivery");
490
- }
491
- const typed = isRecord(input) ? input : {};
492
- const result = await Promise.resolve(backend.sendMessage({
493
- destination: typeof typed.destination === "string" ? typed.destination : "",
494
- message: typeof typed.message === "string" ? typed.message : "",
495
- subject: typeof typed.subject === "string" ? typed.subject : undefined,
496
- metadata: isRecord(typed.metadata) ? typed.metadata : undefined,
497
- }));
498
- if (typeof result === "string") {
499
- return result;
500
- }
501
- return result?.error ?? `Message sent to '${typeof typed.destination === "string" ? typed.destination : ""}'${result?.id ? ` (id: ${result.id})` : ""}.`;
502
- },
503
- });
504
- tools.set("request_approval", {
505
- name: "request_approval",
506
- description: "Request an approval decision from the runtime.",
507
- schema: z.object({
508
- action: z.string(),
509
- reason: z.string().optional(),
510
- details: z.record(z.string(), z.unknown()).optional(),
511
- }).passthrough(),
512
- invoke: async (input) => {
513
- if (typeof backend.requestApproval !== "function") {
514
- return notAvailable("request_approval", "approval requests");
515
- }
516
- const typed = isRecord(input) ? input : {};
517
- const result = await Promise.resolve(backend.requestApproval({
518
- action: typeof typed.action === "string" ? typed.action : "",
519
- reason: typeof typed.reason === "string" ? typed.reason : undefined,
520
- details: isRecord(typed.details) ? typed.details : undefined,
521
- }));
522
- if (typeof result === "string") {
523
- return result;
524
- }
525
- if (result?.error) {
526
- return result.error;
527
- }
528
- return result?.approved === true
529
- ? `Approval granted for '${typeof typed.action === "string" ? typed.action : ""}'${result.id ? ` (id: ${result.id})` : ""}.`
530
- : `Approval requested for '${typeof typed.action === "string" ? typed.action : ""}'${result?.id ? ` (id: ${result.id})` : ""}.`;
531
- },
532
- });
533
- tools.set("schedule_task", {
534
- name: "schedule_task",
535
- description: "Create, inspect, update, list, and delete system-level scheduled tasks.",
536
- schema: z.object({
537
- operation: z.enum(["create", "list", "get", "update", "delete"]).optional(),
538
- scheduleId: z.string().optional(),
539
- name: z.string().optional(),
540
- instruction: z.string().optional(),
541
- agentId: z.string().optional(),
542
- when: z.string().optional(),
543
- schedule: z.object({
544
- type: z.enum(["cron", "interval", "daily", "weekly"]),
545
- expression: z.string().optional(),
546
- everyMinutes: z.number().int().positive().optional(),
547
- time: z.string().optional(),
548
- days: z.array(z.string()).optional(),
549
- }).optional(),
550
- filters: z.object({
551
- scheduleId: z.string().optional(),
552
- name: z.string().optional(),
553
- agentId: z.string().optional(),
554
- source: z.enum(["crontab", "schtasks"]).optional(),
555
- status: z.enum(["active", "missing"]).optional(),
556
- query: z.string().optional(),
557
- }).optional(),
558
- metadata: z.record(z.string(), z.unknown()).optional(),
559
- }).passthrough(),
560
- invoke: async (input) => {
561
- const typed = isRecord(input) ? input : {};
562
- const operation = typeof typed.operation === "string" ? typed.operation : "create";
563
- const normalizedSchedule = isRecord(typed.schedule) && typeof typed.schedule.type === "string"
564
- ? {
565
- type: typed.schedule.type,
566
- ...(typeof typed.schedule.expression === "string" ? { expression: typed.schedule.expression } : {}),
567
- ...(typeof typed.schedule.everyMinutes === "number" ? { everyMinutes: typed.schedule.everyMinutes } : {}),
568
- ...(typeof typed.schedule.time === "string" ? { time: typed.schedule.time } : {}),
569
- ...(Array.isArray(typed.schedule.days)
570
- ? {
571
- days: typed.schedule.days.filter((day) => typeof day === "string"),
572
- }
573
- : {}),
574
- }
575
- : typeof typed.when === "string"
576
- ? parseScheduleWhen(typed.when)
577
- : undefined;
578
- if (typeof backend.manageSchedule === "function") {
579
- return backend.manageSchedule({
580
- operation: operation,
581
- scheduleId: typeof typed.scheduleId === "string" ? typed.scheduleId : undefined,
582
- name: typeof typed.name === "string" ? typed.name : undefined,
583
- instruction: typeof typed.instruction === "string" ? typed.instruction : undefined,
584
- agentId: typeof typed.agentId === "string" ? typed.agentId : undefined,
585
- schedule: normalizedSchedule,
586
- filters: isRecord(typed.filters)
587
- ? {
588
- ...(typeof typed.filters.scheduleId === "string" ? { scheduleId: typed.filters.scheduleId } : {}),
589
- ...(typeof typed.filters.name === "string" ? { name: typed.filters.name } : {}),
590
- ...(typeof typed.filters.agentId === "string" ? { agentId: typed.filters.agentId } : {}),
591
- ...(typed.filters.source === "crontab" || typed.filters.source === "schtasks" ? { source: typed.filters.source } : {}),
592
- ...(typed.filters.status === "active" || typed.filters.status === "missing" ? { status: typed.filters.status } : {}),
593
- ...(typeof typed.filters.query === "string" ? { query: typed.filters.query } : {}),
594
- }
595
- : undefined,
596
- metadata: isRecord(typed.metadata) ? typed.metadata : undefined,
597
- });
598
- }
599
- if (typeof backend.scheduleTask !== "function") {
600
- return notAvailable("schedule_task", "task scheduling");
601
- }
602
- if (operation !== "create") {
603
- return "Error: schedule_task only supports create on this backend.";
604
- }
605
- const result = await Promise.resolve(backend.scheduleTask({
606
- instruction: typeof typed.instruction === "string" ? typed.instruction : "",
607
- when: typeof typed.when === "string" ? typed.when : "",
608
- name: typeof typed.name === "string" ? typed.name : undefined,
609
- metadata: isRecord(typed.metadata) ? typed.metadata : undefined,
610
- }));
611
- if (typeof result === "string") {
612
- return result;
613
- }
614
- return result?.error ?? `Scheduled task '${typeof typed.name === "string" ? typed.name : typeof typed.instruction === "string" ? typed.instruction : ""}' for ${typeof typed.when === "string" ? typed.when : ""}${result?.id ? ` (id: ${result.id})` : ""}.`;
615
- },
616
- });
617
- if (options.includeTaskTool && options.invokeTaskTool) {
618
- const description = buildTaskToolDescription(options.taskSubagents);
619
- tools.set("task", {
620
- name: "task",
621
- description,
622
- schema: buildTaskToolSchema(options.taskSubagents),
623
- invoke: async (input) => options.invokeTaskTool(input),
624
- });
625
- }
626
- return tools;
627
- }
1
+ import y from"node:path";import{z as t}from"zod";import{isSandboxBackend as x}from"deepagents";import{isRecord as d}from"../../../utils/object.js";import{formatBuiltinTodoSnapshot as T,summarizeBuiltinWriteTodosArgs as R,truncateLines as v}from"../runtime-adapter-support.js";import{maybePersistLargeToolOutput as j,resolveToolRuntimeContext as q}from"./tool-output-artifacts.js";function S(n){const s=["Delegate a bounded task to the subagent whose declared description best matches the task.","Use this only when a subagent is a better fit than the current agent. Set subagent_type to exactly one listed subagent name."],a=(n??[]).filter(i=>i.name.trim().length>0).map(i=>{const p=i.description.trim()||"No description provided.";return`- ${i.name}: ${p}`});return a.length>0?[...s,"","Available subagents:",...a].join(`
2
+ `):s.join(" ")}function P(n){const s=(n??[]).map(i=>i.name.trim()).filter(i=>i.length>0),a=s.length>0?t.enum(s):t.string();return t.object({description:t.string().describe("Concrete bounded task for the selected subagent to perform."),subagent_type:a.describe("Exact name of the selected subagent.")}).passthrough()}const I=[{name:"write_todos",description:"Create and update the runtime todo board for multi-step work."},{name:"read_todos",description:"Read the current runtime todo board."},{name:"ls",description:"List files in a directory."},{name:"read_file",description:"Read a file from the workspace filesystem."},{name:"write_file",description:"Write a file in the workspace filesystem."},{name:"edit_file",description:"Replace exact text inside a workspace file."},{name:"glob",description:"Find files matching a glob pattern."},{name:"grep",description:"Search for text across workspace files."},{name:"execute",description:"Run a shell command in the workspace sandbox."},{name:"fetch_url",description:"Fetch a URL and return the response body."},{name:"http_request",description:"Send a structured HTTP request."},{name:"send_message",description:"Send a message through the configured backend."},{name:"request_approval",description:"Request an approval decision from the runtime."},{name:"schedule_task",description:"Create, inspect, update, list, and delete system-level scheduled tasks."},{name:"task",description:"Delegate a bounded task to a subagent."}];function B(n){const s=new Set(["fetch_url","http_request","send_message","request_approval","schedule_task"]),a=Array.isArray(n?.modelExposed)?new Set(n.modelExposed):void 0;return I.filter(i=>!(n?.todos===!1&&(i.name==="write_todos"||i.name==="read_todos")||n?.filesystem===!1&&["ls","read_file","write_file","edit_file","glob","grep","execute"].includes(i.name)||s.has(i.name)&&(n?.modelExposed===!1||a&&!a.has(i.name)))).map(i=>({...i}))}function $(n){return typeof n=="string"?n:n instanceof Uint8Array?new TextDecoder().decode(n):""}function w(n,s){return`Error: ${n} is not available. This backend does not support ${s}.`}function A(n){return`'${n.replace(/'/g,`'"'"'`)}'`}async function E(n,s){if(typeof n.execute!="function"||process.platform==="win32")return;const i=["set -f",`dir=${A(s)}`,'if [ ! -d "$dir" ]; then exit 0; fi',"count=0",'for entry in "$dir"/* "$dir"/.[!.]* "$dir"/..?*; do',' [ -e "$entry" ] || continue',' if [ -d "$entry" ]; then',` printf '%s (directory)\\n' "$entry"`," else",` printf '%s\\n' "$entry"`," fi"," count=$((count + 1))",' if [ "$count" -ge 400 ]; then'," printf '...[truncated]\\n'"," break"," fi","done"].join("; ");try{const p=await Promise.resolve(n.execute(i)),h=typeof p?.output=="string"?p.output.trim():"";return h||void 0}catch{return}}function D(n){const s=n;if(typeof s.rootDir=="string"&&s.rootDir.trim().length>0)return s.rootDir.trim();if(typeof s.root=="string"&&s.root.trim().length>0)return s.root.trim();if(typeof s.cwd=="string"&&s.cwd.trim().length>0)return s.cwd.trim()}function g(n,s){if(!s)return s;const a=D(n);if(!a||!y.isAbsolute(s))return s;if(s.startsWith("/large_tool_results/"))throw new Error(`Path '${s}' is an internal runtime spill path, not a workspace file. Do not read internal runtime spill files such as '/large_tool_results/...'. Use the preview already in context, rerun the producing tool with narrower output, or write the needed data to a workspace-relative file instead.`);const i=y.resolve(a),p=y.resolve(s);if(p===i||p.startsWith(`${i}${y.sep}`))return y.relative(i,p)||".";throw new Error(`Path '${s}' is outside the workspace root '${i}'. Use a workspace-relative path instead.`)}function k(n){if(n?.error)return n.error;const s=$(n?.body??n?.content),a=typeof n?.status=="number"?`${n.status}${n.statusText?` ${n.statusText}`:""}`:null,i=n?.headers?Object.entries(n.headers).map(([h,o])=>`${h}: ${o}`):[],p=[...a?[`Status: ${a}`]:[],...i.length>0?["Headers:",...i]:[],...s?["Body:",s]:[]];return p.length>0?p.join(`
3
+ `):"Request completed."}async function M(n,s){if(typeof n.fetchUrl=="function")try{const i=await Promise.resolve(n.fetchUrl(s));return typeof i=="string"?i:k(i)}catch{}const a=await fetch(s);return k({status:a.status,statusText:a.statusText,headers:Object.fromEntries(a.headers.entries()),body:await a.text()})}function z(n){const s=n.trim().toLowerCase();if(!s)return;const a=/^every\s+(\d+)\s*(minute|minutes|min|mins|hour|hours|hr|hrs)$/u.exec(s);if(a){const i=Number.parseInt(a[1],10);return{type:"interval",everyMinutes:a[2].startsWith("h")?i*60:i}}return s==="hourly"||s==="every hour"?{type:"interval",everyMinutes:60}:{type:"cron",expression:n}}async function F(n,s){const a=new Map,i=s.workspaceRoot?{...n,rootDir:s.workspaceRoot}:n;let p={items:[],summary:{total:0,pending:0,inProgress:0,completed:0,failed:0,cancelled:0}};const h=async(o,e,r)=>j({toolName:o,output:e,toolRuntimeContext:q(r,s.toolRuntimeContext)});if(a.set("write_todos",{name:"write_todos",description:"Create and update the runtime todo board for multi-step work.",schema:t.object({todos:t.array(t.object({id:t.union([t.string(),t.number()]).optional(),content:t.string().optional(),description:t.string().optional(),title:t.string().optional(),name:t.string().optional(),text:t.string().optional(),status:t.enum(["pending","in_progress","completed","failed","cancelled"]).optional(),ownerAgentId:t.string().optional(),startedAt:t.string().optional(),endedAt:t.string().optional(),result:t.unknown().optional(),metadata:t.record(t.string(),t.unknown()).optional()}).passthrough()).optional()}).passthrough(),invoke:async o=>{const e=d(o)?o:{},r=R(e);return p=r,{ok:!0,tool:"write_todos",message:`Tracked ${r.summary.total} todo item(s).`,summary:r}}}),a.set("read_todos",{name:"read_todos",description:"Read the current runtime todo board.",schema:t.object({}).passthrough(),invoke:async()=>({ok:!0,tool:"read_todos",message:T(p),summary:p})}),a.set("ls",{name:"ls",description:"List files in a directory.",schema:t.object({path:t.string().optional().default("/")}).passthrough(),invoke:async(o,e)=>{const r=g(i,d(o)&&typeof o.path=="string"?o.path:"/"),l=await E(i,r);if(typeof l=="string")return h("ls",l.length>0?l:`No files found in ${r}`,e);const u=await Promise.resolve(n.lsInfo?.(r))??[],f=u.length>0?u:((await Promise.resolve(n.ls?.(r)))?.files??[]).map(c=>({path:c.path,is_dir:c.isDir,size:c.size}));return f.length===0?`No files found in ${r}`:h("ls",v(f.map(c=>c.is_dir?`${c.path} (directory)`:`${c.path}${c.size?` (${c.size} bytes)`:""}`)),e)}}),a.set("read_file",{name:"read_file",description:"Read a file from the workspace filesystem.",schema:t.object({file_path:t.string(),offset:t.number().optional(),limit:t.number().optional()}).passthrough(),invoke:async o=>{const e=d(o)?o:{},r=g(i,typeof e.file_path=="string"?e.file_path:""),l=typeof e.offset=="number"?e.offset:0,u=typeof e.limit=="number"?e.limit:500,f=await Promise.resolve(n.read?.(r,l,u));return typeof f=="string"?f:f?.error??$(f?.content)}}),a.set("write_file",{name:"write_file",description:"Write a file in the workspace filesystem.",schema:t.object({file_path:t.string(),content:t.string().optional()}).passthrough(),invoke:async o=>{const e=d(o)?o:{},r=g(i,typeof e.file_path=="string"?e.file_path:""),l=await Promise.resolve(n.write?.(r,typeof e.content=="string"?e.content:""));return l?.error??`Successfully wrote to '${l?.path??r}'`}}),a.set("edit_file",{name:"edit_file",description:"Replace exact text inside a workspace file.",schema:t.object({file_path:t.string(),old_string:t.string(),new_string:t.string(),replace_all:t.boolean().optional()}).passthrough(),invoke:async o=>{const e=d(o)?o:{},r=g(i,typeof e.file_path=="string"?e.file_path:""),l=await Promise.resolve(n.edit?.(r,typeof e.old_string=="string"?e.old_string:"",typeof e.new_string=="string"?e.new_string:"",e.replace_all===!0));return l?.error??`Successfully replaced ${l?.occurrences??0} occurrence(s) in '${l?.path??r}'`}}),a.set("glob",{name:"glob",description:"Find files matching a glob pattern.",schema:t.object({pattern:t.string(),path:t.string().optional().default("/")}).passthrough(),invoke:async o=>{const e=d(o)?o:{},r=typeof e.pattern=="string"?e.pattern:"",l=g(i,typeof e.path=="string"?e.path:"/"),u=await Promise.resolve(n.globInfo?.(r,l))??[],f=u.length>0?u:(await Promise.resolve(n.glob?.(r,l)))?.files??[];return f.length===0?`No files found matching pattern '${r}'`:v(f.map(c=>c.path))}}),a.set("grep",{name:"grep",description:"Search for text across workspace files.",schema:t.object({pattern:t.string(),path:t.string().optional().default("/"),glob:t.string().nullable().optional()}).passthrough(),invoke:async o=>{const e=d(o)?o:{},r=g(i,typeof e.path=="string"?e.path:"/"),l=await Promise.resolve(n.grepRaw?.(typeof e.pattern=="string"?e.pattern:"",r,typeof e.glob=="string"?e.glob:null)),f=(await Promise.resolve(n.grep?.(typeof e.pattern=="string"?e.pattern:"",r,typeof e.glob=="string"?e.glob:null)))?.matches?.map(m=>({path:m.path,line:m.lineNumber??m.line_number??m.line??0,text:m.content??m.text??""})),c=l??f;if(typeof c=="string")return c;if(!c||c.length===0)return`No matches found for pattern '${typeof e.pattern=="string"?e.pattern:""}'`;const b=[];let _="";for(const m of c)m.path!==_&&(_=m.path,b.push(`
4
+ ${_}:`)),b.push(` ${m.line}: ${m.text}`);return v(b)}}),a.set("execute",{name:"execute",description:"Run a shell command in the workspace sandbox.",schema:t.object({command:t.string()}).passthrough(),invoke:async(o,e)=>{if(!x(n)||typeof n.execute!="function")return"Error: Execution not available. This agent's backend does not support command execution (SandboxBackendProtocol).";const r=d(o)?o:{},l=await Promise.resolve(n.execute(typeof r.command=="string"?r.command:"")),u=[l.output];return l.exitCode!==null&&u.push(`
5
+ [Command ${l.exitCode===0?"succeeded":"failed"} with exit code ${l.exitCode}]`),l.truncated&&u.push(`
6
+ [Output was truncated due to size limits]`),h("execute",u.join(""),e)}}),a.set("fetch_url",{name:"fetch_url",description:"Fetch a URL and return the response body.",schema:t.object({url:t.string()}).passthrough(),invoke:async(o,e)=>{const r=d(o)?o:{};return h("fetch_url",await M(n,typeof r.url=="string"?r.url:""),e)}}),a.set("http_request",{name:"http_request",description:"Send a structured HTTP request.",schema:t.object({url:t.string(),method:t.string().optional(),headers:t.record(t.string(),t.string()).optional(),body:t.string().optional()}).passthrough(),invoke:async(o,e)=>{if(typeof n.httpRequest!="function")return w("http_request","structured HTTP requests");const r=d(o)?o:{},l=await Promise.resolve(n.httpRequest({url:typeof r.url=="string"?r.url:"",method:typeof r.method=="string"?r.method:void 0,headers:r.headers&&typeof r.headers=="object"&&!Array.isArray(r.headers)?Object.fromEntries(Object.entries(r.headers).filter(([,u])=>typeof u=="string")):void 0,body:typeof r.body=="string"?r.body:void 0}));return typeof l=="string"?h("http_request",l,e):h("http_request",k(l),e)}}),a.set("send_message",{name:"send_message",description:"Send a message through the configured backend.",schema:t.object({destination:t.string(),message:t.string(),subject:t.string().optional(),metadata:t.record(t.string(),t.unknown()).optional()}).passthrough(),invoke:async o=>{if(typeof n.sendMessage!="function")return w("send_message","message delivery");const e=d(o)?o:{},r=await Promise.resolve(n.sendMessage({destination:typeof e.destination=="string"?e.destination:"",message:typeof e.message=="string"?e.message:"",subject:typeof e.subject=="string"?e.subject:void 0,metadata:d(e.metadata)?e.metadata:void 0}));return typeof r=="string"?r:r?.error??`Message sent to '${typeof e.destination=="string"?e.destination:""}'${r?.id?` (id: ${r.id})`:""}.`}}),a.set("request_approval",{name:"request_approval",description:"Request an approval decision from the runtime.",schema:t.object({action:t.string(),reason:t.string().optional(),details:t.record(t.string(),t.unknown()).optional()}).passthrough(),invoke:async o=>{if(typeof n.requestApproval!="function")return w("request_approval","approval requests");const e=d(o)?o:{},r=await Promise.resolve(n.requestApproval({action:typeof e.action=="string"?e.action:"",reason:typeof e.reason=="string"?e.reason:void 0,details:d(e.details)?e.details:void 0}));return typeof r=="string"?r:r?.error?r.error:r?.approved===!0?`Approval granted for '${typeof e.action=="string"?e.action:""}'${r.id?` (id: ${r.id})`:""}.`:`Approval requested for '${typeof e.action=="string"?e.action:""}'${r?.id?` (id: ${r.id})`:""}.`}}),a.set("schedule_task",{name:"schedule_task",description:"Create, inspect, update, list, and delete system-level scheduled tasks.",schema:t.object({operation:t.enum(["create","list","get","update","delete"]).optional(),scheduleId:t.string().optional(),name:t.string().optional(),instruction:t.string().optional(),agentId:t.string().optional(),when:t.string().optional(),schedule:t.object({type:t.enum(["cron","interval","daily","weekly"]),expression:t.string().optional(),everyMinutes:t.number().int().positive().optional(),time:t.string().optional(),days:t.array(t.string()).optional()}).optional(),filters:t.object({scheduleId:t.string().optional(),name:t.string().optional(),agentId:t.string().optional(),source:t.enum(["crontab","schtasks"]).optional(),status:t.enum(["active","missing"]).optional(),query:t.string().optional()}).optional(),metadata:t.record(t.string(),t.unknown()).optional()}).passthrough(),invoke:async o=>{const e=d(o)?o:{},r=typeof e.operation=="string"?e.operation:"create",l=d(e.schedule)&&typeof e.schedule.type=="string"?{type:e.schedule.type,...typeof e.schedule.expression=="string"?{expression:e.schedule.expression}:{},...typeof e.schedule.everyMinutes=="number"?{everyMinutes:e.schedule.everyMinutes}:{},...typeof e.schedule.time=="string"?{time:e.schedule.time}:{},...Array.isArray(e.schedule.days)?{days:e.schedule.days.filter(f=>typeof f=="string")}:{}}:typeof e.when=="string"?z(e.when):void 0;if(typeof n.manageSchedule=="function")return n.manageSchedule({operation:r,scheduleId:typeof e.scheduleId=="string"?e.scheduleId:void 0,name:typeof e.name=="string"?e.name:void 0,instruction:typeof e.instruction=="string"?e.instruction:void 0,agentId:typeof e.agentId=="string"?e.agentId:void 0,schedule:l,filters:d(e.filters)?{...typeof e.filters.scheduleId=="string"?{scheduleId:e.filters.scheduleId}:{},...typeof e.filters.name=="string"?{name:e.filters.name}:{},...typeof e.filters.agentId=="string"?{agentId:e.filters.agentId}:{},...e.filters.source==="crontab"||e.filters.source==="schtasks"?{source:e.filters.source}:{},...e.filters.status==="active"||e.filters.status==="missing"?{status:e.filters.status}:{},...typeof e.filters.query=="string"?{query:e.filters.query}:{}}:void 0,metadata:d(e.metadata)?e.metadata:void 0});if(typeof n.scheduleTask!="function")return w("schedule_task","task scheduling");if(r!=="create")return"Error: schedule_task only supports create on this backend.";const u=await Promise.resolve(n.scheduleTask({instruction:typeof e.instruction=="string"?e.instruction:"",when:typeof e.when=="string"?e.when:"",name:typeof e.name=="string"?e.name:void 0,metadata:d(e.metadata)?e.metadata:void 0}));return typeof u=="string"?u:u?.error??`Scheduled task '${typeof e.name=="string"?e.name:typeof e.instruction=="string"?e.instruction:""}' for ${typeof e.when=="string"?e.when:""}${u?.id?` (id: ${u.id})`:""}.`}}),s.includeTaskTool&&s.invokeTaskTool){const o=S(s.taskSubagents);a.set("task",{name:"task",description:o,schema:P(s.taskSubagents),invoke:async e=>s.invokeTaskTool(e)})}return a}export{I as BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS,F as createBuiltinMiddlewareTools,B as filterBuiltinMiddlewareToolDescriptors};