mengxaingshuo commited on
Commit
13bbb15
·
1 Parent(s): 07d7c5d

fix: call OpenCode Go API directly

Browse files
Files changed (3) hide show
  1. codex_harness.py +51 -43
  2. start.sh +4 -1
  3. ui_server.py +2 -1
codex_harness.py CHANGED
@@ -1,7 +1,10 @@
1
  from __future__ import annotations
2
 
 
3
  import os
4
- import subprocess
 
 
5
  from dataclasses import dataclass
6
 
7
 
@@ -12,62 +15,67 @@ class CodexResult:
12
 
13
 
14
  class CodexHarness:
 
15
 
16
  def __init__(self, model=None, api_key=None, base_url=None,
17
  session_root=None, system_prompt=None, **kwargs):
18
-
19
- self.model = model or os.environ.get(
20
- "CODEX_MODEL",
21
- "gpt-5-codex"
22
- )
23
-
24
  self.api_key = (
25
  api_key
26
  or os.environ.get("OPENCODE_GO_API_KEY")
27
  or os.environ.get("OPENAI_API_KEY")
28
- )
29
-
30
  self.base_url = (
31
  base_url
32
  or os.environ.get("OPENCODE_GO_BASE_URL")
33
  or os.environ.get("OPENAI_BASE_URL")
34
  or "https://opencode.ai/zen/go/v1"
35
- )
36
-
37
  self.system_prompt = system_prompt or ""
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  def run(self, prompt, session_id=None):
41
-
42
- env = os.environ.copy()
43
-
44
- env["OPENAI_API_KEY"] = self.api_key or ""
45
- env["OPENAI_BASE_URL"] = self.base_url
46
-
47
- full_prompt = self.system_prompt + "\n\n" + prompt
48
-
49
- proc = subprocess.run(
50
- [
51
- "codex",
52
- "exec",
53
- # HF runs the app in /home/user/app, not a trusted Git worktree.
54
- # This disables only Codex CLI's interactive repository guard.
55
- "--skip-git-repo-check",
56
- "--model",
57
- self.model,
58
- full_prompt,
59
- ],
60
- env=env,
61
- capture_output=True,
62
- text=True,
63
- timeout=600,
64
- )
65
-
66
- if proc.returncode != 0:
67
- raise RuntimeError(
68
- proc.stderr[-1000:]
69
- )
70
-
71
- return CodexResult(
72
- final_response=proc.stdout.strip()
73
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from __future__ import annotations
2
 
3
+ import json
4
  import os
5
+ import urllib.error
6
+ import urllib.request
7
+ import uuid
8
  from dataclasses import dataclass
9
 
10
 
 
15
 
16
 
17
  class CodexHarness:
18
+ """Small non-interactive adapter for OpenCode Go's Responses API."""
19
 
20
  def __init__(self, model=None, api_key=None, base_url=None,
21
  session_root=None, system_prompt=None, **kwargs):
22
+ self.model = model or os.environ.get("OPENCODE_GO_MODEL", "gpt-5.6-luna")
 
 
 
 
 
23
  self.api_key = (
24
  api_key
25
  or os.environ.get("OPENCODE_GO_API_KEY")
26
  or os.environ.get("OPENAI_API_KEY")
27
+ or ""
28
+ ).strip()
29
  self.base_url = (
30
  base_url
31
  or os.environ.get("OPENCODE_GO_BASE_URL")
32
  or os.environ.get("OPENAI_BASE_URL")
33
  or "https://opencode.ai/zen/go/v1"
34
+ ).rstrip("/")
 
35
  self.system_prompt = system_prompt or ""
36
 
37
+ @staticmethod
38
+ def _text(payload: dict) -> str:
39
+ text = str(payload.get("output_text") or "").strip()
40
+ if text:
41
+ return text
42
+ parts = []
43
+ for item in payload.get("output") or []:
44
+ for content in item.get("content") or []:
45
+ if content.get("type") in {"output_text", "text"}:
46
+ value = content.get("text")
47
+ if isinstance(value, str):
48
+ parts.append(value)
49
+ elif isinstance(value, dict) and isinstance(value.get("value"), str):
50
+ parts.append(value["value"])
51
+ return "".join(parts).strip()
52
 
53
  def run(self, prompt, session_id=None):
54
+ if not self.api_key:
55
+ raise RuntimeError("OPENCODE_GO_API_KEY is not configured")
56
+ full_prompt = (self.system_prompt + "\n\n" + prompt).strip()
57
+ body = json.dumps({"model": self.model, "input": full_prompt}, ensure_ascii=False).encode("utf-8")
58
+ request = urllib.request.Request(
59
+ self.base_url + "/responses",
60
+ data=body,
61
+ method="POST",
62
+ headers={
63
+ "Authorization": "Bearer " + self.api_key,
64
+ "Content-Type": "application/json",
65
+ "Accept": "application/json",
66
+ "User-Agent": "Global-Marine-Foundation/4.4",
67
+ "x-opencode-session": str(session_id or uuid.uuid4()),
68
+ },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  )
70
+ try:
71
+ with urllib.request.urlopen(request, timeout=600) as response:
72
+ payload = json.loads(response.read().decode("utf-8"))
73
+ except urllib.error.HTTPError as exc:
74
+ detail = exc.read().decode("utf-8", errors="replace")[:1000]
75
+ raise RuntimeError(f"OpenCode Go API {exc.code}: {detail}") from exc
76
+ except urllib.error.URLError as exc:
77
+ raise RuntimeError(f"OpenCode Go connection failed: {exc.reason}") from exc
78
+ answer = self._text(payload)
79
+ if not answer:
80
+ raise RuntimeError("OpenCode Go returned no text: " + json.dumps(payload, ensure_ascii=False)[:800])
81
+ return CodexResult(final_response=answer)
start.sh CHANGED
@@ -36,7 +36,10 @@ fi
36
  export OPENAI_API_KEY="${MODEL_API_KEY}"
37
  # OpenCode is an OpenAI-compatible provider for Codex CLI
38
  export OPENAI_BASE_URL="https://opencode.ai/zen/go/v1"
39
- export CODEX_MODEL="${CODEX_MODEL:-gpt-5-codex}"
 
 
 
40
 
41
  # ============================================================
42
  # Web / Runtime
 
36
  export OPENAI_API_KEY="${MODEL_API_KEY}"
37
  # OpenCode is an OpenAI-compatible provider for Codex CLI
38
  export OPENAI_BASE_URL="https://opencode.ai/zen/go/v1"
39
+ # OpenCode Go's low-cost Responses model. Override only with another model
40
+ # listed by https://opencode.ai/zen/go/v1/models.
41
+ export OPENCODE_GO_MODEL="${OPENCODE_GO_MODEL:-gpt-5.6-luna}"
42
+ export CODEX_MODEL="${CODEX_MODEL:-${OPENCODE_GO_MODEL}}"
43
 
44
  # ============================================================
45
  # Web / Runtime
ui_server.py CHANGED
@@ -129,7 +129,8 @@ FISHERIES_EXPORT_ROOT = Path(
129
  FISHERIES_EXPORT_ROOT.mkdir(parents=True, exist_ok=True)
130
  MODEL = os.environ.get("CODEX_MODEL","gpt-5-codex")
131
 
132
- HARNESS_MODEL = os.environ.get("CODEX_MODEL","gpt-5-codex")
 
133
 
134
  HARNESS_BASE_URL = os.environ.get("OPENAI_BASE_URL","https://opencode.ai/zen/go/v1").rstrip("/")
135
 
 
129
  FISHERIES_EXPORT_ROOT.mkdir(parents=True, exist_ok=True)
130
  MODEL = os.environ.get("CODEX_MODEL","gpt-5-codex")
131
 
132
+ # OpenCode Go uses its own model catalogue; gpt-5-codex is not a Go model.
133
+ HARNESS_MODEL = os.environ.get("OPENCODE_GO_MODEL", "gpt-5.6-luna")
134
 
135
  HARNESS_BASE_URL = os.environ.get("OPENAI_BASE_URL","https://opencode.ai/zen/go/v1").rstrip("/")
136