人工智能AI 应用桌面应用【免费下载链接】open-codesignOpen-source Claude Design alternative. One-click import your Claude Code / Codex API key. Prompt → prototype / slides / PDF. Multi-model (Claude, GPT, Gemini, Kimi, GLM, Ollama). BYOK, local-first, MIT.项目地址https://gitcode.com/gh_mirrors/op/open-codesign点击查看免费下载导读本文以 open-codesign 仓库中的 issue_triage_plan.md 为核心骨架完整还原一次真实的 GitHub Issue 排查与修复工作流如何收集近期 issue 动态、把症状映射到本地代码路径、以最小改动修复可复现的 Gemini 相关问题并完成定向验证。读完本文你将掌握一套可复用的「Issue 分流 → 症状定位 → 最小修复 测试 → 定向验证」方法论同时理解 open-codesign 的模型调用架构约束所有模型调用必须经由mariozechner/pi-ai与 pnpm Vitest Biome 严格 TypeScript 的工程规范。一、Triage 计划的目标与范围原文档将本次任务的Goal界定为三件事这也是任何开源项目 Issue 分流的标准目标集回顾近期 GitHub issue 活动筛选仍处于活跃状态的问题识别近期已关闭 issue 中仍然存在still-active的问题避免「关闭即遗忘」导致的回归或未修复彻底的情况对 Gemini 相关的 issue若能从代码库复现则实施修复。三个目标之间存在明确的优先级递进先收集情报哪些 issue 活跃、再甄别真伪哪些已关闭问题其实还在、最后才动手修复Gemini 问题是本次唯一被点名的修复对象。这种「先收集、后定位、再修复、终验证」的顺序避免了在信息不充分时贸然改代码的常见失误。从仓库现状看本次 triage 的关注点落在了 provider 兼容层——这是 open-codesign 这类「BYOK、多模型」工具最容易出问题的位置因为要同时对接 Claude、GPT、Gemini、Kimi、GLM、Ollama 等不同协议形态的提供商。二、四阶段工作流从 Issue 到修复的最小闭环原文档把整个流程拆成四个阶段并全部标记为完成complete。下面逐一还原每个阶段做了什么、对应的代码证据在哪里。阶段 1收集 GitHub issue 上下文Gather issue context from GitHub, focusing on recent comments and Gemini-related threads.第一阶段只做信息收集不做任何代码改动。重点是两类信息近期评论判断一个 issue 是否仍然活跃评论时间线是最直接的信号Gemini 相关线程本次 triage 唯一明确的修复目标。收集到的信息最终要被转换成可验证的代码级症状描述否则后续阶段无从下手。这也是 triage 与普通「看 issue」的本质区别每个症状都必须能对应到具体代码路径。阶段 2将症状映射到本地代码路径Map the issue symptoms to local code paths and reproduce or explain the bug.第二阶段的核心产出是症状 ↔ 代码路径的映射。本次 Gemini issue 的根因可以完整复现Google 的 OpenAI 兼容端点generativelanguage.googleapis.com/v1beta/openai/接受与 OpenAI Chat Completions 相同的请求结构但会拒绝携带models/前缀的模型 ID——而这个前缀恰恰是 Gemini 自己的/models列表接口返回的格式。该修复的实现位于 packages/providers/src/gemini-compat.ts文件头注释明确引用了 issue #175。核心逻辑只有两个函数export function isGeminiOpenAICompat(baseUrl: string | undefined): boolean { if (!baseUrl) return false; try { const url new URL(baseUrl); return ( url.hostname generativelanguage.googleapis.com /(^|\/)openai(\/|$)/.test(url.pathname) ); } catch { return false; } } export function normalizeGeminiModelId(modelId: string, baseUrl: string | undefined): string { if (!isGeminiOpenAICompat(baseUrl)) return modelId; return modelId.replace(/^models\//, ); }值得注意的设计细节isGeminiOpenAICompat用new URL(baseUrl)解析 hostname 与 pathname这是为了防御字符串包含攻击——例如https://attacker.com/?xgenerativelanguage.googleapis.com/v1这类把目标域名藏在查询参数里的伪造 URL 会被正确判负normalizeGeminiModelId只在判定为 Gemini OpenAI 兼容端点时才剥离models/前缀其他任何 baseUrl包括官方 OpenAI都原样返回模型 ID策略是「只在 wire线上请求层剥离Settings UI 保留带前缀的形式」这样 provider/模型的选择界面始终与/models接口的返回保持一致。这个「显示层保留、传输层归一化」的取舍正是本次修复的最小化原则不改 UI、不改配置存储只改发送请求那一刻的模型 ID。阶段 3实现最小对齐修复并补测试Implement the smallest aligned fix with tests if code changes are needed.修复的落点是一个关键设计不把归一化逻辑散落在各个调用点而是在 provider 层的统一入口处收敛。在 packages/providers/src/index.ts 的complete()函数中发送请求前只做了一行调用const effectiveModelId normalizeGeminiModelId(model.modelId, opts.baseUrl);complete()是所有非流式补全请求的唯一入口在这里归一化意味着所有走 provider 包的上层调用core 的 agent、desktop 的 generation IPC 等自动获得修复无需逐处改动。同时该函数还导出了isGeminiOpenAICompat和normalizeGeminiModelId两个工具供连接测试等其他路径复用见 packages/providers/src/index.ts。测试用例位于 packages/providers/src/gemini-compat.test.ts覆盖了几个关键边界Gemini OpenAI 兼容端点判定为真https://generativelanguage.googleapis.com/v1beta/openai/官方 OpenAI、空值、空字符串、非法 URL 判定为假前缀剥离的正向用例models/gemini-2-pro在 Gemini 兼容端点上被归一化为gemini-2-pro前缀保留的负向用例同样的models/foo在https://api.openai.com/v1下不被剥离models/gemini-2-pro在 baseUrl 为undefined即走 pi-ai 默认端点时也原样保留安全用例https://generativelanguage.googleapis.com.evil.com/v1、https://generativelanguage-googleapis-com.evil.com等伪装域名均判定为非 Gemini 端点。从测试结构可以推断本次修复遵循「先写/补测试锁定行为再验证实现」的 TDD 式路径且测试覆盖了判定函数的攻击面而不仅是正常路径。阶段 4定向验证与剩余风险评估Run targeted verification and summarize remaining risks.最后一个阶段只运行**定向targeted**测试而不是全量跑整个 monorepo。这既符合「改动最小、验证聚焦」的约束也避免了无关包exporters、ui、desktop 渲染层的测试噪声干扰判断。验证的重点就是上文gemini-compat.test.ts所在的 provider 包。三、项目约束为什么模型调用必须经过 pi-ai原文档明确列出的第一约束是Model calls must go throughmariozechner/pi-ai; no direct provider SDK imports in app code.这条约束在源码中有三重证据packages/providers/package.json 的 dependencies 中唯一的外部模型库就是mariozechner/pi-ai^0.72.1packages/providers/src/index.ts 的文件头注释写着这是对 pi-ai 的能力缺口封装层应用代码必须经由本包禁止直接 import 任何 provider SDKcomplete()内部采用懒加载方式await import(mariozechner/pi-ai)避免在应用启动时加载整个 bundle。complete()的GenerateOptions接口packages/providers/src/index.ts展示了封装层补充的能力这些正是 pi-ai 原生的不足参数作用底层实现说明apiKey提供商 API 密钥发送前会trim()空值且未开allowKeyless时抛PROVIDER_AUTH_MISSINGpi-ai 客户端仍要求非空 keykeyless 网关场景用占位符open-codesign-keylessbaseUrl自定义端点DeepSeek、Ollama、LiteLLM、Azure 等当 pi-ai 注册表中查不到模型时用synthesizeWireModel合成 PiModel 走对应 adaptersignal取消信号透传AbortSignal支撑 desktop 端的生成取消maxTokens输出 token 硬上限缺省时 pi-ai 按上下文窗口约 1/3 估算命中上限返回CompletionLengthError且保留 usage、丢弃半截内容便于有界调用方重试而不低估成本reasoning推理级别开关Anthropic 映射 extended thinkingOpenAI/Gemini 映射 reasoning effortoff是 Open CoDesign 配置层独有调用 pi-ai 前会被剔除wirev3 wire 覆盖自定义端点路由到正确的 pi-ai adapter支持anthropic/openai-responses/openai-codex-responses/openai-chathttpHeaders追加 HTTP 头支持 Codex 风格静态网关鉴权合并时用户头优先级最高userImages多模态图片输入base64 mimeTypeallowKeyless允许无 key 的 OpenAI 兼容网关见上文 apiKey 说明封装层还处理了一个真实世界的坑OpenAI 兼容网关DashScope/Qwen、DeepSeek、GLM/BigModel、Moonshot 等会拒绝developer角色的 system promptHTTP 400而 pi-ai 在reasoning: true时会写入该角色。因此 index.ts 只在 baseUrl 命中^https://api.openai.com时才判定为官方 OpenAI并针对 DeepInfra 等网关输出显式的compat标记supportsDeveloperRole: false等见 index.ts。这些细节表明「统一走 pi-ai」不是偷懒的捷径而是把所有协议兼容性补丁收敛到单点维护这正是约束存在的意义。四、工程约束与工具链pnpm、Vitest、Biome、严格 TypeScript原文档的第二组约束是Usepnpm, Vitest, Biome, and strict TypeScript. Keep changes lean, local-first, and scoped.它们在仓库中均有对应依据pnpm仓库根 package.json 声明packageManager: pnpm10.33.4workspace 布局定义在 pnpm-workspace.yamlapps/*、packages/*、website根脚本test为pnpm test:scripts turbo run test构建与开发则交给 Turborepo 编排turbo.json 中test/typecheck依赖^build且不缓存产物Vitestprovider 包的测试脚本为vitest run --passWithNoTestspackages/providers/package.json测试文件与源码同目录共存*.test.tsBiomebiome.json 启用 linter 与 formatter其中apps/desktop/src/main/**、packages/core/src/**、packages/providers/src/**等目录强制noConsole: error而**/*.test.ts与 prompts 目录豁免根脚本提供lint/lint:fix/format严格 TypeScript所有 package 的 typecheck 均为tsc --noEmit如 packages/providers/package.json根脚本typecheck走turbo run typecheck。「lean、local-first、scoped」则约束改动本身的形状能改一行不写十行、数据与密钥留在本地BYOK、修复范围不越出问题所在包。这与阶段 3 的「最小对齐修复」是一体两面。五、踩坑记录两次可复用的排障经验原文档的 Errors Encountered 表格记录了两次真实的工具链故障与解决方式对任何在 monorepo 中做定向测试的开发者都直接可复用。错误 1Vitest 启动失败缺平台绑定现象处理Vitest 启动失败报rolldown/binding-darwin-arm64缺失不在node_modules中运行定向的 provider/core 测试验证问题然后重新安装依赖pnpm i再重跑定向测试rolldown/binding-*是 Rust 写的绑定二进制按平台分发darwin-arm64、linux-x64 等。出现该报错的典型场景是node_modules不完整——例如换机器、换架构后没有重新安装或锁文件更新后未同步安装。教训是遇到平台绑定类错误先重装依赖不要直接怀疑测试代码。错误 2定向 Vitest 命令匹配不到文件现象处理最初的定向 Vitest 命令匹配不到任何文件因为需要包相对路径改用 workspace 根路径 pnpm --filter执行pnpm --dir packages/... exec vitest run src/...重跑后测试正常执行并通过这揭示了 monorepo 中运行测试的一个关键细节路径基准是包目录而非 workspace 根目录。pnpm --dir packages/providers exec vitest run src/gemini-compat.test.ts这种写法把 Vitest 的工作目录切到包内src/...才能正确解析若在根目录直接写packages/providers/src/...反而可能因为 Vitest 配置的 root 设置匹配不到。原文档给出的模板pnpm --dir packages/... exec vitest run src/...可以直接照搬使用。六、可复用的 Issue Triage 方法论总结把这次 triage 的完整流程抽象成方法论可以得到五条通用准则收集先行修复殿后任何代码改动之前先穷尽 issue 评论时间线确认问题仍活跃、症状描述最新症状必须落到代码路径一个 issue 只有在能映射到具体函数如normalizeGeminiModelId时才算「可复现」否则应解释而不是猜测修复选择单点收敛Gemini 的models/前缀问题没有散落在各个调用点修而是在complete()这一统一入口归一化——单点修复天然覆盖所有上游调用方每个修复必须带边界测试既测正常路径也测攻击面伪造域名、非法 URL、undefined baseUrl测试本身就是「是否修对」的唯一裁判验证保持定向只跑受影响包pnpm --dir packages/providers exec vitest run src/...的定向测试用最小验证成本覆盖最小改动面最后再总结剩余风险。这套流程的价值在于可复现、可审计任何一个后来者都能从 triage 计划、源码注释如See issue #175、测试用例三处交叉还原当时的判断依据。对 open-codesign 这类多模型、多网关的本地优先工具而言provider 兼容层的 issue 会持续出现而这套「症状 → 代码路径 → 最小修复 → 定向验证」的闭环正是让这类问题被高效消化而不反复回潮的工程保障。相关参考文件Triage 计划原文.Codex/workspace/issue_triage_plan.mdGemini 兼容归一化实现与测试packages/providers/src/gemini-compat.ts、packages/providers/src/gemini-compat.test.tsprovider 统一入口pi-ai 封装层packages/providers/src/index.tsClaude Code 网关兼容层同属 provider 兼容补丁体系packages/providers/src/claude-code-compat.ts工程规范依据package.json、pnpm-workspace.yaml、biome.json、turbo.json赞分享人工智能AI 应用桌面应用【免费下载链接】open-codesignOpen-source Claude Design alternative. One-click import your Claude Code / Codex API key. Prompt → prototype / slides / PDF. Multi-model (Claude, GPT, Gemini, Kimi, GLM, Ollama). BYOK, local-first, MIT.项目地址https://gitcode.com/gh_mirrors/op/open-codesign点击查看免费下载相关推荐douyin-downloader 抖音去水印批量下载从单条链接到整页主页的完整流程douyin downloader 抖音去水印批量下载从单条链接到整页主页的完整流程 你盯着一条抖音视频链接想要无水印原片而逐条长按保存再裁切水印显然不够网页爬虫CLIIronClaw 仓库 Issue 分级实战用 Claude Code 命令构建可复用的 GitHub Issue Triage 流程IronClaw 仓库 Issue 分级实战用 Claude Code 命令构建可复用的 GitHub Issue Triage 流程 本指南以 IronCl人工智能AI 应用交互助手AI Agentdlt 仓库实战使用 implement-issue 技能端到端实现 GitHub Issue 修复dlt 仓库实战使用 implement issue 技能端到端实现 GitHub Issue 修复 导读 implement issue 是 dlt 仓库数据工程数据集成批处理上一篇gh_mirrors/caf/caffe2算子性能分析热点识别与优化下一篇uni-app 数字角标 uni-badge-view 组件完全指南从属性语义到源码实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考