feat(backends): add resolveModel() to AgentEngine interface#835
Conversation
nhopeatall
left a comment
There was a problem hiding this comment.
Summary
Clean interface addition — the optional resolveModel?() on AgentEngine is well-designed and correctly integrated. However, model resolution is now called twice for engines that implement it, which contradicts the stated goal of centralizing model validation in one place.
Should Fix
-
Double model resolution: The adapter now calls
engine.resolveModel(rawModel)atadapter.ts:191and places the resolved model intoAgentExecutionPlan.model. But each engine'sexecute()method still calls its standalone resolve function oninput.model:claude-code/index.ts:471:resolveClaudeModel(input.model)codex/index.ts:495:resolveCodexModel(input.model)opencode/index.ts:811:resolveOpenCodeModel(input.model)
This is currently safe because all three resolve functions are idempotent (resolving an already-resolved model produces the same result). But it contradicts the PR description's goal of centralizing model validation in one place — validation actually runs in two places now. The
execute()methods should either:- Drop their internal
resolve*Model()calls (relying on the adapter to pre-resolve), or - Be left as-is but with a comment explaining the intentional redundancy for backward compatibility (in case
execute()is called without going through the adapter).
Option (2) seems more practical since removing the internal calls would be a behavior change for any code path that calls
execute()directly.
No blocking issues — the change is safe to merge as-is, but addressing the double-resolution would deliver on the stated design intent.
🕵️ claude-code · claude-opus-4-6 · run details
Add explanatory comments to the resolve*Model() calls in each engine's execute() method clarifying that the redundancy is intentional. These calls remain for backward compatibility when execute() is invoked directly without going through the adapter's pre-resolution step. All three resolve functions are idempotent so the double call is safe. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
nhopeatall
left a comment
There was a problem hiding this comment.
LGTM — Clean, well-scoped change that centralizes model resolution behind the AgentEngine interface.
The design is sound:
- Optional interface method preserves backward compatibility (LlmistEngine omits it, existing mocks/tests pass without it)
- The deliberate double-resolution (adapter pre-resolves +
execute()re-resolves) is justified and well-commented —execute()may be called directly in tests - All three
resolve*Model()functions are genuinely idempotent (verified: repeated application produces the same output) - The
buildExecutionPlansignature addition threads the engine through cleanly toresolvePartialExecutionPlan - Standalone resolve functions remain exported for backward compatibility
No issues found.
🕵️ claude-code · claude-opus-4-6 · run details
Summary
resolveModel?(cascadeModel: string): stringmethod to theAgentEngineinterface intypes.tsClaudeCodeEngine,CodexEngine, andOpenCodeEngineimplementresolveModel()delegating to their existing standalone resolve functionsLlmistEnginedoes NOT implementresolveModel()(passes model through unchanged)adapter.tscallsengine.resolveModel?.(rawModel)during execution plan building, centralizing model validation in one placeresolveClaudeModel,resolveCodexModel,resolveOpenCodeModel) remain exported for backward compatibilityCard: https://trello.com/c/69b572b05754570c0c89fa4f
Test plan
npm run typecheck— zero errorsnpm run lint— zero errorsnpm test— all backend unit tests pass (pre-existing failures in postComment/github gadget tests are unrelated to this change)🤖 Generated with Claude Code
🕵️ claude-code · claude-sonnet-4-6 · run details