Two call sites — workspace_provision.go:537 and org_import.go:54 — duplicated the same `if runtime == "claude-code"` branch deciding the default model when the operator/agent didn't supply one. They were copy-pasted; nothing prevented them from drifting silently. Extract to `models.DefaultModel(runtime string) string`. Both call sites now route through the helper. New runtimes need one entry in DefaultModel + one assertion in TestDefaultModel — pre-fix it required two source edits + an audit. Foundation for the future `RuntimeConfig` interface (RFC #2873 + task #231): once we add `ProvisioningTimeout()`, `CapabilitiesSupported()` etc., the helper expands to per-runtime structs and `DefaultModel` becomes one method on the interface. ## Coverage 15 unit tests pinning the exact contract: - claude-code → "sonnet" - 9 other known runtimes → universal default - empty + unknown → universal default (matches pre-refactor fallthrough) - case-sensitivity preserved (CLAUDE-CODE → universal default) Plus invariant test: `DefaultModel` never returns "" — protects against a future "return early on unknown" regression that would silently break workspace creation. ## Verification - go build ./... clean - 15 model unit tests pass - existing handler tests untouched (no behavior change at call sites) - identical output to pre-refactor for every input First iteration of the OSS-shape refactor program. Each PR meets all 7 bars (plugin/abstract/modular/SSOT/coverage/cleanup/file-split). Refs RFC #2873.
40 lines
1.8 KiB
Go
40 lines
1.8 KiB
Go
package models
|
|
|
|
// runtime_defaults.go — single source of truth for per-runtime defaults
|
|
// the platform applies when the operator/agent didn't supply a value.
|
|
//
|
|
// Why this lives in models/ (not handlers/): default selection is a
|
|
// pure data fact about the runtime, not handler logic. Multiple
|
|
// callers (Create-workspace handler, org-import handler, future
|
|
// auto-provision paths) need the same answer; concentrating the
|
|
// rule here means one edit when a runtime's default changes.
|
|
//
|
|
// Related work (RFC #2873): this is the seed for a future
|
|
// `RuntimeConfig` interface that will also expose `ProvisioningTimeout()`,
|
|
// `CapabilitiesSupported()`, and other per-runtime facts. For now the
|
|
// surface is one helper — extracted from the duplicate branch in
|
|
// workspace_provision.go:537 and org_import.go:54 that diverged silently
|
|
// during refactors before this consolidation.
|
|
|
|
// DefaultModel returns the model slug to use when a workspace is
|
|
// created without an explicit model and the runtime can't infer one
|
|
// from its own config.
|
|
//
|
|
// - claude-code: "sonnet" — Anthropic's CLI accepts the short
|
|
// name and resolves it via the operator's anthropic-oauth or
|
|
// ANTHROPIC_API_KEY chain.
|
|
// - everything else (hermes, langgraph, crewai, autogen, deepagents,
|
|
// codex, openclaw, gemini-cli, external, ""): a fully-qualified
|
|
// vendor:model slug that the universal MODEL_PROVIDER chain in
|
|
// molecule-core PR #247 can route via per-vendor required_env.
|
|
//
|
|
// The function never returns an empty string; an unknown runtime
|
|
// gets the universal default rather than failing closed (matches the
|
|
// pre-refactor behavior — both call sites used the same fallback).
|
|
func DefaultModel(runtime string) string {
|
|
if runtime == "claude-code" {
|
|
return "sonnet"
|
|
}
|
|
return "anthropic:claude-opus-4-7"
|
|
}
|