Skip to content

Commit de95730

Browse files
authored
Merge pull request #6 from ai4curation/add-opencode-support
feat: Add support for opencode.ai
2 parents a25a772 + e5f6911 commit de95730

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

src/metacoder/coders/opencode.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import logging
2+
import shutil
3+
import subprocess
4+
import time
5+
from pathlib import Path
6+
7+
from metacoder.coders.base_coder import (
8+
BaseCoder,
9+
CoderOutput,
10+
change_directory,
11+
)
12+
from metacoder.configuration import ConfigFileRole
13+
14+
logger = logging.getLogger(__name__)
15+
16+
17+
class OpencodeCoder(BaseCoder):
18+
"""
19+
OpenCode.ai AI assistant integration.
20+
21+
Note: Requires opencode CLI to be installed.
22+
"""
23+
24+
@classmethod
25+
def is_available(cls) -> bool:
26+
"""Check if opencode command is available."""
27+
return shutil.which("opencode") is not None
28+
29+
@classmethod
30+
def supports_mcp(cls) -> bool:
31+
return False
32+
33+
@classmethod
34+
def default_config_paths(cls) -> dict[Path, ConfigFileRole]:
35+
return {
36+
Path("AGENTS.md"): ConfigFileRole.PRIMARY_INSTRUCTION,
37+
}
38+
39+
def run(self, input_text: str) -> CoderOutput:
40+
"""
41+
Run opencode with the given input text.
42+
"""
43+
self.prepare_workdir()
44+
with change_directory(self.workdir):
45+
command = ["opencode", "run", self.expand_prompt(input_text)]
46+
if self.params and self.params.get("model"):
47+
command.extend(["--model", self.params["model"]])
48+
49+
logger.info(f"Running command: {' '.join(command)}")
50+
start_time = time.time()
51+
52+
try:
53+
result = self.run_process(command)
54+
except subprocess.CalledProcessError as e:
55+
return CoderOutput(
56+
stdout=e.stdout or "",
57+
stderr=str(e),
58+
result_text=f"Error: {str(e)}",
59+
success=False,
60+
)
61+
62+
end_time = time.time()
63+
logger.info(f"Command took {end_time - start_time:.2f} seconds")
64+
65+
return CoderOutput(
66+
stdout=result.stdout,
67+
stderr=result.stderr,
68+
result_text=result.stdout,
69+
success=True,
70+
)
71+
72+
def default_config_objects(self):
73+
return []

src/metacoder/registry.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from metacoder.coders.codex import CodexCoder
99
from metacoder.coders.dummy import DummyCoder
1010
from metacoder.coders.gemini import GeminiCoder
11+
from metacoder.coders.opencode import OpencodeCoder
1112
from metacoder.coders.qwen import QwenCoder
1213

1314

@@ -16,6 +17,7 @@
1617
"claude": ClaudeCoder,
1718
"codex": CodexCoder,
1819
"gemini": GeminiCoder,
20+
"opencode": OpencodeCoder,
1921
"qwen": QwenCoder,
2022
"dummy": DummyCoder,
2123
}

tests/test_coders/test_coders_basic.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from metacoder.coders.gemini import GeminiCoder
1313
from metacoder.coders.codex import CodexCoder
1414
from metacoder.coders.dummy import DummyCoder
15+
from metacoder.coders.opencode import OpencodeCoder
1516
from metacoder.configuration import CoderConfig, AIModelConfig
1617

1718

@@ -23,6 +24,7 @@
2324
# ("qwen", QwenCoder), ## TODO: fix qwen
2425
("codex", CodexCoder),
2526
("dummy", DummyCoder),
27+
("opencode", OpencodeCoder),
2628
]
2729

2830
# Coders that require LLM access (all except dummy)

0 commit comments

Comments
 (0)