Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,4 @@ decompiled
decompiled-ui
# opencode project-level config (auto-generated tool overrides)
.opencode/tools/
.opencode/opencode.json
71 changes: 6 additions & 65 deletions .opencode/opencode.example.json
Original file line number Diff line number Diff line change
@@ -1,74 +1,15 @@
{
"$schema": "https://opencode.ai/config.json",
"model": "mimo/mimo-v2.5-pro",
"model": "cloudbase/glm-5",
"provider": {
"mimo": {
"npm": "@ai-sdk/openai-compatible",
"name": "MiMo",
"cloudbase": {
"options": {
"baseURL": "{env:OPENAI_API_ENDPOINT}",
"apiKey": "{env:MIMO_API_KEY}"
"baseURL": "https://env-xxxxxxxx.api.tcloudbasegateway.com/v1/ai/cloudbase",
"apiKey": "{env:CLOUDBASE_API_KEY}"
},
"models": {
"mimo-v2.5-pro": {
"name": "MiMo V2.5 Pro",
"tool_call": true,
"limit": {
"context": 1048576,
"output": 131072
},
"modalities": {
"input": ["text", "image"],
"output": ["text"]
}
},
"mimo-v2.5": {
"name": "MiMo V2.5",
"tool_call": true,
"limit": {
"context": 1048576,
"output": 131072
},
"modalities": {
"input": ["text"],
"output": ["text"]
}
},
"mimo-v2.5-tts": {
"name": "MiMo V2.5 TTS",
"tool_call": false,
"limit": {
"context": 8192,
"output": 4096
},
"modalities": {
"input": ["text"],
"output": ["audio"]
}
},
"mimo-v2.5-tts-voiceclone": {
"name": "MiMo V2.5 TTS VoiceClone",
"tool_call": false,
"limit": {
"context": 8192,
"output": 4096
},
"modalities": {
"input": ["text"],
"output": ["audio"]
}
},
"mimo-v2.5-tts-voicedesign": {
"name": "MiMo V2.5 TTS VoiceDesign",
"tool_call": false,
"limit": {
"context": 8192,
"output": 4096
},
"modalities": {
"input": ["text"],
"output": ["audio"]
}
"glm-5": {
"name": "glm-5"
}
}
}
Expand Down
76 changes: 0 additions & 76 deletions .opencode/opencode.json

This file was deleted.

4 changes: 3 additions & 1 deletion .opencode/tools/AskUserQuestion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ export default {
.join('; ')

return {
output: `User answered: ${formatted}. You can continue with these answers in mind.`,
output: formatted,
hint: `You can continue with these answers in mind.`,
// output: `User answered: ${formatted}. You can continue with these answers in mind.`,
metadata: {
answers: data.answers,
},
Expand Down
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ COPY --from=build /app/packages/shared/dist ./packages/shared/dist
# skill-loader-override reads CODEBUDDY_BUNDLED_SKILLS_DIR = packages/server/skills
COPY --from=build /app/.agents/skills/cloudbase ./packages/server/skills/cloudbase

# Copy opencode tool overrides (checked-in, not built into dist).
# opencode-installer.ts:getOpencodeConfigDir() → resolveProjectRoot()/.opencode/,
# and resolveProjectRoot() returns /app (ancestor containing packages/server/), so
# tools must live at /app/.opencode/tools/*.ts in the runtime image.
COPY --from=build /app/.opencode ./.opencode

# Point shared exports to built dist (source .ts files not available at runtime)
RUN sed -i 's|./src/index.ts|./dist/index.js|g' packages/shared/package.json

Expand Down
93 changes: 93 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,96 @@ TCR_REPO_NAME=sandbox
TCR_TAG=latest
```

## OpenCode 模型配置

项目内置 OpenCode ACP runtime。如果前端需要使用 OpenCode agent,需要先配置至少一个
provider(model 提供商)。

### 前置:安装 opencode CLI

```bash
npm i -g opencode-ai
# 验证
opencode --version
```

### 一键配置

```bash
pnpm opencode:setup
```

该命令会:

1. 从 [models.dev](https://models.dev)(opencode 官方 provider catalog)拉取 118+ provider 列表
2. 检测 `.opencode/opencode.json` 已有 provider 的凭证状态,提示补齐缺失的 env
3. 引导选择要新增的 provider(deepseek / moonshot / openai / anthropic / zhipuai / …)
4. 提示输入对应的 API Key(如 `DEEPSEEK_API_KEY`)
5. 选择默认模型
6. 从 catalog 取完整 provider 配置(npm / baseURL / models 等)写入 `.opencode/opencode.json`
7. 把 API Key 写入 `packages/server/.env`

### 生成结果示例

```jsonc
// .opencode/opencode.json(自动生成,字段从 models.dev 获取)
{
"$schema": "https://opencode.ai/config.json",
"model": "deepseek/deepseek-chat",
"provider": {
"deepseek": {
"npm": "@ai-sdk/openai-compatible",
"name": "DeepSeek",
"options": {
"baseURL": "https://api.deepseek.com",
"apiKey": "{env:DEEPSEEK_API_KEY}"
},
"models": {
"deepseek-chat": {
"name": "DeepSeek Chat",
"tool_call": true,
"limit": { "context": 1000000, "output": 384000 },
"modalities": { "input": ["text"], "output": ["text"] }
}
// ... 其他模型
}
}
}
}
```

```bash
# packages/server/.env 会追加 API Key
DEEPSEEK_API_KEY=sk-***
```

> **为什么写完整字段而不是空对象?** opencode 子进程启动时也需要这些配置。如果只写 `{}`,
> 子进程要自己从 models.dev 拉 catalog 才知道 npm / baseURL / models 等信息,一旦拉取失败
> (网络/超时)就无法正常工作。写入完整字段让配置自包含,不依赖运行时网络请求。

### 高级:自定义 provider / 覆盖字段

如果需要:

- 非 catalog 内置的 provider(如内网 LLM 网关、本地 Ollama)
- 覆盖 catalog 默认的 `baseURL` / `headers`(如走国内镜像)
- 用 `whitelist` / `blacklist` 限制要展示的模型
- 配置 variants(如 Anthropic 的 thinking 预算)

请参考 `.opencode/opencode.example.json` 和 [OpenCode 官方 providers 文档](https://opencode.ai/docs/zh-cn/providers/)
直接手动编辑 `.opencode/opencode.json`。

> 提示:`opencode.json` 顶部的 `$schema` 字段让 VS Code / Cursor 等编辑器支持字段自动补全
> 和悬停文档,编辑时按 Ctrl+Space 可查看所有可选字段。

### 重新配置 / 新增 provider

`pnpm opencode:setup` 幂等,可多次运行:

- **已存在的 provider** 不会被覆盖(避免丢失手动调整)
- **已设置的 env key** 不会被重复询问
- **缺失 env 的 provider** 会在启动时提示补齐

## 常用命令

```bash
Expand Down Expand Up @@ -248,6 +338,9 @@ pnpm db:studio # 打开 Drizzle Studio

# TCR
pnpm setup:tcr # 配置容器镜像服务

# OpenCode
pnpm opencode:setup # 配置 OpenCode provider 和模型
```

## 技术栈
Expand Down
53 changes: 52 additions & 1 deletion docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,56 @@ pnpm setup:tcr
pnpm rebuild better-sqlite3
```

## OpenCode Agent 配置(可选)

如果需要在前端使用 OpenCode agent(基于 [opencode-ai](https://github.com/sst/opencode) 的 ACP runtime),需要额外配置 LLM provider。

### 前置:安装 opencode CLI

```bash
npm i -g opencode-ai
opencode --version # 验证安装
```

### 配置 provider

```bash
pnpm opencode:setup
```

脚本会自动完成以下操作:

1. 从 [models.dev](https://models.dev) 拉取 provider catalog(118+ 个 provider)
2. 检测 `.opencode/opencode.json` 中已有 provider 的凭证状态,提示补齐缺失的 env
3. 引导选择要新增的 provider 并输入 API Key
4. 从 catalog 取完整配置写入 `.opencode/opencode.json`(含 npm/baseURL/models 等)
5. 把 API Key 写入 `packages/server/.env`

配置完成后**必须重启 server**(Node.js 的 `--env-file` 只在启动时加载一次)。

### 涉及的文件

| 文件 | 作用 | 是否 gitignore |
|---|---|---|
| `.opencode/opencode.json` | provider + model 定义(opencode 子进程 + server 均读取) | 否(应提交) |
| `packages/server/.env` | API Key 等凭证 | 是 |

### 常见问题

| 问题 | 原因 | 解决 |
|---|---|---|
| 前端 OpenCode agent 模型列表为空 | `opencode.json` 未配置 provider 或对应 env 未设置 | 运行 `pnpm opencode:setup` |
| 前端有模型但选中后 agent 无输出 | opencode.json 中 provider 字段不完整 | 重跑 `pnpm opencode:setup`,或手动补齐 npm/baseURL/models |
| 出现不应该有的模型(如未配置的 OpenAI) | `.env` 中有通用 env 名(如 `OPENAI_API_KEY`)被 catalog 错误匹配 | 删除或注释 `.env` 中不需要的 key |
| 配置后前端没变化 | server 未重启 | 重启 `pnpm dev:server` |

### 更多文档

- [OpenCode 配置](https://opencode.ai/docs/zh-cn/config/)
- [OpenCode 模型](https://opencode.ai/docs/zh-cn/models/)
- [OpenCode Provider](https://opencode.ai/docs/zh-cn/providers/)
- [models.dev catalog](https://models.dev)

## 手动初始化的推荐顺序

如果不使用交互式脚本,建议按照以下顺序手动处理:
Expand All @@ -262,7 +312,8 @@ pnpm rebuild better-sqlite3
4. 配置 CodeBuddy 认证
5. 配置 TCR 镜像
6. 初始化数据库
7. 运行构建或启动命令验证环境
7. (可选)配置 OpenCode provider:`pnpm opencode:setup`
8. 运行构建或启动命令验证环境

## 延伸阅读

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"db:push": "drizzle-kit push",
"db:studio": "drizzle-kit studio",
"setup:tcr": "node scripts/setup-tcr.mjs",
"opencode:setup": "node scripts/opencode-setup.mjs",
"prepare": "husky"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"scripts": {
"dev": "tsup src/sandbox/tool-override.ts --format cjs --outDir dist/sandbox --no-splitting --silent && tsup src/util/skill-loader-override.ts --format cjs --outDir dist/util --no-splitting --silent && DOTENVX_PATH=.env tsx watch --env-file=.env src/index.ts",
"build": "tsup src/sandbox/tool-override.ts --format cjs --outDir dist/sandbox --no-splitting && tsup src/util/skill-loader-override.ts --format cjs --outDir dist/util --no-splitting && tsup src/index.ts --format esm --target node22 && mkdir -p dist/agent/runtime/opencode-tool-templates && cp src/agent/runtime/opencode-tool-templates/*.ts dist/agent/runtime/opencode-tool-templates/",
"build": "tsup src/sandbox/tool-override.ts --format cjs --outDir dist/sandbox --no-splitting && tsup src/util/skill-loader-override.ts --format cjs --outDir dist/util --no-splitting && tsup src/index.ts --format esm --target node22",
"start": "node dist/index.js",
"test": "vitest run",
"test:watch": "vitest",
Expand Down
4 changes: 3 additions & 1 deletion packages/server/src/agent/coding-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ export function getCodingSystemPrompt(envId: string, publishableKey: string): st

<IMPORTANT>
IMPORTANT: 必须先读取 src/utils/cloudbase.ts,将其中的 ENV_ID 和 PUBLISHABLE_KEY 替换为当前环境的真实值。
IMPORTANT: 直接修改代码而非创建 .env 文件。
IMPORTANT: 直接修改代码而非创建 .env 文件。有关登录态判断时使用 auth-web-cloudbase skill 使用 supabase-like 的 api。
- ENV_ID:${envId}
- PUBLISHABLE_KEY:${publishableKey}
IMPORTANT: 注意数据库权限,默认 PUBLISHABLE_KEY 时是匿名身份,刚开始数据库最好公有读写,方便调试,后续完善。
IMPORTANT: 页面需要做好 error 处理,显示出具体的错误堆栈信息,而非直接 crash。需要 toast 等方式显示而非 console 打印。
</IMPORTANT>

<tech-stack>
Expand Down
Loading