mengxaingshuo commited on
Commit
12032b1
·
1 Parent(s): 199daad

switch Codex Harness to OpenCode API

Browse files
Dockerfile CHANGED
@@ -6,8 +6,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
6
  python3 python3-pip python3-venv ca-certificates curl git bash procps \
7
  && rm -rf /var/lib/apt/lists/*
8
 
9
- # CodeWhale is the current continuation of DeepSeek-TUI.
10
- RUN npm install -g codewhale@0.9.10 @openai/codex
11
 
12
  RUN usermod -l user -d /home/user -m node && groupmod -n user node
13
 
@@ -15,7 +15,7 @@ ENV HOME=/home/user \
15
  PATH=/home/user/.local/bin:/usr/local/bin:$PATH \
16
  PYTHONUNBUFFERED=1 \
17
  PORT=7860 \
18
- DEEPSEEK_MCP_CONFIG=/home/user/app/.codewhale/mcp.json
19
 
20
  WORKDIR /home/user/app
21
 
 
6
  python3 python3-pip python3-venv ca-certificates curl git bash procps \
7
  && rm -rf /var/lib/apt/lists/*
8
 
9
+ # Official OpenAI Codex CLI runtime.
10
+ RUN npm install -g @openai/codex
11
 
12
  RUN usermod -l user -d /home/user -m node && groupmod -n user node
13
 
 
15
  PATH=/home/user/.local/bin:/usr/local/bin:$PATH \
16
  PYTHONUNBUFFERED=1 \
17
  PORT=7860 \
18
+
19
 
20
  WORKDIR /home/user/app
21
 
README.md CHANGED
@@ -100,10 +100,10 @@ favorites and preferences. Backups exclude credentials, tokens and uploaded
100
  file contents, providing a manual cross-device migration path without claiming
101
  server-side synchronization.
102
 
103
- Custom chat UI backed by CodeWhale/DeepSeek and a restricted Marine MCP bridge.
104
 
105
  Public UI: port 7860.
106
- Private CodeWhale Runtime: 127.0.0.1:7878.
107
  The Runtime token never enters the browser.
108
 
109
  ## Functional sidebar
 
100
  file contents, providing a manual cross-device migration path without claiming
101
  server-side synchronization.
102
 
103
+ Custom chat UI backed by OpenAI Codex/OpenCode and a restricted Marine MCP bridge.
104
 
105
  Public UI: port 7860.
106
+ Private OpenAI Codex Runtime: 127.0.0.1:7878.
107
  The Runtime token never enters the browser.
108
 
109
  ## Functional sidebar
harness_safe.cordis.yml CHANGED
@@ -1,31 +1,11 @@
1
- - id: sdk-jsonrpc-server
2
- name: '@deepseek-ai/dsh-sdk-jsonrpc-server'
3
- config:
4
- maxTokensAsSuccess: true
5
-
6
- - id: llm-deepseek
7
- name: '@deepseek-ai/dsh-llm-deepseek'
8
- config:
9
- apiKeyEnv: DEEPSEEK_API_KEY
10
- streamIdleTimeoutMs: 300000
11
- models:
12
- - id: !!js process.env.DSH_MODEL ?? 'glm-5.2'
13
- contextWindow: !!js Number(process.env.DSH_CONTEXT_WINDOW ?? 128000)
14
 
15
- - id: agent-spine
16
- name: '@deepseek-ai/dsh-agent-spine-demo'
17
  config:
18
- includeHarnessIdentity: true
19
- includeRuntimeContext: false
20
- persona: !!js process.env.DSH_SYSTEM_PROMPT ?? 'You are Global Marine Foundation Data Agent. Reply in Chinese by default. Only output the final answer.'
21
- workspaceContext: false
22
- skills:
23
- enabled: false
24
- toolBash: false
25
- toolJobs: false
26
 
27
- - id: sessions
28
- name: '@deepseek-ai/dsh-session-persistence-jsonl'
29
- config:
30
- root: !!js process.env.DSH_SESSION_ROOT ?? '/tmp/deepseek-harness-sessions'
31
- compression: none
 
1
+ # Codex Harness configuration
2
+ # Model execution is handled by official OpenAI Codex CLI.
3
+ # Provider endpoint/key are injected through OPENAI-compatible environment variables.
 
 
 
 
 
 
 
 
 
 
4
 
5
+ - id: codex-harness
6
+ name: "@openai/codex"
7
  config:
8
+ modelEnv: CODEX_MODEL
9
+ apiKeyEnv: OPENAI_API_KEY
10
+ baseUrlEnv: OPENAI_BASE_URL
 
 
 
 
 
11
 
 
 
 
 
 
services/chat_runtime.py CHANGED
@@ -263,7 +263,7 @@ async def stream_chat(tid,prompt):
263
  })
264
  turn=((tr or {}).get("turn") or {}).get("id")
265
  answer=""
266
- yield out("status",{"text":"DeepSeek 正在处理…","stage":"compose","step":4,"total_steps":5})
267
 
268
  async for rec in events(tid,since):
269
  if turn and rec.get("turn_id") and rec["turn_id"]!=turn:
@@ -364,7 +364,7 @@ async def stream_chat(tid,prompt):
364
  if detail:
365
  raise RuntimeError(detail)
366
  raise RuntimeError(
367
- "DeepSeek 回合已结束,但 CodeWhale 没有产生 assistant 文本。"
368
  )
369
  final_answer=_sanitize_final_answer(answer)
370
  if not final_answer:
 
263
  })
264
  turn=((tr or {}).get("turn") or {}).get("id")
265
  answer=""
266
+ yield out("status",{"text":"Codex 正在处理…","stage":"compose","step":4,"total_steps":5})
267
 
268
  async for rec in events(tid,since):
269
  if turn and rec.get("turn_id") and rec["turn_id"]!=turn:
 
364
  if detail:
365
  raise RuntimeError(detail)
366
  raise RuntimeError(
367
+ "Codex 回合已结束,但 CodeWhale 没有产生 assistant 文本。"
368
  )
369
  final_answer=_sanitize_final_answer(answer)
370
  if not final_answer:
start.sh CHANGED
@@ -8,33 +8,34 @@ python3 /home/user/app/scripts/preflight.py
8
  # Required non-model settings
9
  # ============================================================
10
 
11
- : "${CODEWHALE_RUNTIME_TOKEN:?Missing CODEWHALE_RUNTIME_TOKEN secret}"
12
  : "${MARINE_API_URL:?Missing MARINE_API_URL variable}"
13
 
14
  # ============================================================
15
  # Model key
16
  #
17
- # We do NOT require or use DEEPSEEK_API_KEY.
18
  # Prefer the dedicated OpenCode Go secret.
19
  # Fall back to OPENAI_API_KEY only if you chose to store the same
20
  # OpenCode Go key under that name in Hugging Face.
21
  # ============================================================
22
 
23
- MODEL_API_KEY="${OPENAI_API_KEY:-}"
24
 
25
  if [ -z "${MODEL_API_KEY}" ]; then
26
  echo "[startup] ERROR: no OpenCode Go key was injected."
27
- echo "[startup] Expected: OPENAI_API_KEY"
28
  echo "[startup] Available environment variable names containing KEY/API:"
29
  env | cut -d= -f1 | grep -E 'KEY|API' | sort || true
30
  exit 1
31
  fi
32
 
33
  # ============================================================
34
- # Force CodeWhale to OpenCode Go -> GLM-5.3
35
  # ============================================================
36
 
37
  export OPENAI_API_KEY="${MODEL_API_KEY}"
 
 
38
  export CODEX_MODEL="${CODEX_MODEL:-gpt-5-codex}"
39
 
40
  # ============================================================
@@ -42,7 +43,6 @@ export CODEX_MODEL="${CODEX_MODEL:-gpt-5-codex}"
42
  # ============================================================
43
 
44
  export PORT="${PORT:-7860}"
45
- export CODEWHALE_INTERNAL_URL="http://127.0.0.1:7878"
46
  export FISHERIES_EXPORT_ROOT="${FISHERIES_EXPORT_ROOT:-/tmp/squid_fisheries_exports}"
47
  export HF_FISHERIES_CACHE_ROOT="${HF_FISHERIES_CACHE_ROOT:-/tmp/squid_hf_fisheries_cache}"
48
  if [ -z "${PUBLIC_BASE_URL:-}" ] && [ -n "${SPACE_HOST:-}" ]; then
@@ -53,7 +53,7 @@ fi
53
  # Build private Marine MCP runtime configuration
54
  # ============================================================
55
 
56
- RUNTIME_MCP_CONFIG="/tmp/codewhale-marine-mcp.json"
57
  export RUNTIME_MCP_CONFIG
58
 
59
  python3 - <<'PY_MCP_CONFIG'
@@ -117,49 +117,6 @@ p.chmod(0o600)
117
  print("[startup] private Marine MCP runtime config ready")
118
  PY_MCP_CONFIG
119
 
120
- # Legacy CodeWhale MCP-config variable name.
121
- # This only points to the MCP config file; it does NOT select DeepSeek.
122
- export DEEPSEEK_MCP_CONFIG="${RUNTIME_MCP_CONFIG}"
123
-
124
- # ============================================================
125
- # Startup information
126
- # ============================================================
127
-
128
- echo "[startup] CodeWhale:"
129
- codewhale --version
130
- echo "[startup] provider=${CODEWHALE_PROVIDER}"
131
- echo "[startup] model=${CODEWHALE_MODEL}"
132
- echo "[startup] endpoint=${OPENAI_BASE_URL:-}"
133
- echo "[startup] OpenCode Go key present=yes"
134
-
135
- # ============================================================
136
- # Start CodeWhale Runtime
137
- # ============================================================
138
-
139
- codewhale app-server --http \
140
- --host 127.0.0.1 \
141
- --port 7878 \
142
- --auth-token "${CODEWHALE_RUNTIME_TOKEN}" &
143
-
144
- CW_PID=$!
145
- trap 'kill "$CW_PID" 2>/dev/null || true' EXIT INT TERM
146
-
147
- for i in $(seq 1 60); do
148
- if curl -fsS --max-time 2 \
149
- http://127.0.0.1:7878/health \
150
- >/dev/null 2>&1; then
151
- echo "[startup] private CodeWhale Runtime ready"
152
- break
153
- fi
154
-
155
- kill -0 "$CW_PID" 2>/dev/null || {
156
- echo "[startup] CodeWhale exited"
157
- exit 1
158
- }
159
-
160
- sleep 1
161
- done
162
-
163
  # ============================================================
164
  # Marine API health check
165
  # ============================================================
 
8
  # Required non-model settings
9
  # ============================================================
10
 
 
11
  : "${MARINE_API_URL:?Missing MARINE_API_URL variable}"
12
 
13
  # ============================================================
14
  # Model key
15
  #
16
+ # We do NOT require or use OPENCODE_API_KEY.
17
  # Prefer the dedicated OpenCode Go secret.
18
  # Fall back to OPENAI_API_KEY only if you chose to store the same
19
  # OpenCode Go key under that name in Hugging Face.
20
  # ============================================================
21
 
22
+ MODEL_API_KEY="${OPENCODE_API_KEY:-${OPENAI_API_KEY:-}}"
23
 
24
  if [ -z "${MODEL_API_KEY}" ]; then
25
  echo "[startup] ERROR: no OpenCode Go key was injected."
26
+ echo "[startup] Expected: OPENCODE_API_KEY or OPENAI_API_KEY"
27
  echo "[startup] Available environment variable names containing KEY/API:"
28
  env | cut -d= -f1 | grep -E 'KEY|API' | sort || true
29
  exit 1
30
  fi
31
 
32
  # ============================================================
33
+ # Official OpenAI Codex CLI runtime
34
  # ============================================================
35
 
36
  export OPENAI_API_KEY="${MODEL_API_KEY}"
37
+ # OpenCode is an OpenAI-compatible provider for Codex CLI
38
+ export OPENAI_BASE_URL="${OPENCODE_BASE_URL:-${OPENAI_BASE_URL:-}}"
39
  export CODEX_MODEL="${CODEX_MODEL:-gpt-5-codex}"
40
 
41
  # ============================================================
 
43
  # ============================================================
44
 
45
  export PORT="${PORT:-7860}"
 
46
  export FISHERIES_EXPORT_ROOT="${FISHERIES_EXPORT_ROOT:-/tmp/squid_fisheries_exports}"
47
  export HF_FISHERIES_CACHE_ROOT="${HF_FISHERIES_CACHE_ROOT:-/tmp/squid_hf_fisheries_cache}"
48
  if [ -z "${PUBLIC_BASE_URL:-}" ] && [ -n "${SPACE_HOST:-}" ]; then
 
53
  # Build private Marine MCP runtime configuration
54
  # ============================================================
55
 
56
+ RUNTIME_MCP_CONFIG="/tmp/codex-marine-mcp.json"
57
  export RUNTIME_MCP_CONFIG
58
 
59
  python3 - <<'PY_MCP_CONFIG'
 
117
  print("[startup] private Marine MCP runtime config ready")
118
  PY_MCP_CONFIG
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  # ============================================================
121
  # Marine API health check
122
  # ============================================================
static/js/app.js CHANGED
@@ -905,7 +905,7 @@ function openServiceDiagnostics(data,appState){
905
  document.querySelector(".drawer-backdrop")?.remove();
906
  const marine=data.marine||{},hf=data.huggingface||{},d=data.diagnostic||{};
907
  const items=[
908
- ["DeepSeek Harness",!!(appState.harness_available||appState.runtime),null,appState.harness_model||appState.model||"-"],
909
  ["Marine API",!!marine.health?.ok,marine.health?.response_ms,serviceText(marine.health)],
910
  ["Domains",!!marine.domains?.ok,marine.domains?.response_ms,serviceText(marine.domains)],
911
  ["Ocean",!!marine.ocean?.ok,marine.ocean?.response_ms,serviceText(marine.ocean)],
@@ -961,7 +961,7 @@ async function renderServices(){
961
  const [appState,data]=await Promise.all([j("/api/status"),j("/api/sidebar/services")]);
962
  const marine=data.marine||{},hf=data.huggingface||{},d=data.diagnostic||{};
963
  const rows=[
964
- {name:appState.harness_available?"DeepSeek Harness":"CodeWhale Runtime",ok:!!(appState.harness_available||appState.runtime),detail:"模型:"+(appState.harness_model||appState.model||"-"),ms:null},
965
  {name:"学校 Marine API",ok:!!marine.health?.ok,detail:serviceText(marine.health),ms:marine.health?.response_ms},
966
  {name:"Ocean 数据域",ok:!!marine.ocean?.ok,detail:serviceText(marine.ocean),ms:marine.ocean?.response_ms},
967
  {name:"Tuna 渔业数据",ok:!!hf.ok&&Number(hf.tuna_file_count||0)>0,detail:hf.ok?("Hugging Face Dataset · "+(hf.tuna_file_count||0)+" 个匹配文件 · "+formatBytes(hf.tuna_size_bytes)):(hf.error||"读取失败"),ms:hf.response_ms},
@@ -1516,8 +1516,8 @@ async function status(){
1516
  const ok=llmOk&&s.marine_api;
1517
  $("dot").className="dot "+(ok?"ok":"warn");
1518
  const runtimeName=s.harness_available
1519
- ? "DeepSeek Harness"
1520
- : "CodeWhale fallback";
1521
  $("st").textContent=ok
1522
  ? runtimeName+" · "+(s.marine_mcp?"Ocean MCP 已连接":"数据服务在线")
1523
  : "部分服务不可用";
 
905
  document.querySelector(".drawer-backdrop")?.remove();
906
  const marine=data.marine||{},hf=data.huggingface||{},d=data.diagnostic||{};
907
  const items=[
908
+ ["OpenAI Codex Harness",!!(appState.harness_available||appState.runtime),null,appState.harness_model||appState.model||"-"],
909
  ["Marine API",!!marine.health?.ok,marine.health?.response_ms,serviceText(marine.health)],
910
  ["Domains",!!marine.domains?.ok,marine.domains?.response_ms,serviceText(marine.domains)],
911
  ["Ocean",!!marine.ocean?.ok,marine.ocean?.response_ms,serviceText(marine.ocean)],
 
961
  const [appState,data]=await Promise.all([j("/api/status"),j("/api/sidebar/services")]);
962
  const marine=data.marine||{},hf=data.huggingface||{},d=data.diagnostic||{};
963
  const rows=[
964
+ {name:appState.harness_available?"OpenAI Codex Harness":"OpenAI Codex Runtime",ok:!!(appState.harness_available||appState.runtime),detail:"模型:"+(appState.harness_model||appState.model||"-"),ms:null},
965
  {name:"学校 Marine API",ok:!!marine.health?.ok,detail:serviceText(marine.health),ms:marine.health?.response_ms},
966
  {name:"Ocean 数据域",ok:!!marine.ocean?.ok,detail:serviceText(marine.ocean),ms:marine.ocean?.response_ms},
967
  {name:"Tuna 渔业数据",ok:!!hf.ok&&Number(hf.tuna_file_count||0)>0,detail:hf.ok?("Hugging Face Dataset · "+(hf.tuna_file_count||0)+" 个匹配文件 · "+formatBytes(hf.tuna_size_bytes)):(hf.error||"读取失败"),ms:hf.response_ms},
 
1516
  const ok=llmOk&&s.marine_api;
1517
  $("dot").className="dot "+(ok?"ok":"warn");
1518
  const runtimeName=s.harness_available
1519
+ ? "OpenAI Codex Harness"
1520
+ : "OpenAI Codex fallback";
1521
  $("st").textContent=ok
1522
  ? runtimeName+" · "+(s.marine_mcp?"Ocean MCP 已连接":"数据服务在线")
1523
  : "部分服务不可用";
ui_server.py CHANGED
@@ -2746,7 +2746,7 @@ input::placeholder{color:#526f86}
2746
  <div class="visual-copy">
2747
  <span class="eyebrow"><i></i>SECURE RESEARCH WORKSPACE</span>
2748
  <h1>连接全球海洋数据<br>与智能分析能力</h1>
2749
- <p>统一访问 Ocean、Tuna 与 Squid 数据资产,连接学校数据服务器、DeepSeek Harness 与 Marine MCP。</p>
2750
  </div>
2751
  <div class="feature-row">
2752
  <span class="feature">🌊 Ocean Data</span>
 
2746
  <div class="visual-copy">
2747
  <span class="eyebrow"><i></i>SECURE RESEARCH WORKSPACE</span>
2748
  <h1>连接全球海洋数据<br>与智能分析能力</h1>
2749
+ <p>统一访问 Ocean、Tuna 与 Squid 数据资产,连接学校数据服务器、OpenAI Codex Harness 与 Marine MCP。</p>
2750
  </div>
2751
  <div class="feature-row">
2752
  <span class="feature">🌊 Ocean Data</span>