@botbotgo/agent-harness 0.0.312 → 0.0.314
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/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/resources/tools/_runtime_tool_helpers.mjs +39 -0
- package/dist/resources/tools/list_files.mjs +5 -1
- package/dist/runtime/adapter/direct-builtin-utility.d.ts +4 -0
- package/dist/runtime/adapter/direct-builtin-utility.js +35 -0
- package/dist/runtime/adapter/tool/builtin-middleware-tools.js +43 -0
- package/dist/runtime/agent-runtime-adapter.d.ts +1 -0
- package/dist/runtime/agent-runtime-adapter.js +66 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.313";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.313";
|
|
@@ -100,6 +100,45 @@ export function truncateLines(lines, maxChars = 12000) {
|
|
|
100
100
|
return truncateText(lines.join("\n"), maxChars);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
export function shellQuote(value) {
|
|
104
|
+
return `'${String(value).replace(/'/g, `'\"'\"'`)}'`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function tryExecuteShallowDirectoryListing(backend, targetPath) {
|
|
108
|
+
if (typeof backend?.execute !== "function" || process.platform === "win32") {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const quotedPath = shellQuote(targetPath);
|
|
113
|
+
const command = [
|
|
114
|
+
"set -f",
|
|
115
|
+
`dir=${quotedPath}`,
|
|
116
|
+
'if [ ! -d "$dir" ]; then exit 0; fi',
|
|
117
|
+
"count=0",
|
|
118
|
+
'for entry in "$dir"/* "$dir"/.[!.]* "$dir"/..?*; do',
|
|
119
|
+
' [ -e "$entry" ] || continue',
|
|
120
|
+
' if [ -d "$entry" ]; then',
|
|
121
|
+
' printf \'%s (directory)\\n\' "$entry"',
|
|
122
|
+
" else",
|
|
123
|
+
' printf \'%s\\n\' "$entry"',
|
|
124
|
+
" fi",
|
|
125
|
+
" count=$((count + 1))",
|
|
126
|
+
' if [ "$count" -ge 400 ]; then',
|
|
127
|
+
" printf '...[truncated]\\n'",
|
|
128
|
+
" break",
|
|
129
|
+
" fi",
|
|
130
|
+
"done",
|
|
131
|
+
].join("; ");
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const result = await backend.execute(command);
|
|
135
|
+
const output = typeof result?.output === "string" ? result.output.trim() : "";
|
|
136
|
+
return output.length > 0 ? output : undefined;
|
|
137
|
+
} catch {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
103
142
|
export function formatHttpResponse(result) {
|
|
104
143
|
if (result?.error) {
|
|
105
144
|
return result.error;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool } from "@botbotgo/agent-harness/tools";
|
|
2
|
-
import { defineSchema, formatListEntries, getBackend, normalizeWorkspacePath, optionalString,
|
|
2
|
+
import { defineSchema, formatListEntries, getBackend, normalizeWorkspacePath, optionalString, tryExecuteShallowDirectoryListing } from "./_runtime_tool_helpers.mjs";
|
|
3
3
|
|
|
4
4
|
export const list_files = tool({
|
|
5
5
|
description: "List files in a workspace directory.",
|
|
@@ -9,6 +9,10 @@ export const list_files = tool({
|
|
|
9
9
|
async invoke(input, context = {}) {
|
|
10
10
|
const backend = getBackend(context);
|
|
11
11
|
const targetPath = normalizeWorkspacePath(context, input.path, ".");
|
|
12
|
+
const shallowListing = await tryExecuteShallowDirectoryListing(backend, targetPath);
|
|
13
|
+
if (typeof shallowListing === "string") {
|
|
14
|
+
return shallowListing;
|
|
15
|
+
}
|
|
12
16
|
const legacyInfos = typeof backend.lsInfo === "function" ? await backend.lsInfo(targetPath) : [];
|
|
13
17
|
const infos = legacyInfos.length > 0
|
|
14
18
|
? legacyInfos
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
const DIRECT_LISTING_PATTERNS = [
|
|
2
|
+
/^ls$/iu,
|
|
3
|
+
/^list files$/iu,
|
|
4
|
+
/^list the files$/iu,
|
|
5
|
+
/^list files in (?:the )?(?:current )?directory$/iu,
|
|
6
|
+
/^show files$/iu,
|
|
7
|
+
/^show me the files$/iu,
|
|
8
|
+
/^show the files$/iu,
|
|
9
|
+
/^列出文件$/u,
|
|
10
|
+
/^列出当前目录(?:下)?文件$/u,
|
|
11
|
+
/^查看文件列表$/u,
|
|
12
|
+
];
|
|
1
13
|
const GENERIC_ASSISTANT_SUMMARY_MAX_CHARS = 180;
|
|
2
14
|
const GENERIC_ASSISTANT_SUMMARY_MAX_LINES = 6;
|
|
3
15
|
function parseListingEntry(line) {
|
|
@@ -88,3 +100,26 @@ export function summarizeAssistantText(text) {
|
|
|
88
100
|
}
|
|
89
101
|
return summarizeGenericAssistantResponse(normalized);
|
|
90
102
|
}
|
|
103
|
+
function extractPlainTextInput(input) {
|
|
104
|
+
if (typeof input === "string") {
|
|
105
|
+
const normalized = input.trim();
|
|
106
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
107
|
+
}
|
|
108
|
+
if (!Array.isArray(input)) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
const text = input
|
|
112
|
+
.filter((part) => part?.type === "text" && typeof part.text === "string")
|
|
113
|
+
.map((part) => part.text.trim())
|
|
114
|
+
.filter((part) => part.length > 0)
|
|
115
|
+
.join("\n")
|
|
116
|
+
.trim();
|
|
117
|
+
return text.length > 0 ? text : undefined;
|
|
118
|
+
}
|
|
119
|
+
export function shouldDirectlyListWorkspaceFiles(input) {
|
|
120
|
+
const normalized = extractPlainTextInput(input);
|
|
121
|
+
if (!normalized) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
return DIRECT_LISTING_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
125
|
+
}
|
|
@@ -36,6 +36,45 @@ function toDisplayContent(content) {
|
|
|
36
36
|
function notAvailable(toolName, capability) {
|
|
37
37
|
return `Error: ${toolName} is not available. This backend does not support ${capability}.`;
|
|
38
38
|
}
|
|
39
|
+
function shellQuote(value) {
|
|
40
|
+
return `'${value.replace(/'/g, `'\"'\"'`)}'`;
|
|
41
|
+
}
|
|
42
|
+
async function tryExecuteShallowDirectoryListing(backend, targetPath) {
|
|
43
|
+
if (typeof backend.execute !== "function" || process.platform === "win32") {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const quotedPath = shellQuote(targetPath);
|
|
47
|
+
const command = [
|
|
48
|
+
"set -f",
|
|
49
|
+
`dir=${quotedPath}`,
|
|
50
|
+
'if [ ! -d "$dir" ]; then exit 0; fi',
|
|
51
|
+
"count=0",
|
|
52
|
+
'for entry in "$dir"/* "$dir"/.[!.]* "$dir"/..?*; do',
|
|
53
|
+
' [ -e "$entry" ] || continue',
|
|
54
|
+
' if [ -d "$entry" ]; then',
|
|
55
|
+
' printf \'%s (directory)\\n\' \"$entry\"',
|
|
56
|
+
" else",
|
|
57
|
+
' printf \'%s\\n\' \"$entry\"',
|
|
58
|
+
" fi",
|
|
59
|
+
" count=$((count + 1))",
|
|
60
|
+
' if [ "$count" -ge 400 ]; then',
|
|
61
|
+
" printf '...[truncated]\\n'",
|
|
62
|
+
" break",
|
|
63
|
+
" fi",
|
|
64
|
+
"done",
|
|
65
|
+
].join("; ");
|
|
66
|
+
try {
|
|
67
|
+
const result = await Promise.resolve(backend.execute(command));
|
|
68
|
+
const output = typeof result?.output === "string" ? result.output.trim() : "";
|
|
69
|
+
if (!output) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
return output;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
39
78
|
function resolveWorkspaceRoot(backend) {
|
|
40
79
|
const typed = backend;
|
|
41
80
|
if (typeof typed.rootDir === "string" && typed.rootDir.trim().length > 0) {
|
|
@@ -163,6 +202,10 @@ export async function createBuiltinMiddlewareTools(backend, options) {
|
|
|
163
202
|
schema: z.object({ path: z.string().optional().default("/") }).passthrough(),
|
|
164
203
|
invoke: async (input) => {
|
|
165
204
|
const targetPath = normalizeWorkspacePathOrThrow(pathScopedBackend, isRecord(input) && typeof input.path === "string" ? input.path : "/");
|
|
205
|
+
const shallowListing = await tryExecuteShallowDirectoryListing(pathScopedBackend, targetPath);
|
|
206
|
+
if (typeof shallowListing === "string") {
|
|
207
|
+
return shallowListing.length > 0 ? shallowListing : `No files found in ${targetPath}`;
|
|
208
|
+
}
|
|
166
209
|
const legacyInfos = (await Promise.resolve(backend.lsInfo?.(targetPath))) ?? [];
|
|
167
210
|
const infos = legacyInfos.length > 0
|
|
168
211
|
? legacyInfos
|
|
@@ -32,6 +32,7 @@ export declare class AgentRuntimeAdapter {
|
|
|
32
32
|
private resolveFilesystemRootDir;
|
|
33
33
|
private resolveBuiltinMiddlewareBackend;
|
|
34
34
|
private buildFunctionToolRuntimeContext;
|
|
35
|
+
private tryHandleDirectWorkspaceListing;
|
|
35
36
|
private createDeclaredMiddlewareResolverOptions;
|
|
36
37
|
private createAssemblyResolvers;
|
|
37
38
|
private invokeBuiltinTaskTool;
|
|
@@ -11,6 +11,7 @@ import { applyToolRecoveryInstruction as applyToolRecoveryInstructionHelper, app
|
|
|
11
11
|
import { invokeBuiltinTaskTool as invokeBuiltinTaskToolHelper, materializeAutomaticSummarizationMiddleware as materializeAutomaticSummarizationMiddlewareHelper, resolveBuiltinMiddlewareBackend as resolveBuiltinMiddlewareBackendHelper, resolveBuiltinMiddlewareTools as resolveBuiltinMiddlewareToolsHelper, resolveLangChainRuntimeExtensionMiddleware as resolveLangChainRuntimeExtensionMiddlewareHelper, resolveMiddleware as resolveMiddlewareHelper, resolveSubagents as resolveSubagentsHelper, } from "./adapter/middleware-assembly.js";
|
|
12
12
|
import { resolveBindingTimeout, resolveStreamIdleTimeout, } from "./adapter/resilience.js";
|
|
13
13
|
import { createResolvedModel } from "./adapter/model/model-providers.js";
|
|
14
|
+
import { shouldDirectlyListWorkspaceFiles } from "./adapter/direct-builtin-utility.js";
|
|
14
15
|
import { resolveAdapterTools } from "./adapter/tool-resolution.js";
|
|
15
16
|
import { resolveRuntimeStreamExecutionContext, } from "./adapter/flow/execution-context.js";
|
|
16
17
|
import { isRetryableProviderError } from "./adapter/resilience.js";
|
|
@@ -173,6 +174,30 @@ export class AgentRuntimeAdapter {
|
|
|
173
174
|
},
|
|
174
175
|
};
|
|
175
176
|
}
|
|
177
|
+
async tryHandleDirectWorkspaceListing(binding, input, options = {}) {
|
|
178
|
+
if (!shouldDirectlyListWorkspaceFiles(input)) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
const builtinTools = await this.resolveBuiltinMiddlewareTools(binding, {
|
|
182
|
+
context: options.context,
|
|
183
|
+
state: options.state,
|
|
184
|
+
files: options.files,
|
|
185
|
+
sessionId: options.sessionId,
|
|
186
|
+
requestId: options.requestId,
|
|
187
|
+
});
|
|
188
|
+
const listTool = builtinTools.get("list_files") ?? builtinTools.get("ls");
|
|
189
|
+
if (!listTool) {
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
const output = await listTool.invoke({ path: "." });
|
|
193
|
+
if (typeof output !== "string" || output.trim().length === 0) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
toolName: listTool.name,
|
|
198
|
+
output,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
176
201
|
createDeclaredMiddlewareResolverOptions(binding, options = {}) {
|
|
177
202
|
return {
|
|
178
203
|
resolveModel: (model) => this.resolveModel(model),
|
|
@@ -398,6 +423,30 @@ export class AgentRuntimeAdapter {
|
|
|
398
423
|
}
|
|
399
424
|
}
|
|
400
425
|
async invoke(binding, input, sessionId, requestId, resumePayload, history = [], options = {}) {
|
|
426
|
+
const directListing = await this.tryHandleDirectWorkspaceListing(binding, input, {
|
|
427
|
+
...options,
|
|
428
|
+
sessionId,
|
|
429
|
+
requestId,
|
|
430
|
+
});
|
|
431
|
+
if (directListing) {
|
|
432
|
+
return {
|
|
433
|
+
sessionId,
|
|
434
|
+
requestId,
|
|
435
|
+
agentId: binding.agent.id,
|
|
436
|
+
state: "completed",
|
|
437
|
+
output: directListing.output,
|
|
438
|
+
finalMessageText: directListing.output,
|
|
439
|
+
metadata: {
|
|
440
|
+
executedToolResults: [{
|
|
441
|
+
toolName: directListing.toolName,
|
|
442
|
+
output: directListing.output,
|
|
443
|
+
}],
|
|
444
|
+
upstreamResult: {
|
|
445
|
+
directUtility: directListing.toolName,
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
};
|
|
449
|
+
}
|
|
401
450
|
const callRuntime = async (activeBinding, activeRequest) => {
|
|
402
451
|
return this.invokeWithProviderRetry(activeBinding, async () => {
|
|
403
452
|
const runnable = await this.create(activeBinding, { sessionId });
|
|
@@ -444,6 +493,23 @@ export class AgentRuntimeAdapter {
|
|
|
444
493
|
}));
|
|
445
494
|
}
|
|
446
495
|
async *stream(binding, input, sessionId, history = [], options = {}) {
|
|
496
|
+
const directListing = await this.tryHandleDirectWorkspaceListing(binding, input, {
|
|
497
|
+
...options,
|
|
498
|
+
sessionId,
|
|
499
|
+
requestId: options.requestId,
|
|
500
|
+
});
|
|
501
|
+
if (directListing) {
|
|
502
|
+
yield {
|
|
503
|
+
kind: "tool-result",
|
|
504
|
+
toolName: directListing.toolName,
|
|
505
|
+
output: directListing.output,
|
|
506
|
+
};
|
|
507
|
+
yield {
|
|
508
|
+
kind: "content",
|
|
509
|
+
content: directListing.output,
|
|
510
|
+
};
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
447
513
|
const invokeTimeoutMs = resolveBindingTimeout(binding);
|
|
448
514
|
const streamIdleTimeoutMs = resolveStreamIdleTimeout(binding);
|
|
449
515
|
const streamDeadlineAt = invokeTimeoutMs ? Date.now() + invokeTimeoutMs : undefined;
|