feat: per-task model and effort selection for workflows#123
Closed
sasicodes wants to merge 12 commits into
Closed
Conversation
Base automatically changed from
chore/remove-google-workflow-rename-and-update-button
to
main
July 6, 2026 09:38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Sub-agents in a workflow now pick their own model and effort per task, instead of all inheriting the parent session's single model/effort. The goal is cost efficiency: match each task to the cheapest model and lowest effort that can do it well.
Model scores (
models.ts){ affordability, intelligence, taste }(0-10, higher is better; affordability higher = cheaper), plus amodelScore(provider, id)lookup.run_workflowtool{ prompt, model, effort }, all mandatory (Valibot-validated).Runtime
Testing
pnpm run lint,pnpm run format,pnpm --filter @start/desktop typecheck- cleanpnpm --filter @start/desktop vitest run- 803 tests passing (added workflow-catalog tests, updated subagent tests)Note
Stacked on #122; merge that first.
Greptile Summary
This PR introduces per-task model and effort selection for sub-agent workflows, replacing the previous single shared model/effort inherited from the parent session. A
ModelScore(affordability/intelligence/taste) is added to each allowed model, and therun_workflowtool description is now built dynamically to list only the models with active credentials, guiding the LLM to pick the cheapest model that fits each task.models.tsgains numeric scores per model;workflowModels()inChatServiceassembles the live menu from the registry.SubagentTaskInputnow requiresmodel(key string) andeffort; Valibot validates both;runtime.tsresolves the model per-task and clamps the thinking level.catalog.ts(new) generates therun_workflowdescription with scored model lines; tests added forworkflow-catalogand updated forsubagents-runtime.Confidence Score: 4/5
Safe to merge after addressing the resolveModel fallback — today it silently runs tasks on the wrong model when the agent provides an unrecognised key.
The resolveModel wiring in chat.ts falls back to pickModel() when findModelByKey returns undefined, so an LLM-supplied key that doesn't exactly match an available model causes the task to run on the user's current session model with no error or log. Every other changed file — the schema, the catalog, the runtime, the types — looks correct and well-tested.
packages/desktop/src/main/chat.ts — the resolveModel closure on line 2008.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant PA as Parent Agent participant RT as run_workflow tool participant RM as resolveModel (ChatService) participant SA as Sub-Agent Session PA->>RT: "run_workflow({ tasks: [{prompt, model, effort}] })" RT->>RT: normalizeSubagentTasks (Valibot validates) loop Each task (up to 4 concurrent) RT->>RM: resolveModel(task.model) alt key found in registry RM-->>RT: ResolvedModel else key not found RM-->>RT: pickModel() fallback (silent) end RT->>SA: "createAgentSession({ model, thinkingLevel: clampThinkingLevel(model, task.effort) })" SA-->>RT: result / error end RT-->>PA: combined result text%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant PA as Parent Agent participant RT as run_workflow tool participant RM as resolveModel (ChatService) participant SA as Sub-Agent Session PA->>RT: "run_workflow({ tasks: [{prompt, model, effort}] })" RT->>RT: normalizeSubagentTasks (Valibot validates) loop Each task (up to 4 concurrent) RT->>RM: resolveModel(task.model) alt key found in registry RM-->>RT: ResolvedModel else key not found RM-->>RT: pickModel() fallback (silent) end RT->>SA: "createAgentSession({ model, thinkingLevel: clampThinkingLevel(model, task.effort) })" SA-->>RT: result / error end RT-->>PA: combined result textReviews (3): Last reviewed commit: "fix: clarify workflow error when no prov..." | Re-trigger Greptile