@botbotgo/agent-harness 0.0.42 → 0.0.44
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 +35 -10
- package/dist/config/agents/direct.yaml +14 -13
- package/dist/config/agents/orchestra.yaml +20 -19
- package/dist/config/mcp.yaml +20 -0
- package/dist/config/stores.yaml +19 -0
- package/dist/config/tools.yaml +13 -0
- package/dist/config/workspace.yaml +5 -4
- package/dist/contracts/types.d.ts +27 -1
- package/dist/extensions.js +2 -3
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/persistence/file-store.d.ts +8 -6
- package/dist/persistence/file-store.js +2 -0
- package/dist/presentation.d.ts +14 -0
- package/dist/presentation.js +146 -0
- package/dist/runtime/agent-runtime-adapter.d.ts +1 -0
- package/dist/runtime/agent-runtime-adapter.js +62 -42
- package/dist/runtime/harness.d.ts +2 -0
- package/dist/runtime/harness.js +98 -12
- package/dist/runtime/inventory.js +2 -1
- package/dist/runtime/support/compiled-binding.d.ts +15 -0
- package/dist/runtime/support/compiled-binding.js +56 -0
- package/dist/runtime/support/harness-support.d.ts +2 -2
- package/dist/runtime/support/harness-support.js +14 -12
- package/dist/workspace/agent-binding-compiler.js +103 -32
- package/dist/workspace/object-loader.js +56 -5
- package/dist/workspace/support/agent-capabilities.d.ts +9 -0
- package/dist/workspace/support/agent-capabilities.js +41 -0
- package/dist/workspace/validate.js +11 -13
- package/package.json +8 -2
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CompiledAgentBinding, CompiledModel, CompiledTool, DeepAgentParams, LangChainAgentParams } from "../../contracts/types.js";
|
|
2
|
+
export declare function getBindingAdapterKind(binding: CompiledAgentBinding): string;
|
|
3
|
+
export declare function getBindingAdapterConfig(binding: CompiledAgentBinding): Record<string, unknown>;
|
|
4
|
+
export declare function getBindingLangChainParams(binding: CompiledAgentBinding): LangChainAgentParams | undefined;
|
|
5
|
+
export declare function getBindingDeepAgentParams(binding: CompiledAgentBinding): DeepAgentParams | undefined;
|
|
6
|
+
export declare function isLangChainBinding(binding: CompiledAgentBinding): boolean;
|
|
7
|
+
export declare function isDeepAgentBinding(binding: CompiledAgentBinding): boolean;
|
|
8
|
+
export declare function getBindingPrimaryTools(binding: CompiledAgentBinding): CompiledTool[];
|
|
9
|
+
export declare function getBindingPrimaryModel(binding: CompiledAgentBinding): CompiledModel | undefined;
|
|
10
|
+
export declare function getBindingSystemPrompt(binding: CompiledAgentBinding): string | undefined;
|
|
11
|
+
export declare function getBindingMiddlewareConfigs(binding: CompiledAgentBinding): Array<Record<string, unknown>> | undefined;
|
|
12
|
+
export declare function getBindingInterruptCompatibilityRules(binding: CompiledAgentBinding): Record<string, boolean | object> | undefined;
|
|
13
|
+
export declare function getBindingModelInit(binding: CompiledAgentBinding): Record<string, unknown> | undefined;
|
|
14
|
+
export declare function getBindingStoreConfig(binding: CompiledAgentBinding): Record<string, unknown> | undefined;
|
|
15
|
+
export declare function bindingHasSubagents(binding: CompiledAgentBinding): boolean;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
function asRecord(value) {
|
|
2
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
3
|
+
? value
|
|
4
|
+
: undefined;
|
|
5
|
+
}
|
|
6
|
+
export function getBindingAdapterKind(binding) {
|
|
7
|
+
return binding.adapter?.kind ?? binding.agent.executionMode;
|
|
8
|
+
}
|
|
9
|
+
export function getBindingAdapterConfig(binding) {
|
|
10
|
+
return binding.adapter?.config ?? {};
|
|
11
|
+
}
|
|
12
|
+
export function getBindingLangChainParams(binding) {
|
|
13
|
+
const adapterParams = asRecord(getBindingAdapterConfig(binding).params);
|
|
14
|
+
if (getBindingAdapterKind(binding) === "langchain-v1" && adapterParams) {
|
|
15
|
+
return adapterParams;
|
|
16
|
+
}
|
|
17
|
+
return binding.langchainAgentParams;
|
|
18
|
+
}
|
|
19
|
+
export function getBindingDeepAgentParams(binding) {
|
|
20
|
+
const adapterParams = asRecord(getBindingAdapterConfig(binding).params);
|
|
21
|
+
if (getBindingAdapterKind(binding) === "deepagent" && adapterParams) {
|
|
22
|
+
return adapterParams;
|
|
23
|
+
}
|
|
24
|
+
return binding.deepAgentParams;
|
|
25
|
+
}
|
|
26
|
+
export function isLangChainBinding(binding) {
|
|
27
|
+
return getBindingAdapterKind(binding) === "langchain-v1" || Boolean(binding.langchainAgentParams);
|
|
28
|
+
}
|
|
29
|
+
export function isDeepAgentBinding(binding) {
|
|
30
|
+
return getBindingAdapterKind(binding) === "deepagent" || Boolean(binding.deepAgentParams);
|
|
31
|
+
}
|
|
32
|
+
export function getBindingPrimaryTools(binding) {
|
|
33
|
+
return binding.langchainAgentParams?.tools ?? binding.deepAgentParams?.tools ?? [];
|
|
34
|
+
}
|
|
35
|
+
export function getBindingPrimaryModel(binding) {
|
|
36
|
+
return binding.langchainAgentParams?.model ?? binding.deepAgentParams?.model;
|
|
37
|
+
}
|
|
38
|
+
export function getBindingSystemPrompt(binding) {
|
|
39
|
+
return binding.langchainAgentParams?.systemPrompt ?? binding.deepAgentParams?.systemPrompt;
|
|
40
|
+
}
|
|
41
|
+
export function getBindingMiddlewareConfigs(binding) {
|
|
42
|
+
return binding.langchainAgentParams?.middleware ?? binding.deepAgentParams?.middleware;
|
|
43
|
+
}
|
|
44
|
+
export function getBindingInterruptCompatibilityRules(binding) {
|
|
45
|
+
return binding.deepAgentParams?.interruptOn ??
|
|
46
|
+
binding.agent.langchainAgentConfig?.interruptOn;
|
|
47
|
+
}
|
|
48
|
+
export function getBindingModelInit(binding) {
|
|
49
|
+
return getBindingPrimaryModel(binding)?.init;
|
|
50
|
+
}
|
|
51
|
+
export function getBindingStoreConfig(binding) {
|
|
52
|
+
return binding.deepAgentParams?.store ?? binding.harnessRuntime.store;
|
|
53
|
+
}
|
|
54
|
+
export function bindingHasSubagents(binding) {
|
|
55
|
+
return (binding.deepAgentParams?.subagents.length ?? 0) > 0;
|
|
56
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { HarnessEvent, InternalApprovalRecord, WorkspaceBundle } from "../../contracts/types.js";
|
|
2
2
|
export declare function renderRuntimeFailure(error: unknown): string;
|
|
3
3
|
export declare function renderToolFailure(toolName: string, output: unknown): string;
|
|
4
4
|
export declare function parseInterruptContent(content: string): {
|
|
@@ -19,7 +19,7 @@ export declare function heuristicRoute(input: string, primaryBinding?: {
|
|
|
19
19
|
};
|
|
20
20
|
}): string;
|
|
21
21
|
export declare function createHarnessEvent(threadId: string, runId: string, sequence: number, eventType: string, payload: Record<string, unknown>, source?: HarnessEvent["source"]): HarnessEvent;
|
|
22
|
-
export declare function createPendingApproval(threadId: string, runId: string, checkpointRef: string, input: string, interruptContent?: string):
|
|
22
|
+
export declare function createPendingApproval(threadId: string, runId: string, checkpointRef: string, input: string, interruptContent?: string): InternalApprovalRecord;
|
|
23
23
|
export declare function inferRoutingBindings(workspace: WorkspaceBundle): {
|
|
24
24
|
primaryBinding: import("../../contracts/types.js").CompiledAgentBinding;
|
|
25
25
|
secondaryBinding: import("../../contracts/types.js").CompiledAgentBinding | undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createPersistentId } from "../../utils/id.js";
|
|
2
|
+
import { isDelegationCapableBinding } from "../../workspace/support/agent-capabilities.js";
|
|
2
3
|
export function renderRuntimeFailure(error) {
|
|
3
4
|
const message = error instanceof Error ? error.message : String(error);
|
|
4
5
|
return `runtime_error=${message}`.trim();
|
|
@@ -131,20 +132,21 @@ export function inferRoutingBindings(workspace) {
|
|
|
131
132
|
const hostBindings = Array.from(workspace.bindings.values()).filter((binding) => binding.harnessRuntime.hostFacing);
|
|
132
133
|
const researchBinding = hostBindings.find((binding) => binding.agent.id === "research-lite" || binding.agent.id === "research");
|
|
133
134
|
const directBinding = hostBindings.find((binding) => binding.agent.id === "direct");
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
135
|
+
const delegationHosts = hostBindings.filter((binding) => isDelegationCapableBinding(binding));
|
|
136
|
+
const lightweightHosts = hostBindings.filter((binding) => !isDelegationCapableBinding(binding));
|
|
137
|
+
const defaultOrchestratingHost = hostBindings.find((binding) => binding.agent.id === "orchestra") ??
|
|
138
|
+
delegationHosts.find((binding) => (binding.deepAgentParams?.subagents.length ?? 0) > 0) ??
|
|
139
|
+
delegationHosts[0];
|
|
140
|
+
const delegationPreferredSecondary = delegationHosts.find((binding) => (binding.deepAgentParams?.subagents.length ?? 0) > 0) ??
|
|
141
|
+
delegationHosts[0];
|
|
142
|
+
const genericLightweightHost = lightweightHosts.find((binding) => binding.agent.id !== researchBinding?.agent.id);
|
|
143
|
+
const primaryBinding = defaultOrchestratingHost ?? directBinding ?? genericLightweightHost ?? hostBindings[0];
|
|
144
|
+
const secondaryBinding = genericLightweightHost && genericLightweightHost.agent.id !== primaryBinding?.agent.id
|
|
145
|
+
? genericLightweightHost
|
|
144
146
|
: directBinding && directBinding.agent.id !== primaryBinding?.agent.id
|
|
145
147
|
? directBinding
|
|
146
|
-
:
|
|
147
|
-
?
|
|
148
|
+
: delegationPreferredSecondary && delegationPreferredSecondary.agent.id !== primaryBinding?.agent.id
|
|
149
|
+
? delegationPreferredSecondary
|
|
148
150
|
: hostBindings.find((binding) => binding.agent.id !== primaryBinding?.agent.id);
|
|
149
151
|
return { primaryBinding, secondaryBinding, researchBinding, hostBindings };
|
|
150
152
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { getSkillInheritancePolicy, resolveToolTargets } from "../extensions.js";
|
|
3
3
|
import { compileModel, compileTool } from "./resource-compilers.js";
|
|
4
|
+
import { inferAgentCapabilities } from "./support/agent-capabilities.js";
|
|
4
5
|
import { discoverSkillPaths } from "./support/discovery.js";
|
|
5
|
-
import { compileAgentMemories, getRuntimeDefaults, resolvePromptValue, resolveRefId } from "./support/workspace-ref-utils.js";
|
|
6
|
+
import { compileAgentMemories, getRuntimeDefaults, getWorkspaceObject, resolvePromptValue, resolveRefId } from "./support/workspace-ref-utils.js";
|
|
6
7
|
const WORKSPACE_BOUNDARY_GUIDANCE = "Keep repository and file exploration bounded to the current workspace root unless the user explicitly asks for broader host or filesystem access. " +
|
|
7
8
|
"Do not inspect absolute paths outside the workspace, system directories, or unrelated repos by default. " +
|
|
8
9
|
"Prefer workspace-local tools, relative paths, and the current repository checkout when analyzing code.";
|
|
@@ -132,15 +133,50 @@ function resolveBackendConfig(agent) {
|
|
|
132
133
|
: undefined;
|
|
133
134
|
return backendConfig ? { config: backendConfig } : undefined;
|
|
134
135
|
}
|
|
135
|
-
function
|
|
136
|
+
function isRefConfig(value) {
|
|
137
|
+
if (typeof value?.ref !== "string" || value.ref.trim().length === 0) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
return Object.keys(value).every((key) => key === "ref");
|
|
141
|
+
}
|
|
142
|
+
function materializeWorkspaceObjectConfig(refs, ref, allowedKinds, ownerLabel) {
|
|
143
|
+
const object = getWorkspaceObject(refs, ref);
|
|
144
|
+
if (!object) {
|
|
145
|
+
throw new Error(`${ownerLabel} references missing object ${ref}`);
|
|
146
|
+
}
|
|
147
|
+
if (!allowedKinds.includes(object.kind)) {
|
|
148
|
+
throw new Error(`${ownerLabel} references ${ref}, but expected one of: ${allowedKinds.join(", ")}`);
|
|
149
|
+
}
|
|
150
|
+
const { id: _id, kind: _kind, ...config } = object.value;
|
|
151
|
+
if (object.kind === "store") {
|
|
152
|
+
const storeKind = typeof config.storeKind === "string" ? config.storeKind : undefined;
|
|
153
|
+
const { storeKind: _storeKind, ...rest } = config;
|
|
154
|
+
return storeKind ? { kind: storeKind, ...rest } : config;
|
|
155
|
+
}
|
|
156
|
+
if (object.kind === "checkpointer" || object.kind === "file-checkpointer" || object.kind === "sqlite-saver") {
|
|
157
|
+
const checkpointerKind = typeof config.checkpointerKind === "string" ? config.checkpointerKind : undefined;
|
|
158
|
+
const { checkpointerKind: _checkpointerKind, ...rest } = config;
|
|
159
|
+
return checkpointerKind ? { kind: checkpointerKind, ...rest } : config;
|
|
160
|
+
}
|
|
161
|
+
return config;
|
|
162
|
+
}
|
|
163
|
+
function resolveStoreConfig(agent, refs) {
|
|
136
164
|
const inlineStore = typeof agent.deepAgentConfig?.store === "object" && agent.deepAgentConfig.store
|
|
137
165
|
? agent.deepAgentConfig.store
|
|
138
166
|
: typeof agent.langchainAgentConfig?.store === "object" && agent.langchainAgentConfig.store
|
|
139
167
|
? agent.langchainAgentConfig.store
|
|
140
168
|
: undefined;
|
|
141
|
-
|
|
169
|
+
if (!inlineStore) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
if (isRefConfig(inlineStore)) {
|
|
173
|
+
return {
|
|
174
|
+
config: materializeWorkspaceObjectConfig(refs, inlineStore.ref, ["store"], `Agent ${agent.id} store`),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return { config: inlineStore };
|
|
142
178
|
}
|
|
143
|
-
function resolveCheckpointerConfig(agent) {
|
|
179
|
+
function resolveCheckpointerConfig(agent, refs) {
|
|
144
180
|
const inlineAgentCheckpointer = typeof agent.deepAgentConfig?.checkpointer === "object" && agent.deepAgentConfig.checkpointer
|
|
145
181
|
? agent.deepAgentConfig.checkpointer
|
|
146
182
|
: typeof agent.deepAgentConfig?.checkpointer === "boolean"
|
|
@@ -150,7 +186,18 @@ function resolveCheckpointerConfig(agent) {
|
|
|
150
186
|
: typeof agent.langchainAgentConfig?.checkpointer === "boolean"
|
|
151
187
|
? agent.langchainAgentConfig.checkpointer
|
|
152
188
|
: undefined;
|
|
153
|
-
|
|
189
|
+
if (inlineAgentCheckpointer === undefined) {
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
if (typeof inlineAgentCheckpointer === "boolean") {
|
|
193
|
+
return { config: inlineAgentCheckpointer };
|
|
194
|
+
}
|
|
195
|
+
if (isRefConfig(inlineAgentCheckpointer)) {
|
|
196
|
+
return {
|
|
197
|
+
config: materializeWorkspaceObjectConfig(refs, inlineAgentCheckpointer.ref, ["checkpointer", "file-checkpointer", "sqlite-saver"], `Agent ${agent.id} checkpointer`),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
return { config: inlineAgentCheckpointer };
|
|
154
201
|
}
|
|
155
202
|
export function compileBinding(workspaceRoot, agent, agents, referencedSubagentIds, refs, models, tools) {
|
|
156
203
|
const internalSubagent = referencedSubagentIds.has(agent.id);
|
|
@@ -159,8 +206,8 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
159
206
|
const compiledAgentMemory = compileAgentMemories(workspaceRoot, agent.memorySources);
|
|
160
207
|
const compiledAgentModel = requireModel(models, agent.modelRef || (internalSubagent ? "model/default" : ""), agent.id);
|
|
161
208
|
const backend = resolveBackendConfig(agent);
|
|
162
|
-
const store = resolveStoreConfig(agent);
|
|
163
|
-
const checkpointer = resolveCheckpointerConfig(agent);
|
|
209
|
+
const store = resolveStoreConfig(agent, refs);
|
|
210
|
+
const checkpointer = resolveCheckpointerConfig(agent, refs);
|
|
164
211
|
const runRoot = typeof agent.runRoot === "string" && agent.runRoot.trim().length > 0
|
|
165
212
|
? path.resolve(workspaceRoot, agent.runRoot)
|
|
166
213
|
: typeof runtimeDefaults?.runRoot === "string" && runtimeDefaults.runRoot.trim().length > 0
|
|
@@ -168,10 +215,21 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
168
215
|
: path.join(workspaceRoot, "run-data");
|
|
169
216
|
const base = {
|
|
170
217
|
agent,
|
|
218
|
+
adapter: {
|
|
219
|
+
kind: agent.executionMode,
|
|
220
|
+
config: agent.executionMode === "deepagent"
|
|
221
|
+
? {
|
|
222
|
+
deepAgent: true,
|
|
223
|
+
}
|
|
224
|
+
: {
|
|
225
|
+
langchainV1: true,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
171
228
|
harnessRuntime: {
|
|
172
229
|
runRoot,
|
|
173
230
|
workspaceRoot,
|
|
174
231
|
hostFacing: !internalSubagent,
|
|
232
|
+
capabilities: inferAgentCapabilities(agent),
|
|
175
233
|
...(checkpointer ? { checkpointer: checkpointer.config } : {}),
|
|
176
234
|
...(store ? { store: store.config } : {}),
|
|
177
235
|
},
|
|
@@ -194,37 +252,50 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
194
252
|
};
|
|
195
253
|
return {
|
|
196
254
|
...base,
|
|
255
|
+
adapter: {
|
|
256
|
+
kind: "langchain-v1",
|
|
257
|
+
config: {
|
|
258
|
+
params: langchainAgentParams,
|
|
259
|
+
},
|
|
260
|
+
},
|
|
197
261
|
langchainAgentParams,
|
|
198
262
|
directAgentParams: langchainAgentParams,
|
|
199
263
|
};
|
|
200
264
|
}
|
|
265
|
+
const deepAgentParams = {
|
|
266
|
+
model: compiledAgentModel,
|
|
267
|
+
tools: requireTools(tools, agent.toolRefs, agent.id),
|
|
268
|
+
systemPrompt: resolveSystemPrompt(agent),
|
|
269
|
+
responseFormat: agent.deepAgentConfig?.responseFormat,
|
|
270
|
+
contextSchema: agent.deepAgentConfig?.contextSchema,
|
|
271
|
+
middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
|
|
272
|
+
description: agent.description,
|
|
273
|
+
subagents: agent.subagentRefs.map((ref) => {
|
|
274
|
+
const subagent = agents.get(resolveRefId(ref));
|
|
275
|
+
if (!subagent) {
|
|
276
|
+
throw new Error(`Missing subagent ${ref} for agent ${agent.id}`);
|
|
277
|
+
}
|
|
278
|
+
return buildSubagent(subagent, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory);
|
|
279
|
+
}),
|
|
280
|
+
interruptOn: resolveInterruptOn(agent),
|
|
281
|
+
...(backend ? { backend: backend.config } : {}),
|
|
282
|
+
...(store ? { store: store.config } : {}),
|
|
283
|
+
name: resolveAgentRuntimeName(agent),
|
|
284
|
+
memory: compiledAgentMemory,
|
|
285
|
+
skills: compiledAgentSkills,
|
|
286
|
+
generalPurposeAgent: typeof agent.deepAgentConfig?.generalPurposeAgent === "boolean" ? agent.deepAgentConfig.generalPurposeAgent : undefined,
|
|
287
|
+
taskDescription: typeof agent.deepAgentConfig?.taskDescription === "string" && agent.deepAgentConfig.taskDescription.trim()
|
|
288
|
+
? agent.deepAgentConfig.taskDescription
|
|
289
|
+
: undefined,
|
|
290
|
+
};
|
|
201
291
|
return {
|
|
202
292
|
...base,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
contextSchema: agent.deepAgentConfig?.contextSchema,
|
|
209
|
-
middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
|
|
210
|
-
description: agent.description,
|
|
211
|
-
subagents: agent.subagentRefs.map((ref) => {
|
|
212
|
-
const subagent = agents.get(resolveRefId(ref));
|
|
213
|
-
if (!subagent) {
|
|
214
|
-
throw new Error(`Missing subagent ${ref} for agent ${agent.id}`);
|
|
215
|
-
}
|
|
216
|
-
return buildSubagent(subagent, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory);
|
|
217
|
-
}),
|
|
218
|
-
interruptOn: resolveInterruptOn(agent),
|
|
219
|
-
...(backend ? { backend: backend.config } : {}),
|
|
220
|
-
...(store ? { store: store.config } : {}),
|
|
221
|
-
name: resolveAgentRuntimeName(agent),
|
|
222
|
-
memory: compiledAgentMemory,
|
|
223
|
-
skills: compiledAgentSkills,
|
|
224
|
-
generalPurposeAgent: typeof agent.deepAgentConfig?.generalPurposeAgent === "boolean" ? agent.deepAgentConfig.generalPurposeAgent : undefined,
|
|
225
|
-
taskDescription: typeof agent.deepAgentConfig?.taskDescription === "string" && agent.deepAgentConfig.taskDescription.trim()
|
|
226
|
-
? agent.deepAgentConfig.taskDescription
|
|
227
|
-
: undefined,
|
|
293
|
+
adapter: {
|
|
294
|
+
kind: "deepagent",
|
|
295
|
+
config: {
|
|
296
|
+
params: deepAgentParams,
|
|
297
|
+
},
|
|
228
298
|
},
|
|
299
|
+
deepAgentParams,
|
|
229
300
|
};
|
|
230
301
|
}
|
|
@@ -88,6 +88,8 @@ function normalizeNamedResourceSpec(document, kind) {
|
|
|
88
88
|
}
|
|
89
89
|
function normalizeKind(kind) {
|
|
90
90
|
switch (kind) {
|
|
91
|
+
case "Agent":
|
|
92
|
+
return "agent";
|
|
91
93
|
case "LangChainAgent":
|
|
92
94
|
return "langchain-agent";
|
|
93
95
|
case "DeepAgent":
|
|
@@ -209,6 +211,37 @@ function readObjectArray(items) {
|
|
|
209
211
|
.map((item) => ({ ...item }));
|
|
210
212
|
return records.length > 0 ? records : undefined;
|
|
211
213
|
}
|
|
214
|
+
function readCapabilities(value) {
|
|
215
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
const typed = value;
|
|
219
|
+
const capabilities = {
|
|
220
|
+
...(typeof typed.delegation === "boolean" ? { delegation: typed.delegation } : {}),
|
|
221
|
+
...(typeof typed.memory === "boolean" ? { memory: typed.memory } : {}),
|
|
222
|
+
};
|
|
223
|
+
return Object.keys(capabilities).length > 0 ? capabilities : undefined;
|
|
224
|
+
}
|
|
225
|
+
function readExecutionConfig(value) {
|
|
226
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
227
|
+
? { ...value }
|
|
228
|
+
: undefined;
|
|
229
|
+
}
|
|
230
|
+
function resolveExecutionBackend(item, current) {
|
|
231
|
+
const execution = readExecutionConfig(item.execution) ?? readExecutionConfig(current?.execution);
|
|
232
|
+
const backend = typeof execution?.backend === "string"
|
|
233
|
+
? execution.backend.trim().toLowerCase()
|
|
234
|
+
: typeof execution?.mode === "string"
|
|
235
|
+
? execution.mode.trim().toLowerCase()
|
|
236
|
+
: undefined;
|
|
237
|
+
if (backend === "langchain-v1" || backend === "langchain" || backend === "langchain-agent") {
|
|
238
|
+
return "langchain-v1";
|
|
239
|
+
}
|
|
240
|
+
if (backend === "deepagent" || backend === "deepagents") {
|
|
241
|
+
return "deepagent";
|
|
242
|
+
}
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
212
245
|
function readSharedAgentConfig(item) {
|
|
213
246
|
const middleware = readMiddlewareArray(item.middleware);
|
|
214
247
|
return {
|
|
@@ -244,12 +277,16 @@ export function parseAgentItem(item, sourcePath) {
|
|
|
244
277
|
const subagentRefs = readRefArray(item.subagents);
|
|
245
278
|
const subagentPathRefs = readPathArray(item.subagents);
|
|
246
279
|
const kind = typeof item.kind === "string" ? item.kind : "agent";
|
|
247
|
-
const executionMode = String((
|
|
280
|
+
const executionMode = String(resolveExecutionBackend(item) ??
|
|
281
|
+
(kind === "langchain-agent" ? "langchain-v1" : undefined) ??
|
|
248
282
|
(kind === "deepagent" ? "deepagent" : undefined) ??
|
|
249
283
|
"deepagent");
|
|
250
284
|
return {
|
|
251
285
|
id: String(item.id),
|
|
252
286
|
executionMode: executionMode,
|
|
287
|
+
capabilities: readCapabilities(item.capabilities) ?? (executionMode === "deepagent"
|
|
288
|
+
? { delegation: true, memory: true }
|
|
289
|
+
: { delegation: false, memory: false }),
|
|
253
290
|
description: String(item.description ?? ""),
|
|
254
291
|
modelRef: readSingleRef(item.modelRef) ?? "",
|
|
255
292
|
runRoot: typeof item.runRoot === "string" ? item.runRoot : undefined,
|
|
@@ -460,16 +497,26 @@ async function readNamedModelItems(root) {
|
|
|
460
497
|
}
|
|
461
498
|
const parsedDocuments = parseAllDocuments(await readYamlOrJson(filePath));
|
|
462
499
|
for (const parsedDocument of parsedDocuments) {
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
500
|
+
const document = parsedDocument.toJSON();
|
|
501
|
+
const catalogItems = normalizeNamedResourceSpec(document, "model");
|
|
502
|
+
if (catalogItems.length > 0) {
|
|
503
|
+
for (const item of catalogItems) {
|
|
504
|
+
records.push({ item: normalizeYamlItem(item), sourcePath: filePath });
|
|
505
|
+
}
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
for (const item of await objectItemsFromDocument(document, filePath)) {
|
|
509
|
+
const normalized = normalizeYamlItem(item);
|
|
510
|
+
if (normalized.kind === "model" && typeof normalized.id === "string" && normalized.id.trim()) {
|
|
511
|
+
records.push({ item: normalized, sourcePath: filePath });
|
|
512
|
+
}
|
|
466
513
|
}
|
|
467
514
|
}
|
|
468
515
|
}
|
|
469
516
|
return records;
|
|
470
517
|
}
|
|
471
518
|
function isAgentKind(kind) {
|
|
472
|
-
return kind === "deepagent" || kind === "langchain-agent";
|
|
519
|
+
return kind === "deepagent" || kind === "langchain-agent" || kind === "agent";
|
|
473
520
|
}
|
|
474
521
|
async function readConfigAgentItems(configRoot) {
|
|
475
522
|
const records = await readYamlItems(configRoot, "agents", { recursive: true });
|
|
@@ -517,6 +564,10 @@ export async function readToolModuleItems(root) {
|
|
|
517
564
|
return records;
|
|
518
565
|
}
|
|
519
566
|
function inferExecutionMode(item, current) {
|
|
567
|
+
const explicitExecution = resolveExecutionBackend(item, current);
|
|
568
|
+
if (explicitExecution) {
|
|
569
|
+
return explicitExecution;
|
|
570
|
+
}
|
|
520
571
|
const kind = typeof item.kind === "string" ? item.kind : typeof current?.kind === "string" ? current.kind : undefined;
|
|
521
572
|
if (kind === "langchain-agent") {
|
|
522
573
|
return "langchain-v1";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CompiledAgentBinding, ParsedAgentObject, RuntimeCapabilities } from "../../contracts/types.js";
|
|
2
|
+
export declare function inferAgentCapabilities(agent: ParsedAgentObject): RuntimeCapabilities;
|
|
3
|
+
export declare function inferBindingCapabilities(binding: CompiledAgentBinding): RuntimeCapabilities;
|
|
4
|
+
export declare function isDelegationCapableAgent(agent: ParsedAgentObject): boolean;
|
|
5
|
+
export declare function isMemoryCapableAgent(agent: ParsedAgentObject): boolean;
|
|
6
|
+
export declare function isDelegationCapableBinding(binding: CompiledAgentBinding): boolean;
|
|
7
|
+
export declare function isMemoryCapableBinding(binding: CompiledAgentBinding): boolean;
|
|
8
|
+
export declare function getAgentSystemPrompt(agent: ParsedAgentObject): string | undefined;
|
|
9
|
+
export declare function hasAgentSystemPrompt(agent: ParsedAgentObject): boolean;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
function normalizeCapabilities(capabilities) {
|
|
2
|
+
return {
|
|
3
|
+
delegation: capabilities?.delegation === true,
|
|
4
|
+
memory: capabilities?.memory === true,
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export function inferAgentCapabilities(agent) {
|
|
8
|
+
if (agent.capabilities) {
|
|
9
|
+
return normalizeCapabilities(agent.capabilities);
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
delegation: agent.executionMode === "deepagent",
|
|
13
|
+
memory: agent.executionMode === "deepagent",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function inferBindingCapabilities(binding) {
|
|
17
|
+
return normalizeCapabilities(binding.harnessRuntime.capabilities ?? binding.agent.capabilities ?? inferAgentCapabilities(binding.agent));
|
|
18
|
+
}
|
|
19
|
+
export function isDelegationCapableAgent(agent) {
|
|
20
|
+
return inferAgentCapabilities(agent).delegation === true;
|
|
21
|
+
}
|
|
22
|
+
export function isMemoryCapableAgent(agent) {
|
|
23
|
+
return inferAgentCapabilities(agent).memory === true;
|
|
24
|
+
}
|
|
25
|
+
export function isDelegationCapableBinding(binding) {
|
|
26
|
+
return inferBindingCapabilities(binding).delegation === true;
|
|
27
|
+
}
|
|
28
|
+
export function isMemoryCapableBinding(binding) {
|
|
29
|
+
return inferBindingCapabilities(binding).memory === true;
|
|
30
|
+
}
|
|
31
|
+
export function getAgentSystemPrompt(agent) {
|
|
32
|
+
const deepagentPrompt = typeof agent.deepAgentConfig?.systemPrompt === "string" ? agent.deepAgentConfig.systemPrompt.trim() : "";
|
|
33
|
+
if (deepagentPrompt) {
|
|
34
|
+
return deepagentPrompt;
|
|
35
|
+
}
|
|
36
|
+
const langchainPrompt = typeof agent.langchainAgentConfig?.systemPrompt === "string" ? agent.langchainAgentConfig.systemPrompt.trim() : "";
|
|
37
|
+
return langchainPrompt || undefined;
|
|
38
|
+
}
|
|
39
|
+
export function hasAgentSystemPrompt(agent) {
|
|
40
|
+
return typeof getAgentSystemPrompt(agent) === "string";
|
|
41
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
+
import { hasAgentSystemPrompt, isDelegationCapableAgent, isMemoryCapableAgent, } from "./support/agent-capabilities.js";
|
|
1
2
|
const allowedExecutionModes = new Set(["deepagent", "langchain-v1"]);
|
|
2
|
-
function hasPromptContent(value) {
|
|
3
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
4
|
-
}
|
|
5
3
|
function validateCheckpointerConfig(agent) {
|
|
6
4
|
const checkpointer = (typeof agent.deepAgentConfig?.checkpointer === "object" && agent.deepAgentConfig.checkpointer) ||
|
|
7
5
|
(typeof agent.deepAgentConfig?.checkpointer === "boolean" ? agent.deepAgentConfig.checkpointer : undefined) ||
|
|
@@ -52,14 +50,14 @@ export function validateAgent(agent) {
|
|
|
52
50
|
if (!agent.description.trim()) {
|
|
53
51
|
throw new Error(`Agent ${agent.id} description must not be empty`);
|
|
54
52
|
}
|
|
55
|
-
if (agent
|
|
56
|
-
throw new Error(`Agent ${agent.id} cannot define subagents unless
|
|
53
|
+
if (!isDelegationCapableAgent(agent) && (agent.subagentRefs.length > 0 || agent.subagentPathRefs.length > 0)) {
|
|
54
|
+
throw new Error(`Agent ${agent.id} cannot define subagents unless it uses a delegation-capable backend`);
|
|
57
55
|
}
|
|
58
|
-
if (agent
|
|
59
|
-
throw new Error(`Agent ${agent.id} cannot define memory unless
|
|
56
|
+
if (!isMemoryCapableAgent(agent) && agent.memorySources.length > 0) {
|
|
57
|
+
throw new Error(`Agent ${agent.id} cannot define memory unless it uses a memory-capable backend`);
|
|
60
58
|
}
|
|
61
|
-
if ((agent.subagentRefs.length > 0 || agent.subagentPathRefs.length > 0) && agent
|
|
62
|
-
throw new Error(`Agent ${agent.id} must use
|
|
59
|
+
if ((agent.subagentRefs.length > 0 || agent.subagentPathRefs.length > 0) && !isDelegationCapableAgent(agent)) {
|
|
60
|
+
throw new Error(`Agent ${agent.id} must use a delegation-capable backend when subagents are defined`);
|
|
63
61
|
}
|
|
64
62
|
validateCheckpointerConfig(agent);
|
|
65
63
|
validateMiddlewareConfig(agent);
|
|
@@ -83,11 +81,11 @@ export function validateTopology(agents) {
|
|
|
83
81
|
if (!referencedSubagentIds.has(agent.id)) {
|
|
84
82
|
continue;
|
|
85
83
|
}
|
|
86
|
-
if (agent
|
|
87
|
-
throw new Error(`Subagent ${agent.id} must use
|
|
84
|
+
if (!isDelegationCapableAgent(agent)) {
|
|
85
|
+
throw new Error(`Subagent ${agent.id} must use a delegation-capable backend`);
|
|
88
86
|
}
|
|
89
|
-
if (!
|
|
90
|
-
throw new Error(`Subagent ${agent.id} requires
|
|
87
|
+
if (!hasAgentSystemPrompt(agent)) {
|
|
88
|
+
throw new Error(`Subagent ${agent.id} requires systemPrompt`);
|
|
91
89
|
}
|
|
92
90
|
}
|
|
93
91
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botbotgo/agent-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.44",
|
|
4
4
|
"description": "Workspace runtime for multi-agent applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@10.9.2",
|
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
"types": "./dist/tools.d.ts",
|
|
27
27
|
"import": "./dist/tools.js",
|
|
28
28
|
"default": "./dist/tools.js"
|
|
29
|
+
},
|
|
30
|
+
"./presentation": {
|
|
31
|
+
"types": "./dist/presentation.d.ts",
|
|
32
|
+
"import": "./dist/presentation.js",
|
|
33
|
+
"default": "./dist/presentation.js"
|
|
29
34
|
}
|
|
30
35
|
},
|
|
31
36
|
"dependencies": {
|
|
@@ -50,8 +55,9 @@
|
|
|
50
55
|
"scripts": {
|
|
51
56
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc -p tsconfig.json && cp -R config dist/",
|
|
52
57
|
"check": "tsc -p tsconfig.json --noEmit",
|
|
53
|
-
"test": "vitest run test/public-api.test.ts test/resource-optional-provider.test.ts test/resource-isolation.test.ts test/stock-research-app-load-harness.test.ts test/stock-research-app-run.test.ts test/release-workflow.test.ts test/release-version.test.ts test/gitignore.test.ts test/package-lock.test.ts test/readme.test.ts test/runtime-adapter-regressions.test.ts test/runtime-recovery.test.ts test/tool-extension-gaps.test.ts test/checkpoint-maintenance.test.ts test/llamaindex-dependency-compat.test.ts test/skill-standard.test.ts test/routing-config.test.ts test/workspace-compat-regressions.test.ts test/upstream-compat-regressions.test.ts",
|
|
58
|
+
"test": "vitest run test/public-api.test.ts test/resource-optional-provider.test.ts test/resource-isolation.test.ts test/stock-research-app-load-harness.test.ts test/stock-research-app-run.test.ts test/release-workflow.test.ts test/release-version.test.ts test/gitignore.test.ts test/package-lock.test.ts test/readme.test.ts test/runtime-adapter-regressions.test.ts test/runtime-recovery.test.ts test/tool-extension-gaps.test.ts test/checkpoint-maintenance.test.ts test/llamaindex-dependency-compat.test.ts test/skill-standard.test.ts test/routing-config.test.ts test/workspace-compat-regressions.test.ts test/upstream-compat-regressions.test.ts test/embedded-browser-bookmarks.test.ts test/presentation-wallee.test.ts",
|
|
54
59
|
"test:real-providers": "vitest run test/real-provider-harness.test.ts",
|
|
60
|
+
"test:integration": "npm run build && node scripts/integration-wallee-browser.mjs",
|
|
55
61
|
"release:prepare": "npm version patch --no-git-tag-version && node ./scripts/sync-example-version.mjs",
|
|
56
62
|
"release:pack": "npm pack --dry-run",
|
|
57
63
|
"release:publish": "npm publish --access public --registry https://registry.npmjs.org/"
|