From d76d797b0b7ff7ed39277e07508d17947d00420d Mon Sep 17 00:00:00 2001 From: Huarch Date: Mon, 18 May 2026 16:48:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=85=8D=E7=BD=AE=EF=BC=8C?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=B5=8C=E5=85=A5=E5=BC=8F=20opencode=20serv?= =?UTF-8?q?er=20=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 14 ++++++------- src/config.ts | 20 ++++--------------- src/runtime/opencode.ts | 44 ++++------------------------------------- src/server.ts | 7 +------ 4 files changed, 15 insertions(+), 70 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index d29f602..9ddc2d9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,19 +13,17 @@ services: NODE_ENV: production HOST: 0.0.0.0 PORT: 8787 - DEEPSEEK_API_KEY: "sk-8941428ad9be4c789becfa8d66534aba" - TJWATER_API_BASE_URL: "http://127.0.0.1:8000" - # OpenCode configurations from smanx/opencode - OPENCODE_HOSTNAME: 0.0.0.0 - OPENCODE_PORT: 4096 + AGENT_INTERNAL_TOKEN: ${AGENT_INTERNAL_TOKEN:-} + OPENCODE_BASE_URL: ${OPENCODE_BASE_URL:-http://127.0.0.1:4096} + DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-} + TJWATER_API_BASE_URL: ${TJWATER_API_BASE_URL:-http://127.0.0.1:8000} volumes: - /home/ubuntu/.config/opencode:/root/.config/opencode - /home/ubuntu/.local/share/opencode:/root/.local/share/opencode - - ./opencode/agents:/app/.opencode/agents - - ./opencode/skills:/app/.opencode/skills + - ./.opencode/agents:/app/.opencode/agents + - ./.opencode/skills:/app/.opencode/skills - ./logs:/app/logs - ./data:/app/data ports: - "8787:8787" - # - "4096:4096" restart: unless-stopped diff --git a/src/config.ts b/src/config.ts index 5621bb6..3d925c2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -18,22 +18,10 @@ const envSchema = z.object({ LLM_REQUEST_AUDIT_LOG_PATH: z .string() .default("./logs/llm-request-audit.log"), - // 内部工具桥调用本服务时使用的鉴权 token;未显式配置时启动阶段会自动生成。 - AGENT_INTERNAL_TOKEN: z.string().optional(), - // embedded opencode server 的监听地址。 - OPENCODE_HOSTNAME: z.string().default("127.0.0.1"), - // embedded opencode server 的监听端口。 - OPENCODE_PORT: z.coerce.number().int().positive().default(4096), - // opencode SDK 启动或连接运行时时的超时时间(毫秒)。 - OPENCODE_TIMEOUT_MS: z.coerce.number().int().positive().default(5000), - // 默认使用的 opencode 模型标识。 - OPENCODE_MODEL: z.string().default("deepseek/deepseek-v4-pro"), - // 外部 opencode server 的基础地址;配置后将跳过 embedded 模式。 - OPENCODE_BASE_URL: z.string().optional(), - // 外部 opencode server 的访问密码(预留)。 - OPENCODE_SERVER_PASSWORD: z.string().optional(), - // 外部 opencode server 的访问用户名(预留)。 - OPENCODE_SERVER_USERNAME: z.string().default("opencode"), + // 外部 opencode server 回调本服务内部工具桥时使用的共享鉴权 token;可暂时留空。 + AGENT_INTERNAL_TOKEN: z.string().default(""), + // 外部 opencode server 的基础地址。 + OPENCODE_BASE_URL: z.string().url(), // chat session 在本地注册表中的保活时长(秒)。 SESSION_TTL_SECONDS: z.coerce.number().int().positive().default(1800), // 提供给本地 opencode tools 读取的会话上下文目录。 diff --git a/src/runtime/opencode.ts b/src/runtime/opencode.ts index b4b17b3..edd9603 100644 --- a/src/runtime/opencode.ts +++ b/src/runtime/opencode.ts @@ -1,5 +1,4 @@ import { - createOpencode, createOpencodeClient, type OpencodeClient, } from "@opencode-ai/sdk/v2"; @@ -19,7 +18,6 @@ type RuntimeModelOverride = { export class OpencodeRuntimeAdapter { private clientPromise: Promise | null = null; - private closeServer: (() => void) | null = null; async ensureClient(): Promise { if (!this.clientPromise) { @@ -99,53 +97,19 @@ export class OpencodeRuntimeAdapter { } async dispose(): Promise { - this.closeServer?.(); - this.closeServer = null; this.clientPromise = null; } private async bootstrapClient(): Promise { - if (config.OPENCODE_BASE_URL) { - logger.info( - { baseUrl: config.OPENCODE_BASE_URL }, - "connecting to external opencode server", - ); - return createOpencodeClient({ - baseUrl: config.OPENCODE_BASE_URL, - }); - } - - // embedded 模式下,把服务内工具桥地址注入到 opencode 进程环境里, - // 这样 .opencode/tools 下的自定义工具可以回调本服务。 - process.env.TJWATER_AGENT_INTERNAL_BASE_URL = `http://127.0.0.1:${config.PORT}`; - process.env.TJWATER_AGENT_INTERNAL_TOKEN = - config.AGENT_INTERNAL_TOKEN ?? - process.env.TJWATER_AGENT_INTERNAL_TOKEN ?? - ""; - logger.info( { - hostname: config.OPENCODE_HOSTNAME, - port: config.OPENCODE_PORT, - model: config.OPENCODE_MODEL, + baseUrl: config.OPENCODE_BASE_URL, }, - "starting embedded opencode server", + "connecting to opencode server", ); - - const runtime = await createOpencode({ - hostname: config.OPENCODE_HOSTNAME, - port: config.OPENCODE_PORT, - timeout: config.OPENCODE_TIMEOUT_MS, - config: { - model: config.OPENCODE_MODEL, - }, + return createOpencodeClient({ + baseUrl: config.OPENCODE_BASE_URL, }); - - this.closeServer = () => { - runtime.server.close(); - }; - - return runtime.client; } } diff --git a/src/server.ts b/src/server.ts index 7ee9166..cfa2fad 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,4 +1,3 @@ -import { randomUUID } from "node:crypto"; import cors from "cors"; import express from "express"; @@ -28,10 +27,7 @@ const learningOrchestrator = new LearningOrchestrator( ); const resultReferenceStore = new ResultReferenceStore(); const dynamicHttpExecutor = new DynamicHttpExecutor(resultReferenceStore); -const internalToken = config.AGENT_INTERNAL_TOKEN ?? randomUUID(); - -// 这个 token 只用于仍需服务端上下文的工具桥(dynamic_http_call / fetch_result_ref)。 -process.env.TJWATER_AGENT_INTERNAL_TOKEN = internalToken; +const internalToken = config.AGENT_INTERNAL_TOKEN; app.use(cors()); app.use(express.json({ limit: "1mb" })); @@ -205,7 +201,6 @@ const shutdown = async () => { logger.info("shutting down TJWaterAgent"); server.close(); resultReferenceStore.stopCleanupLoop(); - // 同步关闭 embedded opencode server,避免本服务退出后留下孤儿进程。 await opencodeRuntime.dispose(); };