molecule-core/workspace-server
Hongming Wang d6abc1286f
fix(workspace): auto-fill model from template's runtime_config when missing (#1779)
Extends the existing "read runtime from template config.yaml"
preflight to also pre-fill `model` from the template's
runtime_config.model (current format) or top-level `model:` (legacy
format). Without this, any create path that names a template but
doesn't pass an explicit model produced a workspace with empty
model — and hermes-agent's compiled-in Anthropic fallback ran with
whatever key the user did provide, 401'ing at the first A2A call.

Affected paths (all produced broken workspaces before this change):
- TemplatePalette "Deploy" button (POSTs only name + template + tier)
- Direct API / script callers (MCP, CI scripts)
- Anyone copying an existing workspace's template name without model

PR #1714 fixed the canvas CreateWorkspaceDialog's hermes branch —
when the user typed template="hermes" in the dialog, a provider
picker + model auto-fill kicked in. But TemplatePalette and direct
API calls bypassed that dialog entirely, so the trap stayed open.

Fix is backend-side so it catches every caller at once (defense in
depth). The parser is line-based + a minimal state var tracking
whether the current line sits under `runtime_config:` — matches the
existing fragile-but-safe style used for `runtime:` above. Strings
are trimmed of quote wrappers so both `model: x` and `model: "x"`
round-trip.

Explicit model in the payload still wins — we only pre-fill when
payload.Model is empty. Added TestWorkspaceCreate_
CallerModelOverridesTemplateDefault to pin that contract.

## Tests
- TestWorkspaceCreate_TemplateDefaultsMissingRuntimeAndModel — the
  hermes-trap fix: runtime=hermes + model=nousresearch/... inherits
  from template when payload omits both.
- TestWorkspaceCreate_TemplateDefaultsLegacyTopLevelModel — legacy
  top-level `model:` still fills.
- TestWorkspaceCreate_CallerModelOverridesTemplateDefault — explicit
  payload.model NOT overwritten.
- Full suite `go test -race ./...` stays green.

## Complementary work in flight
- PR molecule-core#1772 — fixes the E2E Staging SaaS which had the
  same trap on its own POST body (missing provider prefix).
- Canvas TemplatePalette could still surface a richer per-template
  key picker (deferred; MissingKeysModal already handles keys, and
  the default model now flows from the template config).

Co-authored-by: Hongming Wang <hongmingwang.rabbit@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: molecule-ai[bot] <276602405+molecule-ai[bot]@users.noreply.github.com>
2026-04-23 18:58:04 +00:00
..
cmd/server fix(go): replace $1 literal with resp.Body.Close() in 7 files (#1247) 2026-04-21 03:18:21 +00:00
internal fix(workspace): auto-fill model from template's runtime_config when missing (#1779) 2026-04-23 18:58:04 +00:00
migrations fix(review): address code review blockers on tool-trace + instructions 2026-04-22 16:18:06 -07:00
pkg/provisionhook fix(docker): fix plugin go.mod replace for TokenProvider interface (#960) 2026-04-20 13:42:53 -07:00
.ci-force chore: force Platform(Go) CI run on main — validate go vet clean 2026-04-21 15:43:19 +00:00
.gitignore feat(ws-server): pull env from CP on startup 2026-04-19 02:41:15 -07:00
Dockerfile chore: extract ContextMenu Zustand fix + a2a_proxy local-docker SSRF bypass + workspace-server Dockerfile GID entrypoint 2026-04-22 20:00:16 -07:00
Dockerfile.tenant feat(terminal): remote path via aws ec2-instance-connect + pty 2026-04-21 18:13:29 -07:00
entrypoint-tenant.sh fix(security): add USER directive before ENTRYPOINT in all tenant images (#1155) 2026-04-20 23:51:33 +00:00
go.mod Merge main into staging - resolving 1,388 commit divergence for PR #1573 2026-04-22 13:54:53 +00:00
go.sum feat(terminal): remote path via aws ec2-instance-connect + pty 2026-04-21 18:13:29 -07:00