Commit Graph

3 Commits

Author SHA1 Message Date
Hongming Wang
d64641904f feat(workspace-server): mock runtime + mock-bigorg org template
Some checks failed
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 9s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 8s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 8s
Harness Replays / detect-changes (pull_request) Successful in 9s
CI / Python Lint & Test (pull_request) Successful in 6s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 6s
CI / Canvas (Next.js) (pull_request) Successful in 8s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 10s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 12s
Harness Replays / Harness Replays (pull_request) Successful in 8s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 8s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CodeQL / Analyze (${{ matrix.language }}) (python) (pull_request) Failing after 1m36s
cascade-list-drift-gate / check (pull_request) Successful in 5s
CodeQL / Analyze (${{ matrix.language }}) (javascript-typescript) (pull_request) Failing after 1m30s
CodeQL / Analyze (${{ matrix.language }}) (go) (pull_request) Failing after 1m39s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Failing after 2m50s
Retarget main PRs to staging / Retarget to staging (pull_request) Has been skipped
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 5s
CI / Platform (Go) (pull_request) Successful in 4m29s
CI / Detect changes (pull_request) Successful in 6s
E2E API Smoke Test / detect-changes (pull_request) Successful in 8s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 7s
Adds a 'mock' runtime: virtual workspaces with no container, no EC2,
no LLM. Every A2A reply is synthesised from a small canned-variant
pool ('On it!', 'Got it, on it now.', etc.) deterministically seeded
by (workspace_id, request_id).

Built for funding-demo "200-workspace mock org" — renders an
enterprise-scale org chart on the canvas (CEO/VPs/Managers/ICs)
without burning real LLM credits or provisioning 200 EC2 instances.

Surfaces:
  - workspace-server/internal/handlers/mock_runtime.go: A2A proxy
    short-circuit, canned-reply pool, deterministic variant pick.
  - workspace-server/internal/handlers/a2a_proxy.go: gate the
    short-circuit before resolveAgentURL (mock has no URL).
  - workspace-server/internal/handlers/org_import.go: skip Docker
    provisioning for mock workspaces, set status='online' directly,
    drop the per-sibling 2s pacing for mock children (collapses
    a 200-workspace import from ~7min → ~1s).
  - workspace-server/internal/handlers/runtime_registry.go: register
    'mock' in the runtime allowlist (manifest + fallback set).
  - workspace-server/internal/registry/healthsweep.go +
    orphan_sweeper.go: skip mock workspaces in container-health and
    stale-token sweeps (no container by design).
  - workspace-server/internal/handlers/workspace_restart.go: mirror
    the 'external' Restart no-op for mock.
  - manifest.json: register the new
    Molecule-AI/molecule-ai-org-template-mock-bigorg repo.

Tests: 5 new in mock_runtime_test.go covering happy-path, non-mock
regression guard, determinism, IsMockRuntime trim/case, JSON-RPC
id echo. All existing handler + registry tests still pass.

Local-verified: imported the 200-workspace template against a fresh
postgres+redis, confirmed all 200 land in 'online' and stay there
through the 30s health-sweep window, exercised A2A on CEO + VPs +
Managers + ICs and saw the variant pool rotate.

Org template lives at
Molecule-AI/molecule-ai-org-template-mock-bigorg (created today)
and is imported via the existing /org/import flow on the canvas
Template Palette.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 08:40:37 -07:00
Hongming Wang
f33e59ba8c chore(manifest): prune to 4 actively-supported runtimes
Deletes the 5 unsupported workspace_templates from manifest.json
(langgraph, crewai, autogen, deepagents, gemini-cli). The runtime
matrix is now claude-code / hermes / openclaw / codex — the four
templates with shipping images, working A2A integration, and active
CI publish-image cascades.

