Skip to content

feat(opencode): add optional runtime overlay#3761

Open
Danigm-dev wants to merge 37 commits intosimstudioai:stagingfrom
Danigm-dev:feat/opencode-optional-runtime
Open

feat(opencode): add optional runtime overlay#3761
Danigm-dev wants to merge 37 commits intosimstudioai:stagingfrom
Danigm-dev:feat/opencode-optional-runtime

Conversation

@Danigm-dev
Copy link
Copy Markdown
Contributor

@Danigm-dev Danigm-dev commented Mar 25, 2026

Summary

Adds OpenCode as an optional Sim capability without changing the default Sim deployment path or base UX.

This PR introduces:

  • the OpenCode workflow block, tools, API routes, and lib/opencode client/service wiring
  • async dropdown/combobox support needed by the OpenCode block selectors
  • an optional OpenCode runtime with local/prod Docker Compose overlays
  • minimal docs and env examples for opt-in setup
  • a configurable OPENCODE_REPOSITORY_ROOT contract so Sim can also target compatible external OpenCode deployments

The default Sim experience remains unchanged:

  • docker-compose.local.yml is unchanged
  • docker-compose.prod.yml is unchanged
  • the OpenCode block stays hidden unless NEXT_PUBLIC_OPENCODE_ENABLED=true

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

  • timeout 90s bunx vitest run blocks/blocks.test.ts from apps/sim
  • bunx vitest run lib/opencode/service.test.ts app/api/opencode/repos/route.test.ts app/api/tools/opencode/prompt/route.test.ts from apps/sim
  • docker compose -f docker-compose.local.yml -f docker-compose.opencode.local.yml config
  • env OPENCODE_SERVER_PASSWORD=change-me docker compose -f docker-compose.prod.yml -f docker-compose.opencode.yml config
  • Manual validation:
    • Sim only: base UX unchanged and OpenCode hidden by default
    • Sim + OpenCode local overlay: OpenCode service starts, healthcheck passes, repo catalog loads, and prompts execute from the OpenCode block

Reviewer focus:

  • Confirm the default Sim path is unchanged when OpenCode is not enabled
  • Review the OpenCode runtime contract and OPENCODE_REPOSITORY_ROOT handling for external deployments
  • Review shared dropdown/combobox async-loading changes for regressions

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

Not included. The OpenCode block is hidden by default and only appears when NEXT_PUBLIC_OPENCODE_ENABLED=true. Manual validation covered both states and a successful prompt execution flow.

@cursor
Copy link
Copy Markdown

cursor bot commented Mar 25, 2026

PR Summary

Medium Risk
Medium risk because it introduces new authenticated API/tool endpoints and changes shared dropdown/combobox async option-loading behavior (new function signatures, retry/versioning) that could affect other blocks’ selectors if misused.

Overview
Adds an opt-in OpenCode workflow capability behind NEXT_PUBLIC_OPENCODE_ENABLED, including a new OpenCode block that can select a repo/provider/model/agent and execute prompts while optionally reusing threads.

