@botbotgo/agent-harness 0.0.49 → 0.0.51
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 +68 -46
- package/dist/config/agents/direct.yaml +36 -34
- package/dist/config/agents/orchestra.yaml +77 -75
- package/dist/contracts/types.d.ts +14 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/presentation.d.ts +0 -14
- package/dist/presentation.js +0 -146
- package/dist/runtime/agent-runtime-adapter.js +27 -5
- package/dist/runtime/declared-middleware.js +4 -4
- package/dist/runtime/harness.d.ts +1 -0
- package/dist/runtime/harness.js +19 -0
- package/dist/runtime/parsing/output-parsing.d.ts +2 -0
- package/dist/runtime/parsing/output-parsing.js +75 -2
- package/dist/workspace/agent-binding-compiler.js +12 -0
- package/dist/workspace/object-loader.js +110 -31
- package/dist/workspace/validate.js +3 -0
- package/package.json +4 -10
package/README.md
CHANGED
|
@@ -6,16 +6,16 @@
|
|
|
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 product boundary is:
|
|
9
|
+
The product boundary is simple:
|
|
10
10
|
|
|
11
11
|
- LangChain v1 and DeepAgents own agent execution semantics
|
|
12
|
-
- `agent-harness` owns application
|
|
12
|
+
- `agent-harness` owns application-level orchestration and lifecycle management
|
|
13
13
|
|
|
14
14
|
That means:
|
|
15
15
|
|
|
16
16
|
- public API stays small
|
|
17
|
-
- complex
|
|
18
|
-
- runtime lifecycle stays stable even if
|
|
17
|
+
- complex setup and operating policy live in YAML
|
|
18
|
+
- runtime lifecycle stays stable even if backend implementations change
|
|
19
19
|
|
|
20
20
|
What the runtime provides:
|
|
21
21
|
|
|
@@ -81,10 +81,12 @@ try {
|
|
|
81
81
|
- YAML-defined host routing and runtime policy
|
|
82
82
|
- LangChain v1 and DeepAgents backend adaptation
|
|
83
83
|
- Auto-discovered local tools and SKILL packages
|
|
84
|
+
- provider-native tools, MCP tools, and workspace-local tool modules
|
|
85
|
+
- persisted threads, runs, approvals, lifecycle events, and queued runs
|
|
86
|
+
- runtime-managed recovery and checkpoint maintenance
|
|
87
|
+
- structured output and multimodal content preservation in run results
|
|
84
88
|
- MCP bridge support for agent-declared MCP servers
|
|
85
89
|
- MCP server support for exposing harness tools outward
|
|
86
|
-
- Persisted threads, runs, approvals, lifecycle events, and queued runs
|
|
87
|
-
- Runtime-managed recovery and checkpoint maintenance
|
|
88
90
|
|
|
89
91
|
## How To Use
|
|
90
92
|
|
|
@@ -120,7 +122,7 @@ const result = await run(runtime, {
|
|
|
120
122
|
});
|
|
121
123
|
```
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
`run(runtime, { ... })` creates or continues a persisted thread and returns `threadId`, `runId`, `state`, and a simple text `output`. When upstream returns richer output, the runtime also preserves `outputContent`, `contentBlocks`, and `structuredResponse` without making the basic API larger.
|
|
124
126
|
|
|
125
127
|
Use `invocation` as the runtime-facing request envelope:
|
|
126
128
|
|
|
@@ -149,6 +151,9 @@ const result = await run(runtime, {
|
|
|
149
151
|
onChunk(chunk) {
|
|
150
152
|
process.stdout.write(chunk);
|
|
151
153
|
},
|
|
154
|
+
onContentBlocks(blocks) {
|
|
155
|
+
console.log(blocks);
|
|
156
|
+
},
|
|
152
157
|
onEvent(event) {
|
|
153
158
|
console.log(event.eventType, event.payload);
|
|
154
159
|
},
|
|
@@ -196,11 +201,11 @@ metadata:
|
|
|
196
201
|
spec:
|
|
197
202
|
execution:
|
|
198
203
|
backend: deepagent
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
+
modelRef: model/default
|
|
205
|
+
mcpServers:
|
|
206
|
+
- name: browser
|
|
207
|
+
command: node
|
|
208
|
+
args: ["./mcp-browser-server.mjs"]
|
|
204
209
|
```
|
|
205
210
|
|
|
206
211
|
The runtime discovers MCP tools, filters them through agent configuration, and exposes them like other tools.
|
|
@@ -244,8 +249,6 @@ Core workspace files:
|
|
|
244
249
|
- `resources/tools/`
|
|
245
250
|
- `resources/skills/`
|
|
246
251
|
|
|
247
|
-
### Client-Configurable YAML Reference
|
|
248
|
-
|
|
249
252
|
There are three configuration layers:
|
|
250
253
|
|
|
251
254
|
- runtime policy in `config/workspace.yaml`
|
|
@@ -344,6 +347,13 @@ Use this file for named MCP server presets.
|
|
|
344
347
|
|
|
345
348
|
Agents are always declared with `kind: Agent` and `spec.execution.backend`.
|
|
346
349
|
|
|
350
|
+
Use two nested sections inside each agent:
|
|
351
|
+
|
|
352
|
+
- `spec.runtime` for harness-owned runtime placement such as `spec.runtime.runRoot`
|
|
353
|
+
- `spec.execution` for upstream execution semantics and adapter-facing config
|
|
354
|
+
|
|
355
|
+
This keeps the public product model small while letting LangChain v1 and DeepAgents concepts pass through with minimal translation.
|
|
356
|
+
|
|
347
357
|
Example lightweight host:
|
|
348
358
|
|
|
349
359
|
```yaml
|
|
@@ -354,10 +364,11 @@ metadata:
|
|
|
354
364
|
spec:
|
|
355
365
|
execution:
|
|
356
366
|
backend: langchain-v1
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
367
|
+
modelRef: model/default
|
|
368
|
+
config:
|
|
369
|
+
checkpointer:
|
|
370
|
+
ref: checkpointer/default
|
|
371
|
+
systemPrompt: Answer simple requests directly.
|
|
361
372
|
```
|
|
362
373
|
|
|
363
374
|
Example main execution host:
|
|
@@ -370,21 +381,22 @@ metadata:
|
|
|
370
381
|
spec:
|
|
371
382
|
execution:
|
|
372
383
|
backend: deepagent
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
384
|
+
modelRef: model/default
|
|
385
|
+
memory:
|
|
386
|
+
- path: config/agent-context.md
|
|
387
|
+
config:
|
|
388
|
+
store:
|
|
389
|
+
ref: store/default
|
|
390
|
+
checkpointer:
|
|
391
|
+
ref: checkpointer/default
|
|
392
|
+
backend:
|
|
393
|
+
kind: CompositeBackend
|
|
394
|
+
state:
|
|
395
|
+
kind: VfsSandbox
|
|
396
|
+
timeout: 600
|
|
397
|
+
routes:
|
|
398
|
+
/memories/:
|
|
399
|
+
kind: StoreBackend
|
|
388
400
|
```
|
|
389
401
|
|
|
390
402
|
Client-configurable agent fields include:
|
|
@@ -392,19 +404,29 @@ Client-configurable agent fields include:
|
|
|
392
404
|
- `metadata.name`
|
|
393
405
|
- `metadata.description`
|
|
394
406
|
- `spec.execution.backend`
|
|
395
|
-
- `spec.
|
|
396
|
-
- `spec.
|
|
397
|
-
- `spec.tools`
|
|
398
|
-
- `spec.skills`
|
|
399
|
-
- `spec.memory`
|
|
400
|
-
- `spec.
|
|
401
|
-
- `spec.
|
|
402
|
-
- `spec.
|
|
403
|
-
- `spec.
|
|
404
|
-
- `spec.
|
|
405
|
-
- `spec.
|
|
406
|
-
- `spec.
|
|
407
|
-
- `spec.
|
|
407
|
+
- `spec.runtime.runRoot`
|
|
408
|
+
- `spec.execution.modelRef`
|
|
409
|
+
- `spec.execution.tools`
|
|
410
|
+
- `spec.execution.skills`
|
|
411
|
+
- `spec.execution.memory`
|
|
412
|
+
- `spec.execution.subagents`
|
|
413
|
+
- `spec.execution.mcpServers`
|
|
414
|
+
- `spec.execution.config.systemPrompt`
|
|
415
|
+
- `spec.execution.config.checkpointer`
|
|
416
|
+
- `spec.execution.config.store`
|
|
417
|
+
- `spec.execution.config.backend`
|
|
418
|
+
- `spec.execution.config.middleware`
|
|
419
|
+
- `spec.execution.config.responseFormat`
|
|
420
|
+
- `spec.execution.config.contextSchema`
|
|
421
|
+
- `spec.execution.config.stateSchema`
|
|
422
|
+
- `spec.execution.config.interruptOn`
|
|
423
|
+
- `spec.execution.config.filesystem`
|
|
424
|
+
- `spec.execution.config.taskDescription`
|
|
425
|
+
- `spec.execution.config.generalPurposeAgent`
|
|
426
|
+
- `spec.execution.config.includeAgentName`
|
|
427
|
+
- `spec.execution.config.version`
|
|
428
|
+
|
|
429
|
+
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.
|
|
408
430
|
|
|
409
431
|
### `resources/`
|
|
410
432
|
|
|
@@ -9,41 +9,43 @@ 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
|
-
|
|
13
|
-
# Current backend adapter for this host profile.
|
|
14
|
-
backend: langchain-v1
|
|
12
|
+
runtime: {}
|
|
15
13
|
# =====================
|
|
16
14
|
# Runtime Agent Features
|
|
17
15
|
# =====================
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
16
|
+
execution:
|
|
17
|
+
# Current backend adapter for this host profile.
|
|
18
|
+
backend: langchain-v1
|
|
19
|
+
# Upstream execution feature: model ref for the underlying LLM used by the direct-response agent.
|
|
20
|
+
# This should point at a cheap, fast, general-purpose chat model, because `direct` is intended
|
|
21
|
+
# to be the low-latency path for simple requests.
|
|
22
|
+
modelRef: model/default
|
|
23
|
+
config:
|
|
24
|
+
# Runtime execution feature: checkpointer config passed into the selected backend adapter.
|
|
25
|
+
# Even the lightweight direct path can benefit from resumable state during interactive use.
|
|
26
|
+
# Available `kind` options in this harness: `FileCheckpointer`, `MemorySaver`, `SqliteSaver`.
|
|
27
|
+
# `path` is only used by `FileCheckpointer` and `SqliteSaver`; omit it for `MemorySaver`.
|
|
28
|
+
checkpointer:
|
|
29
|
+
ref: checkpointer/default
|
|
30
|
+
# Upstream execution feature: system prompt for the lightweight direct-response host.
|
|
31
|
+
# This prompt should keep the agent focused on:
|
|
32
|
+
# - answering simple requests in one turn
|
|
33
|
+
# - staying lightweight instead of planning or orchestrating
|
|
34
|
+
# - avoiding specialist-style decomposition unless the caller explicitly switches agents
|
|
35
|
+
#
|
|
36
|
+
# The direct host is intentionally narrower than the orchestra host:
|
|
37
|
+
# - `direct` is optimized for latency and straightforward completion
|
|
38
|
+
# - `orchestra` is optimized for multi-step work, tools, delegation, and specialist use
|
|
39
|
+
#
|
|
40
|
+
# Keep this prompt biased toward concise, self-contained answers. If richer routing policy is
|
|
41
|
+
# needed for choosing between host agents, configure that separately via `Runtime.spec.routing`
|
|
42
|
+
# rather than overloading the direct host prompt with classifier behavior.
|
|
43
|
+
systemPrompt: |-
|
|
44
|
+
You are the direct agent.
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
This is a manual low-latency host.
|
|
47
|
+
Answer simple requests directly.
|
|
48
|
+
Keep the path lightweight.
|
|
49
|
+
Do not delegate.
|
|
50
|
+
Do not perform broad multi-step execution.
|
|
51
|
+
Do not behave like the default execution host.
|
|
@@ -9,86 +9,88 @@ 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
|
-
|
|
13
|
-
# Current backend adapter for this host profile.
|
|
14
|
-
backend: deepagent
|
|
12
|
+
runtime: {}
|
|
15
13
|
# =====================
|
|
16
14
|
# Runtime Agent Features
|
|
17
15
|
# =====================
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# Available
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
16
|
+
execution:
|
|
17
|
+
# Current backend adapter for this host profile.
|
|
18
|
+
backend: deepagent
|
|
19
|
+
# Upstream execution feature: model ref for the underlying LLM used by this execution host.
|
|
20
|
+
modelRef: model/default
|
|
21
|
+
memory:
|
|
22
|
+
# Upstream execution feature: bootstrap memory sources supplied to the selected backend at construction time.
|
|
23
|
+
# These paths resolve relative to the workspace root unless they are already absolute.
|
|
24
|
+
# Treat this as agent-owned startup context, not as a dynamic long-term memory sink:
|
|
25
|
+
# - keep `systemPrompt` for stable role, boundaries, and hard behavioral rules
|
|
26
|
+
# - use `memory:` for stable project knowledge, operating conventions, and shared or agent-specific context files
|
|
27
|
+
# - use `/memories/*` via the backend/store below for durable knowledge learned from prior runs
|
|
28
|
+
# - use the harness checkpointer for resumable graph state for an in-flight run
|
|
29
|
+
# Updating these files changes future agent constructions, but they are still bootstrap inputs rather than
|
|
30
|
+
# self-updating runtime memory.
|
|
31
|
+
- path: config/agent-context.md
|
|
32
|
+
config:
|
|
33
|
+
# Runtime execution feature: checkpointer config passed into the selected backend adapter.
|
|
34
|
+
# This persists resumable graph state for this agent.
|
|
35
|
+
# Available `kind` options in this harness: `FileCheckpointer`, `MemorySaver`, `SqliteSaver`.
|
|
36
|
+
# `path` is only used by `FileCheckpointer` and `SqliteSaver`; omit it for `MemorySaver`.
|
|
37
|
+
checkpointer:
|
|
38
|
+
# ref: checkpointer/sqlite
|
|
39
|
+
ref: checkpointer/default
|
|
40
|
+
# Upstream execution feature: store config passed into the selected backend adapter.
|
|
41
|
+
# In the default deepagent adapter this is the LangGraph store used by `StoreBackend` routes.
|
|
42
|
+
# Available `kind` options in this harness: `FileStore`, `InMemoryStore`, `RedisStore`, `PostgresStore`.
|
|
43
|
+
store:
|
|
44
|
+
ref: store/default
|
|
45
|
+
# Upstream execution feature: backend config passed into the selected backend adapter.
|
|
46
|
+
# This directly defines the backend topology for this agent:
|
|
47
|
+
# - workspace execution uses a lightweight VFS sandbox
|
|
48
|
+
# - long-term memory under `/memories/*` uses `StoreBackend`
|
|
49
|
+
# - `CompositeBackend` composes those backend instances together
|
|
50
|
+
# The harness also injects a persistent file-backed store and a file-backed checkpointer so that
|
|
51
|
+
# `/memories/*` and resumable run state survive restarts in the default setup.
|
|
52
|
+
# Available top-level `kind` options in this harness: `CompositeBackend`, `StateBackend`, `StoreBackend`.
|
|
53
|
+
backend:
|
|
54
|
+
kind: CompositeBackend
|
|
55
|
+
state:
|
|
56
|
+
# Available state backend `kind` options today: `StateBackend`, `LocalShellBackend`, `VfsSandbox`.
|
|
57
|
+
kind: VfsSandbox
|
|
58
|
+
timeout: 600
|
|
59
|
+
routes:
|
|
60
|
+
/memories/:
|
|
61
|
+
# Available route backend `kind` options today: `StoreBackend`.
|
|
62
|
+
kind: StoreBackend
|
|
63
|
+
# Upstream execution feature: system prompt for the orchestration host.
|
|
64
|
+
# This becomes the top-level instruction block for the selected execution backend and should hold the
|
|
65
|
+
# agent's durable role, priorities, and behavioral guardrails rather than bulky project facts.
|
|
66
|
+
systemPrompt: |-
|
|
67
|
+
You are the orchestra agent.
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
You are the default execution host.
|
|
70
|
+
Try to finish the request yourself before delegating.
|
|
71
|
+
Use your own tools first when they are sufficient.
|
|
72
|
+
Use your own skills first when they are sufficient.
|
|
73
|
+
Delegate only when a specialist is a clearly better fit or when your own tools and skills are not enough.
|
|
74
|
+
If neither you nor any suitable specialist can do the work, say so plainly.
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
Do not delegate by reflex.
|
|
77
|
+
Do not delegate just because a task has multiple steps.
|
|
78
|
+
Do not delegate when a direct answer or a short local tool pass is enough.
|
|
79
|
+
Keep the critical path local when immediate progress depends on it; otherwise delegate bounded sidecar work to
|
|
80
|
+
the most appropriate specialist.
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
Use your own tools for lightweight discovery, inventory, and context gathering.
|
|
83
|
+
Prefer the structured checkout, indexing, retrieval, and inventory tools that are already attached to you over
|
|
84
|
+
ad hoc shell work when those tools are sufficient.
|
|
85
|
+
Use the attached specialist descriptions as the source of truth for what each specialist is for.
|
|
86
|
+
Do not delegate to a specialist whose description does not clearly match the task.
|
|
87
|
+
Integrate specialist results into one coherent answer and do not claim checks or evidence you did not obtain.
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
When the user asks about available tools, skills, or agents, use the attached inventory tools instead of
|
|
90
|
+
inferring from memory.
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
Write to `/memories/*` only when the information is durable, reusable across future runs or threads, and likely
|
|
93
|
+
to matter again: user preferences, project conventions, confirmed decisions, reusable summaries, and stable
|
|
94
|
+
ownership facts are good candidates.
|
|
95
|
+
Do not store transient reasoning, temporary plans, scratch work, one-off search results, or intermediate
|
|
96
|
+
outputs that can be cheaply recomputed.
|
|
@@ -95,7 +95,9 @@ export type LangChainAgentParams = {
|
|
|
95
95
|
stateSchema?: unknown;
|
|
96
96
|
responseFormat?: unknown;
|
|
97
97
|
contextSchema?: unknown;
|
|
98
|
+
filesystem?: Record<string, unknown>;
|
|
98
99
|
middleware?: Array<Record<string, unknown>>;
|
|
100
|
+
passthrough?: Record<string, unknown>;
|
|
99
101
|
subagents?: CompiledSubAgent[];
|
|
100
102
|
memory?: string[];
|
|
101
103
|
skills?: string[];
|
|
@@ -118,6 +120,7 @@ export type CompiledSubAgent = {
|
|
|
118
120
|
responseFormat?: unknown;
|
|
119
121
|
contextSchema?: unknown;
|
|
120
122
|
middleware?: Array<Record<string, unknown>>;
|
|
123
|
+
passthrough?: Record<string, unknown>;
|
|
121
124
|
};
|
|
122
125
|
export type DeepAgentParams = {
|
|
123
126
|
model: CompiledModel;
|
|
@@ -126,6 +129,7 @@ export type DeepAgentParams = {
|
|
|
126
129
|
responseFormat?: unknown;
|
|
127
130
|
contextSchema?: unknown;
|
|
128
131
|
middleware?: Array<Record<string, unknown>>;
|
|
132
|
+
passthrough?: Record<string, unknown>;
|
|
129
133
|
description: string;
|
|
130
134
|
subagents: CompiledSubAgent[];
|
|
131
135
|
interruptOn?: Record<string, boolean | object>;
|
|
@@ -257,6 +261,9 @@ export type RunResult = {
|
|
|
257
261
|
state: RunState;
|
|
258
262
|
output: string;
|
|
259
263
|
finalMessageText?: string;
|
|
264
|
+
outputContent?: unknown;
|
|
265
|
+
contentBlocks?: unknown[];
|
|
266
|
+
structuredResponse?: unknown;
|
|
260
267
|
interruptContent?: string;
|
|
261
268
|
agentId?: string;
|
|
262
269
|
approvalId?: string;
|
|
@@ -267,6 +274,7 @@ export type RunResult = {
|
|
|
267
274
|
};
|
|
268
275
|
export type RunListeners = {
|
|
269
276
|
onChunk?: (chunk: string) => void | Promise<void>;
|
|
277
|
+
onContentBlocks?: (blocks: unknown[]) => void | Promise<void>;
|
|
270
278
|
onEvent?: (event: HarnessEvent) => void | Promise<void>;
|
|
271
279
|
onReasoning?: (chunk: string) => void | Promise<void>;
|
|
272
280
|
onStep?: (step: string) => void | Promise<void>;
|
|
@@ -318,6 +326,12 @@ export type HarnessStreamItem = {
|
|
|
318
326
|
runId: string;
|
|
319
327
|
agentId: string;
|
|
320
328
|
content: string;
|
|
329
|
+
} | {
|
|
330
|
+
type: "content-blocks";
|
|
331
|
+
threadId: string;
|
|
332
|
+
runId: string;
|
|
333
|
+
agentId: string;
|
|
334
|
+
contentBlocks: unknown[];
|
|
321
335
|
} | {
|
|
322
336
|
type: "reasoning";
|
|
323
337
|
threadId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.50";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.50";
|
package/dist/presentation.d.ts
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
1
|
export declare function escapeHtml(value: string): string;
|
|
2
|
-
/** CSS class for anchors that should open in the host app embedded browser (Wallee). */
|
|
3
|
-
export declare const WALLEE_OUTPUT_LINK_CLASS = "wallee-output-link";
|
|
4
|
-
/** `data-wallee-url` — target URL for the embedded browser (http/https only). */
|
|
5
|
-
export declare const WALLEE_BROWSER_URL_ATTR = "data-wallee-url";
|
|
6
|
-
export declare function isAllowedWalleeBrowserUrl(url: string): boolean;
|
|
7
|
-
/**
|
|
8
|
-
* Escape plain text and wrap http(s) URLs in Wallee output anchors (open in host embedded browser).
|
|
9
|
-
*/
|
|
10
|
-
export declare function linkifyPlainTextForWalleeBrowser(text: string): string;
|
|
11
|
-
/**
|
|
12
|
-
* Like {@link markdownToHtml} but inline http(s) URLs and markdown links `[label](https://…)` render as
|
|
13
|
-
* Wallee embedded-browser anchors (`wallee-output-link` + `data-wallee-url`).
|
|
14
|
-
*/
|
|
15
|
-
export declare function markdownToWalleeOutputHtml(markdown: string): string;
|
|
16
2
|
export declare function markdownToHtml(markdown: string): string;
|
|
17
3
|
export declare function markdownToConsole(markdown: string): string;
|
|
18
4
|
export declare function renderTemplate(data: Record<string, unknown>, template: string): string;
|
package/dist/presentation.js
CHANGED
|
@@ -8,152 +8,6 @@ export function escapeHtml(value) {
|
|
|
8
8
|
.replaceAll('"', """)
|
|
9
9
|
.replaceAll("'", "'");
|
|
10
10
|
}
|
|
11
|
-
/** CSS class for anchors that should open in the host app embedded browser (Wallee). */
|
|
12
|
-
export const WALLEE_OUTPUT_LINK_CLASS = "wallee-output-link";
|
|
13
|
-
/** `data-wallee-url` — target URL for the embedded browser (http/https only). */
|
|
14
|
-
export const WALLEE_BROWSER_URL_ATTR = "data-wallee-url";
|
|
15
|
-
export function isAllowedWalleeBrowserUrl(url) {
|
|
16
|
-
try {
|
|
17
|
-
const u = new URL(url);
|
|
18
|
-
return u.protocol === "http:" || u.protocol === "https:";
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function walleeOutputAnchor(url, labelEscaped) {
|
|
25
|
-
return `<a class="${WALLEE_OUTPUT_LINK_CLASS}" ${WALLEE_BROWSER_URL_ATTR}="${escapeHtml(url)}" href="#">${labelEscaped}</a>`;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Escape plain text and wrap http(s) URLs in Wallee output anchors (open in host embedded browser).
|
|
29
|
-
*/
|
|
30
|
-
export function linkifyPlainTextForWalleeBrowser(text) {
|
|
31
|
-
const urlRe = /\bhttps?:\/\/[^\s<>"']+/g;
|
|
32
|
-
const parts = [];
|
|
33
|
-
let last = 0;
|
|
34
|
-
let m;
|
|
35
|
-
while ((m = urlRe.exec(text)) !== null) {
|
|
36
|
-
parts.push(escapeHtml(text.slice(last, m.index)));
|
|
37
|
-
const raw = m[0];
|
|
38
|
-
const trimmed = raw.replace(/[.,;:!?)\]]+$/u, "");
|
|
39
|
-
const rest = raw.slice(trimmed.length);
|
|
40
|
-
if (isAllowedWalleeBrowserUrl(trimmed)) {
|
|
41
|
-
parts.push(walleeOutputAnchor(trimmed, escapeHtml(trimmed)));
|
|
42
|
-
if (rest) {
|
|
43
|
-
parts.push(escapeHtml(rest));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
parts.push(escapeHtml(raw));
|
|
48
|
-
}
|
|
49
|
-
last = m.index + raw.length;
|
|
50
|
-
}
|
|
51
|
-
parts.push(escapeHtml(text.slice(last)));
|
|
52
|
-
return parts.join("");
|
|
53
|
-
}
|
|
54
|
-
function applyBasicInlineMarkdown(escaped) {
|
|
55
|
-
return escaped
|
|
56
|
-
.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>")
|
|
57
|
-
.replace(/\*(.+?)\*/g, "<em>$1</em>")
|
|
58
|
-
.replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
59
|
-
}
|
|
60
|
-
function linkifyPlainTextSegmentWithWalleeMarkdown(text) {
|
|
61
|
-
const mdLinkPattern = /\[([^\]]*)\]\((https?:\/\/[^)\s]+)\)/g;
|
|
62
|
-
const segments = [];
|
|
63
|
-
let lastIndex = 0;
|
|
64
|
-
let m;
|
|
65
|
-
while ((m = mdLinkPattern.exec(text)) !== null) {
|
|
66
|
-
if (m.index > lastIndex) {
|
|
67
|
-
segments.push({ type: "text", text: text.slice(lastIndex, m.index) });
|
|
68
|
-
}
|
|
69
|
-
segments.push({ type: "mdlink", label: m[1], url: m[2] });
|
|
70
|
-
lastIndex = m.index + m[0].length;
|
|
71
|
-
}
|
|
72
|
-
if (lastIndex < text.length) {
|
|
73
|
-
segments.push({ type: "text", text: text.slice(lastIndex) });
|
|
74
|
-
}
|
|
75
|
-
if (segments.length === 0) {
|
|
76
|
-
segments.push({ type: "text", text });
|
|
77
|
-
}
|
|
78
|
-
return segments
|
|
79
|
-
.map((seg) => {
|
|
80
|
-
if (seg.type === "mdlink") {
|
|
81
|
-
if (!isAllowedWalleeBrowserUrl(seg.url)) {
|
|
82
|
-
return `${escapeHtml(seg.label)} (${escapeHtml(seg.url)})`;
|
|
83
|
-
}
|
|
84
|
-
return walleeOutputAnchor(seg.url, escapeHtml(seg.label));
|
|
85
|
-
}
|
|
86
|
-
return linkifyBareUrlsWithInlineMarkdown(seg.text);
|
|
87
|
-
})
|
|
88
|
-
.join("");
|
|
89
|
-
}
|
|
90
|
-
function linkifyBareUrlsWithInlineMarkdown(text) {
|
|
91
|
-
const urlRe = /\bhttps?:\/\/[^\s<>"']+/g;
|
|
92
|
-
const parts = [];
|
|
93
|
-
let last = 0;
|
|
94
|
-
let m;
|
|
95
|
-
while ((m = urlRe.exec(text)) !== null) {
|
|
96
|
-
parts.push(applyBasicInlineMarkdown(escapeHtml(text.slice(last, m.index))));
|
|
97
|
-
const raw = m[0];
|
|
98
|
-
const trimmed = raw.replace(/[.,;:!?)\]]+$/u, "");
|
|
99
|
-
const rest = raw.slice(trimmed.length);
|
|
100
|
-
if (isAllowedWalleeBrowserUrl(trimmed)) {
|
|
101
|
-
parts.push(walleeOutputAnchor(trimmed, escapeHtml(trimmed)));
|
|
102
|
-
if (rest) {
|
|
103
|
-
parts.push(applyBasicInlineMarkdown(escapeHtml(rest)));
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
parts.push(applyBasicInlineMarkdown(escapeHtml(raw)));
|
|
108
|
-
}
|
|
109
|
-
last = m.index + raw.length;
|
|
110
|
-
}
|
|
111
|
-
parts.push(applyBasicInlineMarkdown(escapeHtml(text.slice(last))));
|
|
112
|
-
return parts.join("");
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Like {@link markdownToHtml} but inline http(s) URLs and markdown links `[label](https://…)` render as
|
|
116
|
-
* Wallee embedded-browser anchors (`wallee-output-link` + `data-wallee-url`).
|
|
117
|
-
*/
|
|
118
|
-
export function markdownToWalleeOutputHtml(markdown) {
|
|
119
|
-
const normalized = markdown.replace(/\r\n/g, "\n");
|
|
120
|
-
const blocks = normalized.split(/\n\n+/);
|
|
121
|
-
const html = [];
|
|
122
|
-
for (const block of blocks) {
|
|
123
|
-
const trimmed = block.trim();
|
|
124
|
-
if (!trimmed) {
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
if (trimmed.startsWith("```") && trimmed.endsWith("```")) {
|
|
128
|
-
const lines = trimmed.split("\n");
|
|
129
|
-
const language = lines[0]?.slice(3).trim();
|
|
130
|
-
const code = lines.slice(1, -1).join("\n");
|
|
131
|
-
html.push(`<pre class="ah-code"><code${language ? ` data-language="${escapeHtml(language)}"` : ""}>${escapeHtml(code)}</code></pre>`);
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
if (/^#{1,6}\s/.test(trimmed)) {
|
|
135
|
-
const match = trimmed.match(/^(#{1,6})\s+(.*)$/);
|
|
136
|
-
const level = match?.[1].length ?? 1;
|
|
137
|
-
const content = linkifyPlainTextSegmentWithWalleeMarkdown(match?.[2] ?? trimmed);
|
|
138
|
-
html.push(`<h${level}>${content}</h${level}>`);
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
if (trimmed.split("\n").every((line) => /^[-*]\s+/.test(line))) {
|
|
142
|
-
const items = trimmed
|
|
143
|
-
.split("\n")
|
|
144
|
-
.map((line) => line.replace(/^[-*]\s+/, ""))
|
|
145
|
-
.map((line) => `<li>${linkifyPlainTextSegmentWithWalleeMarkdown(line)}</li>`)
|
|
146
|
-
.join("");
|
|
147
|
-
html.push(`<ul>${items}</ul>`);
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
html.push(`<p>${trimmed
|
|
151
|
-
.split("\n")
|
|
152
|
-
.map((line) => linkifyPlainTextSegmentWithWalleeMarkdown(line))
|
|
153
|
-
.join("<br />")}</p>`);
|
|
154
|
-
}
|
|
155
|
-
return html.join("");
|
|
156
|
-
}
|
|
157
11
|
function renderInlineMarkdown(text) {
|
|
158
12
|
const escaped = escapeHtml(text);
|
|
159
13
|
return escaped
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { Command, MemorySaver } from "@langchain/langgraph";
|
|
2
3
|
import { tool as createLangChainTool } from "@langchain/core/tools";
|
|
3
4
|
import { createDeepAgent, createMemoryMiddleware, createSkillsMiddleware, createSubAgentMiddleware, FilesystemBackend, } from "deepagents";
|
|
@@ -9,7 +10,7 @@ import { ChatOpenAI } from "@langchain/openai";
|
|
|
9
10
|
import { tools as openAIProviderTools } from "@langchain/openai";
|
|
10
11
|
import { createAgent, humanInTheLoopMiddleware, initChatModel } from "langchain";
|
|
11
12
|
import { z } from "zod";
|
|
12
|
-
import { extractEmptyAssistantMessageFailure, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, isLikelyToolArgsObject, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, sanitizeVisibleText, tryParseJson, wrapResolvedModel, } from "./parsing/output-parsing.js";
|
|
13
|
+
import { extractEmptyAssistantMessageFailure, extractContentBlocks, extractOutputContent, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, isLikelyToolArgsObject, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, sanitizeVisibleText, tryParseJson, wrapResolvedModel, } from "./parsing/output-parsing.js";
|
|
13
14
|
import { computeIncrementalOutput, extractAgentStep, extractInterruptPayload, extractReasoningStreamOutput, extractStateStreamOutput, extractVisibleStreamOutput, extractTerminalStreamOutput, extractToolResult, normalizeTerminalOutputKey, readStreamDelta, } from "./parsing/stream-event-parsing.js";
|
|
14
15
|
import { wrapToolForExecution } from "./tool-hitl.js";
|
|
15
16
|
import { resolveDeclaredMiddleware } from "./declared-middleware.js";
|
|
@@ -475,10 +476,20 @@ export class AgentRuntimeAdapter {
|
|
|
475
476
|
return this.compileInterruptOn(getBindingPrimaryTools(binding), getBindingInterruptCompatibilityRules(binding));
|
|
476
477
|
}
|
|
477
478
|
resolveFilesystemBackend(binding) {
|
|
479
|
+
const filesystemConfig = getBindingLangChainParams(binding)?.filesystem;
|
|
480
|
+
const configuredRootDir = typeof filesystemConfig?.rootDir === "string" && filesystemConfig.rootDir.trim().length > 0
|
|
481
|
+
? filesystemConfig.rootDir
|
|
482
|
+
: undefined;
|
|
483
|
+
const workspaceRoot = binding.harnessRuntime.workspaceRoot;
|
|
484
|
+
const rootDir = configuredRootDir
|
|
485
|
+
? (path.isAbsolute(configuredRootDir) ? configuredRootDir : path.resolve(workspaceRoot ?? process.cwd(), configuredRootDir))
|
|
486
|
+
: workspaceRoot ?? process.cwd();
|
|
478
487
|
return new FilesystemBackend({
|
|
479
|
-
rootDir
|
|
480
|
-
virtualMode:
|
|
481
|
-
maxFileSizeMb:
|
|
488
|
+
rootDir,
|
|
489
|
+
virtualMode: filesystemConfig?.virtualMode === true,
|
|
490
|
+
maxFileSizeMb: typeof filesystemConfig?.maxFileSizeMb === "number" && Number.isFinite(filesystemConfig.maxFileSizeMb)
|
|
491
|
+
? filesystemConfig.maxFileSizeMb
|
|
492
|
+
: 10,
|
|
482
493
|
});
|
|
483
494
|
}
|
|
484
495
|
async resolveLangChainAutomaticMiddleware(binding) {
|
|
@@ -556,6 +567,7 @@ export class AgentRuntimeAdapter {
|
|
|
556
567
|
async resolveSubagents(subagents, binding) {
|
|
557
568
|
return Promise.all(subagents.map(async (subagent) => ({
|
|
558
569
|
...subagent,
|
|
570
|
+
...(subagent.passthrough ?? {}),
|
|
559
571
|
model: subagent.model ? (await this.resolveModel(subagent.model)) : undefined,
|
|
560
572
|
tools: subagent.tools ? this.resolveTools(subagent.tools) : undefined,
|
|
561
573
|
interruptOn: this.compileInterruptOn(subagent.tools ?? [], subagent.interruptOn),
|
|
@@ -578,6 +590,7 @@ export class AgentRuntimeAdapter {
|
|
|
578
590
|
throw new Error(`Agent ${binding.agent.id} configures ${tools.length} tool(s), but resolved model ${params.model.id} does not support tool binding.`);
|
|
579
591
|
}
|
|
580
592
|
return createAgent({
|
|
593
|
+
...(params.passthrough ?? {}),
|
|
581
594
|
model: model,
|
|
582
595
|
tools: tools,
|
|
583
596
|
systemPrompt: params.systemPrompt,
|
|
@@ -598,6 +611,7 @@ export class AgentRuntimeAdapter {
|
|
|
598
611
|
throw new Error(`Agent ${binding.agent.id} has no runnable params`);
|
|
599
612
|
}
|
|
600
613
|
const deepAgentConfig = {
|
|
614
|
+
...(params.passthrough ?? {}),
|
|
601
615
|
model: (await this.resolveModel(params.model)),
|
|
602
616
|
tools: this.resolveTools(params.tools, binding),
|
|
603
617
|
systemPrompt: params.systemPrompt,
|
|
@@ -672,6 +686,9 @@ export class AgentRuntimeAdapter {
|
|
|
672
686
|
}
|
|
673
687
|
const output = visibleOutput || synthesizedOutput || toolFallback || JSON.stringify(result, null, 2);
|
|
674
688
|
const finalMessageText = sanitizeVisibleText(output);
|
|
689
|
+
const outputContent = extractOutputContent(result);
|
|
690
|
+
const contentBlocks = extractContentBlocks(result);
|
|
691
|
+
const structuredResponse = result.structuredResponse;
|
|
675
692
|
return {
|
|
676
693
|
threadId,
|
|
677
694
|
runId,
|
|
@@ -680,8 +697,13 @@ export class AgentRuntimeAdapter {
|
|
|
680
697
|
interruptContent,
|
|
681
698
|
output: finalMessageText,
|
|
682
699
|
finalMessageText,
|
|
700
|
+
...(outputContent !== undefined ? { outputContent } : {}),
|
|
701
|
+
...(contentBlocks.length > 0 ? { contentBlocks } : {}),
|
|
702
|
+
...(structuredResponse !== undefined ? { structuredResponse } : {}),
|
|
683
703
|
metadata: {
|
|
684
|
-
...(
|
|
704
|
+
...(structuredResponse !== undefined ? { structuredResponse } : {}),
|
|
705
|
+
...(outputContent !== undefined ? { outputContent } : {}),
|
|
706
|
+
...(contentBlocks.length > 0 ? { contentBlocks } : {}),
|
|
685
707
|
...(asRecord(result.files) ? { files: asRecord(result.files) } : {}),
|
|
686
708
|
...(this.buildStateSnapshot(result) ? { stateSnapshot: this.buildStateSnapshot(result) } : {}),
|
|
687
709
|
upstreamResult: result,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { anthropicPromptCachingMiddleware, contextEditingMiddleware, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, piiMiddleware,
|
|
1
|
+
import { anthropicPromptCachingMiddleware, contextEditingMiddleware, humanInTheLoopMiddleware, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, piiMiddleware, 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
|
}
|
|
@@ -77,6 +77,9 @@ export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
|
|
|
77
77
|
case "toolEmulator":
|
|
78
78
|
resolved.push(toolEmulatorMiddleware(runtimeConfig));
|
|
79
79
|
break;
|
|
80
|
+
case "humanInTheLoop":
|
|
81
|
+
resolved.push(humanInTheLoopMiddleware(runtimeConfig));
|
|
82
|
+
break;
|
|
80
83
|
case "openAIModeration":
|
|
81
84
|
resolved.push(openAIModerationMiddleware(runtimeConfig));
|
|
82
85
|
break;
|
|
@@ -89,9 +92,6 @@ export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
|
|
|
89
92
|
resolved.push(piiMiddleware(piiType, piiOptions));
|
|
90
93
|
break;
|
|
91
94
|
}
|
|
92
|
-
case "piiRedaction":
|
|
93
|
-
resolved.push(piiRedactionMiddleware(runtimeConfig));
|
|
94
|
-
break;
|
|
95
95
|
case "anthropicPromptCaching":
|
|
96
96
|
resolved.push(anthropicPromptCachingMiddleware(runtimeConfig));
|
|
97
97
|
break;
|
|
@@ -71,6 +71,7 @@ export declare class AgentHarnessRuntime {
|
|
|
71
71
|
private checkpointRefForState;
|
|
72
72
|
private finalizeContinuedRun;
|
|
73
73
|
private emitOutputDeltaAndCreateItem;
|
|
74
|
+
private createContentBlocksItem;
|
|
74
75
|
private emitRunCreated;
|
|
75
76
|
private setRunStateAndEmit;
|
|
76
77
|
private requestApprovalAndEmit;
|
package/dist/runtime/harness.js
CHANGED
|
@@ -525,6 +525,15 @@ export class AgentHarnessRuntime {
|
|
|
525
525
|
content,
|
|
526
526
|
};
|
|
527
527
|
}
|
|
528
|
+
createContentBlocksItem(threadId, runId, agentId, contentBlocks) {
|
|
529
|
+
return {
|
|
530
|
+
type: "content-blocks",
|
|
531
|
+
threadId,
|
|
532
|
+
runId,
|
|
533
|
+
agentId,
|
|
534
|
+
contentBlocks,
|
|
535
|
+
};
|
|
536
|
+
}
|
|
528
537
|
async emitRunCreated(threadId, runId, payload) {
|
|
529
538
|
return this.emit(threadId, runId, 1, "run.created", payload);
|
|
530
539
|
}
|
|
@@ -678,6 +687,10 @@ export class AgentHarnessRuntime {
|
|
|
678
687
|
await this.notifyListener(listeners.onChunk, item.content);
|
|
679
688
|
continue;
|
|
680
689
|
}
|
|
690
|
+
if (item.type === "content-blocks") {
|
|
691
|
+
await this.notifyListener(listeners.onContentBlocks, item.contentBlocks);
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
681
694
|
if (item.type === "reasoning") {
|
|
682
695
|
await this.notifyListener(listeners.onReasoning, item.content);
|
|
683
696
|
continue;
|
|
@@ -890,6 +903,9 @@ export class AgentHarnessRuntime {
|
|
|
890
903
|
}
|
|
891
904
|
if (!assistantOutput) {
|
|
892
905
|
const actual = await this.invokeWithHistory(binding, options.input, threadId, runId);
|
|
906
|
+
if (Array.isArray(actual.contentBlocks) && actual.contentBlocks.length > 0) {
|
|
907
|
+
yield this.createContentBlocksItem(threadId, runId, selectedAgentId, actual.contentBlocks);
|
|
908
|
+
}
|
|
893
909
|
if (actual.output) {
|
|
894
910
|
assistantOutput = actual.output;
|
|
895
911
|
emitted = true;
|
|
@@ -949,6 +965,9 @@ export class AgentHarnessRuntime {
|
|
|
949
965
|
try {
|
|
950
966
|
const actual = await this.invokeWithHistory(binding, options.input, threadId, runId);
|
|
951
967
|
await this.appendAssistantMessage(threadId, runId, actual.output);
|
|
968
|
+
if (Array.isArray(actual.contentBlocks) && actual.contentBlocks.length > 0) {
|
|
969
|
+
yield this.createContentBlocksItem(threadId, runId, selectedAgentId, actual.contentBlocks);
|
|
970
|
+
}
|
|
952
971
|
if (actual.output) {
|
|
953
972
|
yield await this.emitOutputDeltaAndCreateItem(threadId, runId, selectedAgentId, actual.output);
|
|
954
973
|
}
|
|
@@ -6,6 +6,8 @@ export declare function readTextContent(value: unknown): string;
|
|
|
6
6
|
export declare function hasToolCalls(value: unknown): boolean;
|
|
7
7
|
export declare function extractToolFallbackContext(value: unknown): string;
|
|
8
8
|
export declare function extractVisibleOutput(value: unknown): string;
|
|
9
|
+
export declare function extractOutputContent(value: unknown): unknown;
|
|
10
|
+
export declare function extractContentBlocks(value: unknown): unknown[];
|
|
9
11
|
export declare function extractEmptyAssistantMessageFailure(value: unknown): string;
|
|
10
12
|
export declare function isToolCallParseFailure(error: unknown): boolean;
|
|
11
13
|
export declare const STRICT_TOOL_JSON_INSTRUCTION = "When calling tools, return only the tool call itself. The arguments must be a pure JSON object with no explanatory text before or after it.";
|
|
@@ -166,8 +166,8 @@ function extractMessageContent(message) {
|
|
|
166
166
|
if (typeof message !== "object" || !message)
|
|
167
167
|
return "";
|
|
168
168
|
const typed = message;
|
|
169
|
-
if (
|
|
170
|
-
return typed.content;
|
|
169
|
+
if (typed.content !== undefined)
|
|
170
|
+
return readTextContent(typed.content);
|
|
171
171
|
if (typeof typed.kwargs === "object" && typed.kwargs) {
|
|
172
172
|
return readTextContent(typed.kwargs.content);
|
|
173
173
|
}
|
|
@@ -341,6 +341,79 @@ export function extractVisibleOutput(value) {
|
|
|
341
341
|
}
|
|
342
342
|
return "";
|
|
343
343
|
}
|
|
344
|
+
function isContentBlock(value) {
|
|
345
|
+
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
346
|
+
}
|
|
347
|
+
function normalizeContentBlocks(value) {
|
|
348
|
+
if (!Array.isArray(value)) {
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
return value.filter(isContentBlock).map((block) => ({ ...block }));
|
|
352
|
+
}
|
|
353
|
+
function extractStructuredOutputContent(value) {
|
|
354
|
+
if (typeof value !== "object" || !value)
|
|
355
|
+
return undefined;
|
|
356
|
+
const typed = value;
|
|
357
|
+
if (typed.output && typeof typed.output === "object") {
|
|
358
|
+
const nested = extractStructuredOutputContent(typed.output);
|
|
359
|
+
if (nested !== undefined)
|
|
360
|
+
return nested;
|
|
361
|
+
}
|
|
362
|
+
if (typed.content !== undefined) {
|
|
363
|
+
return typed.content;
|
|
364
|
+
}
|
|
365
|
+
if (!Array.isArray(typed.messages)) {
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
for (let index = typed.messages.length - 1; index >= 0; index -= 1) {
|
|
369
|
+
const message = typed.messages[index];
|
|
370
|
+
if (typeof message !== "object" || !message)
|
|
371
|
+
continue;
|
|
372
|
+
const ids = Array.isArray(message.id)
|
|
373
|
+
? (message.id.filter((item) => typeof item === "string"))
|
|
374
|
+
: [];
|
|
375
|
+
const typeName = ids.at(-1);
|
|
376
|
+
const runtimeType = typeof message._getType === "function"
|
|
377
|
+
? message._getType()
|
|
378
|
+
: typeof message.getType === "function"
|
|
379
|
+
? message.getType()
|
|
380
|
+
: undefined;
|
|
381
|
+
if (!(typeName === "AIMessage" || runtimeType === "ai")) {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
if (hasToolCalls(message)) {
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
const directContent = message.content;
|
|
388
|
+
if (directContent !== undefined) {
|
|
389
|
+
return directContent;
|
|
390
|
+
}
|
|
391
|
+
const kwargs = typeof message.kwargs === "object" && message.kwargs
|
|
392
|
+
? (message.kwargs)
|
|
393
|
+
: undefined;
|
|
394
|
+
if (kwargs?.content !== undefined) {
|
|
395
|
+
return kwargs.content;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
export function extractOutputContent(value) {
|
|
401
|
+
const content = extractStructuredOutputContent(value);
|
|
402
|
+
if (content !== undefined) {
|
|
403
|
+
return content;
|
|
404
|
+
}
|
|
405
|
+
return undefined;
|
|
406
|
+
}
|
|
407
|
+
export function extractContentBlocks(value) {
|
|
408
|
+
const outputContent = extractOutputContent(value);
|
|
409
|
+
if (outputContent === undefined) {
|
|
410
|
+
return [];
|
|
411
|
+
}
|
|
412
|
+
if (typeof outputContent === "string") {
|
|
413
|
+
return outputContent.trim() ? [{ type: "text", text: outputContent }] : [];
|
|
414
|
+
}
|
|
415
|
+
return normalizeContentBlocks(outputContent);
|
|
416
|
+
}
|
|
344
417
|
export function extractEmptyAssistantMessageFailure(value) {
|
|
345
418
|
if (typeof value !== "object" || !value)
|
|
346
419
|
return "";
|
|
@@ -105,6 +105,9 @@ function buildSubagent(agent, workspaceRoot, models, tools, parentSkills, parent
|
|
|
105
105
|
responseFormat: agent.deepAgentConfig?.responseFormat,
|
|
106
106
|
contextSchema: agent.deepAgentConfig?.contextSchema,
|
|
107
107
|
middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
|
|
108
|
+
passthrough: typeof agent.deepAgentConfig?.passthrough === "object" && agent.deepAgentConfig.passthrough
|
|
109
|
+
? { ...agent.deepAgentConfig.passthrough }
|
|
110
|
+
: undefined,
|
|
108
111
|
};
|
|
109
112
|
}
|
|
110
113
|
function resolveDirectPrompt(agent) {
|
|
@@ -242,7 +245,13 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
242
245
|
stateSchema: agent.langchainAgentConfig?.stateSchema,
|
|
243
246
|
responseFormat: agent.langchainAgentConfig?.responseFormat,
|
|
244
247
|
contextSchema: agent.langchainAgentConfig?.contextSchema,
|
|
248
|
+
filesystem: typeof agent.langchainAgentConfig?.filesystem === "object" && agent.langchainAgentConfig.filesystem
|
|
249
|
+
? { ...agent.langchainAgentConfig.filesystem }
|
|
250
|
+
: undefined,
|
|
245
251
|
middleware: compileMiddlewareConfigs(agent.langchainAgentConfig?.middleware, models, agent.id),
|
|
252
|
+
passthrough: typeof agent.langchainAgentConfig?.passthrough === "object" && agent.langchainAgentConfig.passthrough
|
|
253
|
+
? { ...agent.langchainAgentConfig.passthrough }
|
|
254
|
+
: undefined,
|
|
246
255
|
subagents: agent.subagentRefs.map((ref) => {
|
|
247
256
|
const subagent = agents.get(resolveRefId(ref));
|
|
248
257
|
if (!subagent) {
|
|
@@ -282,6 +291,9 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
282
291
|
responseFormat: agent.deepAgentConfig?.responseFormat,
|
|
283
292
|
contextSchema: agent.deepAgentConfig?.contextSchema,
|
|
284
293
|
middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
|
|
294
|
+
passthrough: typeof agent.deepAgentConfig?.passthrough === "object" && agent.deepAgentConfig.passthrough
|
|
295
|
+
? { ...agent.deepAgentConfig.passthrough }
|
|
296
|
+
: undefined,
|
|
285
297
|
description: agent.description,
|
|
286
298
|
subagents: agent.subagentRefs.map((ref) => {
|
|
287
299
|
const subagent = agents.get(resolveRefId(ref));
|
|
@@ -61,6 +61,11 @@ function toArray(value) {
|
|
|
61
61
|
function asObject(value) {
|
|
62
62
|
return typeof value === "object" && value ? value : undefined;
|
|
63
63
|
}
|
|
64
|
+
function asMutableObject(value) {
|
|
65
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
66
|
+
? { ...value }
|
|
67
|
+
: undefined;
|
|
68
|
+
}
|
|
64
69
|
function normalizeCatalogSpec(document, options = {}) {
|
|
65
70
|
const typed = asObject(document);
|
|
66
71
|
const spec = typed?.spec;
|
|
@@ -211,9 +216,29 @@ function readCapabilities(value) {
|
|
|
211
216
|
return Object.keys(capabilities).length > 0 ? capabilities : undefined;
|
|
212
217
|
}
|
|
213
218
|
function readExecutionConfig(value) {
|
|
214
|
-
return
|
|
215
|
-
|
|
216
|
-
|
|
219
|
+
return asMutableObject(value);
|
|
220
|
+
}
|
|
221
|
+
function readExecutionAgentConfig(item) {
|
|
222
|
+
const execution = readExecutionConfig(item.execution);
|
|
223
|
+
return asMutableObject(execution?.config) ?? {};
|
|
224
|
+
}
|
|
225
|
+
function readRuntimeConfig(item) {
|
|
226
|
+
return asMutableObject(item.runtime);
|
|
227
|
+
}
|
|
228
|
+
function cloneConfigValue(value) {
|
|
229
|
+
if (Array.isArray(value)) {
|
|
230
|
+
return value.map((item) => cloneConfigValue(item));
|
|
231
|
+
}
|
|
232
|
+
if (typeof value === "object" && value !== null) {
|
|
233
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, cloneConfigValue(entry)]));
|
|
234
|
+
}
|
|
235
|
+
return value;
|
|
236
|
+
}
|
|
237
|
+
function readPassthroughConfig(item, consumedKeys) {
|
|
238
|
+
const passthrough = Object.fromEntries(Object.entries(item)
|
|
239
|
+
.filter(([key]) => !consumedKeys.includes(key))
|
|
240
|
+
.map(([key, value]) => [key, cloneConfigValue(value)]));
|
|
241
|
+
return Object.keys(passthrough).length > 0 ? passthrough : undefined;
|
|
217
242
|
}
|
|
218
243
|
function resolveExecutionBackend(item, current) {
|
|
219
244
|
const execution = readExecutionConfig(item.execution) ?? readExecutionConfig(current?.execution);
|
|
@@ -230,43 +255,97 @@ function resolveExecutionBackend(item, current) {
|
|
|
230
255
|
}
|
|
231
256
|
return undefined;
|
|
232
257
|
}
|
|
233
|
-
function
|
|
234
|
-
const
|
|
258
|
+
function readExecutionSingleRef(item, key) {
|
|
259
|
+
const execution = readExecutionConfig(item.execution);
|
|
260
|
+
return readSingleRef(execution?.[key]);
|
|
261
|
+
}
|
|
262
|
+
function readExecutionRefArray(item, key) {
|
|
263
|
+
const execution = readExecutionConfig(item.execution);
|
|
264
|
+
return readRefArray(execution?.[key]);
|
|
265
|
+
}
|
|
266
|
+
function readExecutionPathArray(item, key) {
|
|
267
|
+
const execution = readExecutionConfig(item.execution);
|
|
268
|
+
return readPathArray(execution?.[key]);
|
|
269
|
+
}
|
|
270
|
+
function readExecutionObjectArray(item, key) {
|
|
271
|
+
const execution = readExecutionConfig(item.execution);
|
|
272
|
+
return readObjectArray(execution?.[key]);
|
|
273
|
+
}
|
|
274
|
+
function readSharedAgentConfig(config) {
|
|
275
|
+
const middleware = readMiddlewareArray(config.middleware);
|
|
235
276
|
return {
|
|
236
|
-
...(typeof
|
|
237
|
-
...((typeof
|
|
238
|
-
? { checkpointer:
|
|
277
|
+
...(typeof config.systemPrompt === "string" ? { systemPrompt: config.systemPrompt } : {}),
|
|
278
|
+
...((typeof config.checkpointer === "object" && config.checkpointer) || typeof config.checkpointer === "boolean"
|
|
279
|
+
? { checkpointer: config.checkpointer }
|
|
239
280
|
: {}),
|
|
240
|
-
...(typeof
|
|
241
|
-
...(
|
|
242
|
-
...(
|
|
243
|
-
...(
|
|
244
|
-
...(
|
|
245
|
-
...(
|
|
281
|
+
...(typeof config.interruptOn === "object" && config.interruptOn ? { interruptOn: config.interruptOn } : {}),
|
|
282
|
+
...(config.stateSchema !== undefined ? { stateSchema: config.stateSchema } : {}),
|
|
283
|
+
...(config.responseFormat !== undefined ? { responseFormat: config.responseFormat } : {}),
|
|
284
|
+
...(config.contextSchema !== undefined ? { contextSchema: config.contextSchema } : {}),
|
|
285
|
+
...(config.includeAgentName === "inline" ? { includeAgentName: "inline" } : {}),
|
|
286
|
+
...(config.version === "v1" || config.version === "v2" ? { version: config.version } : {}),
|
|
287
|
+
...(typeof config.filesystem === "object" && config.filesystem ? { filesystem: config.filesystem } : {}),
|
|
246
288
|
...(middleware ? { middleware } : {}),
|
|
247
289
|
};
|
|
248
290
|
}
|
|
249
291
|
function readLangchainAgentConfig(item) {
|
|
292
|
+
const config = readExecutionAgentConfig(item);
|
|
293
|
+
const passthrough = readPassthroughConfig(config, [
|
|
294
|
+
"systemPrompt",
|
|
295
|
+
"checkpointer",
|
|
296
|
+
"interruptOn",
|
|
297
|
+
"stateSchema",
|
|
298
|
+
"responseFormat",
|
|
299
|
+
"contextSchema",
|
|
300
|
+
"includeAgentName",
|
|
301
|
+
"version",
|
|
302
|
+
"middleware",
|
|
303
|
+
"backend",
|
|
304
|
+
"store",
|
|
305
|
+
"taskDescription",
|
|
306
|
+
"generalPurposeAgent",
|
|
307
|
+
"filesystem",
|
|
308
|
+
]);
|
|
250
309
|
return {
|
|
251
|
-
...readSharedAgentConfig(
|
|
252
|
-
...(typeof
|
|
253
|
-
...(typeof
|
|
254
|
-
...(typeof
|
|
310
|
+
...readSharedAgentConfig(config),
|
|
311
|
+
...(typeof config.store === "object" && config.store ? { store: config.store } : {}),
|
|
312
|
+
...(typeof config.taskDescription === "string" && config.taskDescription.trim() ? { taskDescription: config.taskDescription } : {}),
|
|
313
|
+
...(typeof config.generalPurposeAgent === "boolean" ? { generalPurposeAgent: config.generalPurposeAgent } : {}),
|
|
314
|
+
...(passthrough ? { passthrough } : {}),
|
|
255
315
|
};
|
|
256
316
|
}
|
|
257
317
|
function readDeepAgentConfig(item) {
|
|
318
|
+
const config = readExecutionAgentConfig(item);
|
|
319
|
+
const passthrough = readPassthroughConfig(config, [
|
|
320
|
+
"systemPrompt",
|
|
321
|
+
"checkpointer",
|
|
322
|
+
"interruptOn",
|
|
323
|
+
"stateSchema",
|
|
324
|
+
"responseFormat",
|
|
325
|
+
"contextSchema",
|
|
326
|
+
"includeAgentName",
|
|
327
|
+
"version",
|
|
328
|
+
"middleware",
|
|
329
|
+
"backend",
|
|
330
|
+
"store",
|
|
331
|
+
"taskDescription",
|
|
332
|
+
"generalPurposeAgent",
|
|
333
|
+
"filesystem",
|
|
334
|
+
]);
|
|
258
335
|
return {
|
|
259
|
-
...readSharedAgentConfig(
|
|
260
|
-
...(typeof
|
|
261
|
-
...(typeof
|
|
262
|
-
...(typeof
|
|
263
|
-
...(typeof
|
|
336
|
+
...readSharedAgentConfig(config),
|
|
337
|
+
...(typeof config.backend === "object" && config.backend ? { backend: config.backend } : {}),
|
|
338
|
+
...(typeof config.store === "object" && config.store ? { store: config.store } : {}),
|
|
339
|
+
...(typeof config.taskDescription === "string" && config.taskDescription.trim() ? { taskDescription: config.taskDescription } : {}),
|
|
340
|
+
...(typeof config.generalPurposeAgent === "boolean" ? { generalPurposeAgent: config.generalPurposeAgent } : {}),
|
|
341
|
+
...(passthrough ? { passthrough } : {}),
|
|
264
342
|
};
|
|
265
343
|
}
|
|
266
344
|
export function parseAgentItem(item, sourcePath) {
|
|
267
|
-
const subagentRefs =
|
|
268
|
-
const subagentPathRefs =
|
|
345
|
+
const subagentRefs = readExecutionRefArray(item, "subagents");
|
|
346
|
+
const subagentPathRefs = readExecutionPathArray(item, "subagents");
|
|
269
347
|
const executionMode = String(resolveExecutionBackend(item) ?? "deepagent");
|
|
348
|
+
const runtime = readRuntimeConfig(item);
|
|
270
349
|
return {
|
|
271
350
|
id: String(item.id),
|
|
272
351
|
executionMode: executionMode,
|
|
@@ -274,12 +353,12 @@ export function parseAgentItem(item, sourcePath) {
|
|
|
274
353
|
? { delegation: true, memory: true }
|
|
275
354
|
: { delegation: true, memory: true }),
|
|
276
355
|
description: String(item.description ?? ""),
|
|
277
|
-
modelRef:
|
|
278
|
-
runRoot: typeof
|
|
279
|
-
toolRefs:
|
|
280
|
-
mcpServers:
|
|
281
|
-
skillPathRefs:
|
|
282
|
-
memorySources:
|
|
356
|
+
modelRef: readExecutionSingleRef(item, "modelRef") ?? "",
|
|
357
|
+
runRoot: typeof runtime?.runRoot === "string" ? runtime.runRoot : undefined,
|
|
358
|
+
toolRefs: readExecutionRefArray(item, "tools"),
|
|
359
|
+
mcpServers: readExecutionObjectArray(item, "mcpServers"),
|
|
360
|
+
skillPathRefs: readExecutionPathArray(item, "skills"),
|
|
361
|
+
memorySources: readExecutionPathArray(item, "memory"),
|
|
283
362
|
subagentRefs,
|
|
284
363
|
subagentPathRefs,
|
|
285
364
|
langchainAgentConfig: readLangchainAgentConfig(item),
|
|
@@ -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 === "humanInTheLoop" && typeof typed.interruptOn !== "object") {
|
|
42
|
+
throw new Error(`Agent ${agent.id} humanInTheLoop middleware requires interruptOn`);
|
|
43
|
+
}
|
|
41
44
|
if (kind === "pii" && typeof typed.piiType !== "string") {
|
|
42
45
|
throw new Error(`Agent ${agent.id} pii middleware requires piiType`);
|
|
43
46
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botbotgo/agent-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.51",
|
|
4
4
|
"description": "Workspace runtime for multi-agent applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@10.9.2",
|
|
@@ -26,11 +26,6 @@
|
|
|
26
26
|
"types": "./dist/tools.d.ts",
|
|
27
27
|
"import": "./dist/tools.js",
|
|
28
28
|
"default": "./dist/tools.js"
|
|
29
|
-
},
|
|
30
|
-
"./presentation": {
|
|
31
|
-
"types": "./dist/presentation.d.ts",
|
|
32
|
-
"import": "./dist/presentation.js",
|
|
33
|
-
"default": "./dist/presentation.js"
|
|
34
29
|
}
|
|
35
30
|
},
|
|
36
31
|
"dependencies": {
|
|
@@ -38,7 +33,7 @@
|
|
|
38
33
|
"@langchain/community": "^1.1.24",
|
|
39
34
|
"@langchain/core": "^1.1.33",
|
|
40
35
|
"@langchain/google": "^0.1.7",
|
|
41
|
-
"@langchain/langgraph": "^1.2.
|
|
36
|
+
"@langchain/langgraph": "^1.2.5",
|
|
42
37
|
"@langchain/langgraph-checkpoint-sqlite": "^1.0.1",
|
|
43
38
|
"@langchain/ollama": "^1.2.6",
|
|
44
39
|
"@langchain/openai": "^1.1.0",
|
|
@@ -46,7 +41,7 @@
|
|
|
46
41
|
"@llamaindex/ollama": "^0.1.23",
|
|
47
42
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
48
43
|
"deepagents": "1.8.4",
|
|
49
|
-
"langchain": "1.2.
|
|
44
|
+
"langchain": "^1.2.36",
|
|
50
45
|
"llamaindex": "^0.12.1",
|
|
51
46
|
"mustache": "^4.2.0",
|
|
52
47
|
"yaml": "^2.8.1",
|
|
@@ -55,9 +50,8 @@
|
|
|
55
50
|
"scripts": {
|
|
56
51
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc -p tsconfig.json && cp -R config dist/",
|
|
57
52
|
"check": "tsc -p tsconfig.json --noEmit",
|
|
58
|
-
"test": "vitest run test/public-api.test.ts test/resource-optional-provider.test.ts test/resource-isolation.test.ts test/stock-research-app-load-harness.test.ts test/stock-research-app-run.test.ts test/release-workflow.test.ts test/release-version.test.ts test/gitignore.test.ts test/package-lock.test.ts test/readme.test.ts test/runtime-adapter-regressions.test.ts test/runtime-recovery.test.ts test/tool-extension-gaps.test.ts test/checkpoint-maintenance.test.ts test/llamaindex-dependency-compat.test.ts test/skill-standard.test.ts test/routing-config.test.ts test/workspace-compat-regressions.test.ts test/upstream-compat-regressions.test.ts test/
|
|
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",
|
|
59
54
|
"test:real-providers": "vitest run test/real-provider-harness.test.ts",
|
|
60
|
-
"test:integration": "npm run build && node scripts/integration-wallee-browser.mjs",
|
|
61
55
|
"release:prepare": "npm version patch --no-git-tag-version && node ./scripts/sync-example-version.mjs",
|
|
62
56
|
"release:pack": "npm pack --dry-run",
|
|
63
57
|
"release:publish": "npm publish --access public --registry https://registry.npmjs.org/"
|