@botbotgo/agent-harness 0.0.48 → 0.0.49
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 +120 -318
- package/dist/contracts/types.d.ts +5 -3
- package/dist/extensions.js +38 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/resource/resource-impl.js +0 -6
- package/dist/runtime/agent-runtime-adapter.d.ts +2 -0
- package/dist/runtime/agent-runtime-adapter.js +77 -5
- package/dist/runtime/declared-middleware.js +13 -1
- package/dist/runtime/harness.js +3 -3
- package/dist/workspace/agent-binding-compiler.js +13 -0
- package/dist/workspace/object-loader.js +8 -21
- package/dist/workspace/resource-compilers.js +11 -4
- package/dist/workspace/support/agent-capabilities.js +2 -2
- package/dist/workspace/support/workspace-ref-utils.d.ts +0 -5
- package/dist/workspace/support/workspace-ref-utils.js +1 -11
- package/dist/workspace/validate.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,20 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
`@botbotgo/agent-harness` is a workspace-shaped application runtime for real agent products.
|
|
6
6
|
|
|
7
|
-
It is not a new agent framework. It is the layer
|
|
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 product boundary is:
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
- application runtime
|
|
11
|
+
- LangChain v1 and DeepAgents own agent execution semantics
|
|
12
|
+
- `agent-harness` owns application runtime semantics
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
That means:
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
- public API stays small
|
|
17
|
+
- complex assembly and policy live in YAML
|
|
18
|
+
- runtime lifecycle stays stable even if the backend implementation changes
|
|
19
|
+
|
|
20
|
+
What the runtime provides:
|
|
21
|
+
|
|
22
|
+
- `createAgentHarness(...)`, `run(...)`, `subscribe(...)`, inspection methods, and `stop(...)`
|
|
23
|
+
- YAML-defined workspace assembly for routing, models, tools, stores, MCP, recovery, and maintenance
|
|
24
|
+
- backend-adapted execution with current LangChain v1 and DeepAgents adapters
|
|
25
|
+
- local `resources/tools/` and `resources/skills/` discovery
|
|
26
|
+
- persisted threads, runs, approvals, events, queue state, and recovery metadata
|
|
21
27
|
|
|
22
28
|
## Quick Start
|
|
23
29
|
|
|
@@ -32,8 +38,8 @@ Workspace layout:
|
|
|
32
38
|
```text
|
|
33
39
|
your-workspace/
|
|
34
40
|
config/
|
|
35
|
-
agent-context.md
|
|
36
41
|
workspace.yaml
|
|
42
|
+
agent-context.md
|
|
37
43
|
models.yaml
|
|
38
44
|
embedding-models.yaml
|
|
39
45
|
vector-stores.yaml
|
|
@@ -71,15 +77,14 @@ try {
|
|
|
71
77
|
## Feature List
|
|
72
78
|
|
|
73
79
|
- Workspace runtime for multi-agent applications
|
|
74
|
-
-
|
|
75
|
-
- YAML-defined host routing
|
|
80
|
+
- Small public runtime contract
|
|
81
|
+
- YAML-defined host routing and runtime policy
|
|
82
|
+
- LangChain v1 and DeepAgents backend adaptation
|
|
76
83
|
- Auto-discovered local tools and SKILL packages
|
|
77
84
|
- MCP bridge support for agent-declared MCP servers
|
|
78
85
|
- MCP server support for exposing harness tools outward
|
|
79
|
-
- Persisted threads, runs, approvals, and
|
|
80
|
-
-
|
|
81
|
-
- Background checkpoint maintenance
|
|
82
|
-
- Runtime-level concurrency control and queued-run persistence
|
|
86
|
+
- Persisted threads, runs, approvals, lifecycle events, and queued runs
|
|
87
|
+
- Runtime-managed recovery and checkpoint maintenance
|
|
83
88
|
|
|
84
89
|
## How To Use
|
|
85
90
|
|
|
@@ -91,8 +96,6 @@ import { AgentHarnessRuntime, createAgentHarness } from "@botbotgo/agent-harness
|
|
|
91
96
|
const runtime: AgentHarnessRuntime = await createAgentHarness("/absolute/path/to/workspace");
|
|
92
97
|
```
|
|
93
98
|
|
|
94
|
-
You can also create a runtime from a precompiled `WorkspaceBundle`.
|
|
95
|
-
|
|
96
99
|
`createAgentHarness(...)` loads one workspace, resolves `resources/`, initializes persistence under `runRoot`, and starts runtime maintenance.
|
|
97
100
|
|
|
98
101
|
### Run A Request
|
|
@@ -103,25 +106,28 @@ import { run } from "@botbotgo/agent-harness";
|
|
|
103
106
|
const result = await run(runtime, {
|
|
104
107
|
agentId: "orchestra",
|
|
105
108
|
input: "Summarize the runtime design.",
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
invocation: {
|
|
110
|
+
context: {
|
|
111
|
+
requestId: "req-123",
|
|
112
|
+
},
|
|
113
|
+
inputs: {
|
|
114
|
+
visitCount: 1,
|
|
115
|
+
},
|
|
116
|
+
attachments: {
|
|
117
|
+
"/tmp/spec.md": { content: "draft" },
|
|
118
|
+
},
|
|
111
119
|
},
|
|
112
120
|
});
|
|
113
121
|
```
|
|
114
122
|
|
|
115
123
|
Each run creates or continues a persisted thread and returns `threadId`, `runId`, `state`, and the final user-facing output text.
|
|
116
124
|
|
|
117
|
-
|
|
125
|
+
Use `invocation` as the runtime-facing request envelope:
|
|
118
126
|
|
|
119
|
-
- `invocation.context` for request-scoped context
|
|
127
|
+
- `invocation.context` for request-scoped execution context
|
|
120
128
|
- `invocation.inputs` for additional structured runtime inputs
|
|
121
129
|
- `invocation.attachments` for attachment-like payloads that the active backend can interpret
|
|
122
130
|
|
|
123
|
-
For compatibility, `context`, `state`, and `files` are still accepted as existing aliases and are normalized into the same runtime invocation envelope.
|
|
124
|
-
|
|
125
131
|
### Let The Runtime Route
|
|
126
132
|
|
|
127
133
|
```ts
|
|
@@ -152,7 +158,7 @@ const result = await run(runtime, {
|
|
|
152
158
|
|
|
153
159
|
`subscribe(...)` is a read-only observer surface over stored lifecycle events.
|
|
154
160
|
|
|
155
|
-
The event stream includes:
|
|
161
|
+
The runtime event stream includes:
|
|
156
162
|
|
|
157
163
|
- `run.created`
|
|
158
164
|
- `run.queued`
|
|
@@ -183,14 +189,18 @@ These methods return runtime-facing records, not raw persistence or backend chec
|
|
|
183
189
|
### Bridge MCP Servers Into Agents
|
|
184
190
|
|
|
185
191
|
```yaml
|
|
192
|
+
apiVersion: agent-harness/v1alpha1
|
|
193
|
+
kind: Agent
|
|
194
|
+
metadata:
|
|
195
|
+
name: orchestra
|
|
186
196
|
spec:
|
|
197
|
+
execution:
|
|
198
|
+
backend: deepagent
|
|
199
|
+
modelRef: model/default
|
|
187
200
|
mcpServers:
|
|
188
201
|
- name: browser
|
|
189
202
|
command: node
|
|
190
203
|
args: ["./mcp-browser-server.mjs"]
|
|
191
|
-
- name: docs
|
|
192
|
-
transport: http
|
|
193
|
-
url: https://example.com/mcp
|
|
194
204
|
```
|
|
195
205
|
|
|
196
206
|
The runtime discovers MCP tools, filters them through agent configuration, and exposes them like other tools.
|
|
@@ -214,6 +224,11 @@ await stop(runtime);
|
|
|
214
224
|
|
|
215
225
|
## How To Configure
|
|
216
226
|
|
|
227
|
+
Use Kubernetes-style YAML:
|
|
228
|
+
|
|
229
|
+
- collection files use `apiVersion`, plural `kind`, and `spec: []`
|
|
230
|
+
- single-object files use `apiVersion`, singular `kind`, `metadata`, and `spec`
|
|
231
|
+
|
|
217
232
|
Core workspace files:
|
|
218
233
|
|
|
219
234
|
- `config/workspace.yaml`
|
|
@@ -226,24 +241,14 @@ Core workspace files:
|
|
|
226
241
|
- `config/mcp.yaml`
|
|
227
242
|
- `config/agents/direct.yaml`
|
|
228
243
|
- `config/agents/orchestra.yaml`
|
|
229
|
-
- `resources/package.json`
|
|
230
244
|
- `resources/tools/`
|
|
231
245
|
- `resources/skills/`
|
|
232
246
|
|
|
233
|
-
Use Kubernetes-style YAML:
|
|
234
|
-
|
|
235
|
-
- collection files use `apiVersion`, plural `kind`, and `spec: []`
|
|
236
|
-
- single-object files use `apiVersion`, singular `kind`, `metadata`, and `spec`
|
|
237
|
-
|
|
238
|
-
Use distinct names for named objects such as models, stores, checkpointers, tools, and MCP servers.
|
|
239
|
-
|
|
240
247
|
### Client-Configurable YAML Reference
|
|
241
248
|
|
|
242
|
-
|
|
249
|
+
There are three configuration layers:
|
|
243
250
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
- runtime-level policy in `config/workspace.yaml`
|
|
251
|
+
- runtime policy in `config/workspace.yaml`
|
|
247
252
|
- reusable object catalogs in `config/*.yaml`
|
|
248
253
|
- agent assembly in `config/agents/*.yaml`
|
|
249
254
|
|
|
@@ -253,92 +258,30 @@ Use this file for runtime-level policy shared by the whole workspace.
|
|
|
253
258
|
|
|
254
259
|
Primary fields:
|
|
255
260
|
|
|
256
|
-
- `runRoot
|
|
257
|
-
- `
|
|
258
|
-
- `routing.
|
|
259
|
-
- `routing.
|
|
260
|
-
- `routing.
|
|
261
|
-
- `
|
|
262
|
-
- `
|
|
263
|
-
- `recovery.
|
|
264
|
-
- `recovery.resumeResumingRunsOnStartup
|
|
265
|
-
- `recovery.maxRecoveryAttempts
|
|
266
|
-
- `maintenance.checkpoints.enabled`: turns on background checkpoint cleanup
|
|
267
|
-
- `maintenance.checkpoints.schedule.intervalSeconds`: maintenance loop interval
|
|
268
|
-
- `maintenance.checkpoints.schedule.runOnStartup`: run checkpoint cleanup during startup
|
|
269
|
-
- `maintenance.checkpoints.policies.maxAgeSeconds`: age-based checkpoint cleanup
|
|
270
|
-
- `maintenance.checkpoints.policies.maxBytes`: size-based checkpoint cleanup
|
|
271
|
-
- `maintenance.checkpoints.sqlite.sweepBatchSize`: batch size for SQLite cleanup scans
|
|
272
|
-
- `maintenance.checkpoints.sqlite.vacuum`: vacuum SQLite after deletions
|
|
261
|
+
- `runRoot`
|
|
262
|
+
- `concurrency.maxConcurrentRuns`
|
|
263
|
+
- `routing.defaultAgentId`
|
|
264
|
+
- `routing.rules`
|
|
265
|
+
- `routing.systemPrompt`
|
|
266
|
+
- `routing.modelRouting`
|
|
267
|
+
- `maintenance.checkpoints`
|
|
268
|
+
- `recovery.enabled`
|
|
269
|
+
- `recovery.resumeResumingRunsOnStartup`
|
|
270
|
+
- `recovery.maxRecoveryAttempts`
|
|
273
271
|
|
|
274
272
|
If `runRoot` is omitted, the runtime defaults to `<workspace-root>/run-data`.
|
|
275
273
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
```yaml
|
|
279
|
-
apiVersion: agent-harness/v1alpha1
|
|
280
|
-
kind: Runtime
|
|
281
|
-
metadata:
|
|
282
|
-
name: default
|
|
283
|
-
spec:
|
|
284
|
-
runRoot: ./.agent
|
|
285
|
-
concurrency:
|
|
286
|
-
maxConcurrentRuns: 3
|
|
287
|
-
routing:
|
|
288
|
-
defaultAgentId: orchestra
|
|
289
|
-
modelRouting: false
|
|
290
|
-
rules:
|
|
291
|
-
- agentId: orchestra
|
|
292
|
-
contains: ["latest", "recent", "today", "news"]
|
|
293
|
-
- agentId: orchestra
|
|
294
|
-
regex:
|
|
295
|
-
- "\\b(create|build|implement|fix|debug|review|inspect)\\b"
|
|
296
|
-
maintenance:
|
|
297
|
-
checkpoints:
|
|
298
|
-
enabled: true
|
|
299
|
-
schedule:
|
|
300
|
-
intervalSeconds: 3600
|
|
301
|
-
runOnStartup: true
|
|
302
|
-
policies:
|
|
303
|
-
maxAgeSeconds: 604800
|
|
304
|
-
sqlite:
|
|
305
|
-
sweepBatchSize: 200
|
|
306
|
-
vacuum: false
|
|
307
|
-
recovery:
|
|
308
|
-
enabled: true
|
|
309
|
-
resumeResumingRunsOnStartup: true
|
|
310
|
-
maxRecoveryAttempts: 3
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
Notes:
|
|
314
|
-
|
|
315
|
-
- `routing.rules` only choose the starting host agent; they do not replace backend planning semantics
|
|
316
|
-
- queued runs are persisted under `runRoot` and continue after process restart
|
|
317
|
-
- `running` runs are only replayed on startup when the bound tools are retryable
|
|
274
|
+
Queued runs are persisted under `runRoot` and continue after process restart. `running` runs are only replayed on startup when the bound tools are retryable.
|
|
318
275
|
|
|
319
276
|
### `config/agent-context.md`
|
|
320
277
|
|
|
321
|
-
Use this file for shared
|
|
278
|
+
Use this file for shared bootstrap context loaded into agents at construction time.
|
|
322
279
|
|
|
323
280
|
Put stable project context here. Do not use it as mutable long-term memory.
|
|
324
281
|
|
|
325
|
-
Good uses:
|
|
326
|
-
|
|
327
|
-
- product positioning
|
|
328
|
-
- codebase conventions
|
|
329
|
-
- stable domain vocabulary
|
|
330
|
-
- organization-specific rules
|
|
331
|
-
|
|
332
|
-
Bad uses:
|
|
333
|
-
|
|
334
|
-
- transient scratch notes
|
|
335
|
-
- per-run execution state
|
|
336
|
-
- approval packets
|
|
337
|
-
- long-term memory that should live in the store
|
|
338
|
-
|
|
339
282
|
### `config/models.yaml`
|
|
340
283
|
|
|
341
|
-
Use
|
|
284
|
+
Use named chat-model presets:
|
|
342
285
|
|
|
343
286
|
```yaml
|
|
344
287
|
apiVersion: agent-harness/v1alpha1
|
|
@@ -348,80 +291,21 @@ spec:
|
|
|
348
291
|
provider: openai
|
|
349
292
|
model: gpt-4.1
|
|
350
293
|
temperature: 0.2
|
|
351
|
-
- name: planner
|
|
352
|
-
provider: openai
|
|
353
|
-
model: gpt-4.1-mini
|
|
354
294
|
```
|
|
355
295
|
|
|
356
|
-
These load as `model
|
|
357
|
-
|
|
358
|
-
Client-configurable model fields:
|
|
359
|
-
|
|
360
|
-
- `name`: catalog name referenced by `model/<name>`
|
|
361
|
-
- `provider`: provider family such as `openai`, `openai-compatible`, `ollama`, `anthropic`, or `google`
|
|
362
|
-
- `model`: provider model id
|
|
363
|
-
- top-level provider init fields such as `temperature`, `baseUrl`, API-specific settings, and client options
|
|
364
|
-
- `clientRef`: optional external client reference
|
|
365
|
-
- `fallbacks`: optional fallback model refs
|
|
366
|
-
- `metadata`: optional model metadata
|
|
296
|
+
These load as `model/<name>`.
|
|
367
297
|
|
|
368
298
|
### `config/embedding-models.yaml`
|
|
369
299
|
|
|
370
|
-
Use
|
|
371
|
-
|
|
372
|
-
```yaml
|
|
373
|
-
apiVersion: agent-harness/v1alpha1
|
|
374
|
-
kind: EmbeddingModels
|
|
375
|
-
spec:
|
|
376
|
-
- name: default
|
|
377
|
-
provider: ollama
|
|
378
|
-
model: nomic-embed-text
|
|
379
|
-
baseUrl: http://localhost:11434
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
Client-configurable embedding fields:
|
|
383
|
-
|
|
384
|
-
- `name`
|
|
385
|
-
- `provider`
|
|
386
|
-
- `model`
|
|
387
|
-
- top-level provider init fields such as `baseUrl`
|
|
388
|
-
- `clientRef`
|
|
389
|
-
- `metadata`
|
|
390
|
-
|
|
391
|
-
These load as `embedding-model/default`.
|
|
300
|
+
Use named embedding-model presets for retrieval-oriented tools.
|
|
392
301
|
|
|
393
302
|
### `config/vector-stores.yaml`
|
|
394
303
|
|
|
395
|
-
Use
|
|
396
|
-
|
|
397
|
-
```yaml
|
|
398
|
-
apiVersion: agent-harness/v1alpha1
|
|
399
|
-
kind: VectorStores
|
|
400
|
-
spec:
|
|
401
|
-
- name: default
|
|
402
|
-
storeKind: LibSQLVectorStore
|
|
403
|
-
url: file:.agent/vector-store.db
|
|
404
|
-
table: rag_chunks
|
|
405
|
-
column: embedding
|
|
406
|
-
embeddingModelRef: embedding-model/default
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
Client-configurable vector store fields:
|
|
410
|
-
|
|
411
|
-
- `name`
|
|
412
|
-
- `storeKind`
|
|
413
|
-
- `url`
|
|
414
|
-
- `authToken`
|
|
415
|
-
- `table`
|
|
416
|
-
- `column`
|
|
417
|
-
- `embeddingModelRef`
|
|
418
|
-
- `metadata`
|
|
419
|
-
|
|
420
|
-
These load as `vector-store/default`.
|
|
304
|
+
Use named vector-store presets referenced by retrieval tools.
|
|
421
305
|
|
|
422
306
|
### `config/stores.yaml`
|
|
423
307
|
|
|
424
|
-
Use
|
|
308
|
+
Use reusable store and checkpointer presets:
|
|
425
309
|
|
|
426
310
|
```yaml
|
|
427
311
|
apiVersion: agent-harness/v1alpha1
|
|
@@ -436,119 +320,31 @@ spec:
|
|
|
436
320
|
checkpointerKind: MemorySaver
|
|
437
321
|
```
|
|
438
322
|
|
|
439
|
-
These load as `store/default` and `checkpointer/default`.
|
|
440
|
-
|
|
441
|
-
Client-configurable store fields:
|
|
442
|
-
|
|
443
|
-
- `kind: Store` for backend stores
|
|
444
|
-
- `kind: Checkpointer` for resumable execution state
|
|
445
|
-
- `name` for refs
|
|
446
|
-
- `storeKind` such as `FileStore`, `InMemoryStore`, `RedisStore`, `PostgresStore`
|
|
447
|
-
- `checkpointerKind` such as `MemorySaver`, `FileCheckpointer`, `SqliteSaver`
|
|
448
|
-
- storage-specific fields such as `path`, connection strings, auth, and provider options
|
|
449
|
-
|
|
450
323
|
### `config/tools.yaml`
|
|
451
324
|
|
|
452
|
-
Use this file for reusable tool
|
|
453
|
-
|
|
454
|
-
Minimal collection form:
|
|
325
|
+
Use this file for reusable tool objects.
|
|
455
326
|
|
|
456
|
-
|
|
457
|
-
apiVersion: agent-harness/v1alpha1
|
|
458
|
-
kind: Tools
|
|
459
|
-
spec:
|
|
460
|
-
- kind: Tool
|
|
461
|
-
name: fetch_docs
|
|
462
|
-
type: function
|
|
463
|
-
description: Fetch a documentation page.
|
|
464
|
-
```
|
|
327
|
+
Supported tool families in the built-in runtime include:
|
|
465
328
|
|
|
466
|
-
|
|
329
|
+
- function tools
|
|
330
|
+
- backend tools
|
|
331
|
+
- MCP tools
|
|
332
|
+
- provider-native tools
|
|
333
|
+
- bundles
|
|
467
334
|
|
|
468
|
-
-
|
|
469
|
-
- `type`: `function`, `backend`, `mcp`, or `bundle`
|
|
470
|
-
- `description`
|
|
471
|
-
- `implementationName` for local JS tool modules
|
|
472
|
-
- `inputSchema.ref`
|
|
473
|
-
- `backend.operation`
|
|
474
|
-
- `mcp.ref` or `mcp.tool`
|
|
475
|
-
- `refs` for bundle composition
|
|
476
|
-
- `hitl.enabled` and `hitl.allow` for approval-gated tools
|
|
477
|
-
- `retryable: true` for tools that are safe to replay during startup recovery
|
|
478
|
-
- `config` for tool-specific options
|
|
335
|
+
Provider-native tools are declared in YAML and resolved directly to upstream provider tool factories such as OpenAI and Anthropic tool objects.
|
|
479
336
|
|
|
480
337
|
Use `retryable` carefully. Mark a tool retryable only when repeated execution is safe or intentionally idempotent.
|
|
481
338
|
|
|
482
339
|
### `config/mcp.yaml`
|
|
483
340
|
|
|
484
|
-
Use this file for
|
|
485
|
-
|
|
486
|
-
```yaml
|
|
487
|
-
apiVersion: agent-harness/v1alpha1
|
|
488
|
-
kind: McpServers
|
|
489
|
-
spec:
|
|
490
|
-
- name: docs
|
|
491
|
-
transport: http
|
|
492
|
-
url: https://example.com/mcp
|
|
493
|
-
- name: local-browser
|
|
494
|
-
transport: stdio
|
|
495
|
-
command: node
|
|
496
|
-
args: ["./mcp-browser-server.mjs"]
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
Client-configurable MCP fields:
|
|
500
|
-
|
|
501
|
-
- `name`
|
|
502
|
-
- `transport`: `stdio`, `http`, `sse`, or `websocket`
|
|
503
|
-
- `command`, `args`, `env`, `cwd` for stdio servers
|
|
504
|
-
- `url`, `token`, `headers` for network servers
|
|
505
|
-
|
|
506
|
-
These load as `mcp/<name>`.
|
|
341
|
+
Use this file for named MCP server presets.
|
|
507
342
|
|
|
508
343
|
### `config/agents/*.yaml`
|
|
509
344
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
```yaml
|
|
513
|
-
apiVersion: agent-harness/v1alpha1
|
|
514
|
-
kind: Agent
|
|
515
|
-
metadata:
|
|
516
|
-
name: orchestra
|
|
517
|
-
spec:
|
|
518
|
-
modelRef: model/default
|
|
519
|
-
execution:
|
|
520
|
-
backend: deepagent
|
|
521
|
-
systemPrompt: Coordinate the request.
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
Only `kind: Agent` is supported for agent objects. Select the concrete backend with `spec.execution.backend`.
|
|
525
|
-
|
|
526
|
-
Common client-configurable agent fields:
|
|
527
|
-
|
|
528
|
-
- `metadata.name`
|
|
529
|
-
- `metadata.description`
|
|
530
|
-
- `spec.execution.backend`
|
|
531
|
-
- `spec.modelRef`
|
|
532
|
-
- `spec.systemPrompt`
|
|
533
|
-
- `spec.tools`
|
|
534
|
-
- `spec.skills`
|
|
535
|
-
- `spec.memory`
|
|
536
|
-
- `spec.checkpointer`
|
|
537
|
-
- `spec.store`
|
|
538
|
-
- `spec.backend`
|
|
539
|
-
- `spec.middleware`
|
|
540
|
-
- `spec.subagents`
|
|
541
|
-
- `spec.mcpServers`
|
|
542
|
-
- `spec.responseFormat`
|
|
543
|
-
- `spec.contextSchema`
|
|
544
|
-
|
|
545
|
-
Typical patterns:
|
|
345
|
+
Agents are always declared with `kind: Agent` and `spec.execution.backend`.
|
|
546
346
|
|
|
547
|
-
|
|
548
|
-
- use `orchestra` as the main execution host for tools, multi-step work, and delegation
|
|
549
|
-
- keep routing policy in `config/workspace.yaml`, not buried in prompts
|
|
550
|
-
|
|
551
|
-
Example direct agent:
|
|
347
|
+
Example lightweight host:
|
|
552
348
|
|
|
553
349
|
```yaml
|
|
554
350
|
apiVersion: agent-harness/v1alpha1
|
|
@@ -561,12 +357,10 @@ spec:
|
|
|
561
357
|
modelRef: model/default
|
|
562
358
|
checkpointer:
|
|
563
359
|
ref: checkpointer/default
|
|
564
|
-
systemPrompt:
|
|
565
|
-
You are the direct agent.
|
|
566
|
-
Answer simple requests directly.
|
|
360
|
+
systemPrompt: Answer simple requests directly.
|
|
567
361
|
```
|
|
568
362
|
|
|
569
|
-
Example
|
|
363
|
+
Example main execution host:
|
|
570
364
|
|
|
571
365
|
```yaml
|
|
572
366
|
apiVersion: agent-harness/v1alpha1
|
|
@@ -593,6 +387,25 @@ spec:
|
|
|
593
387
|
kind: StoreBackend
|
|
594
388
|
```
|
|
595
389
|
|
|
390
|
+
Client-configurable agent fields include:
|
|
391
|
+
|
|
392
|
+
- `metadata.name`
|
|
393
|
+
- `metadata.description`
|
|
394
|
+
- `spec.execution.backend`
|
|
395
|
+
- `spec.modelRef`
|
|
396
|
+
- `spec.systemPrompt`
|
|
397
|
+
- `spec.tools`
|
|
398
|
+
- `spec.skills`
|
|
399
|
+
- `spec.memory`
|
|
400
|
+
- `spec.checkpointer`
|
|
401
|
+
- `spec.store`
|
|
402
|
+
- `spec.backend`
|
|
403
|
+
- `spec.middleware`
|
|
404
|
+
- `spec.subagents`
|
|
405
|
+
- `spec.mcpServers`
|
|
406
|
+
- `spec.responseFormat`
|
|
407
|
+
- `spec.contextSchema`
|
|
408
|
+
|
|
596
409
|
### `resources/`
|
|
597
410
|
|
|
598
411
|
Use `resources/` for executable local extensions:
|
|
@@ -604,43 +417,32 @@ Tool modules are discovered from `resources/tools/*.js`, `resources/tools/*.mjs`
|
|
|
604
417
|
|
|
605
418
|
The preferred tool module format is exporting `tool({...})`.
|
|
606
419
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
```js
|
|
610
|
-
import { z } from "zod";
|
|
611
|
-
import { tool } from "@botbotgo/agent-harness/tools";
|
|
612
|
-
|
|
613
|
-
export const local_lookup = tool({
|
|
614
|
-
description: "Lookup a ticker from a local tool module.",
|
|
615
|
-
retryable: true,
|
|
616
|
-
schema: {
|
|
617
|
-
ticker: z.string().min(1),
|
|
618
|
-
},
|
|
619
|
-
async invoke(input) {
|
|
620
|
-
return input.ticker.toUpperCase();
|
|
621
|
-
},
|
|
622
|
-
});
|
|
623
|
-
```
|
|
624
|
-
|
|
625
|
-
Keep runtime extension source under `resources/`. Keep tests outside the published source tree, for example under repository `test/`.
|
|
420
|
+
SKILL packages are discovered from `resources/skills/` and attached to agents through YAML.
|
|
626
421
|
|
|
627
422
|
## Design Notes
|
|
628
423
|
|
|
629
|
-
-
|
|
630
|
-
- agent-level execution behavior stays upstream
|
|
424
|
+
- public runtime contract stays generic and small
|
|
631
425
|
- application-level orchestration and lifecycle management stays in the harness
|
|
632
|
-
-
|
|
633
|
-
-
|
|
426
|
+
- upstream LangChain v1 and DeepAgents concepts should be expressed as directly as possible in YAML
|
|
427
|
+
- recovery, approvals, threads, runs, and events are runtime concepts, not backend-specific escape hatches
|
|
428
|
+
- backend implementation details should stay internal unless product requirements force exposure
|
|
429
|
+
|
|
430
|
+
In short: `agent-harness` is a public runtime contract generic enough to survive backend changes, while the deep execution semantics stay upstream.
|
|
634
431
|
|
|
635
432
|
## API Summary
|
|
636
433
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
- `
|
|
640
|
-
- `
|
|
641
|
-
- `
|
|
642
|
-
- `
|
|
643
|
-
- `
|
|
644
|
-
- `
|
|
645
|
-
- `
|
|
646
|
-
- `
|
|
434
|
+
Primary exports:
|
|
435
|
+
|
|
436
|
+
- `createAgentHarness`
|
|
437
|
+
- `run`
|
|
438
|
+
- `subscribe`
|
|
439
|
+
- `listThreads`
|
|
440
|
+
- `getThread`
|
|
441
|
+
- `deleteThread`
|
|
442
|
+
- `listApprovals`
|
|
443
|
+
- `getApproval`
|
|
444
|
+
- `createToolMcpServer`
|
|
445
|
+
- `serveToolsOverStdio`
|
|
446
|
+
- `stop`
|
|
447
|
+
|
|
448
|
+
`AgentHarnessRuntime` is the concrete runtime class behind the public facade.
|
|
@@ -96,6 +96,11 @@ export type LangChainAgentParams = {
|
|
|
96
96
|
responseFormat?: unknown;
|
|
97
97
|
contextSchema?: unknown;
|
|
98
98
|
middleware?: Array<Record<string, unknown>>;
|
|
99
|
+
subagents?: CompiledSubAgent[];
|
|
100
|
+
memory?: string[];
|
|
101
|
+
skills?: string[];
|
|
102
|
+
generalPurposeAgent?: boolean;
|
|
103
|
+
taskDescription?: string;
|
|
99
104
|
includeAgentName?: "inline";
|
|
100
105
|
version?: "v1" | "v2";
|
|
101
106
|
name?: string;
|
|
@@ -290,9 +295,6 @@ export type RunStartOptions = {
|
|
|
290
295
|
input: MessageContent;
|
|
291
296
|
threadId?: string;
|
|
292
297
|
invocation?: InvocationEnvelope;
|
|
293
|
-
context?: Record<string, unknown>;
|
|
294
|
-
state?: Record<string, unknown>;
|
|
295
|
-
files?: Record<string, unknown>;
|
|
296
298
|
listeners?: RunListeners;
|
|
297
299
|
};
|
|
298
300
|
export type RunDecisionOptions = {
|
package/dist/extensions.js
CHANGED
|
@@ -198,6 +198,44 @@ registerToolKind({
|
|
|
198
198
|
];
|
|
199
199
|
},
|
|
200
200
|
});
|
|
201
|
+
registerToolKind({
|
|
202
|
+
type: "provider",
|
|
203
|
+
validate(tool) {
|
|
204
|
+
if (!tool.name || !tool.description) {
|
|
205
|
+
throw new Error(`Tool ${tool.id} provider tool requires name and description`);
|
|
206
|
+
}
|
|
207
|
+
const providerTool = typeof tool.config?.providerTool === "object" && tool.config.providerTool
|
|
208
|
+
? tool.config.providerTool
|
|
209
|
+
: undefined;
|
|
210
|
+
if (typeof providerTool?.provider !== "string" || !providerTool.provider.trim()) {
|
|
211
|
+
throw new Error(`Tool ${tool.id} provider tool must define providerTool.provider`);
|
|
212
|
+
}
|
|
213
|
+
if (typeof providerTool?.tool !== "string" || !providerTool.tool.trim()) {
|
|
214
|
+
throw new Error(`Tool ${tool.id} provider tool must define providerTool.tool`);
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
compile(tool) {
|
|
218
|
+
return [
|
|
219
|
+
{
|
|
220
|
+
id: tool.id,
|
|
221
|
+
type: "provider",
|
|
222
|
+
name: tool.name,
|
|
223
|
+
description: tool.description,
|
|
224
|
+
config: tool.config,
|
|
225
|
+
inputSchemaRef: tool.inputSchemaRef,
|
|
226
|
+
bundleRefs: [],
|
|
227
|
+
hitl: tool.hitl
|
|
228
|
+
? {
|
|
229
|
+
enabled: tool.hitl.enabled,
|
|
230
|
+
allow: tool.hitl.allow ?? ["approve", "edit", "reject"],
|
|
231
|
+
}
|
|
232
|
+
: undefined,
|
|
233
|
+
retryable: tool.retryable,
|
|
234
|
+
runtimeValue: { name: tool.name, description: tool.description, type: "provider" },
|
|
235
|
+
},
|
|
236
|
+
];
|
|
237
|
+
},
|
|
238
|
+
});
|
|
201
239
|
registerToolKind({
|
|
202
240
|
type: "bundle",
|
|
203
241
|
validate(tool, tools) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.48";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.48";
|
|
@@ -20,12 +20,6 @@ function installedResourceProviderEntry() {
|
|
|
20
20
|
try {
|
|
21
21
|
return require.resolve("@botbotgo/agent-harness-resource");
|
|
22
22
|
}
|
|
23
|
-
catch {
|
|
24
|
-
// Fall through to the legacy package name for backward compatibility only.
|
|
25
|
-
}
|
|
26
|
-
try {
|
|
27
|
-
return require.resolve("@botbotgo/agent-harness-builtin");
|
|
28
|
-
}
|
|
29
23
|
catch {
|
|
30
24
|
return null;
|
|
31
25
|
}
|
|
@@ -33,6 +33,8 @@ export declare class AgentRuntimeAdapter {
|
|
|
33
33
|
private normalizeInterruptPolicy;
|
|
34
34
|
private compileInterruptOn;
|
|
35
35
|
private resolveInterruptOn;
|
|
36
|
+
private resolveFilesystemBackend;
|
|
37
|
+
private resolveLangChainAutomaticMiddleware;
|
|
36
38
|
private resolveMiddleware;
|
|
37
39
|
private resolveCheckpointer;
|
|
38
40
|
private buildRouteSystemPrompt;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Command, MemorySaver } from "@langchain/langgraph";
|
|
2
2
|
import { tool as createLangChainTool } from "@langchain/core/tools";
|
|
3
|
-
import { createDeepAgent } from "deepagents";
|
|
3
|
+
import { createDeepAgent, createMemoryMiddleware, createSkillsMiddleware, createSubAgentMiddleware, FilesystemBackend, } from "deepagents";
|
|
4
4
|
import { ChatAnthropic } from "@langchain/anthropic";
|
|
5
|
+
import { tools as anthropicProviderTools } from "@langchain/anthropic";
|
|
5
6
|
import { ChatGoogle } from "@langchain/google";
|
|
6
7
|
import { ChatOllama } from "@langchain/ollama";
|
|
7
8
|
import { ChatOpenAI } from "@langchain/openai";
|
|
9
|
+
import { tools as openAIProviderTools } from "@langchain/openai";
|
|
8
10
|
import { createAgent, humanInTheLoopMiddleware, initChatModel } from "langchain";
|
|
9
11
|
import { z } from "zod";
|
|
10
12
|
import { extractEmptyAssistantMessageFailure, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, isLikelyToolArgsObject, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, sanitizeVisibleText, tryParseJson, wrapResolvedModel, } from "./parsing/output-parsing.js";
|
|
@@ -112,6 +114,35 @@ function buildToolNameMapping(tools) {
|
|
|
112
114
|
}
|
|
113
115
|
return { originalToModelFacing, modelFacingToOriginal };
|
|
114
116
|
}
|
|
117
|
+
function hasConfiguredSubagentSupport(binding) {
|
|
118
|
+
const params = getBindingLangChainParams(binding);
|
|
119
|
+
if (!params) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return (params.subagents?.length ?? 0) > 0 || params.generalPurposeAgent === true || Boolean(params.taskDescription?.trim());
|
|
123
|
+
}
|
|
124
|
+
function instantiateProviderTool(compiledTool) {
|
|
125
|
+
const providerTool = asRecord(compiledTool.config?.providerTool);
|
|
126
|
+
const provider = typeof providerTool?.provider === "string" ? providerTool.provider.trim().toLowerCase() : "";
|
|
127
|
+
const toolName = typeof providerTool?.tool === "string" ? providerTool.tool.trim() : "";
|
|
128
|
+
const args = asRecord(providerTool?.args) ?? {};
|
|
129
|
+
if (!provider || !toolName) {
|
|
130
|
+
throw new Error(`Provider tool ${compiledTool.id} must define providerTool.provider and providerTool.tool`);
|
|
131
|
+
}
|
|
132
|
+
const registry = provider === "openai"
|
|
133
|
+
? openAIProviderTools
|
|
134
|
+
: provider === "anthropic"
|
|
135
|
+
? anthropicProviderTools
|
|
136
|
+
: undefined;
|
|
137
|
+
if (!registry) {
|
|
138
|
+
throw new Error(`Provider tool ${compiledTool.id} uses unsupported provider ${provider}`);
|
|
139
|
+
}
|
|
140
|
+
const factory = registry[toolName];
|
|
141
|
+
if (typeof factory !== "function") {
|
|
142
|
+
throw new Error(`Provider tool ${compiledTool.id} references unknown ${provider} tool ${toolName}`);
|
|
143
|
+
}
|
|
144
|
+
return factory(args);
|
|
145
|
+
}
|
|
115
146
|
function wrapResolvedToolWithModelFacingName(resolvedTool, modelFacingName) {
|
|
116
147
|
if (typeof resolvedTool !== "object" || resolvedTool === null) {
|
|
117
148
|
return resolvedTool;
|
|
@@ -393,10 +424,10 @@ export class AgentRuntimeAdapter {
|
|
|
393
424
|
resolveTools(tools, binding) {
|
|
394
425
|
const resolved = this.options.toolResolver ? this.options.toolResolver(tools.map((tool) => tool.id), binding) : [];
|
|
395
426
|
const toolNameMapping = this.buildToolNameMapping(tools);
|
|
396
|
-
return
|
|
397
|
-
const
|
|
398
|
-
if (
|
|
399
|
-
return
|
|
427
|
+
return tools.flatMap((compiledTool, index) => {
|
|
428
|
+
const resolvedTool = resolved[index] ?? (compiledTool.type === "provider" ? instantiateProviderTool(compiledTool) : undefined);
|
|
429
|
+
if (resolvedTool === undefined) {
|
|
430
|
+
return [];
|
|
400
431
|
}
|
|
401
432
|
const wrappedTool = wrapToolForExecution(resolvedTool, compiledTool, binding);
|
|
402
433
|
const modelFacingName = toolNameMapping.originalToModelFacing.get(compiledTool.name) ?? compiledTool.name;
|
|
@@ -443,14 +474,55 @@ export class AgentRuntimeAdapter {
|
|
|
443
474
|
resolveInterruptOn(binding) {
|
|
444
475
|
return this.compileInterruptOn(getBindingPrimaryTools(binding), getBindingInterruptCompatibilityRules(binding));
|
|
445
476
|
}
|
|
477
|
+
resolveFilesystemBackend(binding) {
|
|
478
|
+
return new FilesystemBackend({
|
|
479
|
+
rootDir: "/",
|
|
480
|
+
virtualMode: false,
|
|
481
|
+
maxFileSizeMb: 10,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
async resolveLangChainAutomaticMiddleware(binding) {
|
|
485
|
+
const params = getBindingLangChainParams(binding);
|
|
486
|
+
if (!params) {
|
|
487
|
+
return [];
|
|
488
|
+
}
|
|
489
|
+
const automaticMiddleware = [];
|
|
490
|
+
if ((params.skills?.length ?? 0) > 0) {
|
|
491
|
+
automaticMiddleware.push(createSkillsMiddleware({
|
|
492
|
+
backend: this.resolveFilesystemBackend(binding),
|
|
493
|
+
sources: params.skills,
|
|
494
|
+
}));
|
|
495
|
+
}
|
|
496
|
+
if ((params.memory?.length ?? 0) > 0) {
|
|
497
|
+
automaticMiddleware.push(createMemoryMiddleware({
|
|
498
|
+
backend: this.resolveFilesystemBackend(binding),
|
|
499
|
+
sources: params.memory,
|
|
500
|
+
}));
|
|
501
|
+
}
|
|
502
|
+
if (hasConfiguredSubagentSupport(binding)) {
|
|
503
|
+
automaticMiddleware.push(createSubAgentMiddleware({
|
|
504
|
+
defaultModel: (await this.resolveModel(params.model)),
|
|
505
|
+
defaultTools: this.resolveTools(params.tools, binding),
|
|
506
|
+
defaultInterruptOn: getBindingInterruptCompatibilityRules(binding),
|
|
507
|
+
subagents: (await this.resolveSubagents(params.subagents ?? [], binding)),
|
|
508
|
+
generalPurposeAgent: params.generalPurposeAgent,
|
|
509
|
+
taskDescription: params.taskDescription ?? null,
|
|
510
|
+
}));
|
|
511
|
+
}
|
|
512
|
+
return automaticMiddleware;
|
|
513
|
+
}
|
|
446
514
|
async resolveMiddleware(binding, interruptOn) {
|
|
447
515
|
const declarativeMiddleware = await resolveDeclaredMiddleware(getBindingMiddlewareConfigs(binding), {
|
|
448
516
|
resolveModel: (model) => this.resolveModel(model),
|
|
449
517
|
resolveCustom: this.options.declaredMiddlewareResolver,
|
|
450
518
|
binding,
|
|
451
519
|
});
|
|
520
|
+
const automaticMiddleware = isLangChainBinding(binding)
|
|
521
|
+
? await this.resolveLangChainAutomaticMiddleware(binding)
|
|
522
|
+
: [];
|
|
452
523
|
const middleware = [
|
|
453
524
|
...declarativeMiddleware,
|
|
525
|
+
...automaticMiddleware,
|
|
454
526
|
...(this.options.middlewareResolver ? this.options.middlewareResolver(binding) : []),
|
|
455
527
|
];
|
|
456
528
|
if (interruptOn && Object.keys(interruptOn).length > 0) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { anthropicPromptCachingMiddleware, contextEditingMiddleware, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, summarizationMiddleware, todoListMiddleware, toolCallLimitMiddleware, toolEmulatorMiddleware, toolRetryMiddleware, } from "langchain";
|
|
1
|
+
import { anthropicPromptCachingMiddleware, contextEditingMiddleware, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, piiMiddleware, piiRedactionMiddleware, summarizationMiddleware, todoListMiddleware, toolCallLimitMiddleware, toolEmulatorMiddleware, toolRetryMiddleware, } from "langchain";
|
|
2
2
|
function asMiddlewareConfig(value) {
|
|
3
3
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? { ...value } : null;
|
|
4
4
|
}
|
|
@@ -80,6 +80,18 @@ export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
|
|
|
80
80
|
case "openAIModeration":
|
|
81
81
|
resolved.push(openAIModerationMiddleware(runtimeConfig));
|
|
82
82
|
break;
|
|
83
|
+
case "pii": {
|
|
84
|
+
const piiType = typeof runtimeConfig.piiType === "string" ? runtimeConfig.piiType : undefined;
|
|
85
|
+
if (!piiType) {
|
|
86
|
+
throw new Error("pii middleware requires piiType");
|
|
87
|
+
}
|
|
88
|
+
const { piiType: _piiType, ...piiOptions } = runtimeConfig;
|
|
89
|
+
resolved.push(piiMiddleware(piiType, piiOptions));
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case "piiRedaction":
|
|
93
|
+
resolved.push(piiRedactionMiddleware(runtimeConfig));
|
|
94
|
+
break;
|
|
83
95
|
case "anthropicPromptCaching":
|
|
84
96
|
resolved.push(anthropicPromptCachingMiddleware(runtimeConfig));
|
|
85
97
|
break;
|
package/dist/runtime/harness.js
CHANGED
|
@@ -47,9 +47,9 @@ export class AgentHarnessRuntime {
|
|
|
47
47
|
normalizeInvocationEnvelope(options) {
|
|
48
48
|
const invocation = options.invocation;
|
|
49
49
|
return {
|
|
50
|
-
context: invocation?.context
|
|
51
|
-
state: invocation?.inputs
|
|
52
|
-
files: invocation?.attachments
|
|
50
|
+
context: invocation?.context,
|
|
51
|
+
state: invocation?.inputs,
|
|
52
|
+
files: invocation?.attachments,
|
|
53
53
|
invocation,
|
|
54
54
|
};
|
|
55
55
|
}
|
|
@@ -243,6 +243,19 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
243
243
|
responseFormat: agent.langchainAgentConfig?.responseFormat,
|
|
244
244
|
contextSchema: agent.langchainAgentConfig?.contextSchema,
|
|
245
245
|
middleware: compileMiddlewareConfigs(agent.langchainAgentConfig?.middleware, models, agent.id),
|
|
246
|
+
subagents: agent.subagentRefs.map((ref) => {
|
|
247
|
+
const subagent = agents.get(resolveRefId(ref));
|
|
248
|
+
if (!subagent) {
|
|
249
|
+
throw new Error(`Missing subagent ${ref} for agent ${agent.id}`);
|
|
250
|
+
}
|
|
251
|
+
return buildSubagent(subagent, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory);
|
|
252
|
+
}),
|
|
253
|
+
memory: compiledAgentMemory,
|
|
254
|
+
skills: compiledAgentSkills,
|
|
255
|
+
generalPurposeAgent: typeof agent.langchainAgentConfig?.generalPurposeAgent === "boolean" ? agent.langchainAgentConfig.generalPurposeAgent : undefined,
|
|
256
|
+
taskDescription: typeof agent.langchainAgentConfig?.taskDescription === "string" && agent.langchainAgentConfig.taskDescription.trim()
|
|
257
|
+
? agent.langchainAgentConfig.taskDescription
|
|
258
|
+
: undefined,
|
|
246
259
|
includeAgentName: agent.langchainAgentConfig?.includeAgentName === "inline" ? "inline" : undefined,
|
|
247
260
|
version: agent.langchainAgentConfig?.version === "v1" || agent.langchainAgentConfig?.version === "v2"
|
|
248
261
|
? agent.langchainAgentConfig.version
|
|
@@ -222,10 +222,10 @@ function resolveExecutionBackend(item, current) {
|
|
|
222
222
|
: typeof execution?.mode === "string"
|
|
223
223
|
? execution.mode.trim().toLowerCase()
|
|
224
224
|
: undefined;
|
|
225
|
-
if (backend === "langchain-v1"
|
|
225
|
+
if (backend === "langchain-v1") {
|
|
226
226
|
return "langchain-v1";
|
|
227
227
|
}
|
|
228
|
-
if (backend === "deepagent"
|
|
228
|
+
if (backend === "deepagent") {
|
|
229
229
|
return "deepagent";
|
|
230
230
|
}
|
|
231
231
|
return undefined;
|
|
@@ -250,6 +250,8 @@ function readLangchainAgentConfig(item) {
|
|
|
250
250
|
return {
|
|
251
251
|
...readSharedAgentConfig(item),
|
|
252
252
|
...(typeof item.store === "object" && item.store ? { store: item.store } : {}),
|
|
253
|
+
...(typeof item.taskDescription === "string" && item.taskDescription.trim() ? { taskDescription: item.taskDescription } : {}),
|
|
254
|
+
...(typeof item.generalPurposeAgent === "boolean" ? { generalPurposeAgent: item.generalPurposeAgent } : {}),
|
|
253
255
|
};
|
|
254
256
|
}
|
|
255
257
|
function readDeepAgentConfig(item) {
|
|
@@ -264,17 +266,13 @@ function readDeepAgentConfig(item) {
|
|
|
264
266
|
export function parseAgentItem(item, sourcePath) {
|
|
265
267
|
const subagentRefs = readRefArray(item.subagents);
|
|
266
268
|
const subagentPathRefs = readPathArray(item.subagents);
|
|
267
|
-
const
|
|
268
|
-
const executionMode = String(resolveExecutionBackend(item) ??
|
|
269
|
-
(kind === "langchain-agent" ? "langchain-v1" : undefined) ??
|
|
270
|
-
(kind === "deepagent" ? "deepagent" : undefined) ??
|
|
271
|
-
"deepagent");
|
|
269
|
+
const executionMode = String(resolveExecutionBackend(item) ?? "deepagent");
|
|
272
270
|
return {
|
|
273
271
|
id: String(item.id),
|
|
274
272
|
executionMode: executionMode,
|
|
275
273
|
capabilities: readCapabilities(item.capabilities) ?? (executionMode === "deepagent"
|
|
276
274
|
? { delegation: true, memory: true }
|
|
277
|
-
: { delegation:
|
|
275
|
+
: { delegation: true, memory: true }),
|
|
278
276
|
description: String(item.description ?? ""),
|
|
279
277
|
modelRef: readSingleRef(item.modelRef) ?? "",
|
|
280
278
|
runRoot: typeof item.runRoot === "string" ? item.runRoot : undefined,
|
|
@@ -487,7 +485,7 @@ async function readNamedModelItems(root) {
|
|
|
487
485
|
return records;
|
|
488
486
|
}
|
|
489
487
|
function isAgentKind(kind) {
|
|
490
|
-
return kind === "
|
|
488
|
+
return kind === "agent";
|
|
491
489
|
}
|
|
492
490
|
async function readConfigAgentItems(configRoot) {
|
|
493
491
|
const records = await readYamlItems(configRoot, "agents", { recursive: true });
|
|
@@ -536,18 +534,7 @@ export async function readToolModuleItems(root) {
|
|
|
536
534
|
return records;
|
|
537
535
|
}
|
|
538
536
|
function inferExecutionMode(item, current) {
|
|
539
|
-
|
|
540
|
-
if (explicitExecution) {
|
|
541
|
-
return explicitExecution;
|
|
542
|
-
}
|
|
543
|
-
const kind = typeof item.kind === "string" ? item.kind : typeof current?.kind === "string" ? current.kind : undefined;
|
|
544
|
-
if (kind === "langchain-agent") {
|
|
545
|
-
return "langchain-v1";
|
|
546
|
-
}
|
|
547
|
-
if (kind === "deepagent") {
|
|
548
|
-
return "deepagent";
|
|
549
|
-
}
|
|
550
|
-
return undefined;
|
|
537
|
+
return resolveExecutionBackend(item, current);
|
|
551
538
|
}
|
|
552
539
|
export async function loadWorkspaceObjects(workspaceRoot, options = {}) {
|
|
553
540
|
const refs = new Map();
|
|
@@ -207,6 +207,7 @@ export function parseToolObject(object) {
|
|
|
207
207
|
const value = object.value;
|
|
208
208
|
const backend = asObject(value.backend);
|
|
209
209
|
const mcp = asObject(value.mcp);
|
|
210
|
+
const providerTool = asObject(value.providerTool) ?? asObject(value.provider);
|
|
210
211
|
const mcpReferenceConfig = mcp
|
|
211
212
|
? {
|
|
212
213
|
...(typeof mcp.serverRef === "string"
|
|
@@ -226,16 +227,22 @@ export function parseToolObject(object) {
|
|
|
226
227
|
? "bundle"
|
|
227
228
|
: mcp
|
|
228
229
|
? "mcp"
|
|
229
|
-
:
|
|
230
|
-
? "
|
|
231
|
-
:
|
|
230
|
+
: providerTool
|
|
231
|
+
? "provider"
|
|
232
|
+
: backend
|
|
233
|
+
? "backend"
|
|
234
|
+
: "function";
|
|
232
235
|
return {
|
|
233
236
|
id: object.id,
|
|
234
237
|
type: String(inferredType),
|
|
235
238
|
name: String(value.name ?? "").trim(),
|
|
236
239
|
description: String(value.description ?? "").trim(),
|
|
237
240
|
implementationName: typeof value.implementationName === "string" ? value.implementationName : undefined,
|
|
238
|
-
config: mergeObjects(asObject(value.config),
|
|
241
|
+
config: mergeObjects(mergeObjects(asObject(value.config), providerTool
|
|
242
|
+
? {
|
|
243
|
+
providerTool,
|
|
244
|
+
}
|
|
245
|
+
: undefined), (mcpReferenceConfig && Object.keys(mcpReferenceConfig).length > 0) || (mcpServerConfig && Object.keys(mcpServerConfig).length > 0)
|
|
239
246
|
? {
|
|
240
247
|
mcp: mcpReferenceConfig,
|
|
241
248
|
...(mcpServerConfig && Object.keys(mcpServerConfig).length > 0 ? { mcpServer: mcpServerConfig } : {}),
|
|
@@ -9,8 +9,8 @@ export function inferAgentCapabilities(agent) {
|
|
|
9
9
|
return normalizeCapabilities(agent.capabilities);
|
|
10
10
|
}
|
|
11
11
|
return {
|
|
12
|
-
delegation: agent.executionMode === "deepagent",
|
|
13
|
-
memory: agent.executionMode === "deepagent",
|
|
12
|
+
delegation: agent.executionMode === "deepagent" || agent.executionMode === "langchain-v1",
|
|
13
|
+
memory: agent.executionMode === "deepagent" || agent.executionMode === "langchain-v1",
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
export function inferBindingCapabilities(binding) {
|
|
@@ -12,10 +12,6 @@ export type RoutingRule = {
|
|
|
12
12
|
hasThreadId?: boolean;
|
|
13
13
|
caseSensitive?: boolean;
|
|
14
14
|
};
|
|
15
|
-
export type RuntimeRecoveryConfig = {
|
|
16
|
-
enabled: boolean;
|
|
17
|
-
resumeOnStartup: boolean;
|
|
18
|
-
};
|
|
19
15
|
export type RecoveryConfig = {
|
|
20
16
|
enabled: boolean;
|
|
21
17
|
resumeResumingRunsOnStartup: boolean;
|
|
@@ -26,7 +22,6 @@ export type ConcurrencyConfig = {
|
|
|
26
22
|
};
|
|
27
23
|
export declare function getWorkspaceObject(refs: Map<string, WorkspaceObject | ParsedAgentObject>, ref: string | undefined): WorkspaceObject | undefined;
|
|
28
24
|
export declare function getRuntimeDefaults(refs: Map<string, WorkspaceObject | ParsedAgentObject>): Record<string, unknown> | undefined;
|
|
29
|
-
export declare function getRuntimeRecoveryConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): RuntimeRecoveryConfig;
|
|
30
25
|
export declare function getRecoveryConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): RecoveryConfig;
|
|
31
26
|
export declare function getConcurrencyConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): ConcurrencyConfig;
|
|
32
27
|
export declare function getRoutingSystemPrompt(refs: Map<string, WorkspaceObject | ParsedAgentObject>): string | undefined;
|
|
@@ -25,16 +25,6 @@ export function getRuntimeDefaults(refs) {
|
|
|
25
25
|
}
|
|
26
26
|
return runtimes[0].value;
|
|
27
27
|
}
|
|
28
|
-
export function getRuntimeRecoveryConfig(refs) {
|
|
29
|
-
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
30
|
-
const recovery = typeof runtimeDefaults?.recovery === "object" && runtimeDefaults.recovery
|
|
31
|
-
? runtimeDefaults.recovery
|
|
32
|
-
: undefined;
|
|
33
|
-
return {
|
|
34
|
-
enabled: recovery?.enabled !== false,
|
|
35
|
-
resumeOnStartup: recovery?.resumeOnStartup !== false,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
28
|
export function getRecoveryConfig(refs) {
|
|
39
29
|
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
40
30
|
const recovery = typeof runtimeDefaults?.recovery === "object" && runtimeDefaults.recovery
|
|
@@ -49,7 +39,7 @@ export function getRecoveryConfig(refs) {
|
|
|
49
39
|
enabled: recovery.enabled !== false,
|
|
50
40
|
resumeResumingRunsOnStartup: typeof recovery.resumeResumingRunsOnStartup === "boolean"
|
|
51
41
|
? recovery.resumeResumingRunsOnStartup
|
|
52
|
-
:
|
|
42
|
+
: true,
|
|
53
43
|
maxRecoveryAttempts,
|
|
54
44
|
};
|
|
55
45
|
}
|
|
@@ -38,6 +38,9 @@ function validateMiddlewareConfig(agent) {
|
|
|
38
38
|
if (kind === "modelFallback" && !Array.isArray(typed.fallbackModels) && !Array.isArray(typed.models)) {
|
|
39
39
|
throw new Error(`Agent ${agent.id} modelFallback middleware requires fallbackModels or models`);
|
|
40
40
|
}
|
|
41
|
+
if (kind === "pii" && typeof typed.piiType !== "string") {
|
|
42
|
+
throw new Error(`Agent ${agent.id} pii middleware requires piiType`);
|
|
43
|
+
}
|
|
41
44
|
}
|
|
42
45
|
}
|
|
43
46
|
export function validateAgent(agent) {
|