@botbotgo/agent-harness 0.0.51 → 0.0.53
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 +70 -11
- package/dist/config/agents/direct.yaml +22 -1
- package/dist/config/agents/orchestra.yaml +26 -15
- package/dist/config/backends.yaml +18 -0
- package/dist/config/stores.yaml +7 -0
- package/dist/contracts/types.d.ts +0 -1
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/declared-middleware.d.ts +9 -0
- package/dist/runtime/declared-middleware.js +75 -78
- package/dist/workspace/agent-binding-compiler.js +16 -4
- package/dist/workspace/object-loader.js +11 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
It is not a new agent framework. It is the runtime layer around LangChain v1 and DeepAgents that turns one workspace into one operable application runtime.
|
|
8
8
|
|
|
9
|
-
The
|
|
9
|
+
The boundary is strict:
|
|
10
10
|
|
|
11
11
|
- LangChain v1 and DeepAgents own agent execution semantics
|
|
12
12
|
- `agent-harness` owns application-level orchestration and lifecycle management
|
|
@@ -15,12 +15,13 @@ That means:
|
|
|
15
15
|
|
|
16
16
|
- public API stays small
|
|
17
17
|
- complex setup and operating policy live in YAML
|
|
18
|
+
- application-level orchestration and lifecycle management stays in the harness
|
|
18
19
|
- runtime lifecycle stays stable even if backend implementations change
|
|
19
20
|
|
|
20
21
|
What the runtime provides:
|
|
21
22
|
|
|
22
23
|
- `createAgentHarness(...)`, `run(...)`, `subscribe(...)`, inspection methods, and `stop(...)`
|
|
23
|
-
- YAML-defined workspace assembly for routing, models, tools, stores, MCP, recovery, and maintenance
|
|
24
|
+
- YAML-defined workspace assembly for routing, models, tools, stores, backends, MCP, recovery, and maintenance
|
|
24
25
|
- backend-adapted execution with current LangChain v1 and DeepAgents adapters
|
|
25
26
|
- local `resources/tools/` and `resources/skills/` discovery
|
|
26
27
|
- persisted threads, runs, approvals, events, queue state, and recovery metadata
|
|
@@ -44,6 +45,7 @@ your-workspace/
|
|
|
44
45
|
embedding-models.yaml
|
|
45
46
|
vector-stores.yaml
|
|
46
47
|
stores.yaml
|
|
48
|
+
backends.yaml
|
|
47
49
|
tools.yaml
|
|
48
50
|
mcp.yaml
|
|
49
51
|
agents/
|
|
@@ -242,6 +244,7 @@ Core workspace files:
|
|
|
242
244
|
- `config/embedding-models.yaml`
|
|
243
245
|
- `config/vector-stores.yaml`
|
|
244
246
|
- `config/stores.yaml`
|
|
247
|
+
- `config/backends.yaml`
|
|
245
248
|
- `config/tools.yaml`
|
|
246
249
|
- `config/mcp.yaml`
|
|
247
250
|
- `config/agents/direct.yaml`
|
|
@@ -255,6 +258,8 @@ There are three configuration layers:
|
|
|
255
258
|
- reusable object catalogs in `config/*.yaml`
|
|
256
259
|
- agent assembly in `config/agents/*.yaml`
|
|
257
260
|
|
|
261
|
+
The repository-owned default config layer is intentionally full-shaped. The shipped YAML keeps explicit default values for the main runtime knobs so teams can start from concrete config instead of reconstructing adapter defaults from code.
|
|
262
|
+
|
|
258
263
|
### `config/workspace.yaml`
|
|
259
264
|
|
|
260
265
|
Use this file for runtime-level policy shared by the whole workspace.
|
|
@@ -321,6 +326,44 @@ spec:
|
|
|
321
326
|
- kind: Checkpointer
|
|
322
327
|
name: default
|
|
323
328
|
checkpointerKind: MemorySaver
|
|
329
|
+
- kind: Checkpointer
|
|
330
|
+
name: sqlite
|
|
331
|
+
checkpointerKind: SqliteSaver
|
|
332
|
+
path: checkpoints.sqlite
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Built-in store kinds today:
|
|
336
|
+
|
|
337
|
+
- `FileStore`
|
|
338
|
+
- `InMemoryStore`
|
|
339
|
+
|
|
340
|
+
Built-in checkpointer kinds today:
|
|
341
|
+
|
|
342
|
+
- `MemorySaver`
|
|
343
|
+
- `FileCheckpointer`
|
|
344
|
+
- `SqliteSaver`
|
|
345
|
+
|
|
346
|
+
If you need other store or checkpointer implementations, inject them through runtime resolvers instead of treating them as built-in harness features.
|
|
347
|
+
|
|
348
|
+
### `config/backends.yaml`
|
|
349
|
+
|
|
350
|
+
Use reusable DeepAgent backend presets so filesystem and long-term memory topology stays in YAML instead of application code:
|
|
351
|
+
|
|
352
|
+
```yaml
|
|
353
|
+
apiVersion: agent-harness/v1alpha1
|
|
354
|
+
kind: Backends
|
|
355
|
+
spec:
|
|
356
|
+
- kind: Backend
|
|
357
|
+
name: default
|
|
358
|
+
backendKind: CompositeBackend
|
|
359
|
+
state:
|
|
360
|
+
kind: VfsSandbox
|
|
361
|
+
rootDir: .
|
|
362
|
+
virtualMode: true
|
|
363
|
+
timeout: 600
|
|
364
|
+
routes:
|
|
365
|
+
/memories/:
|
|
366
|
+
kind: StoreBackend
|
|
324
367
|
```
|
|
325
368
|
|
|
326
369
|
### `config/tools.yaml`
|
|
@@ -362,12 +405,23 @@ kind: Agent
|
|
|
362
405
|
metadata:
|
|
363
406
|
name: direct
|
|
364
407
|
spec:
|
|
408
|
+
runtime:
|
|
409
|
+
runRoot: ./.agent
|
|
365
410
|
execution:
|
|
366
411
|
backend: langchain-v1
|
|
367
412
|
modelRef: model/default
|
|
413
|
+
tools: []
|
|
414
|
+
skills: []
|
|
415
|
+
memory: []
|
|
416
|
+
subagents: []
|
|
417
|
+
mcpServers: []
|
|
368
418
|
config:
|
|
369
419
|
checkpointer:
|
|
370
420
|
ref: checkpointer/default
|
|
421
|
+
store:
|
|
422
|
+
ref: store/default
|
|
423
|
+
interruptOn: {}
|
|
424
|
+
middleware: []
|
|
371
425
|
systemPrompt: Answer simple requests directly.
|
|
372
426
|
```
|
|
373
427
|
|
|
@@ -379,24 +433,28 @@ kind: Agent
|
|
|
379
433
|
metadata:
|
|
380
434
|
name: orchestra
|
|
381
435
|
spec:
|
|
436
|
+
runtime:
|
|
437
|
+
runRoot: ./.agent
|
|
382
438
|
execution:
|
|
383
439
|
backend: deepagent
|
|
384
440
|
modelRef: model/default
|
|
385
441
|
memory:
|
|
386
442
|
- path: config/agent-context.md
|
|
443
|
+
tools: []
|
|
444
|
+
skills: []
|
|
445
|
+
subagents: []
|
|
446
|
+
mcpServers: []
|
|
387
447
|
config:
|
|
388
448
|
store:
|
|
389
449
|
ref: store/default
|
|
390
450
|
checkpointer:
|
|
391
451
|
ref: checkpointer/default
|
|
392
452
|
backend:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
/memories/:
|
|
399
|
-
kind: StoreBackend
|
|
453
|
+
ref: backend/default
|
|
454
|
+
interruptOn: {}
|
|
455
|
+
middleware: []
|
|
456
|
+
generalPurposeAgent: true
|
|
457
|
+
taskDescription: Complete delegated sidecar work and return concise results.
|
|
400
458
|
```
|
|
401
459
|
|
|
402
460
|
Client-configurable agent fields include:
|
|
@@ -428,6 +486,8 @@ Client-configurable agent fields include:
|
|
|
428
486
|
|
|
429
487
|
For backend-specific agent options, prefer passing the upstream concept directly inside `spec.execution.config`. The loader keeps a small stable product shape, but it also preserves adapter-facing passthrough fields so new LangChain v1 or DeepAgents parameters can flow into adapters without expanding the public API surface.
|
|
430
488
|
|
|
489
|
+
Upstream feature coverage is tracked in [docs/upstream-feature-matrix.md](docs/upstream-feature-matrix.md).
|
|
490
|
+
|
|
431
491
|
### `resources/`
|
|
432
492
|
|
|
433
493
|
Use `resources/` for executable local extensions:
|
|
@@ -448,6 +508,7 @@ SKILL packages are discovered from `resources/skills/` and attached to agents th
|
|
|
448
508
|
- upstream LangChain v1 and DeepAgents concepts should be expressed as directly as possible in YAML
|
|
449
509
|
- recovery, approvals, threads, runs, and events are runtime concepts, not backend-specific escape hatches
|
|
450
510
|
- backend implementation details should stay internal unless product requirements force exposure
|
|
511
|
+
- new LangChain v1 or DeepAgents public config should land in YAML passthrough and compatibility tests before adding new public runtime APIs
|
|
451
512
|
|
|
452
513
|
In short: `agent-harness` is a public runtime contract generic enough to survive backend changes, while the deep execution semantics stay upstream.
|
|
453
514
|
|
|
@@ -466,5 +527,3 @@ Primary exports:
|
|
|
466
527
|
- `createToolMcpServer`
|
|
467
528
|
- `serveToolsOverStdio`
|
|
468
529
|
- `stop`
|
|
469
|
-
|
|
470
|
-
`AgentHarnessRuntime` is the concrete runtime class behind the public facade.
|
|
@@ -9,7 +9,10 @@ metadata:
|
|
|
9
9
|
# agent-harness feature: human-readable summary for inventory and UI.
|
|
10
10
|
description: Manual low-latency host for direct answers and lightweight inventory lookup. Do not use it as the default executor for tool-heavy or specialist-shaped tasks.
|
|
11
11
|
spec:
|
|
12
|
-
runtime:
|
|
12
|
+
runtime:
|
|
13
|
+
# agent-harness feature: host-level run data placement override.
|
|
14
|
+
# This matches the workspace default and keeps the default config shape explicit.
|
|
15
|
+
runRoot: ./.agent
|
|
13
16
|
# =====================
|
|
14
17
|
# Runtime Agent Features
|
|
15
18
|
# =====================
|
|
@@ -20,6 +23,16 @@ spec:
|
|
|
20
23
|
# This should point at a cheap, fast, general-purpose chat model, because `direct` is intended
|
|
21
24
|
# to be the low-latency path for simple requests.
|
|
22
25
|
modelRef: model/default
|
|
26
|
+
# Upstream execution feature: direct host starts with no attached explicit tools by default.
|
|
27
|
+
tools: []
|
|
28
|
+
# Upstream execution feature: direct host starts with no attached local skill packages by default.
|
|
29
|
+
skills: []
|
|
30
|
+
# Upstream execution feature: direct host does not bootstrap project memory by default.
|
|
31
|
+
memory: []
|
|
32
|
+
# Upstream execution feature: direct host does not predeclare specialist subagents by default.
|
|
33
|
+
subagents: []
|
|
34
|
+
# Upstream execution feature: direct host does not attach MCP servers by default.
|
|
35
|
+
mcpServers: []
|
|
23
36
|
config:
|
|
24
37
|
# Runtime execution feature: checkpointer config passed into the selected backend adapter.
|
|
25
38
|
# Even the lightweight direct path can benefit from resumable state during interactive use.
|
|
@@ -27,6 +40,14 @@ spec:
|
|
|
27
40
|
# `path` is only used by `FileCheckpointer` and `SqliteSaver`; omit it for `MemorySaver`.
|
|
28
41
|
checkpointer:
|
|
29
42
|
ref: checkpointer/default
|
|
43
|
+
# Upstream execution feature: LangGraph store available to middleware and runtime context hooks.
|
|
44
|
+
# The default direct host keeps this enabled so middleware can use the same durable store surface as other hosts.
|
|
45
|
+
store:
|
|
46
|
+
ref: store/default
|
|
47
|
+
# Upstream execution feature: no declarative HITL tool routing by default.
|
|
48
|
+
interruptOn: {}
|
|
49
|
+
# Upstream execution feature: no extra declarative middleware beyond the runtime's automatic injections.
|
|
50
|
+
middleware: []
|
|
30
51
|
# Upstream execution feature: system prompt for the lightweight direct-response host.
|
|
31
52
|
# This prompt should keep the agent focused on:
|
|
32
53
|
# - answering simple requests in one turn
|
|
@@ -9,7 +9,10 @@ metadata:
|
|
|
9
9
|
# agent-harness feature: human-readable summary for inventory and UI.
|
|
10
10
|
description: Default execution host. Answer directly when possible, use local tools and skills first, and delegate only when a specialist is a better fit. Not a reflex delegation-only planner.
|
|
11
11
|
spec:
|
|
12
|
-
runtime:
|
|
12
|
+
runtime:
|
|
13
|
+
# agent-harness feature: host-level run data placement override.
|
|
14
|
+
# This matches the workspace default and keeps the default config shape explicit.
|
|
15
|
+
runRoot: ./.agent
|
|
13
16
|
# =====================
|
|
14
17
|
# Runtime Agent Features
|
|
15
18
|
# =====================
|
|
@@ -29,6 +32,14 @@ spec:
|
|
|
29
32
|
# Updating these files changes future agent constructions, but they are still bootstrap inputs rather than
|
|
30
33
|
# self-updating runtime memory.
|
|
31
34
|
- path: config/agent-context.md
|
|
35
|
+
# Upstream execution feature: top-level host starts with no extra direct tool refs beyond discovered workspace tools.
|
|
36
|
+
tools: []
|
|
37
|
+
# Upstream execution feature: top-level host starts with no explicit skill package refs in the default workspace.
|
|
38
|
+
skills: []
|
|
39
|
+
# Upstream execution feature: specialist topology is empty in the repository default and can be filled in YAML.
|
|
40
|
+
subagents: []
|
|
41
|
+
# Upstream execution feature: host-level MCP servers are opt-in and empty by default.
|
|
42
|
+
mcpServers: []
|
|
32
43
|
config:
|
|
33
44
|
# Runtime execution feature: checkpointer config passed into the selected backend adapter.
|
|
34
45
|
# This persists resumable graph state for this agent.
|
|
@@ -39,27 +50,27 @@ spec:
|
|
|
39
50
|
ref: checkpointer/default
|
|
40
51
|
# Upstream execution feature: store config passed into the selected backend adapter.
|
|
41
52
|
# In the default deepagent adapter this is the LangGraph store used by `StoreBackend` routes.
|
|
42
|
-
#
|
|
53
|
+
# Built-in kinds in this harness today: `FileStore`, `InMemoryStore`.
|
|
54
|
+
# Other store kinds should flow through a custom runtime resolver instead of being claimed as built in.
|
|
43
55
|
store:
|
|
44
56
|
ref: store/default
|
|
45
57
|
# Upstream execution feature: backend config passed into the selected backend adapter.
|
|
46
|
-
#
|
|
58
|
+
# Prefer a reusable backend preset via `ref` so backend topology stays declarative and reusable in YAML.
|
|
59
|
+
# The default preset keeps DeepAgent execution semantics upstream-owned:
|
|
47
60
|
# - workspace execution uses a lightweight VFS sandbox
|
|
48
61
|
# - long-term memory under `/memories/*` uses `StoreBackend`
|
|
49
62
|
# - `CompositeBackend` composes those backend instances together
|
|
50
|
-
# The harness
|
|
51
|
-
# `/memories/*` and resumable run state survive restarts in the default setup.
|
|
52
|
-
# Available top-level `kind` options in this harness: `CompositeBackend`, `StateBackend`, `StoreBackend`.
|
|
63
|
+
# The harness injects the resolved store/checkpointer instances, but the backend topology itself stays upstream-shaped.
|
|
53
64
|
backend:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
ref: backend/default
|
|
66
|
+
# Upstream execution feature: no extra declarative HITL rules by default.
|
|
67
|
+
interruptOn: {}
|
|
68
|
+
# Upstream execution feature: no extra declarative middleware beyond upstream deepagents defaults by default.
|
|
69
|
+
middleware: []
|
|
70
|
+
# Upstream execution feature: keep the built-in general-purpose subagent enabled.
|
|
71
|
+
generalPurposeAgent: true
|
|
72
|
+
# Upstream execution feature: bias the general-purpose subagent toward bounded sidecar work and context isolation.
|
|
73
|
+
taskDescription: Complete delegated sidecar work and return concise results without bloating the parent context.
|
|
63
74
|
# Upstream execution feature: system prompt for the orchestration host.
|
|
64
75
|
# This becomes the top-level instruction block for the selected execution backend and should hold the
|
|
65
76
|
# agent's durable role, priorities, and behavioral guardrails rather than bulky project facts.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# agent-harness feature: schema version for reusable backend presets.
|
|
2
|
+
apiVersion: agent-harness/v1alpha1
|
|
3
|
+
# agent-harness feature: object type for named DeepAgent backend presets.
|
|
4
|
+
kind: Backends
|
|
5
|
+
spec:
|
|
6
|
+
# upstream deepagents feature: default hybrid backend for workspace execution plus durable /memories storage.
|
|
7
|
+
- kind: Backend
|
|
8
|
+
name: default
|
|
9
|
+
description: Default DeepAgent backend preset with a virtual workspace sandbox and durable /memories storage.
|
|
10
|
+
backendKind: CompositeBackend
|
|
11
|
+
state:
|
|
12
|
+
kind: VfsSandbox
|
|
13
|
+
rootDir: .
|
|
14
|
+
virtualMode: true
|
|
15
|
+
timeout: 600
|
|
16
|
+
routes:
|
|
17
|
+
/memories/:
|
|
18
|
+
kind: StoreBackend
|
package/dist/config/stores.yaml
CHANGED
|
@@ -15,3 +15,10 @@ spec:
|
|
|
15
15
|
name: default
|
|
16
16
|
description: Default in-memory checkpointer preset for lightweight local development.
|
|
17
17
|
checkpointerKind: MemorySaver
|
|
18
|
+
|
|
19
|
+
# agent-harness feature: reusable sqlite checkpointer preset for longer-lived local runs.
|
|
20
|
+
- kind: Checkpointer
|
|
21
|
+
name: sqlite
|
|
22
|
+
description: Default sqlite-backed checkpointer preset for durable local graph state and maintenance sweeps.
|
|
23
|
+
checkpointerKind: SqliteSaver
|
|
24
|
+
path: checkpoints.sqlite
|
|
@@ -196,7 +196,6 @@ export type CompiledAgentBinding = {
|
|
|
196
196
|
config: Record<string, unknown>;
|
|
197
197
|
};
|
|
198
198
|
langchainAgentParams?: LangChainAgentParams;
|
|
199
|
-
directAgentParams?: LangChainAgentParams;
|
|
200
199
|
deepAgentParams?: DeepAgentParams;
|
|
201
200
|
harnessRuntime: {
|
|
202
201
|
runRoot: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.52";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.52";
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { CompiledAgentBinding, CompiledModel } from "../contracts/types.js";
|
|
2
|
+
type MiddlewareConfig = Record<string, unknown>;
|
|
3
|
+
type MiddlewareFactoryContext = {
|
|
4
|
+
config: MiddlewareConfig;
|
|
5
|
+
resolveModel: (model: CompiledModel) => Promise<unknown>;
|
|
6
|
+
};
|
|
7
|
+
type MiddlewareFactory = (context: MiddlewareFactoryContext) => Promise<unknown | unknown[] | null | undefined>;
|
|
8
|
+
export declare const DECLARATIVE_MIDDLEWARE_REGISTRY: Record<string, MiddlewareFactory>;
|
|
9
|
+
export declare const SUPPORTED_DECLARATIVE_MIDDLEWARE_KINDS: readonly string[];
|
|
2
10
|
export declare function resolveDeclaredMiddleware(middlewareConfigs: unknown[] | undefined, options: {
|
|
3
11
|
resolveModel: (model: CompiledModel) => Promise<unknown>;
|
|
4
12
|
resolveCustom?: (input: {
|
|
@@ -9,3 +17,4 @@ export declare function resolveDeclaredMiddleware(middlewareConfigs: unknown[] |
|
|
|
9
17
|
}) => unknown | unknown[] | null | undefined | Promise<unknown | unknown[] | null | undefined>;
|
|
10
18
|
binding?: CompiledAgentBinding;
|
|
11
19
|
}): Promise<unknown[]>;
|
|
20
|
+
export {};
|
|
@@ -25,6 +25,52 @@ async function resolveReferencedModelList(values, options) {
|
|
|
25
25
|
}
|
|
26
26
|
return Promise.all(values.map((value) => resolveReferencedModel(value, options)));
|
|
27
27
|
}
|
|
28
|
+
async function createSummarizationMiddleware({ config, resolveModel }) {
|
|
29
|
+
const runtimeConfig = { ...config };
|
|
30
|
+
runtimeConfig.model = await resolveReferencedModel(runtimeConfig.model, { resolveModel });
|
|
31
|
+
if (runtimeConfig.model === undefined) {
|
|
32
|
+
throw new Error("summarization middleware requires model or modelRef");
|
|
33
|
+
}
|
|
34
|
+
return summarizationMiddleware(runtimeConfig);
|
|
35
|
+
}
|
|
36
|
+
async function createLlmToolSelectorMiddleware({ config, resolveModel }) {
|
|
37
|
+
const runtimeConfig = { ...config };
|
|
38
|
+
runtimeConfig.model = await resolveReferencedModel(runtimeConfig.model, { resolveModel });
|
|
39
|
+
return llmToolSelectorMiddleware(runtimeConfig);
|
|
40
|
+
}
|
|
41
|
+
async function createModelFallbackDeclarativeMiddleware({ config, resolveModel }) {
|
|
42
|
+
const fallbackModels = (await resolveReferencedModelList(config.fallbackModels, { resolveModel })) ??
|
|
43
|
+
(await resolveReferencedModelList(config.models, { resolveModel }));
|
|
44
|
+
if (!fallbackModels || fallbackModels.length === 0) {
|
|
45
|
+
throw new Error("modelFallback middleware requires fallbackModels or models");
|
|
46
|
+
}
|
|
47
|
+
return modelFallbackMiddleware(...fallbackModels);
|
|
48
|
+
}
|
|
49
|
+
async function createPiiDeclarativeMiddleware({ config }) {
|
|
50
|
+
const piiType = typeof config.piiType === "string" ? config.piiType : undefined;
|
|
51
|
+
if (!piiType) {
|
|
52
|
+
throw new Error("pii middleware requires piiType");
|
|
53
|
+
}
|
|
54
|
+
const { piiType: _piiType, ...piiOptions } = config;
|
|
55
|
+
return piiMiddleware(piiType, piiOptions);
|
|
56
|
+
}
|
|
57
|
+
export const DECLARATIVE_MIDDLEWARE_REGISTRY = {
|
|
58
|
+
summarization: createSummarizationMiddleware,
|
|
59
|
+
llmToolSelector: createLlmToolSelectorMiddleware,
|
|
60
|
+
modelRetry: async ({ config }) => modelRetryMiddleware(config),
|
|
61
|
+
modelFallback: createModelFallbackDeclarativeMiddleware,
|
|
62
|
+
toolRetry: async ({ config }) => toolRetryMiddleware(config),
|
|
63
|
+
toolCallLimit: async ({ config }) => toolCallLimitMiddleware(config),
|
|
64
|
+
modelCallLimit: async ({ config }) => modelCallLimitMiddleware(config),
|
|
65
|
+
todoList: async ({ config }) => todoListMiddleware(config),
|
|
66
|
+
contextEditing: async ({ config }) => contextEditingMiddleware(config),
|
|
67
|
+
toolEmulator: async ({ config }) => toolEmulatorMiddleware(config),
|
|
68
|
+
humanInTheLoop: async ({ config }) => humanInTheLoopMiddleware(config),
|
|
69
|
+
openAIModeration: async ({ config }) => openAIModerationMiddleware(config),
|
|
70
|
+
pii: createPiiDeclarativeMiddleware,
|
|
71
|
+
anthropicPromptCaching: async ({ config }) => anthropicPromptCachingMiddleware(config),
|
|
72
|
+
};
|
|
73
|
+
export const SUPPORTED_DECLARATIVE_MIDDLEWARE_KINDS = Object.freeze(Object.keys(DECLARATIVE_MIDDLEWARE_REGISTRY).sort());
|
|
28
74
|
export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
|
|
29
75
|
const resolved = [];
|
|
30
76
|
for (const rawConfig of middlewareConfigs ?? []) {
|
|
@@ -34,87 +80,38 @@ export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
|
|
|
34
80
|
}
|
|
35
81
|
const kind = requireKind(config);
|
|
36
82
|
const runtimeConfig = omitKind(config);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
83
|
+
const registeredFactory = DECLARATIVE_MIDDLEWARE_REGISTRY[kind];
|
|
84
|
+
if (registeredFactory) {
|
|
85
|
+
const resolvedBuiltin = await registeredFactory({
|
|
86
|
+
config: runtimeConfig,
|
|
87
|
+
resolveModel: options.resolveModel,
|
|
88
|
+
});
|
|
89
|
+
if (Array.isArray(resolvedBuiltin)) {
|
|
90
|
+
resolved.push(...resolvedBuiltin);
|
|
91
|
+
continue;
|
|
45
92
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
break;
|
|
50
|
-
case "modelRetry":
|
|
51
|
-
resolved.push(modelRetryMiddleware(runtimeConfig));
|
|
52
|
-
break;
|
|
53
|
-
case "modelFallback": {
|
|
54
|
-
const fallbackModels = (await resolveReferencedModelList(runtimeConfig.fallbackModels, options)) ??
|
|
55
|
-
(await resolveReferencedModelList(runtimeConfig.models, options));
|
|
56
|
-
if (!fallbackModels || fallbackModels.length === 0) {
|
|
57
|
-
throw new Error("modelFallback middleware requires fallbackModels or models");
|
|
58
|
-
}
|
|
59
|
-
resolved.push(modelFallbackMiddleware(...fallbackModels));
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
case "toolRetry":
|
|
63
|
-
resolved.push(toolRetryMiddleware(runtimeConfig));
|
|
64
|
-
break;
|
|
65
|
-
case "toolCallLimit":
|
|
66
|
-
resolved.push(toolCallLimitMiddleware(runtimeConfig));
|
|
67
|
-
break;
|
|
68
|
-
case "modelCallLimit":
|
|
69
|
-
resolved.push(modelCallLimitMiddleware(runtimeConfig));
|
|
70
|
-
break;
|
|
71
|
-
case "todoList":
|
|
72
|
-
resolved.push(todoListMiddleware(runtimeConfig));
|
|
73
|
-
break;
|
|
74
|
-
case "contextEditing":
|
|
75
|
-
resolved.push(contextEditingMiddleware(runtimeConfig));
|
|
76
|
-
break;
|
|
77
|
-
case "toolEmulator":
|
|
78
|
-
resolved.push(toolEmulatorMiddleware(runtimeConfig));
|
|
79
|
-
break;
|
|
80
|
-
case "humanInTheLoop":
|
|
81
|
-
resolved.push(humanInTheLoopMiddleware(runtimeConfig));
|
|
82
|
-
break;
|
|
83
|
-
case "openAIModeration":
|
|
84
|
-
resolved.push(openAIModerationMiddleware(runtimeConfig));
|
|
85
|
-
break;
|
|
86
|
-
case "pii": {
|
|
87
|
-
const piiType = typeof runtimeConfig.piiType === "string" ? runtimeConfig.piiType : undefined;
|
|
88
|
-
if (!piiType) {
|
|
89
|
-
throw new Error("pii middleware requires piiType");
|
|
90
|
-
}
|
|
91
|
-
const { piiType: _piiType, ...piiOptions } = runtimeConfig;
|
|
92
|
-
resolved.push(piiMiddleware(piiType, piiOptions));
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
case "anthropicPromptCaching":
|
|
96
|
-
resolved.push(anthropicPromptCachingMiddleware(runtimeConfig));
|
|
97
|
-
break;
|
|
98
|
-
default: {
|
|
99
|
-
const customResolved = options.resolveCustom
|
|
100
|
-
? await options.resolveCustom({
|
|
101
|
-
kind,
|
|
102
|
-
config: runtimeConfig,
|
|
103
|
-
binding: options.binding,
|
|
104
|
-
resolveModel: options.resolveModel,
|
|
105
|
-
})
|
|
106
|
-
: undefined;
|
|
107
|
-
if (Array.isArray(customResolved)) {
|
|
108
|
-
resolved.push(...customResolved);
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
if (customResolved) {
|
|
112
|
-
resolved.push(customResolved);
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
throw new Error(`Unsupported declarative middleware kind ${kind}`);
|
|
93
|
+
if (resolvedBuiltin) {
|
|
94
|
+
resolved.push(resolvedBuiltin);
|
|
95
|
+
continue;
|
|
116
96
|
}
|
|
117
97
|
}
|
|
98
|
+
const customResolved = options.resolveCustom
|
|
99
|
+
? await options.resolveCustom({
|
|
100
|
+
kind,
|
|
101
|
+
config: runtimeConfig,
|
|
102
|
+
binding: options.binding,
|
|
103
|
+
resolveModel: options.resolveModel,
|
|
104
|
+
})
|
|
105
|
+
: undefined;
|
|
106
|
+
if (Array.isArray(customResolved)) {
|
|
107
|
+
resolved.push(...customResolved);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (customResolved) {
|
|
111
|
+
resolved.push(customResolved);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`Unsupported declarative middleware kind ${kind}`);
|
|
118
115
|
}
|
|
119
116
|
return resolved;
|
|
120
117
|
}
|
|
@@ -127,14 +127,22 @@ function resolveInterruptOn(agent) {
|
|
|
127
127
|
return (agent.deepAgentConfig?.interruptOn ??
|
|
128
128
|
agent.langchainAgentConfig?.interruptOn);
|
|
129
129
|
}
|
|
130
|
-
function resolveBackendConfig(agent) {
|
|
130
|
+
function resolveBackendConfig(agent, refs) {
|
|
131
131
|
if (agent.executionMode !== "deepagent") {
|
|
132
132
|
return undefined;
|
|
133
133
|
}
|
|
134
134
|
const backendConfig = typeof agent.deepAgentConfig?.backend === "object" && agent.deepAgentConfig.backend
|
|
135
135
|
? agent.deepAgentConfig.backend
|
|
136
136
|
: undefined;
|
|
137
|
-
|
|
137
|
+
if (!backendConfig) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
if (isRefConfig(backendConfig)) {
|
|
141
|
+
return {
|
|
142
|
+
config: materializeWorkspaceObjectConfig(refs, backendConfig.ref, ["backend"], `Agent ${agent.id} backend`),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return { config: backendConfig };
|
|
138
146
|
}
|
|
139
147
|
function isRefConfig(value) {
|
|
140
148
|
if (typeof value?.ref !== "string" || value.ref.trim().length === 0) {
|
|
@@ -161,6 +169,11 @@ function materializeWorkspaceObjectConfig(refs, ref, allowedKinds, ownerLabel) {
|
|
|
161
169
|
const { checkpointerKind: _checkpointerKind, ...rest } = config;
|
|
162
170
|
return checkpointerKind ? { kind: checkpointerKind, ...rest } : config;
|
|
163
171
|
}
|
|
172
|
+
if (object.kind === "backend") {
|
|
173
|
+
const backendKind = typeof config.backendKind === "string" ? config.backendKind : undefined;
|
|
174
|
+
const { backendKind: _backendKind, ...rest } = config;
|
|
175
|
+
return backendKind ? { kind: backendKind, ...rest } : config;
|
|
176
|
+
}
|
|
164
177
|
return config;
|
|
165
178
|
}
|
|
166
179
|
function resolveStoreConfig(agent, refs) {
|
|
@@ -208,7 +221,7 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
208
221
|
const compiledAgentSkills = compileAgentSkills(workspaceRoot, agent);
|
|
209
222
|
const compiledAgentMemory = compileAgentMemories(workspaceRoot, agent.memorySources);
|
|
210
223
|
const compiledAgentModel = requireModel(models, agent.modelRef || (internalSubagent ? "model/default" : ""), agent.id);
|
|
211
|
-
const backend = resolveBackendConfig(agent);
|
|
224
|
+
const backend = resolveBackendConfig(agent, refs);
|
|
212
225
|
const store = resolveStoreConfig(agent, refs);
|
|
213
226
|
const checkpointer = resolveCheckpointerConfig(agent, refs);
|
|
214
227
|
const runRoot = typeof agent.runRoot === "string" && agent.runRoot.trim().length > 0
|
|
@@ -281,7 +294,6 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
281
294
|
},
|
|
282
295
|
},
|
|
283
296
|
langchainAgentParams,
|
|
284
|
-
directAgentParams: langchainAgentParams,
|
|
285
297
|
};
|
|
286
298
|
}
|
|
287
299
|
const deepAgentParams = {
|
|
@@ -242,11 +242,12 @@ function readPassthroughConfig(item, consumedKeys) {
|
|
|
242
242
|
}
|
|
243
243
|
function resolveExecutionBackend(item, current) {
|
|
244
244
|
const execution = readExecutionConfig(item.execution) ?? readExecutionConfig(current?.execution);
|
|
245
|
+
if (typeof execution?.mode === "string" && execution.mode.trim().length > 0) {
|
|
246
|
+
throw new Error("Agent execution.mode is no longer supported; use execution.backend");
|
|
247
|
+
}
|
|
245
248
|
const backend = typeof execution?.backend === "string"
|
|
246
249
|
? execution.backend.trim().toLowerCase()
|
|
247
|
-
:
|
|
248
|
-
? execution.mode.trim().toLowerCase()
|
|
249
|
-
: undefined;
|
|
250
|
+
: undefined;
|
|
250
251
|
if (backend === "langchain-v1") {
|
|
251
252
|
return "langchain-v1";
|
|
252
253
|
}
|
|
@@ -377,11 +378,13 @@ async function objectItemsFromDocument(document, sourcePath) {
|
|
|
377
378
|
? normalizeCatalogSpec(document, { defaultKind: "Model" })
|
|
378
379
|
: catalogKind === "Stores"
|
|
379
380
|
? normalizeCatalogSpec(document)
|
|
380
|
-
: catalogKind === "
|
|
381
|
-
? normalizeCatalogSpec(document, { defaultKind: "
|
|
382
|
-
: catalogKind === "
|
|
383
|
-
? normalizeCatalogSpec(document)
|
|
384
|
-
:
|
|
381
|
+
: catalogKind === "Backends"
|
|
382
|
+
? normalizeCatalogSpec(document, { defaultKind: "Backend" })
|
|
383
|
+
: catalogKind === "Tools"
|
|
384
|
+
? normalizeCatalogSpec(document, { defaultKind: "Tool" })
|
|
385
|
+
: catalogKind === "McpServers"
|
|
386
|
+
? normalizeCatalogSpec(document)
|
|
387
|
+
: [];
|
|
385
388
|
if (catalogItems.length > 0) {
|
|
386
389
|
return catalogItems;
|
|
387
390
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botbotgo/agent-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.53",
|
|
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-capabilities.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/yaml-format.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/stock-research-app-config.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-capabilities.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/yaml-format.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",
|