@botbotgo/agent-harness 0.0.41 → 0.0.43
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 +105 -86
- package/dist/config/agents/direct.yaml +8 -7
- package/dist/config/agents/orchestra.yaml +8 -6
- package/dist/contracts/types.d.ts +35 -2
- 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/runtime/agent-runtime-adapter.d.ts +1 -1
- package/dist/runtime/agent-runtime-adapter.js +68 -80
- package/dist/runtime/checkpoint-maintenance.js +1 -1
- package/dist/runtime/declared-middleware.d.ts +8 -1
- package/dist/runtime/declared-middleware.js +18 -1
- package/dist/runtime/harness.d.ts +6 -0
- package/dist/runtime/harness.js +390 -256
- 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/runtime/support/runtime-factories.d.ts +1 -1
- package/dist/runtime/support/runtime-factories.js +3 -0
- package/dist/workspace/agent-binding-compiler.js +61 -33
- package/dist/workspace/object-loader.js +50 -4
- package/dist/workspace/support/agent-capabilities.d.ts +7 -0
- package/dist/workspace/support/agent-capabilities.js +30 -0
- package/dist/workspace/support/workspace-ref-utils.d.ts +4 -0
- package/dist/workspace/support/workspace-ref-utils.js +15 -1
- package/dist/workspace/validate.js +14 -8
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readSkillMetadata } from "./support/skill-metadata.js";
|
|
2
|
+
import { getBindingPrimaryTools } from "./support/compiled-binding.js";
|
|
2
3
|
function listHostBindings(workspace) {
|
|
3
4
|
return Array.from(workspace.bindings.values()).filter((binding) => binding.harnessRuntime.hostFacing);
|
|
4
5
|
}
|
|
@@ -31,7 +32,7 @@ export function listAgentTools(workspace, agentId) {
|
|
|
31
32
|
if (!binding) {
|
|
32
33
|
return [];
|
|
33
34
|
}
|
|
34
|
-
return dedupeTools(binding
|
|
35
|
+
return dedupeTools(getBindingPrimaryTools(binding));
|
|
35
36
|
}
|
|
36
37
|
export function listAgentSkills(workspace, agentId) {
|
|
37
38
|
const binding = findAgentBinding(workspace, agentId);
|
|
@@ -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,3 +1,3 @@
|
|
|
1
1
|
import { type StoreLike } from "../store.js";
|
|
2
2
|
export declare function createStoreForConfig(storeConfig: Record<string, unknown>, runRoot: string): StoreLike;
|
|
3
|
-
export declare function createCheckpointerForConfig(checkpointerConfig: Record<string, unknown
|
|
3
|
+
export declare function createCheckpointerForConfig(checkpointerConfig: Record<string, unknown> | boolean, runRoot: string): unknown;
|
|
@@ -22,6 +22,9 @@ export function createStoreForConfig(storeConfig, runRoot) {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
export function createCheckpointerForConfig(checkpointerConfig, runRoot) {
|
|
25
|
+
if (typeof checkpointerConfig === "boolean") {
|
|
26
|
+
return checkpointerConfig;
|
|
27
|
+
}
|
|
25
28
|
const kind = typeof checkpointerConfig.kind === "string" ? checkpointerConfig.kind : "FileCheckpointer";
|
|
26
29
|
switch (kind) {
|
|
27
30
|
case "MemorySaver":
|
|
@@ -1,6 +1,7 @@
|
|
|
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
6
|
import { compileAgentMemories, getRuntimeDefaults, 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. " +
|
|
@@ -133,21 +134,24 @@ function resolveBackendConfig(agent) {
|
|
|
133
134
|
return backendConfig ? { config: backendConfig } : undefined;
|
|
134
135
|
}
|
|
135
136
|
function resolveStoreConfig(agent) {
|
|
136
|
-
if (agent.executionMode !== "deepagent") {
|
|
137
|
-
return undefined;
|
|
138
|
-
}
|
|
139
137
|
const inlineStore = typeof agent.deepAgentConfig?.store === "object" && agent.deepAgentConfig.store
|
|
140
138
|
? agent.deepAgentConfig.store
|
|
141
|
-
:
|
|
139
|
+
: typeof agent.langchainAgentConfig?.store === "object" && agent.langchainAgentConfig.store
|
|
140
|
+
? agent.langchainAgentConfig.store
|
|
141
|
+
: undefined;
|
|
142
142
|
return inlineStore ? { config: inlineStore } : undefined;
|
|
143
143
|
}
|
|
144
144
|
function resolveCheckpointerConfig(agent) {
|
|
145
145
|
const inlineAgentCheckpointer = typeof agent.deepAgentConfig?.checkpointer === "object" && agent.deepAgentConfig.checkpointer
|
|
146
146
|
? agent.deepAgentConfig.checkpointer
|
|
147
|
-
: typeof agent.
|
|
148
|
-
? agent.
|
|
149
|
-
:
|
|
150
|
-
|
|
147
|
+
: typeof agent.deepAgentConfig?.checkpointer === "boolean"
|
|
148
|
+
? agent.deepAgentConfig.checkpointer
|
|
149
|
+
: typeof agent.langchainAgentConfig?.checkpointer === "object" && agent.langchainAgentConfig.checkpointer
|
|
150
|
+
? agent.langchainAgentConfig.checkpointer
|
|
151
|
+
: typeof agent.langchainAgentConfig?.checkpointer === "boolean"
|
|
152
|
+
? agent.langchainAgentConfig.checkpointer
|
|
153
|
+
: undefined;
|
|
154
|
+
return inlineAgentCheckpointer !== undefined ? { config: inlineAgentCheckpointer } : undefined;
|
|
151
155
|
}
|
|
152
156
|
export function compileBinding(workspaceRoot, agent, agents, referencedSubagentIds, refs, models, tools) {
|
|
153
157
|
const internalSubagent = referencedSubagentIds.has(agent.id);
|
|
@@ -165,10 +169,21 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
165
169
|
: path.join(workspaceRoot, "run-data");
|
|
166
170
|
const base = {
|
|
167
171
|
agent,
|
|
172
|
+
adapter: {
|
|
173
|
+
kind: agent.executionMode,
|
|
174
|
+
config: agent.executionMode === "deepagent"
|
|
175
|
+
? {
|
|
176
|
+
deepAgent: true,
|
|
177
|
+
}
|
|
178
|
+
: {
|
|
179
|
+
langchainV1: true,
|
|
180
|
+
},
|
|
181
|
+
},
|
|
168
182
|
harnessRuntime: {
|
|
169
183
|
runRoot,
|
|
170
184
|
workspaceRoot,
|
|
171
185
|
hostFacing: !internalSubagent,
|
|
186
|
+
capabilities: inferAgentCapabilities(agent),
|
|
172
187
|
...(checkpointer ? { checkpointer: checkpointer.config } : {}),
|
|
173
188
|
...(store ? { store: store.config } : {}),
|
|
174
189
|
},
|
|
@@ -191,37 +206,50 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
191
206
|
};
|
|
192
207
|
return {
|
|
193
208
|
...base,
|
|
209
|
+
adapter: {
|
|
210
|
+
kind: "langchain-v1",
|
|
211
|
+
config: {
|
|
212
|
+
params: langchainAgentParams,
|
|
213
|
+
},
|
|
214
|
+
},
|
|
194
215
|
langchainAgentParams,
|
|
195
216
|
directAgentParams: langchainAgentParams,
|
|
196
217
|
};
|
|
197
218
|
}
|
|
219
|
+
const deepAgentParams = {
|
|
220
|
+
model: compiledAgentModel,
|
|
221
|
+
tools: requireTools(tools, agent.toolRefs, agent.id),
|
|
222
|
+
systemPrompt: resolveSystemPrompt(agent),
|
|
223
|
+
responseFormat: agent.deepAgentConfig?.responseFormat,
|
|
224
|
+
contextSchema: agent.deepAgentConfig?.contextSchema,
|
|
225
|
+
middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
|
|
226
|
+
description: agent.description,
|
|
227
|
+
subagents: agent.subagentRefs.map((ref) => {
|
|
228
|
+
const subagent = agents.get(resolveRefId(ref));
|
|
229
|
+
if (!subagent) {
|
|
230
|
+
throw new Error(`Missing subagent ${ref} for agent ${agent.id}`);
|
|
231
|
+
}
|
|
232
|
+
return buildSubagent(subagent, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory);
|
|
233
|
+
}),
|
|
234
|
+
interruptOn: resolveInterruptOn(agent),
|
|
235
|
+
...(backend ? { backend: backend.config } : {}),
|
|
236
|
+
...(store ? { store: store.config } : {}),
|
|
237
|
+
name: resolveAgentRuntimeName(agent),
|
|
238
|
+
memory: compiledAgentMemory,
|
|
239
|
+
skills: compiledAgentSkills,
|
|
240
|
+
generalPurposeAgent: typeof agent.deepAgentConfig?.generalPurposeAgent === "boolean" ? agent.deepAgentConfig.generalPurposeAgent : undefined,
|
|
241
|
+
taskDescription: typeof agent.deepAgentConfig?.taskDescription === "string" && agent.deepAgentConfig.taskDescription.trim()
|
|
242
|
+
? agent.deepAgentConfig.taskDescription
|
|
243
|
+
: undefined,
|
|
244
|
+
};
|
|
198
245
|
return {
|
|
199
246
|
...base,
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
contextSchema: agent.deepAgentConfig?.contextSchema,
|
|
206
|
-
middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
|
|
207
|
-
description: agent.description,
|
|
208
|
-
subagents: agent.subagentRefs.map((ref) => {
|
|
209
|
-
const subagent = agents.get(resolveRefId(ref));
|
|
210
|
-
if (!subagent) {
|
|
211
|
-
throw new Error(`Missing subagent ${ref} for agent ${agent.id}`);
|
|
212
|
-
}
|
|
213
|
-
return buildSubagent(subagent, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory);
|
|
214
|
-
}),
|
|
215
|
-
interruptOn: resolveInterruptOn(agent),
|
|
216
|
-
...(backend ? { backend: backend.config } : {}),
|
|
217
|
-
...(store ? { store: store.config } : {}),
|
|
218
|
-
name: resolveAgentRuntimeName(agent),
|
|
219
|
-
memory: compiledAgentMemory,
|
|
220
|
-
skills: compiledAgentSkills,
|
|
221
|
-
generalPurposeAgent: typeof agent.deepAgentConfig?.generalPurposeAgent === "boolean" ? agent.deepAgentConfig.generalPurposeAgent : undefined,
|
|
222
|
-
taskDescription: typeof agent.deepAgentConfig?.taskDescription === "string" && agent.deepAgentConfig.taskDescription.trim()
|
|
223
|
-
? agent.deepAgentConfig.taskDescription
|
|
224
|
-
: undefined,
|
|
247
|
+
adapter: {
|
|
248
|
+
kind: "deepagent",
|
|
249
|
+
config: {
|
|
250
|
+
params: deepAgentParams,
|
|
251
|
+
},
|
|
225
252
|
},
|
|
253
|
+
deepAgentParams,
|
|
226
254
|
};
|
|
227
255
|
}
|
|
@@ -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,11 +211,44 @@ 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 {
|
|
215
248
|
...(typeof item.systemPrompt === "string" ? { systemPrompt: item.systemPrompt } : {}),
|
|
216
|
-
...(typeof item.checkpointer === "object" && item.checkpointer
|
|
249
|
+
...((typeof item.checkpointer === "object" && item.checkpointer) || typeof item.checkpointer === "boolean"
|
|
250
|
+
? { checkpointer: item.checkpointer }
|
|
251
|
+
: {}),
|
|
217
252
|
...(typeof item.interruptOn === "object" && item.interruptOn ? { interruptOn: item.interruptOn } : {}),
|
|
218
253
|
...(item.stateSchema !== undefined ? { stateSchema: item.stateSchema } : {}),
|
|
219
254
|
...(item.responseFormat !== undefined ? { responseFormat: item.responseFormat } : {}),
|
|
@@ -224,7 +259,10 @@ function readSharedAgentConfig(item) {
|
|
|
224
259
|
};
|
|
225
260
|
}
|
|
226
261
|
function readLangchainAgentConfig(item) {
|
|
227
|
-
return
|
|
262
|
+
return {
|
|
263
|
+
...readSharedAgentConfig(item),
|
|
264
|
+
...(typeof item.store === "object" && item.store ? { store: item.store } : {}),
|
|
265
|
+
};
|
|
228
266
|
}
|
|
229
267
|
function readDeepAgentConfig(item) {
|
|
230
268
|
return {
|
|
@@ -239,12 +277,16 @@ export function parseAgentItem(item, sourcePath) {
|
|
|
239
277
|
const subagentRefs = readRefArray(item.subagents);
|
|
240
278
|
const subagentPathRefs = readPathArray(item.subagents);
|
|
241
279
|
const kind = typeof item.kind === "string" ? item.kind : "agent";
|
|
242
|
-
const executionMode = String((
|
|
280
|
+
const executionMode = String(resolveExecutionBackend(item) ??
|
|
281
|
+
(kind === "langchain-agent" ? "langchain-v1" : undefined) ??
|
|
243
282
|
(kind === "deepagent" ? "deepagent" : undefined) ??
|
|
244
283
|
"deepagent");
|
|
245
284
|
return {
|
|
246
285
|
id: String(item.id),
|
|
247
286
|
executionMode: executionMode,
|
|
287
|
+
capabilities: readCapabilities(item.capabilities) ?? (executionMode === "deepagent"
|
|
288
|
+
? { delegation: true, memory: true }
|
|
289
|
+
: { delegation: false, memory: false }),
|
|
248
290
|
description: String(item.description ?? ""),
|
|
249
291
|
modelRef: readSingleRef(item.modelRef) ?? "",
|
|
250
292
|
runRoot: typeof item.runRoot === "string" ? item.runRoot : undefined,
|
|
@@ -464,7 +506,7 @@ async function readNamedModelItems(root) {
|
|
|
464
506
|
return records;
|
|
465
507
|
}
|
|
466
508
|
function isAgentKind(kind) {
|
|
467
|
-
return kind === "deepagent" || kind === "langchain-agent";
|
|
509
|
+
return kind === "deepagent" || kind === "langchain-agent" || kind === "agent";
|
|
468
510
|
}
|
|
469
511
|
async function readConfigAgentItems(configRoot) {
|
|
470
512
|
const records = await readYamlItems(configRoot, "agents", { recursive: true });
|
|
@@ -512,6 +554,10 @@ export async function readToolModuleItems(root) {
|
|
|
512
554
|
return records;
|
|
513
555
|
}
|
|
514
556
|
function inferExecutionMode(item, current) {
|
|
557
|
+
const explicitExecution = resolveExecutionBackend(item, current);
|
|
558
|
+
if (explicitExecution) {
|
|
559
|
+
return explicitExecution;
|
|
560
|
+
}
|
|
515
561
|
const kind = typeof item.kind === "string" ? item.kind : typeof current?.kind === "string" ? current.kind : undefined;
|
|
516
562
|
if (kind === "langchain-agent") {
|
|
517
563
|
return "langchain-v1";
|
|
@@ -0,0 +1,7 @@
|
|
|
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;
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
}
|
|
@@ -21,10 +21,14 @@ export type RecoveryConfig = {
|
|
|
21
21
|
resumeResumingRunsOnStartup: boolean;
|
|
22
22
|
maxRecoveryAttempts: number;
|
|
23
23
|
};
|
|
24
|
+
export type ConcurrencyConfig = {
|
|
25
|
+
maxConcurrentRuns?: number;
|
|
26
|
+
};
|
|
24
27
|
export declare function getWorkspaceObject(refs: Map<string, WorkspaceObject | ParsedAgentObject>, ref: string | undefined): WorkspaceObject | undefined;
|
|
25
28
|
export declare function getRuntimeDefaults(refs: Map<string, WorkspaceObject | ParsedAgentObject>): Record<string, unknown> | undefined;
|
|
26
29
|
export declare function getRuntimeRecoveryConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): RuntimeRecoveryConfig;
|
|
27
30
|
export declare function getRecoveryConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): RecoveryConfig;
|
|
31
|
+
export declare function getConcurrencyConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): ConcurrencyConfig;
|
|
28
32
|
export declare function getRoutingSystemPrompt(refs: Map<string, WorkspaceObject | ParsedAgentObject>): string | undefined;
|
|
29
33
|
export declare function getRoutingDefaultAgentId(refs: Map<string, WorkspaceObject | ParsedAgentObject>): string | undefined;
|
|
30
34
|
export declare function isModelRoutingEnabled(refs: Map<string, WorkspaceObject | ParsedAgentObject>): boolean;
|
|
@@ -47,10 +47,24 @@ export function getRecoveryConfig(refs) {
|
|
|
47
47
|
: 3;
|
|
48
48
|
return {
|
|
49
49
|
enabled: recovery.enabled !== false,
|
|
50
|
-
resumeResumingRunsOnStartup: recovery.resumeResumingRunsOnStartup
|
|
50
|
+
resumeResumingRunsOnStartup: typeof recovery.resumeResumingRunsOnStartup === "boolean"
|
|
51
|
+
? recovery.resumeResumingRunsOnStartup
|
|
52
|
+
: recovery.resumeOnStartup !== false,
|
|
51
53
|
maxRecoveryAttempts,
|
|
52
54
|
};
|
|
53
55
|
}
|
|
56
|
+
export function getConcurrencyConfig(refs) {
|
|
57
|
+
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
58
|
+
const concurrency = typeof runtimeDefaults?.concurrency === "object" && runtimeDefaults.concurrency
|
|
59
|
+
? runtimeDefaults.concurrency
|
|
60
|
+
: {};
|
|
61
|
+
const maxConcurrentRuns = typeof concurrency.maxConcurrentRuns === "number" &&
|
|
62
|
+
Number.isFinite(concurrency.maxConcurrentRuns) &&
|
|
63
|
+
concurrency.maxConcurrentRuns > 0
|
|
64
|
+
? Math.floor(concurrency.maxConcurrentRuns)
|
|
65
|
+
: undefined;
|
|
66
|
+
return { maxConcurrentRuns };
|
|
67
|
+
}
|
|
54
68
|
export function getRoutingSystemPrompt(refs) {
|
|
55
69
|
const routing = getRoutingObject(refs);
|
|
56
70
|
return typeof routing?.systemPrompt === "string" && routing.systemPrompt.trim() ? routing.systemPrompt : undefined;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import { isDelegationCapableAgent, isMemoryCapableAgent } from "./support/agent-capabilities.js";
|
|
1
2
|
const allowedExecutionModes = new Set(["deepagent", "langchain-v1"]);
|
|
2
3
|
function hasPromptContent(value) {
|
|
3
4
|
return typeof value === "string" && value.trim().length > 0;
|
|
4
5
|
}
|
|
5
6
|
function validateCheckpointerConfig(agent) {
|
|
6
7
|
const checkpointer = (typeof agent.deepAgentConfig?.checkpointer === "object" && agent.deepAgentConfig.checkpointer) ||
|
|
8
|
+
(typeof agent.deepAgentConfig?.checkpointer === "boolean" ? agent.deepAgentConfig.checkpointer : undefined) ||
|
|
9
|
+
(typeof agent.langchainAgentConfig?.checkpointer === "boolean" ? agent.langchainAgentConfig.checkpointer : undefined) ||
|
|
7
10
|
(typeof agent.langchainAgentConfig?.checkpointer === "object" && agent.langchainAgentConfig.checkpointer);
|
|
11
|
+
if (typeof checkpointer === "boolean") {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
8
14
|
if (!checkpointer) {
|
|
9
15
|
return;
|
|
10
16
|
}
|
|
@@ -47,14 +53,14 @@ export function validateAgent(agent) {
|
|
|
47
53
|
if (!agent.description.trim()) {
|
|
48
54
|
throw new Error(`Agent ${agent.id} description must not be empty`);
|
|
49
55
|
}
|
|
50
|
-
if (agent
|
|
51
|
-
throw new Error(`Agent ${agent.id} cannot define subagents unless
|
|
56
|
+
if (!isDelegationCapableAgent(agent) && (agent.subagentRefs.length > 0 || agent.subagentPathRefs.length > 0)) {
|
|
57
|
+
throw new Error(`Agent ${agent.id} cannot define subagents unless it uses a delegation-capable backend`);
|
|
52
58
|
}
|
|
53
|
-
if (agent
|
|
54
|
-
throw new Error(`Agent ${agent.id} cannot define memory unless
|
|
59
|
+
if (!isMemoryCapableAgent(agent) && agent.memorySources.length > 0) {
|
|
60
|
+
throw new Error(`Agent ${agent.id} cannot define memory unless it uses a memory-capable backend`);
|
|
55
61
|
}
|
|
56
|
-
if ((agent.subagentRefs.length > 0 || agent.subagentPathRefs.length > 0) && agent
|
|
57
|
-
throw new Error(`Agent ${agent.id} must use
|
|
62
|
+
if ((agent.subagentRefs.length > 0 || agent.subagentPathRefs.length > 0) && !isDelegationCapableAgent(agent)) {
|
|
63
|
+
throw new Error(`Agent ${agent.id} must use a delegation-capable backend when subagents are defined`);
|
|
58
64
|
}
|
|
59
65
|
validateCheckpointerConfig(agent);
|
|
60
66
|
validateMiddlewareConfig(agent);
|
|
@@ -78,8 +84,8 @@ export function validateTopology(agents) {
|
|
|
78
84
|
if (!referencedSubagentIds.has(agent.id)) {
|
|
79
85
|
continue;
|
|
80
86
|
}
|
|
81
|
-
if (agent
|
|
82
|
-
throw new Error(`Subagent ${agent.id} must use
|
|
87
|
+
if (!isDelegationCapableAgent(agent)) {
|
|
88
|
+
throw new Error(`Subagent ${agent.id} must use a delegation-capable backend`);
|
|
83
89
|
}
|
|
84
90
|
if (!hasPromptContent(agent.deepAgentConfig?.systemPrompt)) {
|
|
85
91
|
throw new Error(`Subagent ${agent.id} requires deepagent.systemPrompt`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botbotgo/agent-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.43",
|
|
4
4
|
"description": "Workspace runtime for multi-agent applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@10.9.2",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc -p tsconfig.json && cp -R config dist/",
|
|
52
52
|
"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",
|
|
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",
|
|
54
54
|
"test:real-providers": "vitest run test/real-provider-harness.test.ts",
|
|
55
55
|
"release:prepare": "npm version patch --no-git-tag-version && node ./scripts/sync-example-version.mjs",
|
|
56
56
|
"release:pack": "npm pack --dry-run",
|