@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.
- package/README.md +3 -1234
- package/README.zh.md +3 -1191
- package/dist/acp.js +1 -1
- package/dist/api.js +1 -404
- package/dist/benchmark/checkpoint-resume-cost-benchmark.js +1 -55
- package/dist/benchmark/deepagent-local-model-benchmark.js +2 -35
- package/dist/benchmark/upstream-runtime-ab-benchmark.js +1 -179
- package/dist/cli/chat-interactive.js +25 -244
- package/dist/cli/chat-rendering.js +6 -100
- package/dist/cli/chat-stream.js +23 -512
- package/dist/cli/chat-ui.js +21 -199
- package/dist/cli/chat-workspace.js +2 -210
- package/dist/cli/main.js +21 -428
- package/dist/cli/managed-service-commands.js +9 -63
- package/dist/cli/managed-service.js +2 -137
- package/dist/cli/options-init-chat.js +1 -108
- package/dist/cli/options-runtime.js +1 -158
- package/dist/cli/options-serve.js +1 -282
- package/dist/cli/options.js +2 -19
- package/dist/cli/process-guards.js +1 -139
- package/dist/cli/request-tree.js +7 -296
- package/dist/cli/runtime-commands.js +12 -258
- package/dist/cli/runtime-output.js +16 -155
- package/dist/cli/server-commands.js +16 -270
- package/dist/cli/workspace.js +1 -67
- package/dist/cli.js +1 -7
- package/dist/client/acp.js +1 -1
- package/dist/client/in-process.js +1 -67
- package/dist/client/index.js +1 -2
- package/dist/client/types.js +0 -1
- package/dist/client.js +1 -1
- package/dist/contracts/core.js +1 -1
- package/dist/contracts/runtime-evaluation.js +0 -1
- package/dist/contracts/runtime-memory.js +0 -1
- package/dist/contracts/runtime-observability.js +0 -1
- package/dist/contracts/runtime-requests.js +0 -1
- package/dist/contracts/runtime-scheduling.js +0 -1
- package/dist/contracts/runtime.js +1 -27
- package/dist/contracts/types.js +1 -3
- package/dist/contracts/workspace.js +0 -1
- package/dist/flow/build-flow-graph.js +1 -50
- package/dist/flow/export-mermaid.js +2 -464
- package/dist/flow/export-sequence-mermaid.js +2 -325
- package/dist/flow/flow-graph-normalization.js +1 -214
- package/dist/flow/flow-graph-runtime.js +1 -107
- package/dist/flow/flow-graph-upstream.js +1 -494
- package/dist/flow/index.js +1 -3
- package/dist/flow/types.js +0 -1
- package/dist/index.js +1 -5
- package/dist/init-project.js +1 -1
- package/dist/knowledge/config.js +1 -32
- package/dist/knowledge/contracts.js +0 -1
- package/dist/knowledge/index.js +1 -2
- package/dist/knowledge/module.js +12 -909
- package/dist/knowledge/procedural/config.js +1 -125
- package/dist/knowledge/procedural/index.js +1 -2
- package/dist/knowledge/procedural/manager.js +9 -345
- package/dist/mcp.js +1 -2
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -2
- package/dist/persistence/file-store.js +3 -758
- package/dist/persistence/sqlite-request-context-store.js +5 -54
- package/dist/persistence/sqlite-request-queue-store.js +10 -108
- package/dist/persistence/sqlite-runtime.js +1 -86
- package/dist/persistence/sqlite-store.js +62 -810
- package/dist/persistence/types.js +0 -1
- package/dist/projections/presentation.js +37 -206
- package/dist/projections/request-events.js +2 -502
- package/dist/projections/upstream-events.js +1 -201
- package/dist/protocol/a2a/http-discovery.js +1 -178
- package/dist/protocol/a2a/http-rpc.js +6 -622
- package/dist/protocol/a2a/http.js +1 -138
- package/dist/protocol/a2a/task-state.js +3 -317
- package/dist/protocol/acp/client.js +8 -294
- package/dist/protocol/acp/harness-client.js +1 -218
- package/dist/protocol/acp/http.js +5 -130
- package/dist/protocol/acp/server.js +1 -310
- package/dist/protocol/acp/stdio.js +2 -69
- package/dist/protocol/ag-ui/http.js +3 -378
- package/dist/protocol/mcp/server.js +1 -428
- package/dist/resource/backend/workspace-scoped-backend.js +1 -319
- package/dist/resource/isolation.js +1 -237
- package/dist/resource/mcp/tool-support.js +3 -296
- package/dist/resource/mcp-tool-support.js +1 -2
- package/dist/resource/providers/resource-provider.js +1 -215
- package/dist/resource/resource-impl.js +1 -3
- package/dist/resource/resource-types.js +0 -1
- package/dist/resource/resource.js +1 -1
- package/dist/resource/sources.js +1 -247
- package/dist/resource/tools/function-tool-resolver.js +2 -272
- package/dist/runtime/adapter/compat/deepagent-compat.js +1 -29
- package/dist/runtime/adapter/compat/openai-compatible.js +1 -55
- package/dist/runtime/adapter/direct-builtin-utility.js +2 -90
- package/dist/runtime/adapter/flow/execution-context.js +1 -71
- package/dist/runtime/adapter/flow/invocation-flow.js +8 -425
- package/dist/runtime/adapter/flow/invoke-runtime.js +1 -20
- package/dist/runtime/adapter/flow/stream-runtime.js +11 -1395
- package/dist/runtime/adapter/invocation-result.js +2 -473
- package/dist/runtime/adapter/local-tool-invocation.js +6 -638
- package/dist/runtime/adapter/middleware/context-hygiene.js +1 -83
- package/dist/runtime/adapter/middleware-assembly.js +5 -477
- package/dist/runtime/adapter/model/invocation-request.js +3 -183
- package/dist/runtime/adapter/model/message-assembly.js +1 -28
- package/dist/runtime/adapter/model/model-providers.js +23 -1115
- package/dist/runtime/adapter/model/prompted-json-tool-call-capture.js +1 -40
- package/dist/runtime/adapter/model/prompted-json-tool-policy.js +1 -22
- package/dist/runtime/adapter/resilience.js +1 -104
- package/dist/runtime/adapter/runtime-adapter-support.js +3 -141
- package/dist/runtime/adapter/runtime-shell.js +5 -166
- package/dist/runtime/adapter/stream-event-projection.js +2 -622
- package/dist/runtime/adapter/stream-text-consumption.js +1 -18
- package/dist/runtime/adapter/terminal-status.js +2 -67
- package/dist/runtime/adapter/tool/builtin-middleware-tools.js +6 -627
- package/dist/runtime/adapter/tool/declared-middleware.js +1 -154
- package/dist/runtime/adapter/tool/interrupt-policy.js +1 -34
- package/dist/runtime/adapter/tool/provider-tool.js +1 -25
- package/dist/runtime/adapter/tool/resolved-tool.js +1 -225
- package/dist/runtime/adapter/tool/tool-arguments.js +3 -486
- package/dist/runtime/adapter/tool/tool-hitl.js +1 -346
- package/dist/runtime/adapter/tool/tool-name-mapping.js +1 -128
- package/dist/runtime/adapter/tool/tool-output-artifacts.js +2 -88
- package/dist/runtime/adapter/tool/tool-replay.js +1 -37
- package/dist/runtime/adapter/tool-resolution.js +1 -86
- package/dist/runtime/adapter/upstream-configurable-keys.js +1 -2
- package/dist/runtime/agent-runtime-adapter.js +60 -2338
- package/dist/runtime/agent-runtime-assembly.js +7 -249
- package/dist/runtime/env/runtime-env.js +1 -62
- package/dist/runtime/harness/background-runtime.js +1 -8
- package/dist/runtime/harness/bindings.js +1 -58
- package/dist/runtime/harness/events/event-bus.js +1 -16
- package/dist/runtime/harness/events/event-sink.js +1 -61
- package/dist/runtime/harness/events/events.js +1 -80
- package/dist/runtime/harness/events/listener-runtime.js +1 -13
- package/dist/runtime/harness/events/runtime-event-operations.js +1 -9
- package/dist/runtime/harness/events/streaming.js +1 -100
- package/dist/runtime/harness/events/timeline.js +1 -52
- package/dist/runtime/harness/public-shapes.js +1 -186
- package/dist/runtime/harness/run/artifact-paths.js +1 -15
- package/dist/runtime/harness/run/governance.js +1 -295
- package/dist/runtime/harness/run/helpers.js +1 -71
- package/dist/runtime/harness/run/inspection.js +1 -409
- package/dist/runtime/harness/run/operator-overview.js +1 -80
- package/dist/runtime/harness/run/queue-diagnostics.js +1 -15
- package/dist/runtime/harness/run/recovery.js +1 -162
- package/dist/runtime/harness/run/resources.js +1 -60
- package/dist/runtime/harness/run/resume.js +1 -56
- package/dist/runtime/harness/run/routing.js +1 -48
- package/dist/runtime/harness/run/run-lifecycle.js +1 -66
- package/dist/runtime/harness/run/run-operations.js +1 -217
- package/dist/runtime/harness/run/run-queue.js +1 -43
- package/dist/runtime/harness/run/run-slot-acquisition.js +1 -157
- package/dist/runtime/harness/run/session-records.js +1 -97
- package/dist/runtime/harness/run/start-run.js +1 -120
- package/dist/runtime/harness/run/startup-runtime.js +1 -69
- package/dist/runtime/harness/run/stream-run.js +8 -1418
- package/dist/runtime/harness/run/surface-semantics.js +1 -79
- package/dist/runtime/harness/runtime-defaults.js +1 -39
- package/dist/runtime/harness/system/boundary-analysis.js +1 -234
- package/dist/runtime/harness/system/health-monitor.js +1 -258
- package/dist/runtime/harness/system/inventory.js +1 -129
- package/dist/runtime/harness/system/mem0-ingestion-sync.js +5 -345
- package/dist/runtime/harness/system/policy-engine.js +1 -175
- package/dist/runtime/harness/system/runtime-memory-candidates.js +4 -110
- package/dist/runtime/harness/system/runtime-memory-consolidation.js +1 -51
- package/dist/runtime/harness/system/runtime-memory-manager.js +10 -693
- package/dist/runtime/harness/system/runtime-memory-policy.js +1 -155
- package/dist/runtime/harness/system/runtime-memory-records.js +11 -577
- package/dist/runtime/harness/system/runtime-memory-sync.js +5 -206
- package/dist/runtime/harness/system/session-memory-sync.js +3 -113
- package/dist/runtime/harness/system/skill-requirements.js +1 -112
- package/dist/runtime/harness/system/store.js +9 -365
- package/dist/runtime/harness/tool-gateway/index.js +1 -2
- package/dist/runtime/harness/tool-gateway/policy.js +1 -45
- package/dist/runtime/harness/tool-gateway/validation.js +1 -176
- package/dist/runtime/harness/tool-schema.js +1 -3
- package/dist/runtime/harness.js +3 -1490
- package/dist/runtime/index.js +1 -3
- package/dist/runtime/layout/runtime-layout.js +1 -31
- package/dist/runtime/maintenance/checkpoint-maintenance.js +2 -178
- package/dist/runtime/maintenance/file-checkpoint-saver.js +1 -106
- package/dist/runtime/maintenance/runtime-record-maintenance.js +2 -169
- package/dist/runtime/maintenance/sqlite-checkpoint-saver.js +4 -289
- package/dist/runtime/parsing/output-content.js +10 -550
- package/dist/runtime/parsing/output-parsing.js +1 -4
- package/dist/runtime/parsing/output-recovery.js +3 -213
- package/dist/runtime/parsing/output-tool-args.js +7 -663
- package/dist/runtime/parsing/stream-event-parsing.js +3 -362
- package/dist/runtime/prompts/runtime-prompts.js +4 -73
- package/dist/runtime/scheduling/system-schedule-manager.js +11 -532
- package/dist/runtime/skills/skill-metadata.js +1 -197
- package/dist/runtime/startup-tracing.js +2 -37
- package/dist/runtime/support/compiled-binding.js +1 -290
- package/dist/runtime/support/embedding-models.js +1 -118
- package/dist/runtime/support/harness-support.js +5 -137
- package/dist/runtime/support/llamaindex.js +1 -108
- package/dist/runtime/support/runtime-adapter-options.js +1 -29
- package/dist/runtime/support/runtime-factories.js +1 -51
- package/dist/runtime/support/vector-stores.js +9 -270
- package/dist/scaffold/init-project.js +54 -233
- package/dist/tooling/extensions.js +1 -311
- package/dist/tooling/module-loader.js +1 -55
- package/dist/tools.js +1 -176
- package/dist/utils/agent-display.js +1 -18
- package/dist/utils/bundled-text.js +4 -39
- package/dist/utils/compiled-binding.js +1 -33
- package/dist/utils/fs.js +2 -45
- package/dist/utils/id.js +1 -9
- package/dist/utils/message-content.js +1 -30
- package/dist/utils/object.js +1 -6
- package/dist/workspace/agent-binding-compiler.js +3 -613
- package/dist/workspace/compile.js +1 -472
- package/dist/workspace/framework-contract-validation.js +2 -322
- package/dist/workspace/index.js +1 -1
- package/dist/workspace/object-loader-paths.js +1 -71
- package/dist/workspace/object-loader-readers.js +1 -187
- package/dist/workspace/object-loader.js +1 -754
- package/dist/workspace/resource-compilers.js +1 -374
- package/dist/workspace/support/agent-capabilities.js +1 -37
- package/dist/workspace/support/agent-execution-config.js +1 -44
- package/dist/workspace/support/discovery.js +1 -147
- package/dist/workspace/support/source-collectors.js +1 -30
- package/dist/workspace/support/source-protocols.js +2 -192
- package/dist/workspace/support/workspace-ref-utils.js +1 -362
- package/dist/workspace/tool-hydration.js +1 -280
- package/dist/workspace/validate.js +1 -99
- package/dist/workspace/yaml-object-reader.js +1 -285
- package/package.json +7 -3
|
@@ -1,627 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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};
|