Skip to content

Commit 9aaf35d

Browse files
feat(experimentalist): add the tau3-bench banking benchmark suite (#935)
* feat(experimentalist): make the benchmark harness suite-driven The runner hardcoded Terminal Bench's workspace and framework skill and assumed a package held exactly one domain, so a second suite could not be expressed as a manifest. A manifest now carries its own workspace and framework_skills, and may set task_id_prefix to scope a multi-domain package to one domain; coverage is then enforced against the matching subset. Skill directories resolve before the baseline evaluation, because otherwise a typo'd skill name surfaces hours of image builds later. A config may also name a user_simulator, which exports the OpenAI-style credentials that tau-style task environments and their NL-assertion judge read. Those are assigned rather than defaulted: a developer's ambient OPENAI_API_KEY paired with this gateway's base URL would 401 on every call. Signed-off-by: Aditya Pandey <aditypandey@nvidia.com> * feat(experimentalist): add the tau3-bench banking suite and configs Scopes sierra-research/tau3-bench@1 to its 97 banking_knowledge tasks. The quality partition reuses the 41/28/28 split from optimization-datasets feat/tau2-other-domains, whose tau2-banking-knowledge-NNN names map onto the canonical Hub IDs; only task IDs are recorded here, never task content. The 6/3/3 fast partition draws solely from the 87 tasks whose reward_basis is pure database state, so smoke runs score without an LLM judge. Both partitions were validated against live Harbor Hub. Signed-off-by: Aditya Pandey <aditypandey@nvidia.com> * feat(experimentalist): add the tau3 NOOA agent under test A NOOA CodeAct agent that reaches the tau2 domain tools over MCP from the task's tau3-runtime sidecar. AGENT-SPEC.md stays domain-generic because the policy arrives at runtime in the task instruction, and it is what the Experimentalist mutates. Three things the task images required: Installing from the committed lock uses the pip that python:3.12-slim already ships, since tau3 images carry neither uv nor the curl its installer wants. Terminal Bench's uv-upload machinery is unnecessary here because every tau3 task shares that one base image. Model credentials are handed over at exec time. A task's [environment].env only interpolates its docker-compose file, and upstream wires those variables into the sidecar; the main service declares no environment, so the agent had none. mcp_timeout.py replaces nooa 0.0.6's MCP transport, which is built without an httpx timeout and so inherits httpx's 5 second default. The sidecar runs the user simulator inside start_conversation and send_message_to_user, which take longer; the server completed the work and advanced its state, but the reply landed on an abandoned stream and nooa surfaced no timeout, so the agent hung indefinitely. Verified end to end on the fast test split: all three tasks complete with no harness error, one solved, for a 1/3 baseline the optimizer can improve on. Signed-off-by: Aditya Pandey <aditypandey@nvidia.com> * docs(experimentalist): document the tau3 banking benchmark Turns the single-suite README into one that covers both suites: how a manifest carries its own workspace, framework skills, and optional domain prefix, the banking provenance and partition derivation, and the two-container topology with its memory and build-timeout consequences. Also records that upstream's tau3 Dockerfiles clone tau2-bench without a ref, so a cold layer cache can pick up newer commits than an earlier run saw. Signed-off-by: Aditya Pandey <aditypandey@nvidia.com> * refactor(experimentalist): write partition entries relative to the task-id prefix Every ID in a domain-scoped package repeats the domain prefix, so listing 109 of them buried the part that actually differs and made the banking manifest 143 lines of near-identical strings. Partition entries are now names inside the suite's task_id_prefix, joined back on at load so the rest of the runner keeps working in canonical IDs. The banking manifest drops to 50 lines and its splits are legible at a glance. Suites without a prefix, meaning Terminal Bench, are unaffected. Signed-off-by: Aditya Pandey <aditypandey@nvidia.com> * refactor(experimentalist): name benchmark configs after their suite A config carries the models and optimizer depth for one suite, but the original pair was named only for its partition. Once tau3-smoke.yaml and tau3-quality.yaml sat beside them, smoke.yaml and quality.yaml read as the generic pair rather than the Terminal Bench one. Signed-off-by: Aditya Pandey <aditypandey@nvidia.com> * docs(experimentalist): trim the tau3 section to what a reader needs Drops the container topology, the memory and build-timeout guidance, and the note about upstream's unpinned tau2-bench clone. What remains mirrors the Terminal Bench section: package, hash, Hub record, partition derivation, and the one config field the suite introduces. Signed-off-by: Aditya Pandey <aditypandey@nvidia.com> * build(experimentalist): repin nooa to the upstream MCP timeout fix nooa built its streamable-http transport with an httpx client that had no timeout, so httpx's 5 second default governed the MCP read stream and any tool call taking longer than that hung forever. The tau3 agent hit this on every turn, because the tau3-runtime sidecar runs a user-simulator LLM inside start_conversation and send_message_to_user. That is fixed upstream in NVIDIA-NeMo/labs-OO-Agents#46, so this drops the local mcp_timeout.py shim and goes back to MCPManager.create_from_server, which now takes tool_call_timeout directly. The agent still asks for 300 seconds: nooa's 60 second default would do today but leaves no room for a slower model. The pin is a commit rather than a tag because no release carries the fix yet. The lock's extra wheel rows are generated: no package version moves except nooa. Verified against a live sidecar that start_conversation now returns in 7.3s instead of hanging, and that a full Harbor trial completes with no harness error. Signed-off-by: Aditya Pandey <aditypandey@nvidia.com> --------- Signed-off-by: Aditya Pandey <aditypandey@nvidia.com>
1 parent 01464bd commit 9aaf35d

21 files changed

Lines changed: 2284 additions & 43 deletions

plugins/nemo-experimentalist/AGENTS.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,11 @@ instead of restoring Curator imports, configuration, or aliases. The obsolete
7272
Configure Platform services, trace storage, and Insights analysis according
7373
to the Platform documentation; this repository does not own a service,
7474
scheduler, or testbed setup.
75-
- `nooa` is pinned to a tagged public GitHub release in `pyproject.toml`.
76-
Update the tag and lock file together. Keep the Platform-supplied Insights
77-
plugin separate.
75+
- `nooa` is pinned to an immutable public GitHub revision in `pyproject.toml`,
76+
currently a commit rather than a tag because the MCP transport-timeout fix
77+
landed after `v0.0.6`. Update the revision, the matching pin in
78+
`examples/tau3-nooa-agent/pyproject.toml`, and both lock files together. Keep
79+
the Platform-supplied Insights plugin separate.
7880
- This branch uses merged Platform PR 718 contracts only. After the Platform
7981
handoff lands, rebase and repin before adopting any new Platform testbed or
8082
installer interfaces.

plugins/nemo-experimentalist/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ export NEMO=/path/to/nemo-platform/.venv/bin/nemo
2828
```
2929

3030
The source dependencies are pinned to tagged or immutable revisions in
31-
`pyproject.toml`. NVIDIA-labs OO Agents (NOOA) is pinned to its public
32-
GitHub `v0.0.6` release.
31+
`pyproject.toml`. NVIDIA-labs OO Agents (NOOA) is pinned to a public GitHub
32+
commit, currently one past `v0.0.6` that carries an MCP transport-timeout fix.
3333

3434
## Insight-to-experiment flow
3535

plugins/nemo-experimentalist/benchmarks/README.md

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
# SPDX-License-Identifier: Apache-2.0
33

4-
# Canonical Experimentalist benchmark
4+
# Canonical Experimentalist benchmarks
55

6-
This benchmark measures M2 Experimentalist optimization on Harbor's unmodified
7-
Terminal-Bench 2.1 package. It does not cover M1 Insight → Eval Author behavior
8-
or Tau2's interactive domains.
6+
These benchmarks measure M2 Experimentalist optimization on unmodified Harbor Hub
7+
packages. They do not cover M1 Insight → Eval Author behavior.
98

10-
## Provenance
9+
Two suites ship today. Both store only task IDs and download task definitions into
10+
a local cache; no task content is vendored here.
11+
12+
| Suite | Package | Tasks | Agent under test |
13+
| --- | --- | --- | --- |
14+
| `suites/terminal-bench-2.1.yaml` (default) | `terminal-bench/terminal-bench-2-1@6` | 89 | `examples/terminal-bench-agent` |
15+
| `suites/tau3-banking.yaml` | `sierra-research/tau3-bench@1`, banking scoped | 97 | `examples/tau3-nooa-agent` |
16+
17+
## Terminal-Bench provenance
1118

1219
The suite uses `terminal-bench/terminal-bench-2-1@6` from Harbor Hub:
1320

@@ -17,21 +24,41 @@ The suite uses `terminal-bench/terminal-bench-2-1@6` from Harbor Hub:
1724
- Harbor Hub record:
1825
<https://hub.harborframework.com/datasets/terminal-bench/terminal-bench-2-1/6>
1926

20-
The repository stores only task IDs. Task definitions are downloaded into a
21-
local cache and are never vendored here.
22-
2327
The 38/25/26 quality partition and 35/12/12 fast partition came from Gaia's
2428
`optimization-datasets` commit
2529
`1b7688ad257dacd1a3267dddb88db6cefdc31376`. The manifest corrects
2630
`install-windows-3-11` to the canonical ID `install-windows-3.11`. At startup,
2731
the runner asks Harbor Hub for revision 6, verifies its content hash, and
2832
asserts that the quality partition covers all 89 canonical IDs exactly once.
2933

34+
## tau3 banking provenance
35+
36+
The suite scopes `sierra-research/tau3-bench@1` to its `banking_knowledge` domain:
37+
38+
- 97 of the package's 375 tasks, selected by the
39+
`tau3-bench__tau3-banking_knowledge-` task-ID prefix
40+
- dataset content hash
41+
`sha256:a57304f682894ac061090769af771a3617664f3ff6e5417d4eadf8e30433e4d9`
42+
- Harbor Hub record:
43+
<https://hub.harborframework.com/datasets/sierra-research/tau3-bench/1>
44+
45+
The 41/28/28 quality partition came from `optimization-datasets`
46+
`feat/tau2-other-domains` commit `025ecd2ef2b518ad81f6b22d3f3937af8906fb01`,
47+
whose `tau2-banking-knowledge-NNN` names map onto the canonical
48+
`tau3-bench__tau3-banking_knowledge-task-NNN` IDs. The 6/3/3 fast partition draws
49+
only from the 87 tasks whose `reward_basis` is pure database state, so smoke runs
50+
score deterministically without an LLM judge.
51+
52+
Each task also runs a `tau3-runtime` sidecar hosting the tau2 environment and user
53+
simulator. Tau-style suites set `models.user_simulator`, which makes the runner
54+
export `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `TAU2_USER_MODEL`, and
55+
`TAU2_NL_ASSERTIONS_MODEL` for the sidecar and the verifier.
56+
3057
## Held-out evaluation
3158

3259
The runner:
3360

34-
1. evaluates the unchanged LangChain baseline on the test split;
61+
1. evaluates the unchanged baseline agent on the test split;
3562
2. gives only train and validation IDs to `run_experimentalist`;
3663
3. resolves the validation-selected winner from the Experimentalist run;
3764
4. evaluates that winner on the same test IDs and number of attempts.
@@ -52,7 +79,7 @@ export INFERENCE_API_KEY=...
5279
```
5380

5481
`EXPERIMENTALIST_API_KEY` may be provided instead. The runner maps either credential
55-
to both the LangChain AUT and optimizer, using
82+
to both the AUT and optimizer, using
5683
`https://inference-api.nvidia.com/v1` unless an API base is explicitly set.
5784

5885
Validate provenance and task IDs without Docker or model calls:
@@ -65,20 +92,28 @@ Run the bounded fast benchmark:
6592

6693
```bash
6794
uv run python benchmarks/run.py \
68-
--config benchmarks/configs/smoke.yaml
95+
--config benchmarks/configs/terminal-bench-smoke.yaml
6996
```
7097

7198
Run the reproducible quality benchmark:
7299

73100
```bash
74101
uv run python benchmarks/run.py \
75-
--config benchmarks/configs/quality.yaml
102+
--config benchmarks/configs/terminal-bench-quality.yaml
103+
```
104+
105+
A non-default suite needs its own suite, config, and agent:
106+
107+
```bash
108+
uv run python benchmarks/run.py \
109+
--suite benchmarks/suites/tau3-banking.yaml \
110+
--config benchmarks/configs/tau3-smoke.yaml \
111+
--agent examples/tau3-nooa-agent
76112
```
77113

78-
Both setup and agent execution require network access. The AUT installs a
79-
checksum-pinned static `uv`, uv-managed Python 3.12, and dependencies from its
80-
committed `uv.lock` directly in each canonical task container. It does not need
81-
the image's system Python, package manager, a sidecar, or a Docker socket.
114+
Both setup and agent execution require network access. Each AUT installs its own
115+
dependencies from its committed `uv.lock` inside the task container and does not
116+
need a Docker socket.
82117

83118
Pass the same `--output` directory to resume interrupted Harbor jobs. Use a new
84119
output directory for an intentionally fresh run.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
suite_partition: quality
5+
test_attempts: 3
6+
models:
7+
aut: openai/openai/openai/gpt-5-mini
8+
experimentalist_smart: openai/openai/openai/gpt-5-mini
9+
experimentalist_mid: openai/openai/openai/gpt-5-mini
10+
experimentalist_fast: openai/openai/openai/gpt-5-mini
11+
user_simulator: openai/openai/openai/gpt-5-mini
12+
optimizer:
13+
max_rounds: 3
14+
min_rounds_before_stopping: 2
15+
max_survivors: 2
16+
max_candidates: 3
17+
max_trajectory_tasks: 8
18+
max_train_batch_tasks: 16
19+
train_batch_seed: 20260727
20+
disable_trajectory_scoring: false
21+
disable_convergence_check: false
22+
evaluator:
23+
n_attempts: 2
24+
# Keep at 3 or lower: each task requests 8192 MB and parallel image builds
25+
# have triggered Docker Hub rate limiting and DNS failures.
26+
n_concurrent_trials: 3
27+
quiet: true
28+
agent_setup_timeout_multiplier: 2.0
29+
# tau3 builds two images per task, and the first build clones and installs
30+
# tau2-bench (observed 2m36s cold, 26s warm).
31+
environment_build_timeout_multiplier: 3.0
32+
eval_author:
33+
max_traces: 10
34+
max_validation_repair_attempts: 5
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
suite_partition: fast
5+
test_attempts: 1
6+
models:
7+
aut: openai/openai/openai/gpt-5-mini
8+
experimentalist_smart: openai/openai/openai/gpt-5-mini
9+
experimentalist_mid: openai/openai/openai/gpt-5-mini
10+
experimentalist_fast: openai/openai/openai/gpt-5-mini
11+
user_simulator: openai/openai/openai/gpt-5-mini
12+
optimizer:
13+
max_rounds: 1
14+
min_rounds_before_stopping: 1
15+
max_survivors: 1
16+
max_candidates: 1
17+
max_trajectory_tasks: 2
18+
max_train_batch_tasks: 4
19+
train_batch_seed: 20260727
20+
disable_trajectory_scoring: true
21+
disable_convergence_check: true
22+
evaluator:
23+
n_attempts: 1
24+
n_concurrent_trials: 1
25+
quiet: true
26+
agent_setup_timeout_multiplier: 2.0
27+
# tau3 builds two images per task, and the first build clones and installs
28+
# tau2-bench (observed 2m36s cold, 26s warm).
29+
environment_build_timeout_multiplier: 3.0
30+
eval_author:
31+
max_traces: 3
32+
max_validation_repair_attempts: 2

plugins/nemo-experimentalist/benchmarks/configs/quality.yaml renamed to plugins/nemo-experimentalist/benchmarks/configs/terminal-bench-quality.yaml

File renamed without changes.

plugins/nemo-experimentalist/benchmarks/configs/smoke.yaml renamed to plugins/nemo-experimentalist/benchmarks/configs/terminal-bench-smoke.yaml

File renamed without changes.

plugins/nemo-experimentalist/benchmarks/run.py

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
# SPDX-License-Identifier: Apache-2.0
33

4-
"""Run the canonical Terminal-Bench Experimentalist benchmark."""
4+
"""Run a canonical Experimentalist benchmark suite."""
55

66
import argparse
77
import asyncio
@@ -32,7 +32,7 @@
3232
PLUGIN_ROOT = Path(__file__).resolve().parents[1]
3333
BENCHMARK_ROOT = Path(__file__).resolve().parent
3434
DEFAULT_SUITE = BENCHMARK_ROOT / "suites" / "terminal-bench-2.1.yaml"
35-
DEFAULT_CONFIG = BENCHMARK_ROOT / "configs" / "smoke.yaml"
35+
DEFAULT_CONFIG = BENCHMARK_ROOT / "configs" / "terminal-bench-smoke.yaml"
3636
DEFAULT_AGENT = PLUGIN_ROOT / "examples" / "terminal-bench-agent"
3737
DEFAULT_DATASET_CACHE = PLUGIN_ROOT / "tmp" / "benchmark-datasets"
3838
DEFAULT_RUNTIME_CACHE = PLUGIN_ROOT / "tmp" / "runtime-cache"
@@ -45,6 +45,7 @@ class CanonicalDatasetSpec(BaseModel):
4545
registry_url: str
4646
source_url: str
4747
expected_task_count: int = Field(gt=0)
48+
task_id_prefix: str | None = None
4849

4950
@property
5051
def requested_reference(self) -> str:
@@ -88,13 +89,44 @@ class SuiteSpec(BaseModel):
8889
schema_version: Literal[1]
8990
dataset: CanonicalDatasetSpec
9091
partitions: PartitionsSpec
92+
workspace: str
93+
framework_skills: list[str] = Field(min_length=1)
94+
95+
@model_validator(mode="after")
96+
def expand_partition_task_ids(self) -> Self:
97+
"""Read partition entries as names inside the suite's ``task_id_prefix``.
98+
99+
Every ID in a domain-scoped package repeats that prefix, which buries the part
100+
that differs. Manifests write the distinguishing name and the prefix is joined
101+
back on here, so the rest of the runner still works in canonical IDs. A manifest
102+
that writes full IDs anyway fails the quality-coverage check with both forms in
103+
the message.
104+
"""
105+
prefix = self.dataset.task_id_prefix
106+
if prefix is None:
107+
return self
108+
for split in (self.partitions.quality, self.partitions.fast):
109+
for role in ("train", "validation", "test"):
110+
setattr(split, role, [f"{prefix}{name}" for name in getattr(split, role)])
111+
return self
112+
113+
def framework_skills_dirs(self, plugin_root: Path) -> list[Path]:
114+
"""Resolve framework-skill names to directories, failing on unknown names."""
115+
dirs: list[Path] = []
116+
for name in self.framework_skills:
117+
path = plugin_root / "framework-skills" / name
118+
if not path.is_dir():
119+
raise ValueError(f"Unknown framework skill {name!r}: {path} is not a directory")
120+
dirs.append(path)
121+
return dirs
91122

92123

93124
class ModelSpec(BaseModel):
94125
aut: str
95126
experimentalist_smart: str
96127
experimentalist_mid: str
97128
experimentalist_fast: str
129+
user_simulator: str | None = None
98130

99131

100132
class BenchmarkConfig(BaseModel):
@@ -126,13 +158,23 @@ def validate_canonical_suite(
126158
*,
127159
canonical_task_ids: set[str],
128160
resolved_ref: str,
129-
) -> None:
130-
"""Verify immutable revision, quality coverage, and all partition IDs."""
161+
) -> set[str]:
162+
"""Verify immutable revision, quality coverage, and all partition IDs.
163+
164+
Returns the canonical task IDs scoped to this suite's domain. When the suite
165+
sets ``task_id_prefix``, the package may hold other domains; coverage is then
166+
enforced against the matching subset rather than the whole package.
167+
"""
131168
if resolved_ref != suite.dataset.resolved_ref:
132169
raise ValueError(
133170
f"Dataset {suite.dataset.requested_reference} resolved to {resolved_ref}, "
134171
f"expected {suite.dataset.resolved_ref}"
135172
)
173+
prefix = suite.dataset.task_id_prefix
174+
if prefix is not None:
175+
canonical_task_ids = {task_id for task_id in canonical_task_ids if task_id.startswith(prefix)}
176+
if not canonical_task_ids:
177+
raise ValueError(f"No canonical tasks match task_id_prefix {prefix!r}")
136178
if len(canonical_task_ids) != suite.dataset.expected_task_count:
137179
raise ValueError(
138180
f"Canonical dataset has {len(canonical_task_ids)} tasks, expected {suite.dataset.expected_task_count}"
@@ -147,6 +189,7 @@ def validate_canonical_suite(
147189
unknown_fast = sorted(set(suite.partitions.fast.all_ids()) - canonical_task_ids)
148190
if unknown_fast:
149191
raise ValueError(f"Fast partition contains unknown canonical task IDs: {unknown_fast}")
192+
return canonical_task_ids
150193

151194

152195
def _configure_models(models: ModelSpec) -> None:
@@ -164,6 +207,16 @@ def _configure_models(models: ModelSpec) -> None:
164207
os.environ["EXPERIMENTALIST_MID_MODEL_NAME"] = models.experimentalist_mid
165208
os.environ["EXPERIMENTALIST_FAST_MODEL_NAME"] = models.experimentalist_fast
166209
os.environ.setdefault("NEMO_EXPERIMENTALIST_RUNTIME_CACHE", str(DEFAULT_RUNTIME_CACHE))
210+
if models.user_simulator is not None:
211+
# tau-style tasks run a user simulator and NL-assertion judge inside the task
212+
# environment, which read OpenAI-style variables and need the /v1 suffix.
213+
# Assigned rather than setdefault: an ambient OPENAI_API_KEY from the developer's
214+
# shell would otherwise be paired with this gateway base URL and always 401.
215+
trimmed_base = api_base.rstrip("/")
216+
os.environ["OPENAI_API_KEY"] = api_key
217+
os.environ["OPENAI_BASE_URL"] = trimmed_base if trimmed_base.endswith("/v1") else f"{trimmed_base}/v1"
218+
os.environ["TAU2_USER_MODEL"] = models.user_simulator
219+
os.environ["TAU2_NL_ASSERTIONS_MODEL"] = models.user_simulator
167220

168221

169222
def _agent_digest(agent_dir: Path) -> str:
@@ -342,7 +395,12 @@ async def run_benchmark(args: argparse.Namespace) -> Path:
342395
package_client = PackageDatasetClient()
343396
metadata = await package_client.get_dataset_metadata(suite.dataset.requested_reference)
344397
canonical_task_ids = {task.name for task in metadata.task_ids}
345-
validate_canonical_suite(suite, canonical_task_ids=canonical_task_ids, resolved_ref=metadata.version)
398+
canonical_task_ids = validate_canonical_suite(
399+
suite, canonical_task_ids=canonical_task_ids, resolved_ref=metadata.version
400+
)
401+
# Resolved up front: the optimizer only needs these after the baseline evaluation,
402+
# which is hours of image builds to discover a typo'd skill name.
403+
framework_skills_dirs = suite.framework_skills_dirs(PLUGIN_ROOT)
346404

347405
if args.validate_only:
348406
print(
@@ -397,10 +455,10 @@ async def run_benchmark(args: argparse.Namespace) -> Path:
397455
metadata={"id": f"{benchmark_config.suite_partition}-validation", "task_ids": split.validation},
398456
),
399457
experiment_dir=experimentalist_dir,
400-
workspace="canonical-terminal-bench-2-1",
458+
workspace=suite.workspace,
401459
client=None,
402460
config=benchmark_config.optimizer,
403-
framework_skills_dirs=[PLUGIN_ROOT / "framework-skills" / "langchain-framework"],
461+
framework_skills_dirs=framework_skills_dirs,
404462
)
405463
run_document = json.loads((experimentalist_dir / "eval-and-optimize" / "run.json").read_text(encoding="utf-8"))
406464
winner_label = run_document.get("winner_agent")

0 commit comments

Comments
 (0)