Introduces OpenCode backend plumbing: session-cached OpenCode SDK client, service layer for listing repos/providers/models/agents, prompting, message retrieval, and workspace-scoped session persistence with retry-on-stale-session handling; plus new authenticated routes under /api/opencode/* (UI) and /api/tools/opencode/* (executor/internal).

Updates shared selector components (Dropdown/ComboBox) to support safer async option fetching: fetchOptions/fetchOptionById now receive subBlockId, options props are optional, and fetching gains dedupe/versioning + explicit retry-after-error.

Adds self-hosting/deploy support and docs: new OpenCode Dockerfile and compose overlays (docker-compose.opencode*.yml), new env examples/flag wiring, and build/test aliasing for @opencode-ai/sdk in Next/Vitest, plus README guidance for local vs prod overlays.

Reviewed by Cursor Bugbot for commit 98cae4c. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 25, 2026

@Danigm-dev is attempting to deploy a commit to the Sim Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 25, 2026

Greptile Summary

This PR introduces OpenCode as an optional Sim capability — a new workflow block, a suite of API routes, a library client/service layer, async dropdown/combobox support, and Docker Compose overlays — while leaving the default Sim deployment path completely unchanged.

The implementation is well-structured: the OpenCode block is hidden behind NEXT_PUBLIC_OPENCODE_ENABLED, all new API routes carry proper auth guards (checkSessionOrInternalAuth / checkInternalAuth) and workspace-access checks, the session-persistence layer uses the existing memory table with a verified unique index, and the stale-session retry logic is both correct and thoroughly tested.

Key changes at a glance:

  • lib/opencode/client.ts — OpenCode SDK client with module-level Docker-runtime detection (previously raised caching concern is resolved)
  • lib/opencode/service.ts — full CRUD of OpenCode sessions/repositories/providers/models/agents, plus DB-backed session storage
  • app/api/opencode/* — discovery routes for the block's async dropdowns; app/api/tools/opencode/* — internal tool routes called by the executor
  • blocks/blocks/opencode.ts — block definition with async fetchOptions/fetchOptionById wired to the discovery routes
  • combobox.tsx / dropdown.tsx — extended with fetchOptions, fetchOptionById, dependency-aware refetch, and in-flight deduplication (shared components; regressions reviewed)
  • docker/opencode.Dockerfile + shell helpers — pinned opencode-ai@0.8.0 via ARG, non-root opencode user, git-askpass.sh scoped to GitHub hosts

Minor findings:

  • Port validation in entrypoint.sh accepts out-of-range values
  • fetchOpenCodeOptionById in the block config fetches the full option list to find one entry by ID on hydration

Confidence Score: 5/5

Safe to merge — all remaining findings are P2 style suggestions with no correctness or data-integrity impact.

The PR is well-implemented: auth is enforced at every route, the memory table upsert relies on a verified unique index, stale-session retry logic is correct and covered by tests, previously flagged issues (existsSync caching, unpinned Docker image, GitHub token leakage) are resolved, and the default Sim path is demonstrably unchanged. The two open findings are minor efficiency and validation nits (P2) that do not affect production correctness.

docker/opencode/entrypoint.sh (port range validation) and apps/sim/blocks/blocks/opencode.ts (fetchOptionById efficiency) have minor P2 suggestions, but neither blocks merge.

Important Files Changed

Filename Overview
apps/sim/lib/opencode/service.ts Core service layer: repository discovery, session CRUD, provider/model/agent listing, and DB-backed session persistence via the memory table (unique index confirmed). Logic is sound with correct deduplication and sorting.
apps/sim/lib/opencode/client.ts SDK client with module-level Docker-runtime detection (IS_DOCKER_RUNTIME) and client-instance caching keyed on base URL + auth header. Previously raised concerns are fully resolved.
apps/sim/app/api/tools/opencode/prompt/route.ts Prompt execution route with session reuse, stale-session retry, and soft-error surfacing (success:true + error field); internal-auth-only, well-validated with Zod, and thoroughly tested.
apps/sim/blocks/blocks/opencode.ts Block definition with async fetchOptions/fetchOptionById wired to discovery routes; fetchOptionById fetches the full option list to find a single entry (P2 efficiency concern).
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx Extended with fetchOptions/fetchOptionById, in-flight deduplication, version tracking, and dependency-aware refetch; existing model/permission filtering is preserved.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx Extended with the same async-loading pattern as combobox, including hydration effect, dependency tracking, and in-flight guard; existing dataMode conversion logic is untouched.
docker/opencode.Dockerfile Pinned opencode-ai version via ARG (default 0.8.0), non-root opencode user, minimal debian-slim base; previously raised unpinned-version concern is addressed.
docker/opencode/entrypoint.sh Orchestrates runtime-env file, opencode.json config, cron installation, and initial repo sync; validate_port only checks for numeric input, not the valid 1–65535 range (P2).
docker/opencode/git-askpass.sh GITHUB_TOKEN is now scoped to github.com prompts only; GIT_TOKEN serves other hosts. Previously raised token-leak concern is resolved.
apps/sim/next.config.ts Adds @opencode-ai/sdk alias for both webpack (absolute path) and turbopack (relative path); both constants are intentionally distinct for their respective bundler semantics.

Sequence Diagram

sequenceDiagram
    participant UI as Browser / Block UI
    participant DiscoveryAPI as /api/opencode/*
    participant ToolAPI as /api/tools/opencode/prompt
    participant Service as lib/opencode/service.ts
    participant Client as lib/opencode/client.ts
    participant OC as OpenCode Server
    participant DB as memory table

    Note over UI,OC: Block configuration — async dropdown loading
    UI->>DiscoveryAPI: GET /api/opencode/repos?workspaceId=...
    DiscoveryAPI->>Service: listOpenCodeRepositories()
    Service->>Client: createOpenCodeClient()
    Client->>OC: project.list()
    OC-->>Client: Project[]
    Client-->>Service: projects
    Service-->>DiscoveryAPI: OpenCodeRepositoryOption[]
    DiscoveryAPI-->>UI: {data: [...repos]}

    UI->>DiscoveryAPI: GET /api/opencode/providers?workspaceId=&repository=...
    DiscoveryAPI->>Service: listOpenCodeProviders(repository)
    Service->>OC: config.providers({ directory })
    OC-->>Service: Provider[]
    Service-->>DiscoveryAPI: OpenCodeProviderOption[]
    DiscoveryAPI-->>UI: {data: [...providers]}

    Note over UI,DB: Workflow execution — prompt tool
    UI->>ToolAPI: POST /api/tools/opencode/prompt {repository, prompt, ...}
    ToolAPI->>Service: resolveOpenCodeRepositoryOption(repository)
    Service->>OC: project.list()
    OC-->>Service: repo option
    ToolAPI->>DB: getStoredOpenCodeSession(workspaceId, memoryKey)
    DB-->>ToolAPI: storedSession | null

    alt No stored session or repository mismatch
        ToolAPI->>Service: createOpenCodeSession(repositoryOption, title)
        Service->>OC: session.create({ directory })
        OC-->>Service: {id: sessionId}
    end

    ToolAPI->>Service: promptOpenCodeSession({sessionId, prompt, ...})
    Service->>OC: session.prompt({id, body})
    OC-->>Service: SessionPromptResponse
    Service-->>ToolAPI: OpenCodePromptResult

    alt Stale session error + reusableStoredThread
        ToolAPI->>Service: createOpenCodeSession() [fresh]
        Service->>OC: session.create()
        OC-->>Service: {id: freshSessionId}
        ToolAPI->>Service: promptOpenCodeSession({freshSessionId, ...})
        Service->>OC: session.prompt()
        OC-->>Service: result
    end

    ToolAPI->>DB: storeOpenCodeSession(workspaceId, memoryKey, {sessionId, repository})
    ToolAPI-->>UI: {success: true, output: {content, threadId, cost?}}
Loading

Reviews (2): Last reviewed commit: "Merge branch 'staging' into feat/opencod..." | Re-trigger Greptile

@Danigm-dev
Copy link
Copy Markdown
Contributor Author

Addressed the actionable Greptile findings in the latest branch state.

  • shouldRetryWithFreshOpenCodeSession() was already narrowed in 6160d1c16, so the broad includes("session") case is no longer present.
  • docker/opencode/git-askpass.sh no longer falls back to GITHUB_TOKEN for non-GitHub hosts.
  • docker/opencode.Dockerfile now pins opencode-ai@0.8.0 to keep the runtime aligned with the pinned SDK version.
  • apps/sim/lib/opencode/client.ts now caches Docker runtime detection at module load instead of checking /.dockerenv on every client creation.

Validation run after these changes:

  • bunx vitest run lib/opencode/service.test.ts app/api/opencode/repos/route.test.ts app/api/tools/opencode/prompt/route.test.ts
  • manual shell check for docker/opencode/git-askpass.sh host-specific token behavior

Latest fix commit: 8ec0c5aea.

@waleedlatif1 waleedlatif1 deleted the branch simstudioai:staging April 3, 2026 23:01
@waleedlatif1 waleedlatif1 reopened this Apr 3, 2026
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 98cae4c. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants