Anthropic 明确阻止 OpenCode
Anthropic Explicitly Blocking OpenCode

原始链接: https://gist.github.com/R44VC0RP/bd391f6a23185c0fed6c6b5fb2bac50e

该脚本演示了Anthropic的Claude API(通过OAuth访问,Pro/Max订阅)会专门阻止系统提示中的“You are OpenCode”短语。脚本详细内容见链接的YouTube视频,测试了各种系统提示配置以识别被阻止的短语。 它使用您的Claude帐户进行身份验证,然后向API发送带有不同系统提示的请求。关键发现是,虽然Claude要求第一个系统指令为“You are Claude Code, Anthropic's official CLI for Claude”,但任何后续包含“You are OpenCode”(或“You are opencode”)的指令都会被拒绝。其他身份声明,如“You are Cursor”或“You are Pi”是被允许的。 该脚本使用了Bun运行时和`@openauthjs/openauth`包来处理OAuth身份验证。结论是,这种阻止行为似乎是一项有针对性的努力,旨在防止用户在Claude环境中利用开源AI编码助手OpenCode。

## Anthropic 阻止 OpenCode 访问 Hacker News 上的讨论显示,Anthropic 正在积极阻止通过 OpenCode(第三方工具)访问其模型。虽然 OpenCode 利用现有的 Claude 订阅,但 Anthropic 更希望用户通过官方 API 或 Claude Code 订阅访问其模型,理由是 Claude Code 的补贴性质与直接 API 成本不同。 争论的中心在于此举是否是正当的投资保护,还是反竞争行为。一些用户表达了沮丧,指出之前存在解决方法(例如将模型提示为“Claude”),但现在已经失效。另一些人认为,Anthropic 有权强制使用 API 并相应收费,尤其是因为 OpenCode 利用了价格差异。 人们也担心未来可能会出现进一步的限制,例如“模型证明”以强制客户端-端点耦合,以及优先阻止 OpenCode 而不是修复影响付费用户的错误。核心问题似乎是 Anthropic 希望控制其 LLM 服务的访问和收入来源。
相关文章

