feat: add model roles for small, implementer, and advisor - #56
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds configurable ChangesModel role configuration
Subagent model selection
TUI role management
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant ModelCommand
participant ModelPicker
participant ConfigStore
User->>ModelCommand: select a model role
ModelCommand->>ModelPicker: open picker in role-assignment mode
ModelPicker->>ConfigStore: persist the selected alias
ConfigStore-->>ModelPicker: success or error
ModelPicker-->>User: show status without switching active model
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
commit: |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
packages/agent-core/test/session/subagent-host.test.ts (1)
1871-1904: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for raw role-reference denials.
This test denies
Agent(model:small-model). Add a case that deniesAgent(model:@Small). The current suite would still pass if the raw-reference permission check were removed.As per path instructions, “New behavior should come with vitest coverage.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/agent-core/test/session/subagent-host.test.ts` around lines 1871 - 1904, Add a separate test case alongside the existing role-alias denial test that configures the parent permission rule with pattern Agent(model:`@small`) and exercises the same SessionSubagentHost.spawn flow. Assert the delegated model remains denied or resolves according to the established expected behavior, ensuring raw role-reference permission checks are covered without changing the existing Agent(model:small-model) case.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/pythinker-code/src/tui/commands/config.ts`:
- Line 486: Handle RPC failures in handleModelCommand for both affected paths:
at apps/pythinker-code/src/tui/commands/config.ts:486-486, catch getConfig
failures, display a command-specific error, and return; at
apps/pythinker-code/src/tui/commands/config.ts:502-505, catch setConfig failures
before displaying the success status. Preserve the existing assignment-write
error handling pattern.
- Around line 507-509: Update the single-token role-assignment branch around
showModelPicker so it refreshes the newly opened picker by invoking
refreshModelsForOpenPicker after the picker mounts, before returning. Match the
refresh behavior used by the normal /model path while preserving the existing
role assignment and picker arguments.
- Line 485: Update the regular expression used by requestedAlias.split in the
token parsing logic to include the Unicode flag while preserving its existing
whitespace splitting and empty-token filtering behavior.
In `@docs/configuration/config-files.md`:
- Around line 172-173: Update the explicit `@role` fallback description in the
Agent and DynamicWorkflow model-resolution documentation to state that an
unassigned or unresolvable role falls back directly to the immediate parent’s
configured model alias via parent.config.modelAlias. Remove wording that implies
retrying the profile model or implementer default, while preserving the
documented locked-alias resolution behavior.
In `@packages/agent-core/src/config/model-roles.ts`:
- Around line 15-17: Reserve default consistently across model-role
configuration: retain the default special case in resolveModelRoleAlias, reject
default as a persisted modelRoles key at
packages/agent-core/src/config/schema.ts:277 and as a modelRoles patch key at
packages/agent-core/src/config/schema.ts:323, and exclude default from
documented custom role names at docs/configuration/config-files.md:161.
In `@packages/agent-core/src/tools/builtin/collaboration/dynamic-workflow.ts`:
- Line 105: Update the model precedence description in the dynamic workflow tool
to include the configured implementer role after the subagent type profile model
and before the parent agent model, matching SessionSubagentHost.childModelConfig
behavior when earlier values are unset.
---
Nitpick comments:
In `@packages/agent-core/test/session/subagent-host.test.ts`:
- Around line 1871-1904: Add a separate test case alongside the existing
role-alias denial test that configures the parent permission rule with pattern
Agent(model:`@small`) and exercises the same SessionSubagentHost.spawn flow.
Assert the delegated model remains denied or resolves according to the
established expected behavior, ensuring raw role-reference permission checks are
covered without changing the existing Agent(model:small-model) case.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6e434b4e-37aa-48a7-848d-f405c23617ff
📒 Files selected for processing (16)
.changeset/model-roles.mdapps/pythinker-code/src/tui/commands/config.tsapps/pythinker-code/src/tui/commands/registry.tsapps/pythinker-code/test/tui/commands/model-roles.test.tsdocs/configuration/config-files.mddocs/reference/slash-commands.mdpackages/agent-core/src/config/index.tspackages/agent-core/src/config/model-roles.tspackages/agent-core/src/config/schema.tspackages/agent-core/src/config/toml.tspackages/agent-core/src/session/subagent-host.tspackages/agent-core/src/tools/builtin/collaboration/agent.tspackages/agent-core/src/tools/builtin/collaboration/dynamic-workflow.tspackages/agent-core/test/config/configs.test.tspackages/agent-core/test/config/model-roles.test.tspackages/agent-core/test/session/subagent-host.test.ts
a6ae578 to
62123eb
Compare
Add a model_roles config map that locks a model alias to a named role. @ROLE references resolve wherever a subagent model alias is accepted, and an assigned implementer role becomes the default subagent model. The TUI assigns roles with /model <role>, clears them with /model <role> clear, and lists them with /model roles.
The async model-list refresh re-mounted the picker without the role options, turning a role assignment into a plain model switch. Also salvage model_roles per entry instead of dropping the whole section, and document /model <role> none as an alias of clear.
62123eb to
048c427
Compare
Greptile SummaryThe PR adds configurable model roles for subagent model selection and TUI commands for assigning, listing, and clearing them.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| packages/agent-core/src/config/toml.ts | Serializes, replaces, and removes the model_roles table so role assignments and clears survive reloads. |
| packages/agent-core/src/session/subagent-host.ts | Resolves explicit role references and applies the implementer role as the default subagent model. |
| packages/agent-core/src/config/model-roles.ts | Defines built-in roles and centralizes role-reference expansion. |
| apps/pythinker-code/src/tui/commands/config.ts | Adds role assignment, clearing, and listing through the model command. |
| apps/pythinker-code/src/tui/constant/pythinker-tui.ts | Moves the TUI built-in role constant into the required constant directory. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Model role configuration] --> B[Resolve role to model alias]
B --> C[Agent or DynamicWorkflow subagent]
D[TUI model command] --> E[Config patch]
E --> F[Persist model_roles in TOML]
F --> A
Reviews (3): Last reviewed commit: "fix: drop the model roles table when the..." | Re-trigger Greptile
048c427 to
1e1559e
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/agent-core/src/config/toml.ts`:
- Around line 495-497: In the serialization logic around config.modelRoles,
delete out['model_roles'] before the conditional so undefined modelRoles cannot
preserve stale data; retain cloneUnknown(config.modelRoles) when defined. Add a
round-trip test covering modelRoles: undefined and confirming the old
assignments are not written back.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: a347a109-43f9-485d-b3b2-078bb36204b8
📒 Files selected for processing (7)
apps/pythinker-code/src/tui/commands/config.tsapps/pythinker-code/src/tui/constant/pythinker-tui.tsapps/pythinker-code/test/tui/commands/model-roles.test.tsdocs/configuration/config-files.mddocs/reference/slash-commands.mdpackages/agent-core/src/config/toml.tspackages/agent-core/test/config/configs.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- docs/reference/slash-commands.md
- docs/configuration/config-files.md
- apps/pythinker-code/src/tui/commands/config.ts
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @pythoughts/pythinker-code@0.16.0 ### Minor Changes - [#59](#59) [`6999b68`](6999b68) - Add an opt-in advisor: a second model reviews the conversation after a completed user turn unless another review is already running, and its notes appear as an `<advisory>` block in the agent's next turn; enable with `[advisor] enabled = true` plus an advisor model (the `advisor` model role or `[advisor] model`), and it runs only when the advisor shares the session model's provider. - [#56](#56) [`b71f094`](b71f094) - Add model roles: lock a model alias to the small, implementer, or advisor slot with `/model <role>`, list assignments with `/model roles`, and reference roles as `@small`, `@implementer`, or `@advisor` wherever a subagent model can be set; an assigned implementer role becomes the default model for subagents. - [#57](#57) [`99c427c`](99c427c) - Show what the agent is doing in the working indicator: eligible tool calls whose input schema accepts the injected field now carry a short model-written intent, streamed live into the spinner label (for example "check failing test…") instead of a rotating placeholder; disable with `PYTHINKER_CODE_EXPERIMENTAL_TOOL_INTENT=0`. - [#58](#58) [`065bf2e`](065bf2e) - Redesign core TUI surfaces: tool cards get state-tinted backgrounds with three new theme tokens, a status bar with a per-session accent color appears between the input box and footer, and the prompt box uses a neutral border while permission mode appears in the status bar. The working-label shimmer uses a calmer constant-velocity sweep with alternating mission-control highlights. ### Patch Changes - [#62](#62) [`7fc36fd`](7fc36fd) - Repair invalid escape sequences and unescaped quotes in model-written tool arguments instead of failing the tool call. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Related Issue
No linked issue — this implements a directly requested feature; the problem is explained below.
Problem
There is no way to designate models for specific duties. Subagents always inherit the parent session model unless each call site names an explicit alias, so a user who wants a cheap worker model for subagents, or a designated reviewer model, has to repeat concrete aliases everywhere and update them all when switching providers.
What changed
Adds a
model_rolesconfig map that locks a model alias to a named role, with three built-in roles:small,implementer, andadvisor(custom role keys are also accepted).@<role>references (@small,@implementer,@advisor,@<custom>) resolve through the map wherever a subagent model alias is accepted: theAgentandDynamicWorkflowtoolmodelarguments and agent profile frontmatter. Unassigned or unresolvable roles fall back to the existing precedence;model:permission deny rules are checked against both the raw@roleform and the resolved alias.implementerrole becomes the default model for subagents that set no explicit or profile model./model <role>assigns from the model picker,/model <role> clearunassigns,/model roleslists assignments. Role assignment persists through the standard config patch path; an empty string is the cleared state.advisorrole is configuration-only for now; a follow-up PR adds the runtime that consumes it.This approach keeps the existing alias-based config as the single source of model identity — roles are one indirection layer over aliases, with no new selector grammar.
Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.Summary by CodeRabbit
New Features
small,implementer, andadvisormodel roles, along with custom roles./model <role>, view them with/model roles, and clear assignments when needed.@small,@implementer, and@advisor.Documentation