Roles, capability profiles and help on the new loop (M2.6)
- roles.driver (unset: the planner's model) and roles.classifier (unset: the expert's); the mapping is pinned when an item opens, and the driver and the go-ahead reader run on the item's own (L9). - profiles: in configuration (tools, strengths, weaknesses), used in briefings: the driver's instructions say what its helper and expert are good at, the helper's brief who reads its handback; never a model name. - delegate(task) and ask_expert(question) for the driver. A helper works on a branch off the milestone's; on a handback its work comes back as uncommitted changes, otherwise it is discarded, so harness branches never hold commits only the clone has. ask_expert keeps its budget. - Triggers: failure_limit failed commands in a row (Driver's new "stuck" outcome) or the turn cap, mid-milestone, call a helper in once per milestone; if it fails too, the item waits on the operator. A delegation cut off by a crash is discarded at boot. - Evaluation capture: delegations and ask_expert as before, and the reader's verdicts as classifier pairs. Tests: help tests (merge-back, discard, needs a milestone, the stuck trigger and its once-per-milestone limit, the expert and its budget, pinning, briefings by profile, boot discarding a cut-off delegation), config tests for roles and profiles, and the walk delegating with a scripted helper that sometimes fails, with a delegations_settle property. The walk found helper commits stranded on a merged PR's branch, fixed by returning a helper's work uncommitted. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
This commit is contained in:
1 parent
04c352b30c
commit
59fd00ce8c
19 files changed
+890
-38
No files matched your search
@@ -478,3 +478,29 @@ def test_a_workspace_of_any_project_inside_is_refused(tmp_path: Path) -> None:
|
||||
state_db=str(work / "state.db"),
|
||||
projects__other={**SECOND, "workspace": str(work)},
|
||||
)
|
||||
|
||||
|
||||
# --- roles and profiles (L9) -------------------------------------------------
|
||||
|
||||
|
||||
def test_the_new_loops_roles_fall_back() -> None:
|
||||
config = build()
|
||||
assert config.roles.resolve("driver") == "claude-opus-5" # the planner's
|
||||
assert config.roles.resolve("classifier") == "claude-haiku-4-5" # the expert's
|
||||
named = build(roles__driver="qwen3.8-27b", roles__classifier="gemma-4-12b")
|
||||
assert named.roles.resolve("driver") == "qwen3.8-27b"
|
||||
assert named.roles.pinned()["classifier"] == "gemma-4-12b"
|
||||
|
||||
|
||||
def test_capability_profiles_are_read() -> None:
|
||||
config = build(
|
||||
profiles={"qwen3.8-27b": {"tools": "reliable", "weaknesses": "speed"}}
|
||||
)
|
||||
profile = config.profiles["qwen3.8-27b"]
|
||||
assert profile.describe() == "tool calls: reliable; weak at speed"
|
||||
assert build().profiles == {}
|
||||
|
||||
|
||||
def test_a_bad_profile_is_reported() -> None:
|
||||
with pytest.raises(ConfigError, match="profiles.m.colour: unknown setting"):
|
||||
build(profiles={"m": {"colour": "red"}})
|
||||
Reference in new issue
Block a user