molecule-core/workspace-server/internal/handlers
Hongming Wang 517bd0efc5 feat(canvas+workspace-server): data-driven Provider dropdown (#199)
Option B PR-5. Canvas Config tab now exposes a Provider override input
that's adapter-driven from each runtime's template — no hardcoded
provider list in the canvas. PUT /workspaces/:id/provider on Save
when dirty; auto-restart suppression to avoid double-restart with
the model handler's own restart.

The dropdown's suggestion list comes from /templates →
runtime_config.providers (the field added in
molecule-ai-workspace-template-hermes PR #31). For templates that
haven't migrated to the explicit providers list yet, suggestions
derive from model[].id slug prefixes — still adapter-driven, just
inferred. This keeps existing templates working while platform team
migrates them one at a time.

workspace-server changes:
- Add Providers []string field to templateSummary JSON
- Parse runtime_config.providers in /templates handler
- 2 new tests pin the surfacing + omitempty behavior

canvas changes:
- Remove hardcoded PROVIDER_SUGGESTIONS constant
- Add provider/originalProvider state + PUT-on-save logic
- Add deriveProvidersFromModels() fallback helper
- Wire RuntimeOption.providers from /templates response
- 8 new tests pin the behavior end-to-end

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 11:19:17 -07:00
..
testdata/a2a_corpus test(a2a): protocol-shape replay corpus gate (#2345 follow-up) 2026-04-30 01:26:02 -07:00
a2a_corpus_test.go test(a2a): protocol-shape replay corpus gate (#2345 follow-up) 2026-04-30 01:26:02 -07:00
a2a_proxy_helpers.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
a2a_proxy_test.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
a2a_proxy.go fix(a2a): cover CF 521/522/523 in dead-origin status set 2026-04-30 01:39:04 -07:00
a2a_queue_status_test.go feat(a2a): per-queue-id status endpoint + per-message TTL (RFC #2331 Tier 1) 2026-04-29 20:21:17 -07:00
a2a_queue_status.go feat(a2a): per-queue-id status endpoint + per-message TTL (RFC #2331 Tier 1) 2026-04-29 20:21:17 -07:00
a2a_queue_test.go fix(platform/delegation): classify queued response + stitch drain result back 2026-04-26 10:14:19 -07:00
a2a_queue.go feat(a2a): per-queue-id status endpoint + per-message TTL (RFC #2331 Tier 1) 2026-04-29 20:21:17 -07:00
activity_since_id_test.go feat(activity): since_id cursor on GET /activity (#2339 PR 3) 2026-04-29 22:51:52 -07:00
activity_since_secs_test.go feat(activity): accept ?since_secs= for time-window filtering (#2268) 2026-04-29 05:53:52 -07:00
activity_test.go fix(activity): include request/response bodies in ACTIVITY_LOGGED broadcast 2026-04-27 13:38:23 -07:00
activity.go feat(activity): since_id cursor on GET /activity (#2339 PR 3) 2026-04-29 22:51:52 -07:00
admin_memories_test.go
admin_memories.go
admin_queue_test.go
admin_queue.go
admin_schedules_health_test.go
admin_schedules_health.go
admin_test_token_test.go test(admin_test_token): pin ADMIN_TOKEN IDOR-fix (#112) gate behavior 2026-04-30 02:59:08 -07:00
admin_test_token.go
admin_workspace_images_test.go feat(platform/admin): /admin/workspace-images/refresh + Docker SDK + GHCR auth 2026-04-26 10:17:21 -07:00
admin_workspace_images.go feat(workspace-server): GHCR digest watcher closes runtime CD chain (#2114) 2026-04-26 13:36:26 -07:00
agent_git_identity_test.go
agent_git_identity.go
agent_test.go
agent.go
approvals_test.go
approvals.go
artifacts_test.go
artifacts.go
audit_test.go
audit.go
budget_test.go
budget.go
bundle.go
channels_test.go
channels.go
chat_files_test.go test(chat_files): pin lazy-heal mint contract for both Upload and Download 2026-04-30 02:38:28 -07:00
chat_files.go refactor(chat_files): extract streamWorkspaceResponse helper for Upload+Download 2026-04-30 08:27:45 -07:00
checkpoints_integration_test.go
checkpoints_test.go
checkpoints.go
config_test.go
config.go
container_files_delete_test.go
container_files_test.go fix(handlers): add empty/dot-only path guard to validateRelPath 2026-04-24 07:17:26 +00:00
container_files.go fix(tests): path validation before docker check + a2a queue mock in tests 2026-04-24 11:07:43 +00:00
delegation_test.go fix(platform/delegation): classify queued response + stitch drain result back 2026-04-26 10:14:19 -07:00
delegation.go fix(platform/delegation): classify queued response + stitch drain result back 2026-04-26 10:14:19 -07:00
discovery_test.go fix(discovery): isSafeURL guard on registered URLs (closes #1484) 2026-04-26 06:50:36 -07:00
discovery.go fix(discovery): isSafeURL guard on registered URLs (closes #1484) 2026-04-26 06:50:36 -07:00
events_test.go
events.go
external_connection.go docs(canvas): update Universal MCP snippet — molecule-mcp now standalone 2026-04-30 15:52:15 -07:00
github_token_test.go
github_token.go
handlers_additional_test.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
handlers_extended_test.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
handlers_test.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
hermes_messages_test.go
hermes_messages.go
hibernation_test.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
instructions.go
mcp_test.go
mcp_tools.go
mcp.go
memories_test.go
memories.go
memory_test.go
memory.go
native_session_test.go feat(runtime): native_session skips a2a_queue enqueue — primitive #5 of 6 2026-04-26 23:34:04 -07:00
native_status_mgmt_test.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
org_helpers.go
org_import_force_removed_test.go fix(org-import): remove force=true bypass of required-env preflight 2026-04-29 03:23:23 -07:00
org_import.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
org_include_test.go
org_include.go
org_path_test.go
org_plugin_allowlist_test.go
org_plugin_allowlist.go
org_prompt_ref_test.go
org_test.go feat(org-templates): add ux-ab-lab + manifest entry + schema smoke test 2026-04-24 16:22:14 -07:00
org_tokens_test.go
org_tokens.go
org.go fix(org-import): remove force=true bypass of required-env preflight 2026-04-29 03:23:23 -07:00
plugins_install_pipeline_test.go
plugins_install_pipeline.go test(plugins): unblock TestResolveAndStage_NoInternalErrorsInHTTPErr (#1814) 2026-04-27 04:00:39 -07:00
plugins_install.go
plugins_listing.go
plugins_sources.go
plugins_test.go
plugins.go test(plugins): unblock TestResolveAndStage_NoInternalErrorsInHTTPErr (#1814) 2026-04-27 04:00:39 -07:00
registry_test.go fix(workspace): deliver platform_inbound_secret on every heartbeat 2026-04-30 17:36:33 -07:00
registry.go fix(workspace): deliver platform_inbound_secret on every heartbeat 2026-04-30 17:36:33 -07:00
restart_context_test.go
restart_context.go
restart_template_test.go fix(handlers): apply sanitizeRuntime allowlist before Tier 4 filepath.Join (CWE-22) 2026-04-24 11:37:19 +00:00
restart_template.go fix(handlers): apply sanitizeRuntime allowlist before Tier 4 filepath.Join (CWE-22) 2026-04-24 11:37:19 +00:00
runtime_overrides_test.go feat(runtime): native_scheduler skip — primitive #3 of 6 2026-04-26 22:47:00 -07:00
runtime_overrides.go feat(runtime): native_scheduler skip — primitive #3 of 6 2026-04-26 22:47:00 -07:00
runtime_provision_timeouts_test.go feat(workspace-server): surface provision_timeout_ms in workspace API (#2054 phase 2) 2026-04-26 06:37:45 -07:00
runtime_provision_timeouts.go refactor(handlers): apply simplify findings on PR #2094 2026-04-26 06:40:15 -07:00
runtime_registry_test.go feat(external-runtime): first-class BYO-compute workspaces + manifest-driven registry 2026-04-24 15:34:10 -07:00
runtime_registry.go feat(external-runtime): first-class BYO-compute workspaces + manifest-driven registry 2026-04-24 15:34:10 -07:00
schedules_test.go
schedules.go
secrets_test.go feat(workspace-server): PUT /provider endpoint for explicit LLM provider (#196) 2026-04-30 22:25:48 -07:00
secrets.go feat(workspace-server): PUT /provider endpoint for explicit LLM provider (#196) 2026-04-30 22:25:48 -07:00
security_regression_685_686_687_688_test.go
socket.go
sse_test.go
sse.go
ssrf_test.go test(ssrf): pin dev-mode RFC-1918 allow contract (follow-up to #2103) 2026-04-26 10:32:33 -07:00
ssrf.go fix(platform/ssrf): allow RFC-1918 in MOLECULE_ENV=development 2026-04-26 10:14:47 -07:00
team_test.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
team.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
template_files_eic_test.go
template_files_eic.go
template_import_test.go
template_import.go
templates_test.go feat(canvas+workspace-server): data-driven Provider dropdown (#199) 2026-05-01 11:19:17 -07:00
templates.go feat(canvas+workspace-server): data-driven Provider dropdown (#199) 2026-05-01 11:19:17 -07:00
terminal_diagnose_test.go fix(terminal-diagnose): KI-005 hierarchy check + race-free stderr capture 2026-04-30 21:19:18 -07:00
terminal_diagnose.go fix(terminal-diagnose): KI-005 hierarchy check + race-free stderr capture 2026-04-30 21:19:18 -07:00
terminal_test.go test(terminal): update exact-argv snapshot to include ConnectTimeout 2026-04-30 20:23:48 -07:00
terminal.go fix(terminal): cap ssh handshake at 10s so hung sshd surfaces fast 2026-04-30 20:16:41 -07:00
tokens_sqlmock_test.go test(handlers): sqlmock coverage for tokens.go (closes #1819) 2026-04-26 02:50:42 -07:00
tokens_test.go
tokens.go
traces_test.go
traces.go
transcript_test.go
transcript.go
viewport_test.go
viewport.go
webhooks_test.go
webhooks_workflow_test.go
webhooks.go
workspace_bootstrap_test.go refactor(workspace-status): catch missed literal in workspace_bootstrap.go + add literal-drift gate 2026-04-30 10:51:01 -07:00
workspace_bootstrap.go refactor(workspace-status): catch missed literal in workspace_bootstrap.go + add literal-drift gate 2026-04-30 10:51:01 -07:00
workspace_budget_test.go feat(workspaces): delivery_mode column + poll-mode register flow (#2339 PR 1) 2026-04-29 21:47:14 -07:00
workspace_crud.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
workspace_metrics_test.go
workspace_metrics.go
workspace_preflight_test.go
workspace_preflight.go
workspace_provision_shared_test.go test(provision): direct unit tests for readOrLazyHealInboundSecret 2026-04-30 04:41:13 -07:00
workspace_provision_shared.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
workspace_provision_test.go refactor(workspace-status): typed constants + AST-based drift gate 2026-04-30 10:41:41 -07:00
workspace_provision.go fix(provision): share Docker+SaaS prepare path so both mint workspace secrets (RFC #2312) 2026-04-30 02:18:08 -07:00
workspace_restart_async_test.go Move /restart Stop into the async goroutine 2026-04-30 19:35:29 -07:00
workspace_restart_coalesce_test.go fix(restart): clear running flag on panic in cycle() 2026-04-29 00:00:12 -07:00
workspace_restart_test.go fix(workspace-server): skip provision pipeline on Restart for runtime=external 2026-04-30 15:08:48 -07:00
workspace_restart.go Move /restart Stop into the async goroutine 2026-04-30 19:35:29 -07:00
workspace_test.go fix(workspace-server): emit null removed_at when timestamp fetch fails 2026-04-30 22:24:59 -07:00
workspace.go fix(workspace-server): emit null removed_at when timestamp fetch fails 2026-04-30 22:24:59 -07:00