Mirrors the prune in:
  - workspace-server/internal/handlers/runtime_registry.go
    (fallbackRuntimes for dev/test contexts that boot without the
    manifest mounted)
  - workspace-server/internal/handlers/workspace_provision.go
    (sanitizeRuntime: empty/unknown → "claude-code", was "langgraph";
    removes the langgraph/deepagents-specific runtime_config skip
    branch — they're no longer supported, so the block is dead)
  - tests for both: rename TestEnsureDefaultConfig_LangGraph →
    _Hermes, TestEnsureDefaultConfig_EmptyRuntimeDefaultsToLangGraph
    → _ClaudeCode, drop TestEnsureDefaultConfig_DeepAgents,
    update TestSanitizeRuntime_Allowlist + the two
    TestResolveRestartTemplate_* cases that pinned langgraph-default
    as the safe-default name

Why this is safe: production reads manifest.json at boot and uses it
as the authoritative allowlist; the 5 removed runtimes have not
shipped working images for ≥1 release cycle. Any provision request
naming one will now coerce to claude-code (with a log line) instead
of returning a runtime that has no functioning template repo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 19:21:47 -07:00
Hongming Wang
1e8b5e0167 feat(external-runtime): first-class BYO-compute workspaces + manifest-driven registry
## Problem

Two issues the external-workspace path was silently dropping:

1. `knownRuntimes` was a hardcoded Go map that drifted from
   manifest.json — e.g. `gemini-cli` was in manifest but missing
   from the Go allowlist, so any workspace provisioning with
   runtime=gemini-cli got silently coerced to langgraph.

2. No end-to-end "bring your own compute" story. The canvas UI
   had no way to pick runtime=external; the partial backend code
   required the operator to already have a URL ready (chicken-and-
   egg with the agent that doesn't exist yet), and no workspace_auth
   _token was minted so the external agent couldn't authenticate its
   register call.

## Change

### Runtime registry driven by manifest.json

- New `runtime_registry.go` reads `manifest.json` at service init.
  Each `workspace_templates[].name` becomes a runtime identifier
  (with the `-default` suffix stripped so `claude-code-default`
  and `claude-code` resolve to the same runtime).
- `external` is always injected (no template repo exists for it).
- Falls back to a static map on manifest load failure so tests /
  dev containers keep working.
- 5 new tests including a real-manifest sanity check.

### First-class external workspace flow

When `POST /workspaces` is called with `runtime: "external"` AND
no URL supplied:

1. Workspace row inserted with `status='awaiting_agent'`
   (distinct from `provisioning` so canvas doesn't trip its
   provisioning-timeout UX).
2. A workspace_auth_token is minted via `wsauth.IssueToken`.
3. Response body includes a `connection` object with:
   - `workspace_id`, `platform_url`, `auth_token`
   - `registry_endpoint`, `heartbeat_endpoint`
   - `curl_register_template` — zero-dep one-shot register snippet
   - `python_snippet` — full SDK setup w/ heartbeat loop,
     paired with molecule-sdk-python PR #13's A2AServer
4. The platform URL is resolved from `EXTERNAL_PLATFORM_URL` env
   (ops-configurable per tenant) or falls back to request headers.

The legacy `payload.External` + `payload.URL` path is preserved —
org-import and other callers that already have a URL still work.

### Canvas UI

- New "External agent (bring your own compute)" checkbox in
  CreateWorkspaceDialog.
- When checked, template/model/hermes-provider fields are hidden
  and the POST body includes `runtime: "external"`.
- New `ExternalConnectModal` component: shown once after create,
  renders Python / curl / raw-fields tabs with copy-to-clipboard
  buttons. Stays mounted as a sibling of the create dialog so the
  token survives the create dialog unmount.
- `auth_token` is interpolated into the snippet client-side so the
  copied block is truly ready to run — operator only has to fill
  in their agent's public URL.

## Tests

- Go: 5 new runtime_registry tests (happy path, -default strip,
  external always injected, missing file, malformed JSON, real
  manifest sanity). All existing handler tests still pass.
- TypeScript: no type errors on my files; pre-existing
  canvas-batch-partial-failure type drift is on main already and
  tracked on the #2061 branch.

## Follow-ups (filed separately)

- Cut molecule-sdk-python v0.y to PyPI so the snippet can use
  `pip install molecule-ai-sdk` instead of `git+main`.
- Add a `runtime: string` field per template in manifest.json so
  one template can declare its runtime explicitly (instead of
  deriving it from name conventions). Unblocks N-templates-per-
  runtime (e.g. hermes-minimax, hermes-anthropic both runtime=hermes).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 15:34:10 -07:00