Skip to content

Let the supervisor choose model and effort for each worker it delegates (#318) - #325

Merged
oldsj-mainloop[bot] merged 2 commits into
mainfrom
mainloop/delegate-model-effort-318-c
Oct 23, 2026
Merged

oldsj-mainloop[bot] merged 2 commits into
mainfrom
mainloop/delegate-model-effort-318-c

Conversation

@oldsj-mainloop

Copy link
Copy Markdown
Contributor

Summary

  • Add optional model and effort to TaskCreate and the delegate MCP tool, validated at task creation against the resolved provider profile's models/effort_levels (explicit provider_profile_id, else the project's or installation's default). Either named but not offered answers 422 with a TaskError whose detail carries allowed_models/allowed_effort_levels, via a new apierr.ReasonDetail/tasks.Error.Detail. Leaving both unset is unchanged behavior.
  • Persist a valid choice on the task, copy it onto the attempt when the attempt is made, and apply it as the new session's own /model//effort override (SetModelOverride/SetEffortOverride, the same storage the owner's routes use) before the attempt's first brief is sent in sendBrief — never by a call after the fact that could race the first turn.
  • Show the chosen model and effort on the task view (Task/TaskAttempt.model/.effort); a task-owned session's own view already shows them automatically, since they're the same override storage the chat composer already reads.
  • Expand the delegate tool's description with short, provider-neutral guidance for choosing a tier: scope/risk/reversibility, mechanical vs. judgment work, a cost bias toward the cheapest choice likely to succeed, and preferring a higher tier when re-delegating a failure. It names no provider's models, pointing at the resolved profile's own list instead.
  • New migration 00340_task_model_effort.sql adds model/effort columns to tasks and task_attempts, and includes the attempt's columns in the existing routing-immutability trigger.
  • Docs: docs/specs/delegation.md (new "Choosing a worker's model and effort" section), docs/specs/sessions.md, docs/specs/chat.md (cross-reference).

Note: task_retry/task_reassign (handoff) remain stubbed/unavailable in this codebase, so there's no live "resume" path to exercise yet; the attempt-level copy (beginCreate) is the inheritance primitive the issue asks for, ready for when handoff lands.

Test plan

  • go build ./..., go vet, golangci-lint run clean on touched packages
  • go generate ./... produces no further diff (contract/codegen drift check)
  • New test TestCreateValidatesModelAndEffort (server/internal/tasks/service_test.go): validation against the resolved profile, persistence, 422 allowed-values detail, unchanged default — passing against a real test Postgres
  • New integration test TestDelegateAppliesModelAndEffortBeforeTheFirstTurn (server/internal/tasks/provision_test.go): attempt persistence + override applied before the first brief + unchanged default when unset — passing
  • Existing server/internal/tasks, server/internal/sessions, server/internal/mcpserver, server/internal/app (apicheck) suites pass against a real test Postgres
  • Web: tsc -b, eslint, vitest run src/lib/taskState.test.ts, vite build all clean; new modelEffortLabel test
  • pnpm dlx redocly lint api/openapi.yaml valid
  • Synced to mainloop-dev: sync id 6f03c26a77bd16bbddd4a049f544653a50e1b0ed6126416841d3318da7c35eed, health_ok: true, smoke 10 ok/0 fail/1 skip

🤖 Generated with Claude Code

oldsj and others added 2 commits October 23, 2026 03:34
…es (#318)

TaskCreate and the delegate MCP tool take optional model and effort,
validated at task creation against the resolved provider profile's
models/effort_levels (422 with the allowed values otherwise), recorded
on the task and its attempt, and applied as the new session's /model
and /effort override before the attempt's first brief — never by a
call after the fact. Leaving both unset is unchanged behavior.

Show the chosen model and effort on the task view, and expand the
delegate tool's guidance with provider-neutral rules for choosing a
tier, reading model names from the resolved profile instead of
hardcoding one provider's.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@oldsj-mainloop
oldsj-mainloop Bot merged commit fd8e17e into main Oct 23, 2026
13 checks passed
@oldsj-mainloop
oldsj-mainloop Bot deleted the mainloop/delegate-model-effort-318-c branch October 23, 2026 03:55
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