@botbotgo/agent-harness 0.0.306 → 0.0.308
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 +45 -9
- package/README.zh.md +45 -9
- package/dist/config/runtime/workspace.yaml +16 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/procedural/index.d.ts +1 -0
- package/dist/procedural/index.js +1 -0
- package/dist/procedural/manager.d.ts +59 -0
- package/dist/procedural/manager.js +345 -0
- package/dist/resource/isolation.js +6 -1
- package/dist/resources/prompts/runtime/procedural-memory-manager.md +40 -0
- package/dist/runtime/adapter/model/invocation-request.d.ts +1 -0
- package/dist/runtime/adapter/model/invocation-request.js +4 -0
- package/dist/runtime/harness.d.ts +6 -0
- package/dist/runtime/harness.js +144 -14
- package/dist/runtime/support/runtime-prompts.d.ts +7 -0
- package/dist/runtime/support/runtime-prompts.js +14 -0
- package/dist/workspace/compile.js +135 -5
- package/dist/workspace/object-loader.js +27 -17
- package/dist/workspace/resource-compilers.js +3 -3
- package/dist/workspace/support/source-protocols.d.ts +19 -0
- package/dist/workspace/support/source-protocols.js +192 -0
- package/dist/workspace/support/workspace-ref-utils.d.ts +4 -0
- package/dist/workspace/support/workspace-ref-utils.js +4 -0
- package/package.json +1 -1
|
@@ -302,9 +302,9 @@ export function parseToolObject(object) {
|
|
|
302
302
|
...(mcpServerConfig && Object.keys(mcpServerConfig).length > 0 ? { mcpServer: mcpServerConfig } : {}),
|
|
303
303
|
}
|
|
304
304
|
: undefined),
|
|
305
|
-
subprocess: value.subprocess === true,
|
|
305
|
+
subprocess: value.subprocess === true ? true : undefined,
|
|
306
306
|
inputSchemaRef: typeof asObject(value.inputSchema)?.ref === "string" ? String(asObject(value.inputSchema)?.ref) : undefined,
|
|
307
|
-
hasModuleSchema: value.hasModuleSchema === true,
|
|
307
|
+
hasModuleSchema: value.hasModuleSchema === true ? true : undefined,
|
|
308
308
|
modelSchema: asObject(value.modelSchema),
|
|
309
309
|
embeddingModelRef: typeof value.embeddingModelRef === "string"
|
|
310
310
|
? value.embeddingModelRef
|
|
@@ -325,7 +325,7 @@ export function parseToolObject(object) {
|
|
|
325
325
|
: undefined,
|
|
326
326
|
bundleRefs,
|
|
327
327
|
hitl: parseHitlPolicy(value.hitl),
|
|
328
|
-
retryable: value.retryable === true,
|
|
328
|
+
retryable: value.retryable === true ? true : undefined,
|
|
329
329
|
sourcePath: object.sourcePath,
|
|
330
330
|
};
|
|
331
331
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const DEFAULT_TOOL_SOURCE_URIS: string[];
|
|
2
|
+
export declare const DEFAULT_SKILL_SOURCE_URIS: string[];
|
|
3
|
+
export type RuntimeSourceConfig = {
|
|
4
|
+
tools: string[];
|
|
5
|
+
skills: string[];
|
|
6
|
+
};
|
|
7
|
+
type ToolPackageInstallation = {
|
|
8
|
+
entryPath: string;
|
|
9
|
+
packageRoot: string;
|
|
10
|
+
packageName: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function readRuntimeSources(runtimeDefaults: Record<string, unknown> | undefined): RuntimeSourceConfig;
|
|
13
|
+
export declare function isFileSourceUri(value: string): boolean;
|
|
14
|
+
export declare function isNpmSourceUri(value: string): boolean;
|
|
15
|
+
export declare function isHttpSourceUri(value: string): boolean;
|
|
16
|
+
export declare function resolveFileSourcePath(uri: string, workspaceRoot: string): string;
|
|
17
|
+
export declare function ensureToolPackageSource(uri: string, workspaceRoot: string): Promise<ToolPackageInstallation>;
|
|
18
|
+
export declare function ensureRemoteSkillSource(uri: string): Promise<string>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
7
|
+
import { execFile } from "node:child_process";
|
|
8
|
+
import { promisify } from "node:util";
|
|
9
|
+
import { parse as parseYaml } from "yaml";
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
export const DEFAULT_TOOL_SOURCE_URIS = ["file://./resources/tools"];
|
|
12
|
+
export const DEFAULT_SKILL_SOURCE_URIS = ["file://./resources/skills"];
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
function normalizeSourceList(value, fallback) {
|
|
15
|
+
if (!Array.isArray(value)) {
|
|
16
|
+
return [...fallback];
|
|
17
|
+
}
|
|
18
|
+
return value
|
|
19
|
+
.filter((item) => typeof item === "string" && item.trim().length > 0)
|
|
20
|
+
.map((item) => item.trim());
|
|
21
|
+
}
|
|
22
|
+
export function readRuntimeSources(runtimeDefaults) {
|
|
23
|
+
const rawSources = typeof runtimeDefaults?.sources === "object" && runtimeDefaults.sources && !Array.isArray(runtimeDefaults.sources)
|
|
24
|
+
? runtimeDefaults.sources
|
|
25
|
+
: {};
|
|
26
|
+
return {
|
|
27
|
+
tools: normalizeSourceList(rawSources.tools, DEFAULT_TOOL_SOURCE_URIS),
|
|
28
|
+
skills: normalizeSourceList(rawSources.skills, DEFAULT_SKILL_SOURCE_URIS),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function isFileSourceUri(value) {
|
|
32
|
+
return value.startsWith("file://");
|
|
33
|
+
}
|
|
34
|
+
export function isNpmSourceUri(value) {
|
|
35
|
+
return value.startsWith("npm://");
|
|
36
|
+
}
|
|
37
|
+
export function isHttpSourceUri(value) {
|
|
38
|
+
return value.startsWith("http://") || value.startsWith("https://");
|
|
39
|
+
}
|
|
40
|
+
export function resolveFileSourcePath(uri, workspaceRoot) {
|
|
41
|
+
if (!isFileSourceUri(uri)) {
|
|
42
|
+
throw new Error(`Unsupported file source URI ${uri}`);
|
|
43
|
+
}
|
|
44
|
+
const rawPath = uri.slice("file://".length).trim();
|
|
45
|
+
if (!rawPath) {
|
|
46
|
+
throw new Error(`File source URI ${uri} must include a path`);
|
|
47
|
+
}
|
|
48
|
+
return path.isAbsolute(rawPath) ? rawPath : path.resolve(workspaceRoot, rawPath);
|
|
49
|
+
}
|
|
50
|
+
function parseToolPackageName(spec, workspaceRoot) {
|
|
51
|
+
if (spec.startsWith("file:")) {
|
|
52
|
+
const localPath = spec.slice("file:".length);
|
|
53
|
+
const resolvedPath = path.isAbsolute(localPath) ? localPath : path.resolve(workspaceRoot, localPath);
|
|
54
|
+
const packageJsonPath = path.join(resolvedPath, "package.json");
|
|
55
|
+
if (!existsSync(packageJsonPath)) {
|
|
56
|
+
throw new Error(`Package tool source ${spec} is missing package.json`);
|
|
57
|
+
}
|
|
58
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
59
|
+
if (typeof packageJson.name !== "string" || packageJson.name.trim().length === 0) {
|
|
60
|
+
throw new Error(`Package tool source ${spec} must define a package.json name`);
|
|
61
|
+
}
|
|
62
|
+
return packageJson.name.trim();
|
|
63
|
+
}
|
|
64
|
+
const match = spec.match(/^(@[^/]+\/[^@/]+|[^@/]+)(?:@.+)?$/);
|
|
65
|
+
if (!match?.[1]) {
|
|
66
|
+
throw new Error(`Unsupported package tool source ${spec}. Use npm://<package-name> or npm://<package-name>@<version>.`);
|
|
67
|
+
}
|
|
68
|
+
return match[1];
|
|
69
|
+
}
|
|
70
|
+
function packageInstallCacheRoot(spec) {
|
|
71
|
+
const digest = createHash("sha256").update(spec).digest("hex").slice(0, 16);
|
|
72
|
+
return path.join(os.tmpdir(), "agent-harness-package-tools", digest);
|
|
73
|
+
}
|
|
74
|
+
function resolvePackageEntry(packageRoot, pkg) {
|
|
75
|
+
const exportsField = pkg.exports;
|
|
76
|
+
if (typeof exportsField === "string") {
|
|
77
|
+
return path.resolve(packageRoot, exportsField);
|
|
78
|
+
}
|
|
79
|
+
if (exportsField && typeof exportsField === "object" && "." in exportsField) {
|
|
80
|
+
const rootExport = exportsField["."];
|
|
81
|
+
if (typeof rootExport === "string") {
|
|
82
|
+
return path.resolve(packageRoot, rootExport);
|
|
83
|
+
}
|
|
84
|
+
if (rootExport && typeof rootExport === "object") {
|
|
85
|
+
const importEntry = rootExport.import ?? rootExport.default;
|
|
86
|
+
if (typeof importEntry === "string") {
|
|
87
|
+
return path.resolve(packageRoot, importEntry);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (typeof pkg.module === "string") {
|
|
92
|
+
return path.resolve(packageRoot, pkg.module);
|
|
93
|
+
}
|
|
94
|
+
if (typeof pkg.main === "string") {
|
|
95
|
+
return path.resolve(packageRoot, pkg.main);
|
|
96
|
+
}
|
|
97
|
+
return path.resolve(packageRoot, "index.js");
|
|
98
|
+
}
|
|
99
|
+
function resolveInstalledPackageRoot(packageName, workspaceRoot) {
|
|
100
|
+
const packageJsonRef = `${packageName}/package.json`;
|
|
101
|
+
const directNodeModulesPath = path.join(workspaceRoot, "node_modules", ...packageName.split("/"), "package.json");
|
|
102
|
+
if (existsSync(directNodeModulesPath)) {
|
|
103
|
+
return path.dirname(directNodeModulesPath);
|
|
104
|
+
}
|
|
105
|
+
for (const candidateRoot of [workspaceRoot, process.cwd()]) {
|
|
106
|
+
try {
|
|
107
|
+
const candidateRequire = createRequire(path.join(candidateRoot, "__agent_harness_package_resolve__.cjs"));
|
|
108
|
+
return path.dirname(candidateRequire.resolve(packageJsonRef));
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
async function installPackageToolSource(spec, workspaceRoot) {
|
|
117
|
+
const packageName = parseToolPackageName(spec, workspaceRoot);
|
|
118
|
+
const installRoot = packageInstallCacheRoot(spec);
|
|
119
|
+
const packageJsonPath = path.join(installRoot, "package.json");
|
|
120
|
+
await mkdir(installRoot, { recursive: true });
|
|
121
|
+
if (!existsSync(packageJsonPath)) {
|
|
122
|
+
await writeFile(packageJsonPath, `${JSON.stringify({ name: "agent-harness-package-tool-cache", private: true }, null, 2)}\n`, "utf8");
|
|
123
|
+
}
|
|
124
|
+
const installedRoot = path.join(installRoot, "node_modules", ...packageName.split("/"));
|
|
125
|
+
if (!existsSync(path.join(installedRoot, "package.json"))) {
|
|
126
|
+
await execFileAsync("npm", ["install", "--no-save", spec], {
|
|
127
|
+
cwd: installRoot,
|
|
128
|
+
maxBuffer: 1024 * 1024 * 20,
|
|
129
|
+
env: process.env,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const packageJson = JSON.parse(await readFile(path.join(installedRoot, "package.json"), "utf8"));
|
|
133
|
+
return {
|
|
134
|
+
packageName,
|
|
135
|
+
packageRoot: installedRoot,
|
|
136
|
+
entryPath: resolvePackageEntry(installedRoot, packageJson),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export async function ensureToolPackageSource(uri, workspaceRoot) {
|
|
140
|
+
if (!isNpmSourceUri(uri)) {
|
|
141
|
+
throw new Error(`Unsupported package source URI ${uri}`);
|
|
142
|
+
}
|
|
143
|
+
const spec = uri.slice("npm://".length).trim();
|
|
144
|
+
if (!spec) {
|
|
145
|
+
throw new Error(`Package source URI ${uri} must include a package name`);
|
|
146
|
+
}
|
|
147
|
+
const packageName = parseToolPackageName(spec, workspaceRoot);
|
|
148
|
+
const installedRoot = resolveInstalledPackageRoot(packageName, workspaceRoot);
|
|
149
|
+
if (installedRoot && !spec.startsWith("file:") && !spec.includes("@", packageName.startsWith("@") ? packageName.length : 0)) {
|
|
150
|
+
const packageJson = JSON.parse(await readFile(path.join(installedRoot, "package.json"), "utf8"));
|
|
151
|
+
return {
|
|
152
|
+
packageName,
|
|
153
|
+
packageRoot: installedRoot,
|
|
154
|
+
entryPath: resolvePackageEntry(installedRoot, packageJson),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return installPackageToolSource(spec, workspaceRoot);
|
|
158
|
+
}
|
|
159
|
+
function parseSkillFrontmatterName(document) {
|
|
160
|
+
const match = document.match(/^---\s*\n([\s\S]*?)\n---\s*(?:\n|$)/);
|
|
161
|
+
if (!match?.[1]) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
const parsed = parseYaml(match[1]);
|
|
165
|
+
return typeof parsed?.name === "string" && parsed.name.trim().length > 0 ? parsed.name.trim() : undefined;
|
|
166
|
+
}
|
|
167
|
+
function sanitizeSkillDirName(input) {
|
|
168
|
+
const normalized = input.trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
169
|
+
return normalized || "remote-skill";
|
|
170
|
+
}
|
|
171
|
+
function remoteSkillCacheRoot(uri) {
|
|
172
|
+
const digest = createHash("sha256").update(uri).digest("hex").slice(0, 16);
|
|
173
|
+
return path.join(os.tmpdir(), "agent-harness-remote-skills", digest);
|
|
174
|
+
}
|
|
175
|
+
export async function ensureRemoteSkillSource(uri) {
|
|
176
|
+
if (!isHttpSourceUri(uri)) {
|
|
177
|
+
throw new Error(`Unsupported remote skill source ${uri}`);
|
|
178
|
+
}
|
|
179
|
+
const response = await fetch(uri);
|
|
180
|
+
if (!response.ok) {
|
|
181
|
+
throw new Error(`Remote skill source ${uri} returned ${response.status}`);
|
|
182
|
+
}
|
|
183
|
+
const document = await response.text();
|
|
184
|
+
const skillName = sanitizeSkillDirName(parseSkillFrontmatterName(document)
|
|
185
|
+
?? path.basename(new URL(uri).pathname).replace(/\.md$/i, "")
|
|
186
|
+
?? "remote-skill");
|
|
187
|
+
const cacheRoot = remoteSkillCacheRoot(uri);
|
|
188
|
+
const skillRoot = path.join(cacheRoot, skillName);
|
|
189
|
+
await mkdir(skillRoot, { recursive: true });
|
|
190
|
+
await writeFile(path.join(skillRoot, "SKILL.md"), document, "utf8");
|
|
191
|
+
return skillRoot;
|
|
192
|
+
}
|
|
@@ -44,6 +44,10 @@ export type RuntimeStorageRoots = {
|
|
|
44
44
|
};
|
|
45
45
|
export declare function getRuntimeStorageRoots(refs: Map<string, WorkspaceObject | ParsedAgentObject>, workspaceRoot: string): RuntimeStorageRoots;
|
|
46
46
|
export declare function getRuntimeResources(refs: Map<string, WorkspaceObject | ParsedAgentObject>): string[];
|
|
47
|
+
export declare function getRuntimeSources(refs: Map<string, WorkspaceObject | ParsedAgentObject>): {
|
|
48
|
+
tools: string[];
|
|
49
|
+
skills: string[];
|
|
50
|
+
};
|
|
47
51
|
export declare function getToolModuleDiscoveryConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): ToolModuleDiscoveryConfig;
|
|
48
52
|
export declare function getRuntimeMemoryDefaults(refs: Map<string, WorkspaceObject | ParsedAgentObject>): Record<string, unknown> | undefined;
|
|
49
53
|
export declare function getProceduralMemoryDefaults(refs: Map<string, WorkspaceObject | ParsedAgentObject>): Record<string, unknown> | undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { readRuntimeSources } from "./source-protocols.js";
|
|
3
4
|
function getRoutingObject(refs) {
|
|
4
5
|
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
5
6
|
return typeof runtimeDefaults?.routing === "object" && runtimeDefaults.routing
|
|
@@ -60,6 +61,9 @@ export function getRuntimeResources(refs) {
|
|
|
60
61
|
.filter((value) => typeof value === "string" && value.trim().length > 0)
|
|
61
62
|
.map((value) => value.trim());
|
|
62
63
|
}
|
|
64
|
+
export function getRuntimeSources(refs) {
|
|
65
|
+
return readRuntimeSources(getRuntimeDefaults(refs));
|
|
66
|
+
}
|
|
63
67
|
export function getToolModuleDiscoveryConfig(refs) {
|
|
64
68
|
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
65
69
|
const toolModuleDiscovery = typeof runtimeDefaults?.toolModuleDiscovery === "object" && runtimeDefaults.toolModuleDiscovery
|