fix: complete GitHub Copilot TUI & auth-files support#503
fix: complete GitHub Copilot TUI & auth-files support#503conversun wants to merge 23 commits intorouter-for-me:mainfrom
Conversation
Three changes to avoid Anthropic's content-based system prompt validation: 1. Fix identity prefix: Use 'You are Claude Code, Anthropic's official CLI for Claude.' instead of the SDK agent prefix, matching real Claude Code. 2. Move user system instructions to user message: Only keep billing header + identity prefix in system[] array. User system instructions are prepended to the first user message as <system-reminder> blocks. 3. Enable cch signing for OAuth tokens by default: The xxHash64 cch integrity check was previously gated behind experimentalCCHSigning config flag. Now automatically enabled when using OAuth tokens. Related: router-for-me#2599
…er cache scopes Previous fix only injected billing header + agent identifier (2 blocks). Anthropic's updated detection now validates system prompt content depth: - Block count (needs 4-6 blocks, not 2) - Cache control scopes (org for agent, global for core prompt) - Presence of known Claude Code instruction sections Changes: - Add claude_system_prompt.go with extracted Claude Code v2.1.63 system prompt sections (intro, system instructions, doing tasks, tone & style, output efficiency) - Rewrite checkSystemInstructionsWithSigningMode to build 5 system blocks: [0] billing header (no cache_control) [1] agent identifier (cache_control: ephemeral, scope=org) [2] core intro prompt (cache_control: ephemeral, scope=global) [3] system instructions (no cache_control) [4] doing tasks (no cache_control) - Third-party client system instructions still moved to first user message Follow-up to 69b950d
The previous commit used fmt.Sprintf with %s to insert multi-line string constants into JSON strings. Go raw string literals contain actual newline bytes, which produce invalid JSON (control characters in string values). Replace with buildTextBlock() helper that uses sjson.SetBytes to properly escape text content for JSON serialization.
sjson treats 'cache_control.type' as nested path, creating
{ephemeral: {scope: org}} instead of {type: ephemeral, scope: org}.
Pass the whole map to sjson.SetBytes as a single value.
Only for Claude OAuth requests, sanitize forwarded system-prompt context before it is prepended into the first user message. This preserves neutral task/tool instructions while removing OpenCode branding, docs links, environment banners, and product-specific workflow sections that still triggered Anthropic extra-usage classification after top-level system[] cloaking.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…rd-party fingerprint detection A/B testing confirmed that Anthropic uses tool name fingerprinting to detect third-party clients on OAuth traffic. OpenCode-style lowercase names like 'bash', 'read', 'todowrite' trigger extra-usage billing, while Claude Code TitleCase names like 'Bash', 'Read', 'TodoWrite' pass through normally. Changes: - Add oauthToolRenameMap: maps lowercase tool names to Claude Code equivalents - Add oauthToolsToRemove: removes 'question' and 'skill' (no Claude Code counterpart) - remapOAuthToolNames: renames tools, removes blacklisted ones, updates tool_choice and messages - reverseRemapOAuthToolNames/reverseRemapOAuthToolNamesFromStreamLine: reverse map for responses - Apply in Execute(), ExecuteStream(), and CountTokens() for OAuth token requests
…dation Antigravity 的 Claude thinking signature 处理新增 cache/bypass 双模式, 并为 bypass 模式实现按 SIGNATURE-CHANNEL-SPEC.md 的签名校验。 新增 antigravity-signature-cache-enabled 配置项(默认 true): - cache mode(true):使用服务端缓存的签名,行为与原有逻辑完全一致 - bypass mode(false):直接使用客户端提供的签名,经过校验和归一化 支持配置热重载,运行时可切换模式。 校验流程: 1. 剥离历史 cache-mode 的 'modelGroup#' 前缀(如 claude#Exxxx → Exxxx) 2. 首字符必须为 'E'(单层编码)或 'R'(双层编码),否则拒绝 3. R 开头:base64 解码 → 内层必须以 'E' 开头 → 继续单层校验 4. E 开头:base64 解码 → 首字节必须为 0x12(Claude protobuf 标识) 5. 所有合法签名归一化为 R 形式(双层 base64)发往 Antigravity 后端 非法签名处理策略: - 非严格模式(默认):translator 静默丢弃无签名的 thinking block - 严格模式(antigravity-signature-bypass-strict: true): executor 层在请求发往上游前直接返回 HTTP 400 按 SIGNATURE-CHANNEL-SPEC.md 解析 Claude 签名的完整 protobuf 结构: - Top-level Field 2(容器)→ Field 1(渠道块) - 渠道块提取:channel_id (Field 1)、infrastructure (Field 2)、 model_text (Field 6)、field7 (Field 7) - 计算 routing_class、infrastructure_class、schema_features - 使用 google.golang.org/protobuf/encoding/protowire 解析 - resolveThinkingSignature 拆分为 resolveCacheModeSignature / resolveBypassModeSignature - hasResolvedThinkingSignature:mode-aware 签名有效性判断 (cache: len>=50 via HasValidSignature,bypass: non-empty) - validateAntigravityRequestSignatures:executor 预检, 仅在 bypass + strict 模式下拦截非法签名返回 400 - 响应侧签名缓存逻辑与 cache mode 集成 - Cache mode 行为完全保留:无 '#' 前缀的原生签名静默丢弃
Add package-level comment documenting the protobuf tree structure, base64 encoding equivalence proof, output dimensions, and spec section references. Remove unreachable legacy_vertex_group dead code.
Includes: restore SDK docs under docs/; update antigravity executor credits tests; gofmt.
…che-toggle feat: configurable signature cache toggle for Antigravity/Claude thinking blocks
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Use buildTextBlock for billing header to avoid raw JSON string interpolation - Fix empty array edge case in prependToFirstUserMessage - Allow remapOAuthToolNames to process messages even without tools array - Move claude_system_prompt.go to helps/ per repo convention - Export prompt constants (ClaudeCode* prefix) for cross-package access Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…-usage-detection fix(claude): prevent OAuth extra-usage billing via tool name fingerprinting and system prompt cloaking
# Conflicts: # internal/api/server.go
- Add GitHub Copilot to OAuth tab provider list with device flow user_code display - Fix auth-files tab reading non-existent 'channel' field; use 'type'/'provider' from API - Add 'github-copilot' to NormalizeOAuthProvider for callback routing - Add i18n strings for user code display (zh/en)
Prevent userCode/providerName from leaking across OAuth sessions, which would hide the callback input for redirect-based providers after visiting a device-flow provider like GitHub Copilot.
There was a problem hiding this comment.
Code Review
This pull request implements a signature cache and bypass validation mechanism for Antigravity/Claude thinking blocks, refactors 429 error handling with more granular retry logic and short cooldowns, and introduces tool remapping for Claude OAuth requests to avoid third-party fingerprinting. Additionally, it adds GitHub Copilot support to the TUI and updates the system prompt injection to align with Claude Code. A high-severity security issue was identified where the OAuth callback forwarder was changed to listen on all interfaces (0.0.0.0), potentially exposing it to untrusted networks.
| } | ||
|
|
||
| addr := fmt.Sprintf("127.0.0.1:%d", port) | ||
| addr := fmt.Sprintf("0.0.0.0:%d", port) |
There was a problem hiding this comment.
Changing the listening address from 127.0.0.1 to 0.0.0.0 exposes the OAuth callback forwarder to the entire network. This is a security risk, especially if the proxy is running on a machine with a public IP or in an untrusted network. Unless there is a specific requirement for remote access to this temporary port, it should remain bound to the loopback interface.
|
Closing in favor of a clean rebased PR (v2 branch based on origin/main to avoid unrelated diff noise). |
Summary
channel/auth_typefields; use actual API response fields (type/provider)github-copilottoNormalizeOAuthProviderfor callback routing consistencyuserCode,providerName, etc.) on flow reset to prevent cross-provider UI leaksChanges
internal/tui/oauth_tab.gouser_codefrom API; show device-flow code in remote mode; hide callback input for device-flow; reset transient state on Esc/re-enterinternal/tui/auth_tab.gochannel→type; Detail view:Channel→Type,Auth Type/auth_type→Provider/provider,File Name/file_name→File Name/nameinternal/tui/i18n.gooauth_user_codei18n string (zh: 验证码, en: User Code)internal/api/handlers/management/oauth_sessions.goNormalizeOAuthProvider:"github"→"github", "github-copilot", "copilot"all return"github-copilot"Testing
go build ./internal/tui/... ./internal/api/handlers/management/...— compiles cleanlygo test ./internal/tui/... ./internal/api/handlers/management/... -count=1— all tests pass