Skip to content

Let a deployment designate which Agent each LLM subscriber acts as - #701

Merged
xmap merged 1 commit into
mainfrom
feat/subscriber-agent-designation
Aug 21, 2026
Merged

Let a deployment designate which Agent each LLM subscriber acts as#701
xmap merged 1 commit into
mainfrom
feat/subscriber-agent-designation

Conversation

@xmap

@xmap xmap commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • RunDebrieferSubscriber and CautionDrafterSubscriber hardcoded the seeded singleton Agent id; both seeded Agents declare provider=anthropic, and every LLM adapter refuses a request whose model_ref.provider isn't its own, so on a deployment that cannot reach api.anthropic.com (2-BM's controls network) the autonomous path was structurally dead.
  • Add run_debriefer_agent_id / caution_drafter_agent_id settings (default None = seeded singleton, so nothing changes on upgrade), threaded through both subscribers as a keyword-only constructor arg.
  • Validation lives on the per-apply gate path: a designated Agent that doesn't exist or is the wrong kind skips with a named reason; the seeded default stays exempt from the existence check, same as regenerate_run_debrief.
  • Fix caution_drafter.py, which never served the Agent's declared model (unlike run_debriefer.py).
  • Add report_designated_agents(deps), called from main.py after both singleton seeds: a boot-time report (never a gate) naming the effective Agent per subscriber and warning on a provider mismatch.
  • ModelRef stays immutable; no update_agent_model_ref command added. The approved-model catalog gate isn't re-checked at designation.
  • Updated .env.example and docs/deployments/2-bm/llm_debrief.md (which already covered exactly this gap).

Test plan

  • pytest tests/unit/agent — 948 passed
  • pytest tests/unit (full) — 13954 passed, 1 pre-existing skip
  • pytest tests/integration/test_run_debriefer_subscriber_postgres.py tests/integration/test_caution_drafter_subscriber_postgres.py — 13 passed
  • pytest tests/integration/scenarios/test_2bm_run_debriefer*.py — 3 passed
  • ruff check / ruff format --check clean
  • pyright clean (with --all-extras synced)

🤖 Generated with Claude Code

RunDebrieferSubscriber and CautionDrafterSubscriber hardcoded the seeded
singleton Agent id, and both seeded Agents declare provider=anthropic.
Every LLM adapter refuses a request whose model_ref.provider is not its
own, so on a deployment where api.anthropic.com is unreachable (2-BM's
controls network has no internet) the autonomous path is structurally
dead: LLM_ENABLED=true would defer every completed Run instead of
debriefing it. The on-demand regenerate_run_debrief path already lets
an operator name the Agent; the subscribers did not.

Add run_debriefer_agent_id / caution_drafter_agent_id settings (UUID |
None, default None = the seeded singleton, so nothing changes on
upgrade). Thread the id through both subscribers as a keyword-only
constructor argument so the class stays unit-testable without Settings.
Validation lives on the per-apply gate path, gated on designation being
explicit: a designated Agent that doesn't exist or is the wrong kind
skips with a named reason; the seeded default stays exempt from the
existence check the way regenerate_run_debrief already exempts it.

caution_drafter.py never served the Agent's declared model (unlike
run_debriefer.py, which already did); fixed so designating a
CautionDrafter Agent that declares a reachable provider actually
changes what gets served.

report_designated_agents(deps), called from main.py after both
singleton seeds, logs which Agent is effective for each subscriber and
warns on a provider mismatch. It is a report, never a gate: the adapter
already refuses the call at request time and is the authority, so a
second gate here would re-decide a verdict that already exists. The
warning exists only because that refusal otherwise arrives per-event,
hours later, as a deferred Decision that never names the mismatch.

ModelRef stays immutable; no update_agent_model_ref command is added.
The approved-model catalog gate is not re-checked at designation
(define_agent already checked it).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  apps/api/src/cora/agent
  __init__.py
  _subscribers.py
  apps/api/src/cora/agent/subscribers
  caution_drafter.py
  run_debriefer.py
  apps/api/src/cora/api
  main.py
  apps/api/src/cora/infrastructure
  config.py
Project Total  

This report was generated by python-coverage-comment-action

@xmap
xmap merged commit f04c3cb into main Aug 21, 2026
19 checks passed
@xmap
xmap deleted the feat/subscriber-agent-designation branch August 21, 2026 03:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant