Skip to content

feat(agent): add OpenCode adapter#498

Merged
sergeyklay merged 2 commits intomainfrom
feat/opencode-adapter
Apr 26, 2026
Merged

feat(agent): add OpenCode adapter#498
sergeyklay merged 2 commits intomainfrom
feat/opencode-adapter

Conversation

@sergeyklay
Copy link
Copy Markdown
Member

🎯 Scope & Context

Type: Feat

Intent: Adds a fork-per-turn OpenCode adapter so Sortie can orchestrate the OpenCode CLI agent (opencode run --format json). The adapter handles subprocess lifecycle, JSON event normalization, permission policy synthesis, SSH remote execution, and export-based token accounting.

Related Issues: #476

🧭 Reviewer Guide

Complexity: High

Entry Point

internal/agent/opencode/opencode.go — contains the adapter lifecycle (StartSession, RunTurn, StopSession), subprocess management, single stdout reader goroutine, stall watchdog integration, and event normalization. Understanding the read loop and waitResult channel is critical to reviewing concurrency safety.

Sensitive Areas

  • internal/agent/opencode/opencode.go: subprocess fork-per-turn lifecycle, mutex discipline, and process-group teardown — review for races and deadlocks
  • internal/agent/opencode/command.go: permission policy synthesis and SSH remote command construction — workspace path containment and env scrubbing
  • internal/agent/opencode/parse.go: queryExportUsage spawns a subprocess to recover token counts; argument construction must match OpenCode CLI contract

⚠️ Risk Assessment

  • Breaking Changes: No breaking changes — additive adapter behind the existing domain.AgentAdapter interface
  • Migrations/State: No migrations or state changes

Implements the fork-per-turn OpenCode adapter using `opencode run --format json`.

- command.go: config parsing, argument/env construction, permission policy
  synthesis, and SSH remote command construction
- parse.go: JSON envelope parsing, part parsers, and export-based token
  usage recovery via `opencode export --sanitize`
- opencode.go: session lifecycle, subprocess management, event normalization,
  and stall watchdog integration
- Full test suite: unit tests with fixtures, subprocess-backed Unix tests,
  and env-gated integration tests (SORTIE_OPENCODE_TEST=1)
- Register adapter in binary and add registry metadata assertion
- Add *_unix_test.go file nesting pattern to VS Code explorer settings

Closes #476
@sergeyklay sergeyklay requested a review from serghei-dev as a code owner April 26, 2026 17:13
Copilot AI review requested due to automatic review settings April 26, 2026 17:13
@sergeyklay sergeyklay added the area:agent-adapter Agent interface, Claude Code adapter, Copilot adapter, mock label Apr 26, 2026
@sergeyklay sergeyklay linked an issue Apr 26, 2026 that may be closed by this pull request
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 26, 2026

Codecov Report

❌ Patch coverage is 68.93082% with 247 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/agent/opencode/opencode.go 67.70% 143 Missing and 23 partials ⚠️
internal/agent/opencode/parse.go 61.81% 48 Missing and 15 partials ⚠️
internal/agent/opencode/command.go 84.48% 11 Missing and 7 partials ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new internal/agent/opencode implementation of domain.AgentAdapter so Sortie can orchestrate the OpenCode CLI (opencode run --format json) with per-turn subprocess lifecycles, stdout JSONL normalization, permission-policy env synthesis, SSH execution support, and export-based token usage recovery.

Changes:

  • Register new agent kind opencode in the agent registry and Sortie main binary.
  • Implement OpenCode adapter lifecycle + subprocess/event parsing + token usage export parsing.
  • Add unit + (guarded) integration tests plus JSONL/JSON fixtures for parsing and lifecycle cases.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
internal/registry/adapter_meta_test.go Ensures opencode registration metadata is exercised in real-registration tests.
cmd/sortie/main.go Adds blank import so the opencode adapter registers in the built binary.
internal/agent/opencode/opencode.go Core adapter implementation: fork-per-turn process lifecycle, reader/wait coordination, event normalization, export usage emission.
internal/agent/opencode/command.go Builds opencode run args, managed env, permission policy, and SSH remote command prefix.
internal/agent/opencode/parse.go Parses JSONL run envelopes and opencode export output into normalized token usage.
internal/agent/opencode/command_test.go Unit tests for args/env/policy construction and SSH command assembly.
internal/agent/opencode/parse_test.go Unit tests for JSONL envelope parsing and export-output parsing.
internal/agent/opencode/parse_unix_test.go Unix-only tests for export-usage subprocess invocation (local + SSH).
internal/agent/opencode/opencode_test.go Unix-only tests for session lifecycle, cancellation, oversized lines, and event semantics.
internal/agent/opencode/integration_test.go Guarded integration tests against a real OpenCode binary (SORTIE_OPENCODE_TEST=1).
internal/agent/opencode/testdata/simple_turn.jsonl Fixture: basic step/text/finish event flow.
internal/agent/opencode/testdata/resume_turn.jsonl Fixture: resume-style step flow.
internal/agent/opencode/testdata/tool_success.jsonl Fixture: tool_use success envelope with large output.
internal/agent/opencode/testdata/permission_warning_then_error.txt Fixture: plain-text permission warning + tool_use error JSON line.
internal/agent/opencode/testdata/malformed_event.jsonl Fixture: unknown event type handling.
internal/agent/opencode/testdata/logical_failure_exit0.jsonl Fixture: logical failure via error envelope despite exit code 0.
internal/agent/opencode/testdata/export_usage.json Fixture: opencode export --sanitize usage payload with tokens/model/cost.
internal/agent/opencode/testdata/export_usage_missing_tokens.json Fixture: export payload missing token info.
.vscode/settings.json Updates file nesting to include _unix_test.go alongside other Go test files.

Comment thread internal/agent/opencode/opencode.go Outdated
Comment thread internal/agent/opencode/opencode.go
Comment thread internal/agent/opencode/opencode.go Outdated
Comment thread internal/agent/opencode/opencode.go
Comment thread internal/agent/opencode/parse.go Outdated
Comment thread internal/agent/opencode/command_test.go Outdated
Fix the OpenCode session handle and teardown behavior after PR review.

- return the resumed session ID instead of leaking workspace paths via Session.ID
- honor StopSession(ctx) with a bounded graceful shutdown path
- correct the managed-environment warning text in export usage recovery
- remove the dead errors import placeholder and add regression coverage for stop deadlines
@sergeyklay sergeyklay merged commit bcf5823 into main Apr 26, 2026
4 of 5 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Sortie Roadmap Apr 26, 2026
@sergeyklay sergeyklay deleted the feat/opencode-adapter branch April 26, 2026 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:agent-adapter Agent interface, Claude Code adapter, Copilot adapter, mock

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Implement OpenCode CLI agent adapter, registered under kind opencode

3 participants