feat(engine): the manager — chat orders, team, triage, verdicts, bootstrap
Phase 3 of the AI-workforce engine (TODO-agent-2): - engine/manager.py: ManagerTurns.chat (CREATE_TASK/PAUSE/RESUME/CANCEL, HIRE/UPDATE_EMPLOYEE/FIRE, KNOWLEDGE), triage (ASSIGN/REJECT/ASK_USER), final_review (COMPLETE/REVISE +cycle), error_review (RESOLVE_ERROR/CANCEL), bootstrap_team; post_user_message now delegates to it. - One billing path: call_model/BillingScope in runner.py is the single model entry point (fixes the agybot chat-billing bug). - Team changes capped at 3/turn, employee cap, last manager cannot be fired, hires pick a granted model of the requested tier strictly. - container_engine.py wires the real WorkforceBootstrapPort. - Fixes: REVISE is a body tag (prompt and parser now agree); ASSIGN employee="" means pick-for-me; the runner's protocol-error retry is capped by engine_max_protocol_retries (was unbounded until the turn timeout). - 20 new manager tests + regression tests; report in docs/plan/reports/agent-2-phase-3.md.
This commit is contained in:
@@ -37,6 +37,7 @@ from app.domain.workforce.models import RoleKey
|
||||
from app.domain.workforce.pipeline import Mode
|
||||
|
||||
MANAGER_TRIAGE = {"role": RoleKey.MANAGER, "mode": Mode.TRIAGE}
|
||||
MANAGER_FINAL = {"role": RoleKey.MANAGER, "mode": Mode.FINAL}
|
||||
MANAGER_CHAT = {"role": RoleKey.MANAGER, "mode": Mode.CHAT}
|
||||
DEVELOPER = {"role": RoleKey.DEVELOPER, "mode": Mode.WORK}
|
||||
PLANNER = {"role": RoleKey.PLANNER, "mode": Mode.WORK}
|
||||
@@ -249,6 +250,23 @@ def test_assign_requires_an_employee_or_a_task():
|
||||
assign_of(tag)
|
||||
|
||||
|
||||
def test_an_empty_employee_means_pick_for_me():
|
||||
"""``employee=""`` is a *deliberate* value, unlike an absent attribute."""
|
||||
tag = parse_reply('[[ASSIGN employee="" pipeline="plan_code_test"/]]', **MANAGER_TRIAGE).first(
|
||||
TagName.ASSIGN
|
||||
)
|
||||
assign = assign_of(tag)
|
||||
assert assign.employee == ""
|
||||
assert assign.pipeline == "plan_code_test"
|
||||
|
||||
|
||||
def test_revise_carries_a_body():
|
||||
"""The prompt asks for ``[[REVISE]]reason[[/REVISE]]``; so does the parser."""
|
||||
reply = parse_reply("[[REVISE]]تستها قرمز است[[/REVISE]]", **MANAGER_FINAL)
|
||||
assert reply.errors == ()
|
||||
assert reply.first(TagName.REVISE).body == "تستها قرمز است"
|
||||
|
||||
|
||||
def test_assign_refuses_an_unknown_pipeline():
|
||||
reply = parse_reply('[[ASSIGN employee="سارا" pipeline="plan_ship_test"/]]', **MANAGER_TRIAGE)
|
||||
with pytest.raises(ProtocolError):
|
||||
|
||||
Reference in New Issue
Block a user