Skip to content

honor the per-app provider/model pin on every CoS task type, and edit it from one control - #4815

Merged
atomantic merged 2 commits into
mainfrom
claim/issue-4783
Aug 22, 2026
Merged

honor the per-app provider/model pin on every CoS task type, and edit it from one control#4815
atomantic merged 2 commits into
mainfrom
claim/issue-4783

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

A per-app taskTypeOverrides[<taskType>].providerId / .model pin only reached the agent spawn for layered-intelligence — every other task type merged taskMetadata off the same record and then took its provider from the global Schedule pin, so a pin set on Edit App → Automation silently never ran.

  • Every task type honors the pin now. The generic generator applies the per-app pin over the Schedule pin through a shared resolver (server/services/appTaskProviderPin.js), which also carries the api-provider harness guard hoisted out of layeredIntelligenceHooks.js: an api-typed per-app pin (no file-writing harness, so the agent could never do the work) falls back to the Schedule pin instead of reaching the spawn. That deletes the whole providerOverrideCapable pipeline — server stamp, schedule status, workflow node, client props, and both copy blocks.
  • One editing surface. A shared AppProviderPin control plus one providerPinPatch normalizer replaces the three write sites' three different clears (model: '', model: null, '' → null), so clearing the pin from Automation, the Schedule/Timeline rows, or the Intelligence tab produces the same stored result. The Schedule and Timeline rows gain a real picker where they previously offered only a "clear" link.
  • Timeline shows names, not ids. WorkflowTab receives the providers list ChiefOfStaff already owns, so its per-app rows resolve display names like the Schedule tab does.
  • Provider-scoped models (found in local review): each pin layer now takes its own model or none. Overriding only the provider used to leave the previous layer's model behind, and agentProviderResolution honors an explicit metadata.model as a CLI pass-through — so the leak shipped a CLI a model it cannot run, on every retry until the task blocked.

Test plan

  • server/services/appTaskProviderPin.test.js — the resolution walk: app pin over schedule pin, api-typed fallback (provider and model), refusal to heal onto an unresolvable pin, provider-not-agent-capable when nothing has a harness, lazy single read of the schedule pin.
  • server/services/cosTaskGenerator.providerPin.test.js — end to end on ux (no buildTaskInput hook), asserting the generated task's metadata: spawns on the app pin, an api-typed pin does not wedge, an api-only schedule pin is left for the spawn-time error, a model pinned without a provider survives, and a provider swap drops the stale model.
  • client/src/components/cos/tabs/WorkflowTab.providers.test.jsx — Timeline rows render provider display names and write the pin through the shared override mutation.
  • Updated AppOverrideRow, AutomationTab, LayeredIntelligenceTab, and cos/constants suites to cover the identical clear across all three surfaces.
  • Full server (32829 passed) and client (9363 passed) suites green; client biome lint clean.

Closes #4783

… layered-intelligence (#4783)

A per-app `taskTypeOverrides[<taskType>].providerId`/`.model` only reached the
spawn for layered-intelligence, because only its buildTaskInput hook read the
field. Every other type merged taskMetadata off the same record and then took
its provider from the global Schedule pin, so a pin set on Edit App -> Automation
silently never ran.

- The generic generator now applies the per-app pin over the Schedule pin for
  every task type, through a shared resolver (`appTaskProviderPin.js`) that also
  carries the api-harness guard hoisted out of layered-intelligence: an api-typed
  per-app pin (no file-writing harness) falls back to the Schedule pin instead of
  reaching an agent that can never do the work. That deletes the whole
  `providerOverrideCapable` pipeline - server stamp, schedule status, workflow
  node, client props, and both copy blocks.
- One shared `AppProviderPin` control + `providerPinPatch` normalizer replaces the
  three write sites' three different clears (`model: ''`, `model: null`, '' -> null),
  so clearing the pin from Automation, the Schedule rows, or the Intelligence tab
  produces the same stored result. The Schedule/Timeline rows gain a real picker
  where they previously offered only a "clear" link.
- The Timeline tab receives the providers list, so its per-app rows show provider
  display names instead of raw ids.
…fic pin swaps the provider

A model is provider-scoped, and agentProviderResolution honors an explicit
metadata.model as a CLI pass-through rather than dropping it. Overriding only the
PROVIDER therefore shipped the previous layer's model to a CLI that cannot run it
(the `claude --model gemini-…` failure mode), on every retry until the task
blocked. Each pin layer now takes its own model or none, so selectModelForTask
resolves the new provider's default.
@atomantic
atomantic merged commit 0aa27a7 into main Aug 22, 2026
7 checks passed
@atomantic
atomantic deleted the claim/issue-4783 branch August 22, 2026 04:17
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.

Honor the per-app provider/model override for every task type, and edit it from one control

1 participant