Skip to content

[Bug]: Please help to disable SSL for custom LLM provider #229

Closed

Description

@skz-2026

Description

sorry I cannot pull request due my network limit:

总共做了两类修复:

  1. SSL/TLS 绕过
    根本原因:Node.js 22 的内置 fetch 用的是 undici,它忽略 NODE_TLS_REJECT_UNAUTHORIZED 环境变量。
    修复:新建 apps/desktop/src/main/tls-override.ts,用 undici 的 setGlobalDispatcher API 在请求前后动态替换全局 dispatcher:
    setGlobalDispatcher(new Agent({ connect: { rejectUnauthorized: false } }))

在 packages/shared/src/config.ts 的 provider schema 里加了 tlsRejectUnauthorized: boolean 字段,通过 connection-ipc.ts、index.ts 等地方传递,当 provider 配置了该字段时自动开启。

  1. developer role 被 Bedrock 拒绝
    根本原因:pi-ai 库发现模型 ID 匹配 /(^|/)claude-(?:opus|sonnet)-4/i,就会把 system prompt 用 developer role 发送(OpenAI Reasoning 模型规范)。但 Own LLM 后端是 AWS Bedrock,只接受 user/assistant。
    修复:在 ~/.config/open-codesign/config.toml 的 provider 配置里加:
    capabilities = {supportsReasoning = false}

这会让 packages/providers/src/wire-policy.ts 里的 inferReasoning() 返回 false,从而关闭 developer role,system prompt 改用标准 system 字段发送。

Steps to reproduce

cfg own LLM provider find 401 error

Expected behavior

no issue

Actual behavior

Error invoking remote method 'codesign:v1:generate': CodesignError: 400 service… --

open-codesign version

0.1.4

Platform

Windows

OS version

No response

Model provider (if relevant)

None

Error code

No response

Diagnostics bundle

No response

Logs

