@botbotgo/agent-harness 0.0.8 → 0.0.9
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/config/orchestra.yaml +3 -5
- package/dist/contracts/types.d.ts +4 -1
- package/dist/extensions.js +5 -5
- package/dist/resource/builtins.d.ts +1 -0
- package/dist/resource/builtins.js +1 -0
- package/dist/resource/resource-impl.d.ts +30 -0
- package/dist/resource/resource-impl.js +250 -0
- package/dist/resource/resource.d.ts +1 -0
- package/dist/resource/resource.js +1 -0
- package/dist/{vendor → resource}/sources.d.ts +3 -0
- package/dist/{vendor → resource}/sources.js +53 -0
- package/dist/runtime/agent-runtime-adapter.js +3 -2
- package/dist/runtime/file-checkpoint-saver.js +17 -2
- package/dist/runtime/harness.js +3 -3
- package/dist/runtime/support/vector-stores.js +1 -1
- package/dist/workspace/compile.js +44 -19
- package/dist/workspace/object-loader.d.ts +5 -0
- package/dist/workspace/object-loader.js +180 -36
- package/dist/workspace/resource-compilers.js +1 -0
- package/dist/workspace/support/discovery.js +19 -14
- package/dist/workspace/support/source-collectors.js +2 -2
- package/package.json +27 -5
- package/dist/vendor/builtins.d.ts +0 -24
- package/dist/vendor/builtins.js +0 -118
|
@@ -39,7 +39,7 @@ spec:
|
|
|
39
39
|
path: store.json
|
|
40
40
|
# DeepAgents aligned feature: backend config passed into `createDeepAgent({ backend })`.
|
|
41
41
|
# This directly defines the backend topology for this agent:
|
|
42
|
-
# -
|
|
42
|
+
# - workspace execution uses a lightweight VFS sandbox
|
|
43
43
|
# - long-term memory under `/memories/*` uses `StoreBackend`
|
|
44
44
|
# - `CompositeBackend` composes those backend instances together
|
|
45
45
|
# The harness also injects a persistent file-backed store and a file-backed checkpointer so that
|
|
@@ -48,11 +48,9 @@ spec:
|
|
|
48
48
|
backend:
|
|
49
49
|
kind: CompositeBackend
|
|
50
50
|
state:
|
|
51
|
-
# Available state backend `kind` options today: `StateBackend`, `LocalShellBackend`.
|
|
52
|
-
kind:
|
|
53
|
-
inheritEnv: true
|
|
51
|
+
# Available state backend `kind` options today: `StateBackend`, `LocalShellBackend`, `VfsSandbox`.
|
|
52
|
+
kind: VfsSandbox
|
|
54
53
|
timeout: 600
|
|
55
|
-
maxOutputBytes: 200000
|
|
56
54
|
routes:
|
|
57
55
|
/memories/:
|
|
58
56
|
# Available route backend `kind` options today: `StoreBackend`.
|
|
@@ -57,6 +57,7 @@ export type ParsedToolObject = {
|
|
|
57
57
|
type: string;
|
|
58
58
|
name: string;
|
|
59
59
|
description: string;
|
|
60
|
+
implementationName?: string;
|
|
60
61
|
config?: Record<string, unknown>;
|
|
61
62
|
inputSchemaRef?: string;
|
|
62
63
|
backendOperation?: string;
|
|
@@ -158,7 +159,8 @@ export type CompiledAgentBinding = {
|
|
|
158
159
|
};
|
|
159
160
|
export type WorkspaceBundle = {
|
|
160
161
|
workspaceRoot: string;
|
|
161
|
-
|
|
162
|
+
resourceSources: string[];
|
|
163
|
+
builtinSources?: string[];
|
|
162
164
|
refs: Map<string, WorkspaceObject | ParsedAgentObject>;
|
|
163
165
|
models: Map<string, ParsedModelObject>;
|
|
164
166
|
embeddings: Map<string, ParsedEmbeddingModelObject>;
|
|
@@ -169,6 +171,7 @@ export type WorkspaceBundle = {
|
|
|
169
171
|
};
|
|
170
172
|
export type WorkspaceLoadOptions = {
|
|
171
173
|
overlayRoots?: string[];
|
|
174
|
+
resourceSources?: string[];
|
|
172
175
|
builtinSources?: string[];
|
|
173
176
|
};
|
|
174
177
|
export type ThreadSummary = {
|
package/dist/extensions.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
3
|
-
import { isExternalSourceLocator,
|
|
2
|
+
import { defaultResourceSkillsRoot } from "./resource/resource.js";
|
|
3
|
+
import { isExternalSourceLocator, resolveExternalResourcePath } from "./resource/sources.js";
|
|
4
4
|
const toolKindAdapters = new Map();
|
|
5
5
|
const skillSourceResolvers = new Map();
|
|
6
6
|
const skillInheritancePolicies = new Map();
|
|
@@ -217,7 +217,7 @@ registerSkillSourceResolver({
|
|
|
217
217
|
}
|
|
218
218
|
const candidate = String(skill.sourcePathRef);
|
|
219
219
|
if (isExternalSourceLocator(candidate)) {
|
|
220
|
-
return [
|
|
220
|
+
return [resolveExternalResourcePath(candidate, workspaceRoot)];
|
|
221
221
|
}
|
|
222
222
|
return [candidate.startsWith("/") ? candidate : `${workspaceRoot}/${candidate}`];
|
|
223
223
|
},
|
|
@@ -225,7 +225,7 @@ registerSkillSourceResolver({
|
|
|
225
225
|
registerSkillSourceResolver({
|
|
226
226
|
kind: "builtin",
|
|
227
227
|
resolve({ skill }) {
|
|
228
|
-
return [path.join(
|
|
228
|
+
return [path.join(defaultResourceSkillsRoot(), skill.sourcePathRef)];
|
|
229
229
|
},
|
|
230
230
|
});
|
|
231
231
|
registerSkillInheritancePolicy({
|
|
@@ -244,7 +244,7 @@ registerSkillPackagingConvention({
|
|
|
244
244
|
resolve({ workspaceRoot, skill }) {
|
|
245
245
|
const candidate = String(skill.sourcePathRef);
|
|
246
246
|
if (isExternalSourceLocator(candidate)) {
|
|
247
|
-
return [
|
|
247
|
+
return [resolveExternalResourcePath(candidate, workspaceRoot)];
|
|
248
248
|
}
|
|
249
249
|
return [candidate.startsWith("/") ? candidate : `${workspaceRoot}/${candidate}`];
|
|
250
250
|
},
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { builtinConfigRoot, builtinSkillsRoot, createBuiltinBackendResolver, createBuiltinToolResolver, ensureBuiltinSources, listBuiltinTools, listBuiltinToolsForSource, resolveLocalBuiltinsEntry, } from "./resource.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { builtinConfigRoot, builtinSkillsRoot, createBuiltinBackendResolver, createBuiltinToolResolver, ensureBuiltinSources, listBuiltinTools, listBuiltinToolsForSource, resolveLocalBuiltinsEntry, } from "./resource.js";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RuntimeAdapterOptions, WorkspaceBundle } from "../contracts/types.js";
|
|
2
|
+
export declare function resolveLocalBuiltinsEntry(currentResourceDir: string, resolveInstalledEntry?: () => string | null): string;
|
|
3
|
+
export type ResourceToolInfo = {
|
|
4
|
+
toolPath: string;
|
|
5
|
+
backendOperation: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
hitl?: {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
allow: Array<"approve" | "edit" | "reject">;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export declare function ensureResourceSources(sources?: string[], workspaceRoot?: string): Promise<void>;
|
|
14
|
+
export declare function defaultResourceSkillsRoot(): string;
|
|
15
|
+
export declare function defaultResourceConfigRoot(): string;
|
|
16
|
+
export declare function listResourceTools(sources?: string[], workspaceRoot?: string): Promise<ResourceToolInfo[]>;
|
|
17
|
+
export declare function listResourceToolsForSource(source: string, workspaceRoot?: string): Promise<ResourceToolInfo[]>;
|
|
18
|
+
export declare function createResourceBackendResolver(workspace: WorkspaceBundle): NonNullable<RuntimeAdapterOptions["backendResolver"]>;
|
|
19
|
+
export declare function createResourceToolResolver(workspace: WorkspaceBundle, options?: {
|
|
20
|
+
getStore?: (_binding?: WorkspaceBundle["bindings"] extends Map<any, infer T> ? T : never) => unknown;
|
|
21
|
+
getEmbeddingModel?: (embeddingModelRef?: string, _binding?: WorkspaceBundle["bindings"] extends Map<any, infer T> ? T : never) => Promise<unknown>;
|
|
22
|
+
getVectorStore?: (vectorStoreRef?: string, _binding?: WorkspaceBundle["bindings"] extends Map<any, infer T> ? T : never) => Promise<unknown>;
|
|
23
|
+
}): NonNullable<RuntimeAdapterOptions["toolResolver"]>;
|
|
24
|
+
export declare const ensureBuiltinSources: typeof ensureResourceSources;
|
|
25
|
+
export declare const builtinSkillsRoot: typeof defaultResourceSkillsRoot;
|
|
26
|
+
export declare const builtinConfigRoot: typeof defaultResourceConfigRoot;
|
|
27
|
+
export declare const listBuiltinTools: typeof listResourceTools;
|
|
28
|
+
export declare const listBuiltinToolsForSource: typeof listResourceToolsForSource;
|
|
29
|
+
export declare const createBuiltinBackendResolver: typeof createResourceBackendResolver;
|
|
30
|
+
export declare const createBuiltinToolResolver: typeof createResourceToolResolver;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { stat } from "node:fs/promises";
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
+
import { ensureExternalResourceSource, ensureExternalSource, isExternalSourceLocator, parseExternalSourceLocator } from "./sources.js";
|
|
8
|
+
const resourceDir = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
function installedBuiltinsEntry() {
|
|
11
|
+
try {
|
|
12
|
+
return require.resolve("@botbotgo/agent-harness-builtin");
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function resolveLocalBuiltinsEntry(currentResourceDir, resolveInstalledEntry = installedBuiltinsEntry) {
|
|
19
|
+
const candidates = [
|
|
20
|
+
path.resolve(currentResourceDir, "../../../builtins/dist/src/index.js"),
|
|
21
|
+
path.resolve(currentResourceDir, "../../../agent-harness/packages/builtins/dist/src/index.js"),
|
|
22
|
+
path.resolve(currentResourceDir, "../../../builtins/src/index.ts"),
|
|
23
|
+
path.resolve(currentResourceDir, "../../../agent-harness/packages/builtins/src/index.ts"),
|
|
24
|
+
resolveInstalledEntry(),
|
|
25
|
+
].filter((candidate) => typeof candidate === "string" && candidate.length > 0);
|
|
26
|
+
for (const candidate of candidates) {
|
|
27
|
+
if (existsSync(candidate)) {
|
|
28
|
+
return candidate;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return candidates.at(-1) ?? path.resolve(currentResourceDir, "../../../agent-harness/packages/builtins/dist/src/index.js");
|
|
32
|
+
}
|
|
33
|
+
const builtinsEntry = resolveLocalBuiltinsEntry(resourceDir);
|
|
34
|
+
async function loadLocalResource(entry) {
|
|
35
|
+
if (!existsSync(entry)) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const imported = await import(pathToFileURL(entry).href);
|
|
39
|
+
return (imported.default ?? imported);
|
|
40
|
+
}
|
|
41
|
+
const localResource = await loadLocalResource(builtinsEntry);
|
|
42
|
+
function listProviderTools(provider) {
|
|
43
|
+
const rawTools = provider?.listResourceTools?.() ?? provider?.listBuiltinTools?.() ?? [];
|
|
44
|
+
return rawTools.map((tool) => ({
|
|
45
|
+
...tool,
|
|
46
|
+
toolPath: tool.toolPath ?? tool.builtinPath ?? "",
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
function createProviderToolResolver(provider, workspace, options) {
|
|
50
|
+
return (provider?.createResourceToolResolver?.(workspace, options) ??
|
|
51
|
+
provider?.createBuiltinToolResolver?.(workspace, options));
|
|
52
|
+
}
|
|
53
|
+
function createProviderBackendResolver(provider, workspace) {
|
|
54
|
+
return (provider?.createResourceBackendResolver?.(workspace) ??
|
|
55
|
+
provider?.createBuiltinBackendResolver?.(workspace));
|
|
56
|
+
}
|
|
57
|
+
function requireLocalResource(feature) {
|
|
58
|
+
if (localResource) {
|
|
59
|
+
return localResource;
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`agent-harness optional tool bundle support is unavailable for ${feature}. Install the matching provider package or provide a local sibling checkout.`);
|
|
62
|
+
}
|
|
63
|
+
const remoteResourceCache = new Map();
|
|
64
|
+
async function findPackageRoot(startPath) {
|
|
65
|
+
let current = path.dirname(startPath);
|
|
66
|
+
for (;;) {
|
|
67
|
+
try {
|
|
68
|
+
await stat(path.join(current, "package.json"));
|
|
69
|
+
return current;
|
|
70
|
+
}
|
|
71
|
+
catch { }
|
|
72
|
+
const parent = path.dirname(current);
|
|
73
|
+
if (parent === current) {
|
|
74
|
+
return path.dirname(startPath);
|
|
75
|
+
}
|
|
76
|
+
current = parent;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const functionToolModuleCache = new Map();
|
|
80
|
+
async function loadFunctionToolModule(tool) {
|
|
81
|
+
const cacheKey = `${tool.sourcePath}:${tool.implementationName ?? tool.id}`;
|
|
82
|
+
const cached = functionToolModuleCache.get(cacheKey);
|
|
83
|
+
if (cached) {
|
|
84
|
+
return cached;
|
|
85
|
+
}
|
|
86
|
+
const loading = (async () => {
|
|
87
|
+
const imported = await import(pathToFileURL(tool.sourcePath).href);
|
|
88
|
+
const implementationName = tool.implementationName ?? tool.id;
|
|
89
|
+
const invoke = imported[implementationName];
|
|
90
|
+
const schema = imported[`${implementationName}Schema`];
|
|
91
|
+
if (typeof invoke !== "function") {
|
|
92
|
+
throw new Error(`Tool module ${tool.sourcePath} must export function ${implementationName}.`);
|
|
93
|
+
}
|
|
94
|
+
if (!schema?.parse) {
|
|
95
|
+
throw new Error(`Tool module ${tool.sourcePath} must export ${implementationName}Schema as a Zod schema.`);
|
|
96
|
+
}
|
|
97
|
+
return { invoke, schema };
|
|
98
|
+
})();
|
|
99
|
+
functionToolModuleCache.set(cacheKey, loading);
|
|
100
|
+
return loading;
|
|
101
|
+
}
|
|
102
|
+
function createFunctionToolResolver(workspace) {
|
|
103
|
+
const functionTools = new Map(Array.from(workspace.tools.values())
|
|
104
|
+
.filter((tool) => tool.type === "function" && tool.sourcePath.endsWith(".mjs"))
|
|
105
|
+
.map((tool) => [tool.id, tool]));
|
|
106
|
+
return (toolIds) => toolIds.flatMap((toolId) => {
|
|
107
|
+
const tool = functionTools.get(toolId);
|
|
108
|
+
if (!tool) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
return [
|
|
112
|
+
{
|
|
113
|
+
name: tool.name,
|
|
114
|
+
description: tool.description,
|
|
115
|
+
async invoke(input) {
|
|
116
|
+
const loaded = await loadFunctionToolModule(tool);
|
|
117
|
+
const parsedInput = loaded.schema.parse(input ?? {});
|
|
118
|
+
const toolPackageRoot = await findPackageRoot(tool.sourcePath);
|
|
119
|
+
return loaded.invoke(parsedInput, {
|
|
120
|
+
appRoot: workspace.workspaceRoot,
|
|
121
|
+
toolId: tool.id,
|
|
122
|
+
toolPath: tool.sourcePath,
|
|
123
|
+
toolPackageRoot,
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function resolvePackageEntry(packageRoot, pkg) {
|
|
131
|
+
const exportsField = pkg.exports;
|
|
132
|
+
if (typeof exportsField === "string") {
|
|
133
|
+
return path.resolve(packageRoot, exportsField);
|
|
134
|
+
}
|
|
135
|
+
if (exportsField && typeof exportsField === "object" && "." in exportsField) {
|
|
136
|
+
const rootExport = exportsField["."];
|
|
137
|
+
if (typeof rootExport === "string") {
|
|
138
|
+
return path.resolve(packageRoot, rootExport);
|
|
139
|
+
}
|
|
140
|
+
if (rootExport && typeof rootExport === "object") {
|
|
141
|
+
const importEntry = rootExport.import ?? rootExport.default;
|
|
142
|
+
if (typeof importEntry === "string") {
|
|
143
|
+
return path.resolve(packageRoot, importEntry);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (typeof pkg.module === "string") {
|
|
148
|
+
return path.resolve(packageRoot, pkg.module);
|
|
149
|
+
}
|
|
150
|
+
if (typeof pkg.main === "string") {
|
|
151
|
+
return path.resolve(packageRoot, pkg.main);
|
|
152
|
+
}
|
|
153
|
+
return path.resolve(packageRoot, "index.js");
|
|
154
|
+
}
|
|
155
|
+
async function loadRemoteResource(source, workspaceRoot) {
|
|
156
|
+
const cached = remoteResourceCache.get(source);
|
|
157
|
+
if (cached !== undefined) {
|
|
158
|
+
return cached;
|
|
159
|
+
}
|
|
160
|
+
if (!isExternalSourceLocator(source)) {
|
|
161
|
+
throw new Error(`Unsupported resource source ${source}. Use npm:, tgz:, or file:.`);
|
|
162
|
+
}
|
|
163
|
+
const parsed = parseExternalSourceLocator(source);
|
|
164
|
+
if (parsed.subpath) {
|
|
165
|
+
throw new Error(`Resource source ${source} must point at a package root, not a subpath`);
|
|
166
|
+
}
|
|
167
|
+
await ensureExternalResourceSource(source, workspaceRoot);
|
|
168
|
+
const packageRoot = await ensureExternalSource(source, workspaceRoot);
|
|
169
|
+
const pkg = JSON.parse(await readFile(path.join(packageRoot, "package.json"), "utf8"));
|
|
170
|
+
const entry = resolvePackageEntry(packageRoot, pkg);
|
|
171
|
+
if (!existsSync(entry)) {
|
|
172
|
+
remoteResourceCache.set(source, null);
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
const imported = await import(pathToFileURL(entry).href);
|
|
176
|
+
const provider = (imported.default ?? imported);
|
|
177
|
+
if (listProviderTools(provider).length === 0 &&
|
|
178
|
+
!provider.listResourceTools &&
|
|
179
|
+
!provider.listBuiltinTools) {
|
|
180
|
+
remoteResourceCache.set(source, null);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
if (!provider.createResourceToolResolver && !provider.createBuiltinToolResolver) {
|
|
184
|
+
remoteResourceCache.set(source, null);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const typedProvider = provider;
|
|
188
|
+
remoteResourceCache.set(source, typedProvider);
|
|
189
|
+
return typedProvider;
|
|
190
|
+
}
|
|
191
|
+
export async function ensureResourceSources(sources = [], workspaceRoot = process.cwd()) {
|
|
192
|
+
await Promise.all(sources.map((source) => loadRemoteResource(source, workspaceRoot)));
|
|
193
|
+
}
|
|
194
|
+
export function defaultResourceSkillsRoot() {
|
|
195
|
+
const provider = requireLocalResource("default resource skill resolution");
|
|
196
|
+
return provider.defaultResourceSkillsRoot?.() ?? provider.builtinSkillsRoot?.() ?? "";
|
|
197
|
+
}
|
|
198
|
+
export function defaultResourceConfigRoot() {
|
|
199
|
+
const provider = requireLocalResource("default resource config resolution");
|
|
200
|
+
return provider.defaultResourceConfigRoot?.() ?? provider.builtinConfigRoot?.() ?? provider.builtinDefaultsRoot?.() ?? "";
|
|
201
|
+
}
|
|
202
|
+
export async function listResourceTools(sources = [], workspaceRoot = process.cwd()) {
|
|
203
|
+
await ensureResourceSources(sources, workspaceRoot);
|
|
204
|
+
const deduped = new Map();
|
|
205
|
+
for (const tool of listProviderTools(localResource)) {
|
|
206
|
+
deduped.set(tool.toolPath, tool);
|
|
207
|
+
}
|
|
208
|
+
for (const source of sources) {
|
|
209
|
+
for (const tool of listProviderTools(remoteResourceCache.get(source) ?? undefined)) {
|
|
210
|
+
deduped.set(tool.toolPath, tool);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return Array.from(deduped.values());
|
|
214
|
+
}
|
|
215
|
+
export async function listResourceToolsForSource(source, workspaceRoot = process.cwd()) {
|
|
216
|
+
await ensureResourceSources([source], workspaceRoot);
|
|
217
|
+
return listProviderTools(remoteResourceCache.get(source) ?? undefined);
|
|
218
|
+
}
|
|
219
|
+
export function createResourceBackendResolver(workspace) {
|
|
220
|
+
const localResolver = createProviderBackendResolver(localResource, workspace);
|
|
221
|
+
return (binding) => localResolver?.(binding) ?? [];
|
|
222
|
+
}
|
|
223
|
+
export function createResourceToolResolver(workspace, options = {}) {
|
|
224
|
+
const functionResolver = createFunctionToolResolver(workspace);
|
|
225
|
+
const localResolver = createProviderToolResolver(localResource, workspace, options);
|
|
226
|
+
const remoteResolvers = (workspace.resourceSources ?? workspace.builtinSources ?? [])
|
|
227
|
+
.map((source) => remoteResourceCache.get(source))
|
|
228
|
+
.filter((provider) => Boolean(provider))
|
|
229
|
+
.map((provider) => createProviderToolResolver(provider, workspace, options))
|
|
230
|
+
.filter((resolver) => Boolean(resolver));
|
|
231
|
+
return (toolIds, binding) => {
|
|
232
|
+
const resolved = [
|
|
233
|
+
...functionResolver(toolIds, binding),
|
|
234
|
+
...(localResolver?.(toolIds, binding) ?? []),
|
|
235
|
+
...remoteResolvers.flatMap((resolver) => resolver(toolIds, binding)),
|
|
236
|
+
];
|
|
237
|
+
const deduped = new Map();
|
|
238
|
+
for (const tool of resolved) {
|
|
239
|
+
deduped.set(String(tool.name), tool);
|
|
240
|
+
}
|
|
241
|
+
return Array.from(deduped.values());
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
export const ensureBuiltinSources = ensureResourceSources;
|
|
245
|
+
export const builtinSkillsRoot = defaultResourceSkillsRoot;
|
|
246
|
+
export const builtinConfigRoot = defaultResourceConfigRoot;
|
|
247
|
+
export const listBuiltinTools = listResourceTools;
|
|
248
|
+
export const listBuiltinToolsForSource = listResourceToolsForSource;
|
|
249
|
+
export const createBuiltinBackendResolver = createResourceBackendResolver;
|
|
250
|
+
export const createBuiltinToolResolver = createResourceToolResolver;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type ResourceToolInfo, ensureResourceSources, defaultResourceSkillsRoot, defaultResourceConfigRoot, listResourceTools, listResourceToolsForSource, createResourceBackendResolver, createResourceToolResolver, ensureBuiltinSources, builtinSkillsRoot, builtinConfigRoot, listBuiltinTools, listBuiltinToolsForSource, createBuiltinBackendResolver, createBuiltinToolResolver, resolveLocalBuiltinsEntry, } from "./resource-impl.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ensureResourceSources, defaultResourceSkillsRoot, defaultResourceConfigRoot, listResourceTools, listResourceToolsForSource, createResourceBackendResolver, createResourceToolResolver, ensureBuiltinSources, builtinSkillsRoot, builtinConfigRoot, listBuiltinTools, listBuiltinToolsForSource, createBuiltinBackendResolver, createBuiltinToolResolver, resolveLocalBuiltinsEntry, } from "./resource-impl.js";
|
|
@@ -3,10 +3,13 @@ type ParsedLocator = {
|
|
|
3
3
|
spec: string;
|
|
4
4
|
subpath?: string;
|
|
5
5
|
};
|
|
6
|
+
export declare function resolveResourcePackageRoot(root: string): string | null;
|
|
6
7
|
export declare function isExternalSourceLocator(value: unknown): boolean;
|
|
7
8
|
export declare function parseExternalSourceLocator(locator: string): ParsedLocator;
|
|
8
9
|
export declare function ensureExternalSource(locator: string, workspaceRoot: string): Promise<string>;
|
|
10
|
+
export declare function ensureExternalResourceSource(locator: string, workspaceRoot: string): Promise<string>;
|
|
9
11
|
export declare function ensureExternalSources(locators: string[], workspaceRoot: string): Promise<void>;
|
|
10
12
|
export declare function resolveExternalSourcePath(locator: string, workspaceRoot: string): string;
|
|
13
|
+
export declare function resolveExternalResourcePath(locator: string, workspaceRoot: string): string;
|
|
11
14
|
export declare function isDirectoryPath(candidate: string): boolean;
|
|
12
15
|
export {};
|
|
@@ -14,6 +14,23 @@ function sourceCacheDir(locator) {
|
|
|
14
14
|
const digest = createHash("sha256").update(locator).digest("hex").slice(0, 16);
|
|
15
15
|
return path.join(cacheRoot(), digest);
|
|
16
16
|
}
|
|
17
|
+
export function resolveResourcePackageRoot(root) {
|
|
18
|
+
const candidates = path.basename(root) === "resources" ? [root] : [path.join(root, "resources")];
|
|
19
|
+
for (const candidate of candidates) {
|
|
20
|
+
if (!existsSync(candidate)) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (!statSync(candidate).isDirectory()) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const packageJsonPath = path.join(candidate, "package.json");
|
|
27
|
+
if (!existsSync(packageJsonPath)) {
|
|
28
|
+
throw new Error(`Resource package ${candidate} is missing package.json.`);
|
|
29
|
+
}
|
|
30
|
+
return candidate;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
17
34
|
export function isExternalSourceLocator(value) {
|
|
18
35
|
return typeof value === "string" && /^(npm|tgz|file):/.test(value);
|
|
19
36
|
}
|
|
@@ -91,6 +108,24 @@ export async function ensureExternalSource(locator, workspaceRoot) {
|
|
|
91
108
|
sourceCache.set(cacheKey, basePath);
|
|
92
109
|
return parsed.subpath ? path.join(basePath, parsed.subpath) : basePath;
|
|
93
110
|
}
|
|
111
|
+
export async function ensureExternalResourceSource(locator, workspaceRoot) {
|
|
112
|
+
const parsed = parseExternalSourceLocator(locator);
|
|
113
|
+
const baseLocator = `${parsed.kind}:${parsed.spec}`;
|
|
114
|
+
const packageRoot = await ensureExternalSource(baseLocator, workspaceRoot);
|
|
115
|
+
const resourcesRoot = path.join(packageRoot, "resources");
|
|
116
|
+
if (!existsSync(resourcesRoot) || !statSync(resourcesRoot).isDirectory()) {
|
|
117
|
+
throw new Error(`External source ${baseLocator} is missing resources/.`);
|
|
118
|
+
}
|
|
119
|
+
const resourcePackageJson = path.join(resourcesRoot, "package.json");
|
|
120
|
+
if (!existsSync(resourcePackageJson)) {
|
|
121
|
+
throw new Error(`External source ${baseLocator} is missing resources/package.json.`);
|
|
122
|
+
}
|
|
123
|
+
const resourcePackageRoot = resolveResourcePackageRoot(packageRoot);
|
|
124
|
+
if (!resourcePackageRoot) {
|
|
125
|
+
throw new Error(`External source ${baseLocator} is missing resources/package.json.`);
|
|
126
|
+
}
|
|
127
|
+
return parsed.subpath ? path.join(resourcePackageRoot, parsed.subpath) : resourcePackageRoot;
|
|
128
|
+
}
|
|
94
129
|
export async function ensureExternalSources(locators, workspaceRoot) {
|
|
95
130
|
await Promise.all(Array.from(new Set(locators)).map((locator) => ensureExternalSource(locator, workspaceRoot)));
|
|
96
131
|
}
|
|
@@ -110,6 +145,24 @@ export function resolveExternalSourcePath(locator, workspaceRoot) {
|
|
|
110
145
|
}
|
|
111
146
|
throw new Error(`External source ${locator} must be preloaded before synchronous resolution`);
|
|
112
147
|
}
|
|
148
|
+
export function resolveExternalResourcePath(locator, workspaceRoot) {
|
|
149
|
+
const parsed = parseExternalSourceLocator(locator);
|
|
150
|
+
const baseLocator = `${parsed.kind}:${parsed.spec}`;
|
|
151
|
+
const packageRoot = resolveExternalSourcePath(baseLocator, workspaceRoot);
|
|
152
|
+
const resourcesRoot = path.join(packageRoot, "resources");
|
|
153
|
+
if (!existsSync(resourcesRoot) || !statSync(resourcesRoot).isDirectory()) {
|
|
154
|
+
throw new Error(`External source ${baseLocator} is missing resources/.`);
|
|
155
|
+
}
|
|
156
|
+
const resourcePackageJson = path.join(resourcesRoot, "package.json");
|
|
157
|
+
if (!existsSync(resourcePackageJson)) {
|
|
158
|
+
throw new Error(`External source ${baseLocator} is missing resources/package.json.`);
|
|
159
|
+
}
|
|
160
|
+
const resourcePackageRoot = resolveResourcePackageRoot(packageRoot);
|
|
161
|
+
if (!resourcePackageRoot) {
|
|
162
|
+
throw new Error(`External source ${baseLocator} is missing resources/package.json.`);
|
|
163
|
+
}
|
|
164
|
+
return parsed.subpath ? path.join(resourcePackageRoot, parsed.subpath) : resourcePackageRoot;
|
|
165
|
+
}
|
|
113
166
|
export function isDirectoryPath(candidate) {
|
|
114
167
|
return existsSync(candidate) && statSync(candidate).isDirectory();
|
|
115
168
|
}
|
|
@@ -318,7 +318,7 @@ export class AgentRuntimeAdapter {
|
|
|
318
318
|
if (!params) {
|
|
319
319
|
throw new Error(`Agent ${binding.agent.id} has no runnable params`);
|
|
320
320
|
}
|
|
321
|
-
|
|
321
|
+
const deepAgentConfig = {
|
|
322
322
|
model: (await this.resolveModel(params.model)),
|
|
323
323
|
tools: this.resolveTools(params.tools, binding),
|
|
324
324
|
systemPrompt: params.systemPrompt,
|
|
@@ -331,7 +331,8 @@ export class AgentRuntimeAdapter {
|
|
|
331
331
|
name: params.name,
|
|
332
332
|
memory: params.memory,
|
|
333
333
|
skills: params.skills,
|
|
334
|
-
}
|
|
334
|
+
};
|
|
335
|
+
return createDeepAgent(deepAgentConfig);
|
|
335
336
|
}
|
|
336
337
|
async route(input, primaryBinding, secondaryBinding, options = {}) {
|
|
337
338
|
const routeModelConfig = primaryBinding.langchainAgentParams?.model ??
|
|
@@ -29,6 +29,21 @@ function decodeBinary(value) {
|
|
|
29
29
|
}
|
|
30
30
|
return value;
|
|
31
31
|
}
|
|
32
|
+
function pruneThreadEntries(record, threadId) {
|
|
33
|
+
for (const key of Object.keys(record)) {
|
|
34
|
+
if (key.includes(threadId)) {
|
|
35
|
+
delete record[key];
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const value = record[key];
|
|
39
|
+
if (typeof value === "object" && value && !Array.isArray(value)) {
|
|
40
|
+
pruneThreadEntries(value, threadId);
|
|
41
|
+
if (Object.keys(value).length === 0) {
|
|
42
|
+
delete record[key];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
32
47
|
export class FileCheckpointSaver extends MemorySaver {
|
|
33
48
|
filePath;
|
|
34
49
|
loaded = false;
|
|
@@ -83,9 +98,9 @@ export class FileCheckpointSaver extends MemorySaver {
|
|
|
83
98
|
}
|
|
84
99
|
async deleteThread(threadId) {
|
|
85
100
|
await this.ensureLoaded();
|
|
86
|
-
|
|
101
|
+
pruneThreadEntries(this.storage, threadId);
|
|
102
|
+
pruneThreadEntries(this.writes, threadId);
|
|
87
103
|
await this.persist();
|
|
88
|
-
return result;
|
|
89
104
|
}
|
|
90
105
|
}
|
|
91
106
|
export { FileCheckpointSaver as FileCheckpointer };
|
package/dist/runtime/harness.js
CHANGED
|
@@ -2,7 +2,7 @@ import { AUTO_AGENT_ID } from "../contracts/types.js";
|
|
|
2
2
|
import { FilePersistence } from "../persistence/file-store.js";
|
|
3
3
|
import { createPersistentId } from "../utils/id.js";
|
|
4
4
|
import { AGENT_INTERRUPT_SENTINEL_PREFIX, AgentRuntimeAdapter } from "./agent-runtime-adapter.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createResourceBackendResolver, createResourceToolResolver } from "../resource/resource.js";
|
|
6
6
|
import { EventBus } from "./event-bus.js";
|
|
7
7
|
import { PolicyEngine } from "./policy-engine.js";
|
|
8
8
|
import { getRoutingSystemPrompt } from "../workspace/support/workspace-ref-utils.js";
|
|
@@ -115,7 +115,7 @@ export class AgentHarness {
|
|
|
115
115
|
this.runtimeAdapter = new AgentRuntimeAdapter({
|
|
116
116
|
...runtimeAdapterOptions,
|
|
117
117
|
toolResolver: runtimeAdapterOptions.toolResolver ??
|
|
118
|
-
|
|
118
|
+
createResourceToolResolver(workspace, {
|
|
119
119
|
getStore: (binding) => this.resolveStore(binding),
|
|
120
120
|
getEmbeddingModel: (embeddingModelRef) => this.resolveEmbeddingModel(embeddingModelRef),
|
|
121
121
|
getVectorStore: (vectorStoreRef) => this.resolveVectorStore(vectorStoreRef),
|
|
@@ -135,7 +135,7 @@ export class AgentHarness {
|
|
|
135
135
|
storeResolver: runtimeAdapterOptions.storeResolver ??
|
|
136
136
|
((binding) => this.resolveStore(binding)),
|
|
137
137
|
backendResolver: runtimeAdapterOptions.backendResolver ??
|
|
138
|
-
((binding) =>
|
|
138
|
+
((binding) => createResourceBackendResolver(workspace)(binding)),
|
|
139
139
|
});
|
|
140
140
|
this.routingSystemPrompt = getRoutingSystemPrompt(workspace.refs);
|
|
141
141
|
this.threadMemorySync = new ThreadMemorySync(this.persistence, this.defaultStore);
|
|
@@ -110,7 +110,7 @@ export async function resolveCompiledVectorStore(workspace, vectorStore, options
|
|
|
110
110
|
table,
|
|
111
111
|
column,
|
|
112
112
|
});
|
|
113
|
-
const rows = await store.similaritySearchWithScore(query, limit);
|
|
113
|
+
const rows = (await store.similaritySearchWithScore(query, limit));
|
|
114
114
|
return rows.map(([document, score]) => ({
|
|
115
115
|
pageContent: document.pageContent,
|
|
116
116
|
metadata: document.metadata,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { ensureResourceSources, listResourceTools, listResourceToolsForSource } from "../resource/resource.js";
|
|
4
|
+
import { ensureExternalResourceSource, isExternalSourceLocator } from "../resource/sources.js";
|
|
5
|
+
import { loadWorkspaceObjects, readToolModuleItems } from "./object-loader.js";
|
|
4
6
|
import { parseEmbeddingModelObject, parseModelObject, parseToolObject, parseVectorStoreObject, validateEmbeddingModelObject, validateModelObject, validateToolObject, validateVectorStoreObject, } from "./resource-compilers.js";
|
|
5
7
|
import { validateAgent, validateTopology } from "./validate.js";
|
|
6
8
|
import { compileBinding } from "./agent-binding-compiler.js";
|
|
@@ -32,34 +34,56 @@ function collectParsedResources(refs) {
|
|
|
32
34
|
}
|
|
33
35
|
return { embeddings, models, vectorStores, tools };
|
|
34
36
|
}
|
|
35
|
-
async function
|
|
37
|
+
async function hydrateResourceAndExternalTools(tools, toolSourceRefs, workspaceRoot) {
|
|
36
38
|
for (const source of toolSourceRefs) {
|
|
37
39
|
if (isExternalSourceLocator(source)) {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
+
const externalRoot = await ensureExternalResourceSource(source, workspaceRoot);
|
|
41
|
+
const discoveredToolRefs = [];
|
|
42
|
+
const sourcePrefix = `external.${createHash("sha256").update(source).digest("hex").slice(0, 12)}`;
|
|
43
|
+
for (const { item, sourcePath } of await readToolModuleItems(path.join(externalRoot, "tools"))) {
|
|
44
|
+
const toolId = typeof item.id === "string" ? item.id : undefined;
|
|
45
|
+
if (!toolId) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const namespacedId = `${sourcePrefix}.${toolId}`;
|
|
49
|
+
const parsed = parseToolObject({
|
|
50
|
+
id: namespacedId,
|
|
51
|
+
kind: "tool",
|
|
52
|
+
sourcePath,
|
|
53
|
+
value: {
|
|
54
|
+
...item,
|
|
55
|
+
id: namespacedId,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
tools.set(parsed.id, parsed);
|
|
59
|
+
discoveredToolRefs.push(`tool/${parsed.id}`);
|
|
60
|
+
}
|
|
61
|
+
const sourceTools = await listResourceToolsForSource(source, workspaceRoot);
|
|
62
|
+
const bundleRefs = [...sourceTools.map((tool) => tool.toolPath), ...discoveredToolRefs];
|
|
63
|
+
if (bundleRefs.length > 0) {
|
|
40
64
|
tools.set(source, {
|
|
41
65
|
id: source,
|
|
42
66
|
type: "bundle",
|
|
43
67
|
name: source,
|
|
44
|
-
description: `External
|
|
45
|
-
bundleRefs
|
|
68
|
+
description: `External tool resource loaded from ${source}`,
|
|
69
|
+
bundleRefs,
|
|
46
70
|
sourcePath: source,
|
|
47
71
|
});
|
|
48
72
|
}
|
|
49
73
|
}
|
|
50
74
|
}
|
|
51
|
-
for (const
|
|
52
|
-
const existing = tools.get(
|
|
53
|
-
tools.set(
|
|
54
|
-
id:
|
|
75
|
+
for (const resourceTool of await listResourceTools(toolSourceRefs, workspaceRoot)) {
|
|
76
|
+
const existing = tools.get(resourceTool.toolPath);
|
|
77
|
+
tools.set(resourceTool.toolPath, {
|
|
78
|
+
id: resourceTool.toolPath,
|
|
55
79
|
type: existing?.type ?? "backend",
|
|
56
|
-
name: existing?.name ||
|
|
57
|
-
description: existing?.description ||
|
|
80
|
+
name: existing?.name || resourceTool.name,
|
|
81
|
+
description: existing?.description || resourceTool.description,
|
|
58
82
|
config: existing?.config,
|
|
59
|
-
backendOperation: existing?.backendOperation ??
|
|
83
|
+
backendOperation: existing?.backendOperation ?? resourceTool.backendOperation,
|
|
60
84
|
bundleRefs: existing?.bundleRefs ?? [],
|
|
61
|
-
hitl: existing?.hitl ??
|
|
62
|
-
sourcePath: existing?.sourcePath ??
|
|
85
|
+
hitl: existing?.hitl ?? resourceTool.hitl,
|
|
86
|
+
sourcePath: existing?.sourcePath ?? resourceTool.toolPath,
|
|
63
87
|
});
|
|
64
88
|
}
|
|
65
89
|
}
|
|
@@ -90,11 +114,12 @@ export async function loadWorkspace(workspaceRoot, options = {}) {
|
|
|
90
114
|
}
|
|
91
115
|
const { embeddings, models, vectorStores, tools } = collectParsedResources(loaded.refs);
|
|
92
116
|
const toolSourceRefs = collectToolSourceRefs(tools, loaded.agents, options);
|
|
93
|
-
await
|
|
94
|
-
await
|
|
117
|
+
await ensureResourceSources(toolSourceRefs, workspaceRoot);
|
|
118
|
+
await hydrateResourceAndExternalTools(tools, toolSourceRefs, workspaceRoot);
|
|
95
119
|
validateWorkspaceResources(embeddings, models, vectorStores, tools, loaded.agents);
|
|
96
120
|
return {
|
|
97
121
|
workspaceRoot,
|
|
122
|
+
resourceSources: [...toolSourceRefs],
|
|
98
123
|
builtinSources: [...toolSourceRefs],
|
|
99
124
|
refs: loaded.refs,
|
|
100
125
|
embeddings,
|
|
@@ -4,6 +4,7 @@ export type WorkspaceObjects = {
|
|
|
4
4
|
refs: RefMap;
|
|
5
5
|
agents: ParsedAgentObject[];
|
|
6
6
|
};
|
|
7
|
+
export declare function conventionalPackageRoots(root: string, relativeDir: "tools" | "skills"): string[];
|
|
7
8
|
export declare function normalizeYamlItem(item: Record<string, unknown>): Record<string, unknown>;
|
|
8
9
|
export declare function parseAgentItem(item: Record<string, unknown>, sourcePath: string): ParsedAgentObject;
|
|
9
10
|
export declare function readYamlItems(root: string, relativeDir?: string, options?: {
|
|
@@ -12,5 +13,9 @@ export declare function readYamlItems(root: string, relativeDir?: string, option
|
|
|
12
13
|
item: Record<string, unknown>;
|
|
13
14
|
sourcePath: string;
|
|
14
15
|
}>>;
|
|
16
|
+
export declare function readToolModuleItems(root: string): Promise<Array<{
|
|
17
|
+
item: Record<string, unknown>;
|
|
18
|
+
sourcePath: string;
|
|
19
|
+
}>>;
|
|
15
20
|
export declare function loadWorkspaceObjects(workspaceRoot: string, options?: WorkspaceLoadOptions): Promise<WorkspaceObjects>;
|
|
16
21
|
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { existsSync, statSync } from "node:fs";
|
|
3
|
-
import { readdir } from "node:fs/promises";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import { parseAllDocuments } from "yaml";
|
|
6
|
+
import { resolveResourcePackageRoot } from "../resource/sources.js";
|
|
6
7
|
import { fileExists, listFilesRecursive, readYamlOrJson } from "../utils/fs.js";
|
|
7
8
|
const ROOT_AGENT_FILENAMES = [
|
|
8
9
|
"agent.yaml",
|
|
@@ -15,21 +16,51 @@ const ROOT_AGENT_FILENAMES = [
|
|
|
15
16
|
"research.yml",
|
|
16
17
|
];
|
|
17
18
|
const LEGACY_GLOBAL_AGENT_FILENAMES = ["agent.yaml", "agent.yml"];
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const CONVENTIONAL_OBJECT_DIRECTORIES = ["tools"];
|
|
20
|
+
function conventionalConfigRoot(root) {
|
|
21
|
+
if (path.basename(root) === "config" && existsSync(root) && statSync(root).isDirectory()) {
|
|
22
|
+
return root;
|
|
23
|
+
}
|
|
24
|
+
const candidate = path.join(root, "config");
|
|
25
|
+
if (existsSync(candidate) && statSync(candidate).isDirectory()) {
|
|
26
|
+
return candidate;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
function conventionalDirectoryRoots(root, relativeDir) {
|
|
31
|
+
const resourceRoot = resolveResourcePackageRoot(root);
|
|
32
|
+
const configRoot = conventionalConfigRoot(root);
|
|
33
|
+
const candidates = relativeDir === "agents"
|
|
34
|
+
? [
|
|
35
|
+
...(configRoot ? [path.join(configRoot, "agents")] : []),
|
|
36
|
+
path.join(root, "agents"),
|
|
37
|
+
]
|
|
38
|
+
: [
|
|
39
|
+
...(resourceRoot ? [path.join(resourceRoot, relativeDir)] : []),
|
|
40
|
+
path.join(root, relativeDir),
|
|
41
|
+
];
|
|
42
|
+
return Array.from(new Set(candidates));
|
|
43
|
+
}
|
|
44
|
+
export function conventionalPackageRoots(root, relativeDir) {
|
|
45
|
+
const resourceRoot = resolveResourcePackageRoot(root);
|
|
46
|
+
const candidates = resourceRoot ? [path.join(resourceRoot, relativeDir), resourceRoot] : [];
|
|
47
|
+
return Array.from(new Set(candidates));
|
|
48
|
+
}
|
|
49
|
+
function frameworkWorkspaceRoot() {
|
|
50
|
+
const resolved = fileURLToPath(new URL("../..", import.meta.url));
|
|
51
|
+
const distSegment = `${path.sep}dist`;
|
|
52
|
+
if (!resolved.endsWith(distSegment)) {
|
|
22
53
|
return resolved;
|
|
23
54
|
}
|
|
24
|
-
const
|
|
25
|
-
if (!existsSync(
|
|
55
|
+
const sourceRoot = resolved.slice(0, -distSegment.length);
|
|
56
|
+
if (!existsSync(sourceRoot)) {
|
|
26
57
|
return resolved;
|
|
27
58
|
}
|
|
28
59
|
try {
|
|
29
|
-
return statSync(
|
|
60
|
+
return statSync(sourceRoot).mtimeMs >= statSync(resolved).mtimeMs ? sourceRoot : resolved;
|
|
30
61
|
}
|
|
31
62
|
catch {
|
|
32
|
-
return
|
|
63
|
+
return sourceRoot;
|
|
33
64
|
}
|
|
34
65
|
}
|
|
35
66
|
function toArray(value) {
|
|
@@ -106,7 +137,7 @@ export function normalizeYamlItem(item) {
|
|
|
106
137
|
...(kind ? { kind } : {}),
|
|
107
138
|
};
|
|
108
139
|
}
|
|
109
|
-
function
|
|
140
|
+
function normalizeResourceItem(item) {
|
|
110
141
|
if ("metadata" in item || "spec" in item || "path" in item || typeof item.name !== "string") {
|
|
111
142
|
return item;
|
|
112
143
|
}
|
|
@@ -215,7 +246,7 @@ async function objectItemsFromDocument(document, sourcePath) {
|
|
|
215
246
|
}
|
|
216
247
|
continue;
|
|
217
248
|
}
|
|
218
|
-
records.push(
|
|
249
|
+
records.push(normalizeResourceItem(typedItem));
|
|
219
250
|
}
|
|
220
251
|
return records;
|
|
221
252
|
}
|
|
@@ -292,6 +323,66 @@ async function readNamedYamlItems(root, filenames) {
|
|
|
292
323
|
}
|
|
293
324
|
return records;
|
|
294
325
|
}
|
|
326
|
+
function isAgentKind(kind) {
|
|
327
|
+
return kind === "deepagent" || kind === "langchain-agent";
|
|
328
|
+
}
|
|
329
|
+
async function readConfigAgentItems(configRoot) {
|
|
330
|
+
const records = await readYamlItems(configRoot, undefined, { recursive: true });
|
|
331
|
+
return records.filter(({ item, sourcePath }) => {
|
|
332
|
+
const kind = typeof item.kind === "string" ? item.kind : undefined;
|
|
333
|
+
if (!isAgentKind(kind)) {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
const parentDir = path.dirname(sourcePath);
|
|
337
|
+
const filename = path.basename(sourcePath).toLowerCase();
|
|
338
|
+
return !(parentDir === configRoot && ROOT_AGENT_FILENAMES.includes(filename));
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
function discoverAnnotatedFunctionNames(sourceText) {
|
|
342
|
+
const matches = sourceText.matchAll(/@tool[\s\S]*?export\s+(?:async\s+)?function\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/g);
|
|
343
|
+
return Array.from(matches, (match) => match[1]);
|
|
344
|
+
}
|
|
345
|
+
export async function readToolModuleItems(root) {
|
|
346
|
+
if (!(await fileExists(root))) {
|
|
347
|
+
return [];
|
|
348
|
+
}
|
|
349
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
350
|
+
const files = entries
|
|
351
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".mjs"))
|
|
352
|
+
.map((entry) => path.join(root, entry.name))
|
|
353
|
+
.sort();
|
|
354
|
+
const records = [];
|
|
355
|
+
for (const filePath of files) {
|
|
356
|
+
const sourceText = await readFile(filePath, "utf8");
|
|
357
|
+
const functionNames = discoverAnnotatedFunctionNames(sourceText);
|
|
358
|
+
if (functionNames.length === 0) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const imported = await import(pathToFileURL(filePath).href);
|
|
362
|
+
for (const functionName of functionNames) {
|
|
363
|
+
const invoke = imported[functionName];
|
|
364
|
+
const schema = imported[`${functionName}Schema`];
|
|
365
|
+
if (typeof invoke !== "function") {
|
|
366
|
+
throw new Error(`Tool module ${filePath} must export function ${functionName}.`);
|
|
367
|
+
}
|
|
368
|
+
if (!schema?.parse) {
|
|
369
|
+
throw new Error(`Tool module ${filePath} must export ${functionName}Schema as a Zod schema.`);
|
|
370
|
+
}
|
|
371
|
+
records.push({
|
|
372
|
+
item: {
|
|
373
|
+
kind: "tool",
|
|
374
|
+
id: functionName,
|
|
375
|
+
type: "function",
|
|
376
|
+
name: functionName,
|
|
377
|
+
description: typeof schema.description === "string" ? schema.description : `Auto-discovered tool ${functionName}`,
|
|
378
|
+
implementationName: functionName,
|
|
379
|
+
},
|
|
380
|
+
sourcePath: filePath,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return records;
|
|
385
|
+
}
|
|
295
386
|
function isPrimaryAgentFile(sourcePath) {
|
|
296
387
|
const base = path.basename(sourcePath).toLowerCase();
|
|
297
388
|
return ROOT_AGENT_FILENAMES.includes(base);
|
|
@@ -337,35 +428,39 @@ export async function loadWorkspaceObjects(workspaceRoot, options = {}) {
|
|
|
337
428
|
const refs = new Map();
|
|
338
429
|
const mergedAgents = new Map();
|
|
339
430
|
const mergedObjects = new Map();
|
|
340
|
-
const roots = [
|
|
431
|
+
const roots = [frameworkWorkspaceRoot(), ...(options.overlayRoots ?? []), workspaceRoot];
|
|
341
432
|
let sharedAgentDefaults = {};
|
|
342
433
|
let sharedAgentDefaultsByMode = {};
|
|
343
434
|
for (const root of roots) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
435
|
+
const configRoot = conventionalConfigRoot(root) ?? root;
|
|
436
|
+
const namedAgentRoots = Array.from(new Set([root, configRoot]));
|
|
437
|
+
for (const namedAgentRoot of namedAgentRoots) {
|
|
438
|
+
for (const { item, sourcePath } of await readNamedYamlItems(namedAgentRoot, [...ROOT_AGENT_FILENAMES])) {
|
|
439
|
+
const id = typeof item.id === "string" ? item.id : undefined;
|
|
440
|
+
if (!id) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
const current = mergedAgents.get(id);
|
|
444
|
+
mergedAgents.set(id, {
|
|
445
|
+
item: current ? mergeValues(current.item, item) : item,
|
|
446
|
+
sourcePath,
|
|
447
|
+
});
|
|
448
|
+
const filename = path.basename(sourcePath).toLowerCase();
|
|
449
|
+
if (LEGACY_GLOBAL_AGENT_FILENAMES.includes(filename)) {
|
|
450
|
+
sharedAgentDefaults = mergeValues(sharedAgentDefaults, extractSharedAgentDefaults(item));
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
const executionMode = inferExecutionMode(item, current?.item);
|
|
454
|
+
if (executionMode) {
|
|
455
|
+
sharedAgentDefaultsByMode = {
|
|
456
|
+
...sharedAgentDefaultsByMode,
|
|
457
|
+
[executionMode]: mergeValues(sharedAgentDefaultsByMode[executionMode] ?? {}, extractSharedAgentDefaults(item)),
|
|
458
|
+
};
|
|
459
|
+
}
|
|
365
460
|
}
|
|
366
461
|
}
|
|
367
462
|
}
|
|
368
|
-
for (const { item, sourcePath } of await
|
|
463
|
+
for (const { item, sourcePath } of await readConfigAgentItems(configRoot)) {
|
|
369
464
|
const id = typeof item.id === "string" ? item.id : undefined;
|
|
370
465
|
if (!id) {
|
|
371
466
|
continue;
|
|
@@ -377,7 +472,56 @@ export async function loadWorkspaceObjects(workspaceRoot, options = {}) {
|
|
|
377
472
|
sourcePath,
|
|
378
473
|
});
|
|
379
474
|
}
|
|
380
|
-
for (const
|
|
475
|
+
for (const directory of CONVENTIONAL_OBJECT_DIRECTORIES) {
|
|
476
|
+
for (const objectRoot of conventionalDirectoryRoots(root, directory)) {
|
|
477
|
+
for (const { item, sourcePath } of await readYamlItems(objectRoot, undefined, { recursive: true })) {
|
|
478
|
+
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
479
|
+
if (!workspaceObject) {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
const ref = `${workspaceObject.kind}/${workspaceObject.id}`;
|
|
483
|
+
const current = mergedObjects.get(ref);
|
|
484
|
+
mergedObjects.set(ref, {
|
|
485
|
+
item: current ? mergeValues(current.item, item) : item,
|
|
486
|
+
sourcePath,
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
for (const { item, sourcePath } of await readToolModuleItems(objectRoot)) {
|
|
490
|
+
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
491
|
+
if (!workspaceObject) {
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
const ref = `${workspaceObject.kind}/${workspaceObject.id}`;
|
|
495
|
+
const current = mergedObjects.get(ref);
|
|
496
|
+
mergedObjects.set(ref, {
|
|
497
|
+
item: current ? mergeValues(current.item, item) : item,
|
|
498
|
+
sourcePath,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if (conventionalConfigRoot(root)) {
|
|
504
|
+
for (const { item, sourcePath } of await readYamlItems(configRoot, undefined, { recursive: true })) {
|
|
505
|
+
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
506
|
+
if (!workspaceObject) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
if (isAgentKind(workspaceObject.kind)) {
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
const ref = `${workspaceObject.kind}/${workspaceObject.id}`;
|
|
513
|
+
const current = mergedObjects.get(ref);
|
|
514
|
+
mergedObjects.set(ref, {
|
|
515
|
+
item: current ? mergeValues(current.item, item) : item,
|
|
516
|
+
sourcePath,
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
for (const { item, sourcePath } of (await readYamlItems(root)).filter(({ sourcePath: fullPath }) => !fullPath.includes(`${path.sep}config${path.sep}`) &&
|
|
521
|
+
!fullPath.includes(`${path.sep}resources${path.sep}`) &&
|
|
522
|
+
!fullPath.includes(`${path.sep}agents${path.sep}`) &&
|
|
523
|
+
!CONVENTIONAL_OBJECT_DIRECTORIES.some((directory) => fullPath.includes(`${path.sep}${directory}${path.sep}`)) &&
|
|
524
|
+
!isPrimaryAgentFile(fullPath))) {
|
|
381
525
|
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
382
526
|
if (!workspaceObject) {
|
|
383
527
|
continue;
|
|
@@ -161,6 +161,7 @@ export function parseToolObject(object) {
|
|
|
161
161
|
type: String(inferredType),
|
|
162
162
|
name: String(value.name ?? "").trim(),
|
|
163
163
|
description: String(value.description ?? "").trim(),
|
|
164
|
+
implementationName: typeof value.implementationName === "string" ? value.implementationName : undefined,
|
|
164
165
|
config: asObject(value.config),
|
|
165
166
|
inputSchemaRef: typeof asObject(value.inputSchema)?.ref === "string" ? String(asObject(value.inputSchema)?.ref) : undefined,
|
|
166
167
|
backendOperation: typeof backend?.operation === "string"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { defaultResourceConfigRoot, defaultResourceSkillsRoot } from "../../resource/resource.js";
|
|
4
|
+
import { ensureExternalResourceSource, isDirectoryPath, isExternalSourceLocator, resolveExternalResourcePath, resolveResourcePackageRoot, } from "../../resource/sources.js";
|
|
5
5
|
import { parseAgentItem, readYamlItems } from "../object-loader.js";
|
|
6
6
|
function resolveBuiltinPath(kind, ref) {
|
|
7
7
|
const normalized = ref.replace(/^builtin:\/\//, "").replace(/^\/+/, "");
|
|
@@ -10,7 +10,7 @@ function resolveBuiltinPath(kind, ref) {
|
|
|
10
10
|
throw new Error(`Unsupported builtin skill discovery path ${ref}`);
|
|
11
11
|
}
|
|
12
12
|
const suffix = normalized.replace(/^skills\/?/, "");
|
|
13
|
-
const root =
|
|
13
|
+
const root = defaultResourceSkillsRoot();
|
|
14
14
|
if (!suffix) {
|
|
15
15
|
return root;
|
|
16
16
|
}
|
|
@@ -18,8 +18,8 @@ function resolveBuiltinPath(kind, ref) {
|
|
|
18
18
|
if (existsSync(candidate)) {
|
|
19
19
|
return candidate;
|
|
20
20
|
}
|
|
21
|
-
const sourceFallback = root.includes(`${path.sep}dist${path.sep}skills`)
|
|
22
|
-
? path.join(path.resolve(root, "..", ".."), "skills", suffix)
|
|
21
|
+
const sourceFallback = root.includes(`${path.sep}dist${path.sep}resources${path.sep}skills`)
|
|
22
|
+
? path.join(path.resolve(root, "..", "..", ".."), "resources", "skills", suffix)
|
|
23
23
|
: null;
|
|
24
24
|
if (sourceFallback && existsSync(sourceFallback)) {
|
|
25
25
|
return sourceFallback;
|
|
@@ -30,7 +30,7 @@ function resolveBuiltinPath(kind, ref) {
|
|
|
30
30
|
throw new Error(`Unsupported builtin subagent discovery path ${ref}`);
|
|
31
31
|
}
|
|
32
32
|
const suffix = normalized.replace(/^agents\/?/, "");
|
|
33
|
-
const root = path.join(
|
|
33
|
+
const root = path.join(defaultResourceConfigRoot(), "agents");
|
|
34
34
|
if (!suffix) {
|
|
35
35
|
return root;
|
|
36
36
|
}
|
|
@@ -47,9 +47,14 @@ function resolveBuiltinPath(kind, ref) {
|
|
|
47
47
|
return candidate;
|
|
48
48
|
}
|
|
49
49
|
function preferPackageConvention(root, kind) {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
const resourceRoot = resolveResourcePackageRoot(root);
|
|
51
|
+
const candidates = resourceRoot
|
|
52
|
+
? kind === "skills"
|
|
53
|
+
? [path.join(root, "config", "skills"), path.join(resourceRoot, "skills"), resourceRoot]
|
|
54
|
+
: [path.join(root, "config", "agents"), path.join(root, "agents"), path.join(resourceRoot, "agents"), resourceRoot]
|
|
55
|
+
: kind === "skills"
|
|
56
|
+
? [path.join(root, "config", "skills"), path.join(root, "skills"), root]
|
|
57
|
+
: [path.join(root, "config", "agents"), path.join(root, "agents"), root];
|
|
53
58
|
for (const candidate of candidates) {
|
|
54
59
|
if (isDirectoryPath(candidate)) {
|
|
55
60
|
return candidate;
|
|
@@ -60,25 +65,25 @@ function preferPackageConvention(root, kind) {
|
|
|
60
65
|
export async function ensureDiscoverySources(locators, workspaceRoot) {
|
|
61
66
|
await Promise.all(Array.from(new Set(locators))
|
|
62
67
|
.filter((locator) => isExternalSourceLocator(locator))
|
|
63
|
-
.map((locator) =>
|
|
68
|
+
.map((locator) => ensureExternalResourceSource(locator, workspaceRoot)));
|
|
64
69
|
}
|
|
65
70
|
export function resolveDiscoveryRoot(ref, workspaceRoot, kind) {
|
|
66
71
|
if (ref.startsWith("builtin://")) {
|
|
67
72
|
return resolveBuiltinPath(kind, ref);
|
|
68
73
|
}
|
|
69
74
|
if (isExternalSourceLocator(ref)) {
|
|
70
|
-
return preferPackageConvention(
|
|
75
|
+
return preferPackageConvention(resolveExternalResourcePath(ref, workspaceRoot), kind);
|
|
71
76
|
}
|
|
72
|
-
return path.resolve(workspaceRoot, ref);
|
|
77
|
+
return preferPackageConvention(path.resolve(workspaceRoot, ref), kind);
|
|
73
78
|
}
|
|
74
79
|
async function resolveDiscoveryRootAsync(ref, workspaceRoot, kind) {
|
|
75
80
|
if (ref.startsWith("builtin://")) {
|
|
76
81
|
return resolveBuiltinPath(kind, ref);
|
|
77
82
|
}
|
|
78
83
|
if (isExternalSourceLocator(ref)) {
|
|
79
|
-
return preferPackageConvention(await
|
|
84
|
+
return preferPackageConvention(await ensureExternalResourceSource(ref, workspaceRoot), kind);
|
|
80
85
|
}
|
|
81
|
-
return path.resolve(workspaceRoot, ref);
|
|
86
|
+
return preferPackageConvention(path.resolve(workspaceRoot, ref), kind);
|
|
82
87
|
}
|
|
83
88
|
export function discoverSkillPaths(rootRefs, workspaceRoot) {
|
|
84
89
|
const discovered = new Map();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isExternalSourceLocator } from "../../
|
|
1
|
+
import { isExternalSourceLocator } from "../../resource/sources.js";
|
|
2
2
|
export function collectToolSourceRefs(tools, agents, options) {
|
|
3
|
-
const refs = new Set(options.builtinSources ?? []);
|
|
3
|
+
const refs = new Set(options.resourceSources ?? options.builtinSources ?? []);
|
|
4
4
|
for (const tool of tools.values()) {
|
|
5
5
|
for (const ref of tool.bundleRefs) {
|
|
6
6
|
if (isExternalSourceLocator(ref)) {
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botbotgo/agent-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "Agent Harness framework package",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"packageManager": "npm@10.9.2",
|
|
6
7
|
"main": "./dist/index.js",
|
|
7
8
|
"module": "./dist/index.js",
|
|
8
9
|
"types": "./dist/index.d.ts",
|
|
@@ -14,8 +15,7 @@
|
|
|
14
15
|
},
|
|
15
16
|
"repository": {
|
|
16
17
|
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/botbotgo/agent-harness.git"
|
|
18
|
-
"directory": "packages/framework"
|
|
18
|
+
"url": "git+https://github.com/botbotgo/agent-harness.git"
|
|
19
19
|
},
|
|
20
20
|
"exports": {
|
|
21
21
|
".": {
|
|
@@ -25,10 +25,32 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@
|
|
28
|
+
"@langchain/anthropic": "^1.1.0",
|
|
29
|
+
"@langchain/community": "^1.1.24",
|
|
30
|
+
"@langchain/core": "^1.1.33",
|
|
31
|
+
"@langchain/google": "^0.1.7",
|
|
32
|
+
"@langchain/langgraph": "^1.2.3",
|
|
33
|
+
"@langchain/langgraph-checkpoint-sqlite": "^1.0.1",
|
|
34
|
+
"@langchain/ollama": "^1.2.6",
|
|
35
|
+
"@langchain/openai": "^1.1.0",
|
|
36
|
+
"@libsql/client": "^0.17.0",
|
|
37
|
+
"@llamaindex/ollama": "^0.1.24",
|
|
38
|
+
"deepagents": "1.8.4",
|
|
39
|
+
"langchain": "1.2.34",
|
|
40
|
+
"llamaindex": "^0.12.1",
|
|
41
|
+
"mustache": "^4.2.0",
|
|
42
|
+
"yaml": "^2.8.1"
|
|
29
43
|
},
|
|
30
44
|
"scripts": {
|
|
31
45
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc -p tsconfig.json && cp -R config dist/",
|
|
32
|
-
"check": "tsc -p tsconfig.json --noEmit"
|
|
46
|
+
"check": "tsc -p tsconfig.json --noEmit",
|
|
47
|
+
"test": "vitest run test/public-api.test.ts test/resource-optional-provider.test.ts test/stock-research-app-load-harness.test.ts test/release-workflow.test.ts test/release-version.test.ts test/gitignore.test.ts test/package-lock.test.ts",
|
|
48
|
+
"release:pack": "npm pack --dry-run",
|
|
49
|
+
"release:publish": "npm publish --access public --registry https://registry.npmjs.org/"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^24.6.0",
|
|
53
|
+
"typescript": "^5.9.3",
|
|
54
|
+
"vitest": "^3.2.4"
|
|
33
55
|
}
|
|
34
56
|
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { RuntimeAdapterOptions, WorkspaceBundle } from "../contracts/types.js";
|
|
2
|
-
export declare function resolveLocalBuiltinsEntry(currentVendorDir: string, resolveInstalledEntry?: () => string | null): string;
|
|
3
|
-
type BuiltinToolInfo = {
|
|
4
|
-
builtinPath: string;
|
|
5
|
-
backendOperation: string;
|
|
6
|
-
name: string;
|
|
7
|
-
description: string;
|
|
8
|
-
hitl?: {
|
|
9
|
-
enabled: boolean;
|
|
10
|
-
allow: Array<"approve" | "edit" | "reject">;
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
export declare function ensureBuiltinSources(sources?: string[], workspaceRoot?: string): Promise<void>;
|
|
14
|
-
export declare const builtinSkillsRoot: () => string;
|
|
15
|
-
export declare const builtinConfigRoot: () => string;
|
|
16
|
-
export declare function listBuiltinTools(sources?: string[], workspaceRoot?: string): Promise<BuiltinToolInfo[]>;
|
|
17
|
-
export declare function listBuiltinToolsForSource(source: string, workspaceRoot?: string): Promise<BuiltinToolInfo[]>;
|
|
18
|
-
export declare function createBuiltinBackendResolver(workspace: WorkspaceBundle): NonNullable<RuntimeAdapterOptions["backendResolver"]>;
|
|
19
|
-
export declare function createBuiltinToolResolver(workspace: WorkspaceBundle, options?: {
|
|
20
|
-
getStore?: (_binding?: WorkspaceBundle["bindings"] extends Map<any, infer T> ? T : never) => unknown;
|
|
21
|
-
getEmbeddingModel?: (embeddingModelRef?: string, _binding?: WorkspaceBundle["bindings"] extends Map<any, infer T> ? T : never) => Promise<unknown>;
|
|
22
|
-
getVectorStore?: (vectorStoreRef?: string, _binding?: WorkspaceBundle["bindings"] extends Map<any, infer T> ? T : never) => Promise<unknown>;
|
|
23
|
-
}): NonNullable<RuntimeAdapterOptions["toolResolver"]>;
|
|
24
|
-
export {};
|
package/dist/vendor/builtins.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { readFile } from "node:fs/promises";
|
|
5
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
-
import { ensureExternalSource, isExternalSourceLocator, parseExternalSourceLocator } from "./sources.js";
|
|
7
|
-
const vendorDir = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const require = createRequire(import.meta.url);
|
|
9
|
-
function installedBuiltinsEntry() {
|
|
10
|
-
try {
|
|
11
|
-
return require.resolve("@botbotgo/agent-harness-builtin");
|
|
12
|
-
}
|
|
13
|
-
catch {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
export function resolveLocalBuiltinsEntry(currentVendorDir, resolveInstalledEntry = installedBuiltinsEntry) {
|
|
18
|
-
const candidates = [
|
|
19
|
-
path.resolve(currentVendorDir, "../../../builtins/dist/src/index.js"),
|
|
20
|
-
resolveInstalledEntry(),
|
|
21
|
-
path.resolve(currentVendorDir, "../../../builtins/src/index.ts"),
|
|
22
|
-
].filter((candidate) => typeof candidate === "string" && candidate.length > 0);
|
|
23
|
-
for (const candidate of candidates) {
|
|
24
|
-
if (existsSync(candidate)) {
|
|
25
|
-
return candidate;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return candidates.at(-1) ?? path.resolve(currentVendorDir, "../../../builtins/src/index.ts");
|
|
29
|
-
}
|
|
30
|
-
const builtinsEntry = resolveLocalBuiltinsEntry(vendorDir);
|
|
31
|
-
const localBuiltins = await import(pathToFileURL(builtinsEntry).href);
|
|
32
|
-
const remoteProviderCache = new Map();
|
|
33
|
-
function resolvePackageEntry(packageRoot, pkg) {
|
|
34
|
-
const exportsField = pkg.exports;
|
|
35
|
-
if (typeof exportsField === "string") {
|
|
36
|
-
return path.resolve(packageRoot, exportsField);
|
|
37
|
-
}
|
|
38
|
-
if (exportsField && typeof exportsField === "object" && "." in exportsField) {
|
|
39
|
-
const rootExport = exportsField["."];
|
|
40
|
-
if (typeof rootExport === "string") {
|
|
41
|
-
return path.resolve(packageRoot, rootExport);
|
|
42
|
-
}
|
|
43
|
-
if (rootExport && typeof rootExport === "object") {
|
|
44
|
-
const importEntry = rootExport.import ?? rootExport.default;
|
|
45
|
-
if (typeof importEntry === "string") {
|
|
46
|
-
return path.resolve(packageRoot, importEntry);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (typeof pkg.module === "string") {
|
|
51
|
-
return path.resolve(packageRoot, pkg.module);
|
|
52
|
-
}
|
|
53
|
-
if (typeof pkg.main === "string") {
|
|
54
|
-
return path.resolve(packageRoot, pkg.main);
|
|
55
|
-
}
|
|
56
|
-
return path.resolve(packageRoot, "index.js");
|
|
57
|
-
}
|
|
58
|
-
async function loadRemoteProvider(source, workspaceRoot) {
|
|
59
|
-
const cached = remoteProviderCache.get(source);
|
|
60
|
-
if (cached) {
|
|
61
|
-
return cached;
|
|
62
|
-
}
|
|
63
|
-
if (!isExternalSourceLocator(source)) {
|
|
64
|
-
throw new Error(`Unsupported builtin source ${source}. Use npm:, tgz:, or file:.`);
|
|
65
|
-
}
|
|
66
|
-
const parsed = parseExternalSourceLocator(source);
|
|
67
|
-
if (parsed.subpath) {
|
|
68
|
-
throw new Error(`Builtin source ${source} must point at a package root, not a subpath`);
|
|
69
|
-
}
|
|
70
|
-
const packageRoot = await ensureExternalSource(source, workspaceRoot);
|
|
71
|
-
const pkg = JSON.parse(await readFile(path.join(packageRoot, "package.json"), "utf8"));
|
|
72
|
-
const entry = resolvePackageEntry(packageRoot, pkg);
|
|
73
|
-
const imported = await import(pathToFileURL(entry).href);
|
|
74
|
-
const provider = (imported.default ?? imported);
|
|
75
|
-
if (typeof provider.listBuiltinTools !== "function" || typeof provider.createBuiltinToolResolver !== "function") {
|
|
76
|
-
throw new Error(`Remote builtin source ${source} must export listBuiltinTools() and createBuiltinToolResolver().`);
|
|
77
|
-
}
|
|
78
|
-
const typedProvider = provider;
|
|
79
|
-
remoteProviderCache.set(source, typedProvider);
|
|
80
|
-
return typedProvider;
|
|
81
|
-
}
|
|
82
|
-
export async function ensureBuiltinSources(sources = [], workspaceRoot = process.cwd()) {
|
|
83
|
-
await Promise.all(sources.map((source) => loadRemoteProvider(source, workspaceRoot)));
|
|
84
|
-
}
|
|
85
|
-
export const builtinSkillsRoot = localBuiltins.builtinSkillsRoot;
|
|
86
|
-
export const builtinConfigRoot = (localBuiltins.builtinConfigRoot ?? localBuiltins.builtinDefaultsRoot);
|
|
87
|
-
export async function listBuiltinTools(sources = [], workspaceRoot = process.cwd()) {
|
|
88
|
-
await ensureBuiltinSources(sources, workspaceRoot);
|
|
89
|
-
const deduped = new Map();
|
|
90
|
-
const local = localBuiltins.listBuiltinTools;
|
|
91
|
-
for (const tool of local()) {
|
|
92
|
-
deduped.set(tool.builtinPath, tool);
|
|
93
|
-
}
|
|
94
|
-
for (const source of sources) {
|
|
95
|
-
for (const tool of remoteProviderCache.get(source)?.listBuiltinTools() ?? []) {
|
|
96
|
-
deduped.set(tool.builtinPath, tool);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return Array.from(deduped.values());
|
|
100
|
-
}
|
|
101
|
-
export async function listBuiltinToolsForSource(source, workspaceRoot = process.cwd()) {
|
|
102
|
-
await ensureBuiltinSources([source], workspaceRoot);
|
|
103
|
-
return remoteProviderCache.get(source)?.listBuiltinTools() ?? [];
|
|
104
|
-
}
|
|
105
|
-
export function createBuiltinBackendResolver(workspace) {
|
|
106
|
-
return localBuiltins.createBuiltinBackendResolver(workspace);
|
|
107
|
-
}
|
|
108
|
-
export function createBuiltinToolResolver(workspace, options = {}) {
|
|
109
|
-
const localResolver = localBuiltins.createBuiltinToolResolver(workspace, options);
|
|
110
|
-
const remoteResolvers = workspace.builtinSources
|
|
111
|
-
.map((source) => remoteProviderCache.get(source))
|
|
112
|
-
.filter((provider) => Boolean(provider))
|
|
113
|
-
.map((provider) => provider.createBuiltinToolResolver(workspace));
|
|
114
|
-
return (toolIds, binding) => [
|
|
115
|
-
...localResolver(toolIds, binding),
|
|
116
|
-
...remoteResolvers.flatMap((resolver) => resolver(toolIds, binding)),
|
|
117
|
-
];
|
|
118
|
-
}
|