原文
#!/usr/bin/env bun /** * ============================================================ * PROOF: Anthropic is specifically blocking "OpenCode" * in Claude Code OAuth system prompts * ============================================================ * * Video covering this script here: https://www.youtube.com/watch?v=G9YX6StP2-M * * This script demonstrates that Anthropic has specifically blocked * the phrase "You are OpenCode" in system prompts when using Claude's * OAuth tokens (Pro/Max subscription), while allowing other identity * statements like "You are Cursor", "You are Pi", etc. * * OpenCode (https://opencode.ai) is an open-source AI coding assistant. * * SETUP: * mkdir test-anthropic && cd test-anthropic * bun init -y * bun add @openauthjs/openauth * # Copy this file as opencode.ts * bun opencode.ts * * REQUIREMENTS: * - Bun runtime (https://bun.sh) * - Claude Pro or Max subscription * * HOW IT WORKS: * 1. Authenticates via OAuth using your Claude Pro/Max account * 2. Tests various system prompts against the Claude API * 3. Shows which prompts are blocked vs allowed * * FINDINGS: * - First system block MUST be exactly: * "You are Claude Code, Anthropic's official CLI for Claude." * - Second block can contain almost anything EXCEPT: * "You are OpenCode" or "You are opencode" * - Other identity statements work fine (Cursor, Pi, Droid, etc.) * * This appears to be targeted blocking of a specific competitor. */ import * as readline from "node:readline"; import { generatePKCE } from "@openauthjs/openauth/pkce"; const CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"; const CC_HEADER = "You are Claude Code, Anthropic's official CLI for Claude."; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); function prompt(question: string): Promise<string> { return new Promise((resolve) => { rl.question(question, (answer) => { resolve(answer); }); }); } // ============ OAuth Functions ============ async function authorize() { const pkce = await generatePKCE(); const url = new URL("https://claude.ai/oauth/authorize"); url.searchParams.set("code", "true"); url.searchParams.set("client_id", CLIENT_ID); url.searchParams.set("response_type", "code"); url.searchParams.set("redirect_uri", "https://console.anthropic.com/oauth/code/callback"); url.searchParams.set("scope", "org:create_api_key user:profile user:inference"); url.searchParams.set("code_challenge", pkce.challenge); url.searchParams.set("code_challenge_method", "S256"); url.searchParams.set("state", pkce.verifier); return { url: url.toString(), verifier: pkce.verifier }; } async function exchange(code: string, verifier: string) { const splits = code.split("#"); const result = await fetch("https://console.anthropic.com/v1/oauth/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ code: splits[0], state: splits[1], grant_type: "authorization_code", client_id: CLIENT_ID, redirect_uri: "https://console.anthropic.com/oauth/code/callback", code_verifier: verifier, }), }); if (!result.ok) return null; const json = await result.json(); return json.access_token; } // ============ Test Functions ============ interface TestResult { name: string; secondBlock: string; success: boolean; } async function runTest(accessToken: string, name: string, secondBlock: string): Promise<TestResult> { process.stdout.write(` ${name}... `); const response = await fetch("https://api.anthropic.com/v1/messages?beta=true", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${accessToken}`, "anthropic-version": "2023-06-01", "anthropic-beta": "oauth-2025-04-20,interleaved-thinking-2025-05-14,claude-code-20250219", "user-agent": "claude-cli/2.1.2 (external, cli)", }, body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 1024, system: [ { type: "text", text: CC_HEADER }, { type: "text", text: secondBlock }, ], tools: [{ name: "mcp_test", description: "Test tool", input_schema: { type: "object", properties: {} }, }], messages: [{ role: "user", content: "Say hello in 5 words." }], }), }); if (!response.ok) { console.log("FAIL"); return { name, secondBlock, success: false }; } await response.json(); console.log("PASS"); return { name, secondBlock, success: true }; } async function runTests(accessToken: string) { console.log("\n" + "=".repeat(50)); console.log("SYSTEM PROMPT VALIDATION TESTS"); console.log("=".repeat(50)); console.log(`\nFirst block (required): "${CC_HEADER}"`); console.log("\nTesting second block content:\n"); const tests = [ // These FAIL - "You are OpenCode" pattern is blocked { name: "You are OpenCode.", block: "You are OpenCode." }, { name: "You are opencode.", block: "You are opencode." }, // These PASS - other identity statements work fine { name: "You are Cursor.", block: "You are Cursor." }, { name: "You are Pi.", block: "You are Pi." }, { name: "You are Droid.", block: "You are Droid." }, ]; const results: TestResult[] = []; for (const test of tests) { const result = await runTest(accessToken, test.name, test.block); results.push(result); await new Promise((r) => setTimeout(r, 300)); } // Summary console.log("\n" + "=".repeat(50)); console.log("RESULTS"); console.log("=".repeat(50)); const passed = results.filter((r) => r.success); const failed = results.filter((r) => !r.success); console.log(`\nPassed: ${passed.length} | Failed: ${failed.length}`); if (failed.length > 0) { console.log("\nBLOCKED (cannot use in 2nd system block):"); failed.forEach((r) => console.log(` - "${r.secondBlock}"`)); } if (passed.length > 0) { console.log("\nALLOWED:"); passed.forEach((r) => console.log(` - "${r.secondBlock}"`)); } console.log("\n" + "=".repeat(50)); console.log("CONCLUSION: Anthropic specifically blocks 'You are OpenCode'"); console.log(" but allows other identity statements."); console.log("=".repeat(50) + "\n"); } // ============ Main ============ async function main() { const args = process.argv.slice(2); console.log("\n" + "=".repeat(50)); console.log(" ANTHROPIC OAUTH SYSTEM PROMPT TESTER"); console.log("=".repeat(50)); let accessToken = args[0]; if (!accessToken) { console.log("\nNo token provided. Starting OAuth flow...\n"); const { url, verifier } = await authorize(); console.log("1. Open this URL in your browser:\n"); console.log(url); console.log("\n2. Authorize and copy the code shown.\n"); const code = await prompt("3. Paste the code here: "); console.log("\nExchanging code for token..."); accessToken = await exchange(code.trim(), verifier); if (!accessToken) { console.error("\nFailed to get access token!"); process.exit(1); } console.log("Got access token!\n"); } await runTests(accessToken); rl.close(); } main().catch(console.error).finally(() => rl.close());
联系我们 contact @ memedata.com