Activity

  1. added
    bugSomething isn't working
    triageAwaiting maintainer review
    on Apr 25, 2026
  2. github-actions commented on Apr 25, 2026

    @github-actions
    Contributor

    感谢反馈,也感谢你把定位思路写得这么具体。

    我按当前仓库代码核对了一下,这里可以确认两件事:

    1. 对于自定义 / imported provider,capabilities.supportsReasoning = false 这条路径当前代码里是存在的,而且会进入实际生成请求。
    2. 但我在当前代码树里没有找到 tlsRejectUnauthorized、setGlobalDispatcher()、rejectUnauthorized 这类 TLS 绕过实现;目前只能确认到 SSL 诊断文案,没找到对应的配置字段或运行时接线。

    Relevant code:

    • packages/shared/src/config.ts:102 — ProviderCapabilitiesSchema 里包含 supportsReasoning
    • apps/desktop/src/main/provider-settings.ts:246 — 解析 provider 的 capabilities / explicitCapabilities
    • apps/desktop/src/main/index.ts:872 — 生成时把 active.capabilities 和 active.explicitCapabilities 传到 provider 层
    • packages/providers/src/wire-policy.ts:75 — inferReasoning() 会尊重自定义 provider 的 supportsReasoning: false
    • packages/providers/src/index.test.ts:745 — 测试覆盖了自定义网关显式关闭 reasoning 的情况
    • packages/shared/src/diagnostics.ts:144 — SSL 错误会提示 “Disable TLS verify”,但当前树里我没有核实到对应功能实现

    按这份代码看,如果你当前的问题是 Bedrock / 自建 OpenAI 兼容网关不接受 reasoning / developer-role,那么 capabilities.supportsReasoning = false 确实是现有实现里已经接通的一条规避路径。TLS 关闭开关这部分,在当前仓库里我这里只能确认“提示存在”,功能实现未找到。

    Need more info:

    • 你当前自定义 provider 选的是 openai-chat 还是 openai-responses?
    • 脱敏后的 baseUrl 是什么?
    • 现在实际报错到底是 SSL / 证书错误,还是 400 / 401?你贴的描述里这几种都有。
    • 如果方便,请贴一下该 provider 的脱敏 capabilities 配置片段。

    补充一句,项目目前还是 pre-alpha,很多路线图里的能力还没完全落地;自定义 provider / 第三方网关兼容性这块还在持续补齐。


    open-codesign Bot

  3. skz-2026 commented on Apr 25, 2026

    @skz-2026
    Author

    Issue: Custom OpenAI-compatible providers fail with two compatibility errors

    Environment

    • Electron: 39.8.8
    • Node.js: 22.22.1
    • Provider: internal OpenAI-compatible endpoint proxied through AWS Bedrock
    • Model: anthropic::claude-4-6-sonnet (via openai-chat wire)

    Problem 1 — TLS certificate errors with internal/self-signed CA

    Symptom

    CodesignError: Connection error.
    fetch failed — certificate verify failed
    

    Root cause

    Node.js 22’s built-in fetch is implemented by undici. Unlike legacy node-fetch, undici ignores the NODE_TLS_REJECT_UNAUTHORIZED environment variable. There is no per-request way to bypass TLS verification without replacing the global undici dispatcher.

    Proposed fix

    1. Add tlsRejectUnauthorized?: boolean to ProviderEntrySchema in packages/shared/src/config.ts.
    2. Thread this field through:
      • provider-settings.ts → connection-ipc.ts and index.ts
    3. Add apps/desktop/src/main/tls-override.ts — a reference-counted helper that swaps the global undici dispatcher before each request and restores it after:
    import { Agent, getGlobalDispatcher, setGlobalDispatcher } from 'undici';
    
    let refCount = 0;
    let savedDispatcher = null;
    
    export function acquireTlsOverride() {
      if (refCount === 0) {
        savedDispatcher = getGlobalDispatcher();
        setGlobalDispatcher(new Agent({ connect: { rejectUnauthorized: false } }));
      }
      refCount++;
    }
    
    export function releaseTlsOverride() {
      if (--refCount === 0 && savedDispatcher) {
        setGlobalDispatcher(savedDispatcher);
        savedDispatcher = null;
      }
    }

    Config example

    [providers.my-internal-provider]
    tlsRejectUnauthorized = false

    Problem 2 — developer role rejected by non-OpenAI backends

    Symptom

    CodesignError: 400 service error: ValidationException:
    Value 'developer' at 'messages.1.member.role' failed to satisfy constraint:
    Member must satisfy enum value set: [user, assistant]
    

    Root cause

    pi-ai detects model IDs matching:

    • /((^|\/)claude-(?:opus|sonnet)-4)/i

    …and sets model.reasoning = true, which causes the OpenAI SDK to send system prompts as role: "developer" (OpenAI o-series reasoning convention). Backends that strictly follow OpenAI Chat Completions — including AWS Bedrock — reject this role.

    Proposed fix

    Expose a capabilities.supportsReasoning field in ProviderEntrySchema. When set to false, inferReasoning() in packages/providers/src/wire-policy.ts returns false regardless of model ID heuristics, suppressing the developer role.

    Config example

    [providers.my-internal-provider]
    capabilities = { supportsReasoning = false }

    Files changed

    • packages/shared/src/config.ts

      • Add tlsRejectUnauthorized and capabilities.supportsReasoning to schema
    • apps/desktop/src/main/tls-override.ts

      • New — reference-counted undici dispatcher swap
    • apps/desktop/src/main/provider-settings.ts

      • Thread tlsRejectUnauthorized through resolution
    • apps/desktop/src/main/connection-ipc.ts

      • Wrap test handlers with TLS override
    • apps/desktop/src/main/index.ts

      • Wrap generate handler with TLS override
    • apps/desktop/src/main/onboarding-ipc.ts

      • Support setting tlsRejectUnauthorized via UI

    If submitting a PR instead of an Issue, the above can be used directly as the PR description, and you can attach the git diff below it.


  4. added
    bot-rerunTemporary label to rerun automation
    and removed
    bot-rerunTemporary label to rerun automation
    on May 1, 2026
  5. github-actions commented on May 1, 2026

    @github-actions
    Contributor

    非常感谢您如此详尽的排查和修复方案,这非常有价值。

    针对您提到的两个问题,我核对了一下当前仓库代码的状态:

    1. Developer role 被 Bedrock 拒绝

    这个问题已经在 changeset fix-reasoning-flag-openai-compat.md 中针对类似场景(issue #183)做了修复。涉及的代码路径包括:

    • packages/providers/src/wire-policy.ts 中的 inferReasoning() 会尊重自定义 provider 的 supportsReasoning 字段。
    • packages/shared/src/config.ts 的 ProviderCapabilitiesSchema 已经包含了 supportsReasoning。
    • 当您在 provider 配置中设置 capabilities = { supportsReasoning = false } 时,pi-ai 会使用标准的 system 角色而非 developer,从而绕过 Bedrock 的校验。

    如果您当前的版本尚未包含该修复(该 changeset 还在 .changeset 目录中,可能尚未发布),您可以手动应用类似逻辑,或者等待下一个版本(预计是 0.1.5 或 0.2.0)。

    2. SSL/TLS 绕过(tlsRejectUnauthorized)

    我检查了代码树,目前没有找到您提到的 tlsRejectUnauthorized 配置项、setGlobalDispatcher 调用或相关的 TLS 绕过实现。packages/shared/src/diagnostics.ts 中虽然包含 SSL 错误的诊断文案(如 "Disable TLS verify"),但并未提供实际的绕过机制。

    您的方案——通过 undici 的 setGlobalDispatcher 在请求前后动态替换 dispatcher——是合理的。由于当前代码中所有 HTTP 请求都通过 pi-ai 发出,而 pi-ai 底层使用的是 Node.js 内置 fetch(即 undici),因此这个方案可以工作。但需要注意全局 dispatcher 的线程安全问题,您提供的引用计数模式是很好的实践。

    建议:

    • 对于 developer role 问题,请确认您使用的版本是否包含上述 changeset(查看 packages/providers/src/wire-policy.ts 中是否存在 supportsReasoning 的判断逻辑)。如果已包含,直接配置即可;如果未包含,可以等待下一个版本或手动 cherry-pick。
    • 对于 TLS 绕过问题,目前没有现成的实现,欢迎您提交 PR 实现该功能。您已经给出了非常清晰的代码结构和文件修改清单,直接包装成 PR 会很顺畅。

    再次感谢您如此细致的分析,即使无法提交 PR,这些信息对维护者也极有帮助。我们已将您的方案记录在 issue 中供后续参考。

    Relevant code:

    • packages/providers/src/wire-policy.ts — inferReasoning() 逻辑(处理 supportsReasoning)
    • packages/shared/src/config.ts — ProviderCapabilitiesSchema 定义
    • packages/shared/src/diagnostics.ts:144 — SSL 错误诊断文案
    • .changeset/fix-reasoning-flag-openai-compat.md — 类似的 developer 角色修复

    Open-CoDesign Bot

  6. hqhq1025 commented on May 23, 2026

    @hqhq1025
    Collaborator

    Update — splitting this into two threads so each can land independently.

    ✅ Part A: developer-role rejected by Bedrock — already solvable today

    This path is wired up in the current tree. For any custom / imported provider that doesn't accept the developer role (Bedrock, certain corp gateways), set the capability explicitly in ~/.config/open-codesign/config.toml:

    [providers.your-provider-id]
    # ...other fields...
    capabilities = { supportsReasoning = false }

    packages/providers/src/wire-policy.ts (inferReasoning()) honors this and falls back to the standard system role rather than developer. Tested at packages/providers/src/index.test.ts:745.

    🚧 Part B: TLS bypass via undici setGlobalDispatcher — not implemented

    Your proposed approach (ref-counted global dispatcher swap + tlsRejectUnauthorized field on provider schema) is the right shape — Node 22's built-in fetch is undici and does ignore NODE_TLS_REJECT_UNAUTHORIZED. I'm picking this up as a separate PR so it can be reviewed and shipped on its own; will link the PR here when it's open. Closing this issue now since Part A unblocks you immediately; the TLS work will continue on the dedicated PR.

    Thanks again for the very thorough write-up — it saved a lot of investigation time.


    Open-CoDesign Maintainer

  7. github-actions commented on May 23, 2026

    @github-actions
    Contributor

    Thanks for the detailed breakdown, @hqhq1025.

    Part A is indeed already wired – packages/providers/src/wire-policy.ts:75 respects supportsReasoning = false (test coverage at packages/providers/src/index.test.ts:745), so setting capabilities = { supportsReasoning = false } in the provider config will switch from developer to system role and unblock Bedrock users immediately.

    Part B (TLS bypass) is correctly noted as not implemented yet. The proposed ref-counted setGlobalDispatcher approach is sound and avoids global state issues. We'll track that in the dedicated PR as you mentioned.

    I'll leave the issue open per the plan; once the Part B PR is linked, a maintainer can close this. If the original reporter has any follow-up questions on Part A, feel free to ask.


    Open-CoDesign Bot

  8. added a commit that references this issue on May 23, 2026
    6cbb639
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtriageAwaiting maintainer review

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions