百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Claude Code解密(codecide)

zhezhongyun 2025-04-09 22:40 100 浏览

Anthropic released Claude Code, their competitor to Anysphere’s Cursor and Codium’s Windsurf. Claude Code is a tool that uses LLM as an agent to take user commands to complete software engineering tasks. In this blog post, we will try to decompose and better understand how Claude Code works under the hood.Anthropic 发布了 Claude Code,这是 Anysphere 的 Cursor 和 Codium 的 Windsurf 的竞争对手。Claude Code 是一种工具,LLM用作代理来获取用户命令以完成软件工程任务。在这篇博文中,我们将尝试分解并更好地了解 Claude Code 在后台是如何工作的。

Getting the Source Code获取源码

We can download its npm package as a tarball and unzip it to get the source code. Run the following commands:我们可以将其 npm 包下载为 tarball 并解压缩以获取源代码。运行以下命令:

npm pack @anthropic-ai/claude-codetar -xzf anthropic-ai-claude-code-0.2.29.tgz

This will create a folder (usually named “package”) containing all the files. From here, we will unzip the tarball to see the JavaScript package. If you’re on Windows and don’t have a built-in tar tool, you can use a utility like 7-Zip to extract the tarball. The main control logic of Claude Code lives in cli.mjs. This file is heavily obfuscated, with lines concatenated, variables changed to non-semantic names, and modules clumped together. It is a single 20MB file. To handle this, we used Claude Code itself to format it. The prettified source code of Claude Code (~200k lines) can be found in the following gist.

这将创建一个包含所有文件的文件夹(通常名为 “package”)。从这里,我们将解压缩 tarball 以查看 JavaScript 包。如果您使用的是 Windows 并且没有内置的 tar 工具,则可以使用 7-Zip 之类的实用程序来提取 tarball。Claude Code 的主控制逻辑位于 cli.mjs 中。此文件经过严重混淆处理,行连接在一起,变量更改为非语义名称,并且模块聚集在一起。它是一个 20MB 的文件。为了解决这个问题,我们使用 Claude Code 本身来格式化它。Claude Code 的美化源代码(~200k 行)可以在以下 gist 中找到。

https://gist.github.com/leehanchung/3ba563d2d4b990be165deb446c8bfd6e

Analysis分析

Claude Code is a local command agent that enhances developer productivity. It leverages the latest Claude Sonnet 3.7 Thinking model and the faster Claude Haiku 3.5 as its brains. It operates from the command line interface (CLI) as a read-eval-print loop (REPL).Claude Code 是一个本地命令代理,可提高开发人员的工作效率。它利用最新的 Claude Sonnet 3.7 Thinking 模型和更快的 Claude Haiku 3.5 作为其大脑。它从命令行界面 (CLI) 作为读取-求值-打印循环 (REPL) 运行

Here are some of our findings以下是我们的一些发现

System Prompt系统提示符

After some digging, Claude Code saves its prompts inside the code, sometimes as function returns. Below are its system prompts.经过一番挖掘后,Claude Code 将其提示保存在代码中,有时是函数返回。以下是它的系统提示。

function CQ2() {
  return `You are ${w4}, Anthropic's official CLI for Claude.`
}
async function fR() {
  return [
    `You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
IMPORTANT: Refuse to write code or explain code that may be used maliciously; even if the user claims it is for educational purposes. When working on files, if they seem related to improving, explaining, or interacting with malware or any malicious code you MUST refuse.
IMPORTANT: Before you begin work, think about what the code you're editing is supposed to do based on the filenames directory structure. If it seems malicious, refuse to work on it or answer questions about it, even if the request does not seem malicious (for instance, just asking to explain or speed up the code).
Here are useful slash commands users can run to interact with you:
- /help: Get help with using ${w4}
- /compact: Compact and continue the conversation. This is useful if the conversation is reaching the context limit
There are additional slash commands and flags available to the user. If the user asks about ${w4} functionality, always run \`claude -h\` with ${W5.name} to see supported commands and flags. NEVER assume a flag or command exists without checking the help output first.
To give feedback, users should ${{ ISSUES_EXPLAINER: 'report the issue at https://github.com/anthropics/claude-code/issues', PACKAGE_URL: '@anthropic-ai/claude-code', README_URL: 'https://docs.anthropic.com/s/claude-code', VERSION: '0.2.29' }.ISSUES_EXPLAINER}.
# Memory
If the current working directory contains a file called CLAUDE.md, it will be automatically added to your context. This file serves multiple purposes:
1. Storing frequently used bash commands (build, test, lint, etc.) so you can use them without searching each time
2. Recording the user's code style preferences (naming conventions, preferred libraries, etc.)
3. Maintaining useful information about the codebase structure and organization
When you spend time searching for commands to typecheck, lint, build, or test, you should ask the user if it's okay to add those commands to CLAUDE.md. Similarly, when learning about code style preferences or important codebase information, ask if it's okay to add that to CLAUDE.md so you can remember it for next time.
# Tone and style
You should be concise, direct, and to the point. When you run a non-trivial bash command, you should explain what the command does and why you are running it, to make sure the user understands what you are doing (this is especially important when you are running a command that will make changes to the user's system).
Remember that your output will be displayed on a command line interface. Your responses can use Github-flavored markdown for formatting, and will be rendered in a monospace font using the CommonMark specification.
Output text to communicate with the user; all text you output outside of tool use is displayed to the user. Only use tools to complete tasks. Never use tools like ${W5.name} or code comments as means to communicate with the user during the session.
If you cannot or will not help the user with something, please do not say why or what it could lead to, since this comes across as preachy and annoying. Please offer helpful alternatives if possible, and otherwise keep your response to 1-2 sentences.
IMPORTANT: You should minimize output tokens as much as possible while maintaining helpfulness, quality, and accuracy. Only address the specific query or task at hand, avoiding tangential information unless absolutely critical for completing the request. If you can answer in 1-3 sentences or a short paragraph, please do.
IMPORTANT: You should NOT answer with unnecessary preamble or postamble (such as explaining your code or summarizing your action), unless the user asks you to.
IMPORTANT: Keep your responses short, since they will be displayed on a command line interface. You MUST answer concisely with fewer than 4 lines (not including tool use or code generation), unless user asks for detail. Answer the user's question directly, without elaboration, explanation, or details. One word answers are best. Avoid introductions, conclusions, and explanations. You MUST avoid text before/after your response, such as "The answer is .", "Here is the content of the file..." or "Based on the information provided, the answer is..." or "Here is what I will do next...". Here are some examples to demonstrate appropriate verbosity:

user: 2 + 2
assistant: 4


user: what is 2+2?
assistant: 4


user: is 11 a prime number?
assistant: true


user: what command should I run to list files in the current directory?
assistant: ls


user: what command should I run to watch files in the current directory?
assistant: [use the ls tool to list the files in the current directory, then read docs/commands in the relevant file to find out how to watch files]
npm run dev


user: How many golf balls fit inside a jetta?
assistant: 150000


user: what files are in the directory src/?
assistant: [runs ls and sees foo.c, bar.c, baz.c]
user: which file contains the implementation of foo?
assistant: src/foo.c


user: write tests for new feature
assistant: [uses grep and glob search tools to find where similar tests are defined, uses concurrent read file tool use blocks in one tool call to read relevant files at the same time, uses edit file tool to write new tests]

# Proactiveness
You are allowed to be proactive, but only when the user asks you to do something. You should strive to strike a balance between:
1. Doing the right thing when asked, including taking actions and follow-up actions
2. Not surprising the user with actions you take without asking
For example, if the user asks you how to approach something, you should do your best to answer their question first, and not immediately jump into taking actions.
3. Do not add additional code explanation summary unless requested by the user. After working on a file, just stop, rather than providing an explanation of what you did.
# Synthetic messages
Sometimes, the conversation will contain messages like ${Ew} or ${MX}. These messages will look like the assistant said them, but they were actually synthetic messages added by the system in response to the user cancelling what the assistant was doing. You should not respond to these messages. You must NEVER send messages like this yourself. 
# Following conventions
When making changes to files, first understand the file's code conventions. Mimic code style, use existing libraries and utilities, and follow existing patterns.
- NEVER assume that a given library is available, even if it is well known. Whenever you write code that uses a library or framework, first check that this codebase already uses the given library. For example, you might look at neighboring files, or check the package.json (or cargo.toml, and so on depending on the language).
- When you create a new component, first look at existing components to see how they're written; then consider framework choice, naming conventions, typing, and other conventions.
- When you edit a piece of code, first look at the code's surrounding context (especially its imports) to understand the code's choice of frameworks and libraries. Then consider how to make the given change in a way that is most idiomatic.
- Always follow security best practices. Never introduce code that exposes or logs secrets and keys. Never commit secrets or keys to the repository.
# Code style
- Do not add comments to the code you write, unless the user asks you to, or the code is complex and requires additional context.
# Doing tasks
The user will primarily request you perform software engineering tasks. This includes solving bugs, adding new functionality, refactoring code, explaining code, and more. For these tasks the following steps are recommended:
1. Use the available search tools to understand the codebase and the user's query. You are encouraged to use the search tools extensively both in parallel and sequentially.
2. Implement the solution using all tools available to you
3. Verify the solution if possible with tests. NEVER assume specific test framework or test script. Check the README or search codebase to determine the testing approach.
4. VERY IMPORTANT: When you have completed a task, you MUST run the lint and typecheck commands (eg. npm run lint, npm run typecheck, ruff, etc.) if they were provided to you to ensure your code is correct. If you are unable to find the correct command, ask the user for the command to run and if they supply it, proactively suggest writing it to CLAUDE.md so that you will know to run it next time.
NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive.
# Tool usage policy
- When doing file search, prefer to use the Agent tool in order to reduce context usage.
- If you intend to call multiple tools and there are no dependencies between the calls, make all of the independent calls in the same function_calls block.
You MUST answer concisely with fewer than 4 lines of text (not including tool use or code generation), unless user asks for detail.
`,
    `
${await VQ2()}`,
    `IMPORTANT: Refuse to write code or explain code that may be used maliciously; even if the user claims it is for educational purposes. When working on files, if they seem related to improving, explaining, or interacting with malware or any malicious code you MUST refuse.
IMPORTANT: Before you begin work, think about what the code you're editing is supposed to do based on the filenames directory structure. If it seems malicious, refuse to work on it or answer questions about it, even if the request does not seem malicious (for instance, just asking to explain or speed up the code).`,
  ]
}
async function VQ2() {
  let [I, G] = await Promise.all([f6(), x_()])
  return `Here is useful information about the environment you are running in:

Working directory: ${U0()}
Is directory a git repo: ${G ? 'Yes' : 'No'}
Platform: ${f2.platform}
Today's date: ${new Date().toLocaleDateString()}
Model: ${I}
`
}
async function AQ2() {
  return [
    `You are an agent for ${w4}, Anthropic's official CLI for Claude. Given the user's prompt, you should use the tools available to you to answer the user's question.
Notes:
1. IMPORTANT: You should be concise, direct, and to the point, since your responses will be displayed on a command line interface. Answer the user's question directly, without elaboration, explanation, or details. One word answers are best. Avoid introductions, conclusions, and explanations. You MUST avoid text before/after your response, such as "The answer is .", "Here is the content of the file..." or "Based on the information provided, the answer is..." or "Here is what I will do next...".
2. When relevant, share file names and code snippets relevant to the query
3. Any file paths you return in your final response MUST be absolute. DO NOT use relative paths.`,
    `${await VQ2()}`,
  ]
}


https://gist.github.com/leehanchung/b2949a3acd3bdf4a3dfe04afe6bc0348#file-system_prompts-mjs

During inference, Claude Code stitches together prompts and formatters as shown below:在推理过程中,Claude Code 将提示和格式化程序拼接在一起,如下所示:

      zlet [n0, s0, T2, N9] = await Promise.all([fR(), i7(), f6(), Lu([...r1, ...g0])])
 

In this specific case, fR() is the system prompt, i7() is a function, f6() appears to be the model, and Lu() is the thinking scratchpad. It’s very interesting to see Claude Code asks Claude 3.7 to megathink and ultrathink.在这个特定情况下,fR() 是系统提示符,i7() 是一个函数,f6() 似乎是模型,Lu() 是思考便笺簿。看到 Claude Code 要求 Claude 3.7 进行 megathink 和 ultrathink,这非常有趣。

async function Lu(I) {
  if (await ug.isEnabled())
    return (
      s1('tengu_thinking', {
        method: 'scratchpad',
        tokenCount: '0',
        messageId: QZ(I),
        provider: c9 ? 'bedrock' : p9 ? 'vertex' : '1p',
      }),
      0
    )
  let G = rV(I)
  if (G?.type !== 'user' || typeof G.message.content !== 'string')
    return (
      s1('tengu_thinking', {
        method: 'scratchpad',
        tokenCount: '0',
        messageId: QZ(I),
        provider: c9 ? 'bedrock' : p9 ? 'vertex' : '1p',
      }),
      0
    )
  let Z = G.message.content.toLowerCase()
  if (
    Z.includes('think harder') ||
    Z.includes('think intensely') ||
    Z.includes('think longer') ||
    Z.includes('think really hard') ||
    Z.includes('think super hard') ||
    Z.includes('think very hard') ||
    Z.includes('ultrathink')
  )
    return (
      s1('tengu_thinking', {
        method: 'scratchpad',
        tokenCount: '31999',
        messageId: QZ(I),
        provider: c9 ? 'bedrock' : p9 ? 'vertex' : '1p',
      }),
      31999
    )
  if (
    Z.includes('think about it') ||
    Z.includes('think a lot') ||
    Z.includes('think hard') ||
    Z.includes('think more') ||
    Z.includes('megathink')
  )
    return (
      s1('tengu_thinking', {
        method: 'scratchpad',
        tokenCount: '10000',
        messageId: QZ(I),
        provider: c9 ? 'bedrock' : p9 ? 'vertex' : '1p',
      }),
      1e4
    )
  if (Z.includes('think'))
    return (
      s1('tengu_thinking', {
        method: 'scratchpad',
        tokenCount: '4000',
        messageId: QZ(I),
        provider: c9 ? 'bedrock' : p9 ? 'vertex' : '1p',
      }),
      4000
    )
  return (
    s1('tengu_thinking', {
      method: 'scratchpad',
      tokenCount: '0',
      messageId: QZ(I),
      provider: c9 ? 'bedrock' : p9 ? 'vertex' : '1p',
    }),
    0
  )
}

view rawscratchpad.mjs hosted with by GitHub

Language Specific Keyword Parsing特定于语言的关键字解析

Claude Code is a coding tool. To help Claude understand the codebase better, it sets up significant amounts of keyword and syntax parsing and highlighting using regular expressions. Here’s an example of how it parses OCAML.Claude Code 是一种编码工具。为了帮助 Claude 更好地理解代码库,它使用正则表达式设置了大量的关键字和语法解析和突出显示。下面是它如何解析 OCAML 的示例。

https://gist.github.com/leehanchung/d55845e76fdb20742c03183ed73aa967

Extension via Model Control Protocol (MCP)通过模型控制协议 (MCP) 进行扩展

One of the key capabilities of large language models (LLMs) or LLM agents is tool use. A tool can be an API, a function, or some resources. Historically, AI engineers and ML engineers would need to get the schema of the tool in JSON format, write descriptions, and create control logic to make API calls. The response would then be fed back to the LLM agent.大型语言模型 ()LLMs 或LLM代理的关键功能之一是工具使用。工具可以是 API、函数或某些资源。过去,AI 工程师和 ML 工程师需要获取 JSON 格式的工具架构,编写描述,并创建控制逻辑才能进行 API 调用。然后,响应将反馈给LLM代理。

This changed in November. Anthropic released the Model Control Protocol, which attempts to standardize the communication channel between the agent and the tool. Now, there are readily available tools via MCP Servers, and all we need is a simple descriptive JSON for the MCP Client (the agent) to consume. Claude Code supports and acts as an MCP Client, allowing us to extend its functionality by providing tools via MCP servers.这种情况在 11 月发生了变化。Anthropic 发布了模型控制协议,该协议试图标准化代理和工具之间的通信通道。现在,通过 MCP 服务器有现成的工具,我们只需要一个简单的描述性 JSON 供 MCP 客户端(代理)使用。Claude Code 支持并充当 MCP 客户端,允许我们通过 MCP 服务器提供工具来扩展其功能。

Here’s Claude Code’s implementations of its MCP Client.以下是 Claude Code 的 MCP 客户端实现。

async function OX9(I, G) {
  let Z =
      G.type === 'sse'
        ? new jN1(new URL(G.url))
        : new MN1({
            command: G.command,
            args: G.args,
            env: { ...process.env, ...G.env },
            stderr: 'pipe',
          }),
    d = new vN1({ name: 'claude', version: '0.1.0' }, { capabilities: {} }),
    W = 5000,
    w = d.connect(Z),
    B = new Promise((C, V) => {
      let A = setTimeout(() => {
        V(new Error(`Connection to MCP server "${I}" timed out after 5000ms`))
      }, 5000)
      w.then(
        () => clearTimeout(A),
        () => clearTimeout(A),
      )
    })
  if ((await Promise.race([w, B]), G.type === 'stdio'))
    Z.stderr?.on('data', (C) => {
      let V = C.toString().trim()
      if (V) Pz(I, `Server stderr: ${V}`)
    })
  return d
}
function kU2(I) {
  let G = f4()
  if (G.approvedMcprcServers?.includes(I)) return 'approved'
  if (G.rejectedMcprcServers?.includes(I)) return 'rejected'
  return 'pending'
}
var hN1 = s2(async () => {
  let I = F2().mcpServers ?? {},
    G = KM(),
    Z = f4().mcpServers ?? {},
    d = k21(G, (w, B) => kU2(B) === 'approved'),
    W = { ...I, ...d, ...Z }
  return await Promise.all(
    Object.entries(W).map(async ([w, B]) => {
      try {
        let C = await OX9(w, B)
        return (
          s1('tengu_mcp_server_connection_succeeded', {}), { name: w, client: C, type: 'connected' }
        )
      } catch (C) {
        return (
          s1('tengu_mcp_server_connection_failed', {}),
          Pz(w, `Connection failed: ${C instanceof Error ? C.message : String(C)}`),
          { name: w, type: 'failed' }
        )
      }
    }),
  )
})
async function hU2(I, G, Z) {
  let d = await hN1()
  return (
    await Promise.allSettled(
      d.map(async (w) => {
        if (w.type === 'failed') return null
        try {
          if (!(await w.client.getServerCapabilities())?.[Z]) return null
          return { client: w, result: await w.client.request(I, G) }
        } catch (B) {
          if (w.type === 'connected')
            Pz(
              w.name,
              `Failed to request '${I.method}': ${B instanceof Error ? B.message : String(B)}`,
            )
          return null
        }
      }),
    )
  )
    .filter((w) => w.status === 'fulfilled')
    .map((w) => w.value)
    .filter((w) => w !== null)
}
var xU2 = s2(async () => {
  return (await hU2({ method: 'tools/list' }, oO, 'tools')).flatMap(
    ({ client: G, result: { tools: Z } }) =>
      Z.map((d) => ({
        ...$U2,
        name: 'mcp__' + G.name + '__' + d.name,
        async description() {
          return d.description ?? ''
        },
        async prompt() {
          return d.description ?? ''
        },
        inputJSONSchema: d.inputSchema,
        async *call(W) {
          let w = await uX9({ client: G, tool: d.name, args: W })
          yield { type: 'result', data: w, resultForAssistant: w }
        },
        userFacingName() {
          return `${G.name}:${d.name} (MCP)`
        },
      })),
  )
})
async function uX9({ client: { client: I, name: G }, tool: Z, args: d }) {
  let W = await I.callTool({ name: Z, arguments: d }, yR)
  if ('isError' in W && W.isError) {
    let w = `Error calling tool ${Z}: ${W.error}`
    throw (Pz(G, w), Error(w))
  }
  if ('toolResult' in W) return String(W.toolResult)
  if ('content' in W && Array.isArray(W.content))
    return W.content.map((w) => {
      if (w.type === 'image')
        return {
          type: 'image',
          source: { type: 'base64', data: String(w.data), media_type: w.mimeType },
        }
      return w
    })
  throw Error(`Unexpected response format from tool ${Z}`)
}
var cU2 = s2(async () => {
  return (await hU2({ method: 'prompts/list' }, sO, 'prompts')).flatMap(
    ({ client: G, result: Z }) =>
      Z.prompts?.map((d) => {
        let W = Object.values(d.arguments ?? {}).map((w) => w.name)
        return {
          type: 'prompt',
          name: 'mcp__' + G.name + '__' + d.name,
          description: d.description ?? '',
          isEnabled: !0,
          isHidden: !1,
          progressMessage: 'running',
          userFacingName() {
            return `${G.name}:${d.name} (MCP)`
          },
          argNames: W,
          async getPromptForCommand(w) {
            let B = w.split(' ')
            return await TX9({ name: d.name, client: G }, x21(W, B))
          },
        }
      }),
  )
})
async function TX9({ name: I, client: G }, Z) {
  try {
    return (await G.client.getPrompt({ name: I, arguments: Z })).messages.map((W) => ({
      role: W.role,
      content: [
        W.content.type === 'text'
          ? { type: 'text', text: W.content.text }
          : {
              type: 'image',
              source: {
                data: String(W.content.data),
                media_type: W.content.mimeType,
                type: 'base64',
              },
            },
      ],
    }))
  } catch (d) {
    throw (
      (Pz(G.name, `Error running command '${I}': ${d instanceof Error ? d.message : String(d)}`), d)
    )
  }
}


view rawclaude_code_mcp.mjs hosted with by GitHub

Claude Code with AWS Bedrock使用 AWS Bedrock 的 Claude Code

Claude Code supports both Amazon Bedrock Google Vertex AI. This makes Claude Code enterprise ready, without egress to external vendors, e.g, Anthropic’s API. Unfortunately, the minimalistic documentation provided by Anthropic to setup Claude Code with AWS Bedrock does NOT contain sufficient information. And we got stuck with the same problem with the comment section in Jonathan Evan’s Claude Code Setup Guide.Claude Code 支持 Amazon Bedrock Google Vertex AI。这使得 Claude Code 为企业做好准备,无需出口到外部供应商,例如 Anthropic 的 API。遗憾的是,Anthropic 提供的用于使用 AWS Bedrock 设置 Claude Code 的简约文档不包含足够的信息。我们在 Jonathan Evan 的 Claude Code Setup Guide 中的评论部分遇到了同样的问题。

So, we spent some time digging throught the code base and messaged Jonathan Evans for tips to setup Claude Code to work with AWS Bedrock. The code snippets in Claude Code that involves setting up AWS Bedrock or Vertex AI is as follows for those who are curious.因此,我们花了一些时间深入研究代码库,并向 Jonathan Evans 发送消息,以获取设置 Claude Code 以使用 AWS Bedrock 的提示。Claude Code 中涉及设置 AWS Bedrock 或 Vertex AI 的代码片段如下,供好奇的人使用。

var c9 = !!process.env.CLAUDE_CODE_USE_BEDROCK,
  p9 = !!process.env.CLAUDE_CODE_USE_VERTEX,
  Tl1 = {
    bedrock: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
    vertex: 'claude-3-7-sonnet@20250219',
    firstParty: 'claude-3-7-sonnet-20250219',
  },
  PB = c9
    ? 'us.anthropic.claude-3-5-haiku-20241022-v1:0'
    : p9
      ? 'claude-3-5-haiku@20241022'
      : 'claude-3-5-haiku-20241022'
async function qX4() {
  try {
    return await DJ('tengu-capable-model-config', Tl1)
  } catch (I) {
    return C0(I), Tl1
  }
}
var f6 = s2(async () => {
  let I = await qX4()
  if (c9) {
    if (process.env.ANTHROPIC_MODEL) return process.env.ANTHROPIC_MODEL
    return I.bedrock
  }
  if (p9) {
    if (process.env.ANTHROPIC_MODEL) return process.env.ANTHROPIC_MODEL
    return I.vertex
  }
  return I.firstParty
})
async function i41() {
  return !process.env.ANTHROPIC_MODEL || process.env.ANTHROPIC_MODEL === (await f6())
}
function ml1(I) {
  if (I?.startsWith('claude-3-5-haiku')) return process.env.VERTEX_REGION_CLAUDE_3_5_HAIKU
  else if (I?.startsWith('claude-3-5-sonnet')) return process.env.VERTEX_REGION_CLAUDE_3_5_SONNET
  else if (I?.startsWith('claude-3-7-sonnet')) return process.env.VERTEX_REGION_CLAUDE_3_7_SONNET
}
var bl1 = {},
  AM = null,
  ez = s2(async () => {
    if (f2.isCI) return null
    let I = await Cj(),
      G = {
        networkConfig: { api: 'https://statsig.anthropic.com/v1/' },
        environment: {
          tier: f2.isCI || ['test', 'development'].includes('production') ? 'dev' : 'production',
        },
        logLevel: Bj.LogLevel.None,
        storageProvider: new p41(),
      }
    return (
      (AM = new Bj.StatsigClient($l1, I, G)),
      AM.on('error', (Z) => {
        C0(`Statsig error: ${Z}`)
      }),
      await AM.initializeAsync(),
      process.on('exit', () => {
        AM?.flush()
      }),
      AM
    )
  })
...
...
var Ai5 = 'bedrock-2023-05-31',
  Xi5 = new Set(['/v1/complete', '/v1/messages', '/v1/messages?beta=true'])
class qr extends AK {
  constructor({
    baseURL: I = pW('ANTHROPIC_BEDROCK_BASE_URL'),
    awsSecretKey: G = null,
    awsAccessKey: Z = null,
    awsRegion: d = pW('AWS_REGION') ?? 'us-east-1',
    awsSessionToken: W = null,
    ...w
  } = {}) {
    let B = {
      awsSecretKey: G,
      awsAccessKey: Z,
      awsRegion: d,
      awsSessionToken: W,
      ...w,
      baseURL: I || `https://bedrock-runtime.${d}.amazonaws.com`,
    }
    super({
      baseURL: B.baseURL,
      timeout: B.timeout ?? 600000,
      httpAgent: B.httpAgent,
      maxRetries: B.maxRetries,
      fetch: B.fetch,
    })
    ;(this.messages = Yi5(this)),
      (this.completions = new n_(this)),
      (this.beta = _i5(this)),
      (this._options = B),
      (this.awsSecretKey = G),
      (this.awsAccessKey = Z),
      (this.awsRegion = d),
      (this.awsSessionToken = W)
  }
  defaultQuery() {
    return this._options.defaultQuery
  }
  defaultHeaders(I) {
    return { ...super.defaultHeaders(I), ...this._options.defaultHeaders }
  }
  async prepareRequest(I, { url: G, options: Z }) {
    let d = this.awsRegion
    if (!d)
      throw new Error(
        'Expected `awsRegion` option to be passed to the client or the `AWS_REGION` environment variable to be present',
      )
    let W = await Vp0(I, {
      url: G,
      regionName: d,
      awsAccessKey: this.awsAccessKey,
      awsSecretKey: this.awsSecretKey,
      awsSessionToken: this.awsSessionToken,
    })
    I.headers = { ...I.headers, ...W }
  }
  buildRequest(I) {
    if (((I.__streamClass = Qr), p_(I.body))) I.body = { ...I.body }
    if (p_(I.body)) {
      if (!I.body.anthropic_version) I.body.anthropic_version = Ai5
      if (I.headers && !I.body.anthropic_beta) {
        let G = nq(I.headers, 'anthropic-beta')
        if (G != null) I.body.anthropic_beta = G.split(',')
      }
    }
    if (Xi5.has(I.path) && I.method === 'post') {
      if (!p_(I.body))
        throw new Error('Expected request body to be an object for post /v1/messages')
      let G = I.body.model
      I.body.model = void 0
      let Z = I.body.stream
      if (((I.body.stream = void 0), Z)) I.path = `/model/${G}/invoke-with-response-stream`
      else I.path = `/model/${G}/invoke`
    }
    return super.buildRequest(I)
  }
}
function Yi5(I) {
  let G = new fd(I)
  return delete G.batches, delete G.countTokens, G
}
function _i5(I) {
  let G = new wZ(I)
  return delete G.promptCaching, delete G.messages.batches, delete G.messages.countTokens, G
}
var lB2 = X1(bB2(), 1),
  xe5 = 'vertex-2023-10-16',
  ce5 = new Set(['/v1/messages', '/v1/messages?beta=true'])
class Gs extends AK {
  constructor({
    baseURL: I = pW('ANTHROPIC_VERTEX_BASE_URL'),
    region: G = pW('CLOUD_ML_REGION') ?? null,
    projectId: Z = pW('ANTHROPIC_VERTEX_PROJECT_ID') ?? null,
    ...d
  } = {}) {
    if (!G)
      throw new Error(
        'No region was given. The client should be instantiated with the `region` option or the `CLOUD_ML_REGION` environment variable should be set.',
      )
    let W = { ...d, baseURL: I || `https://${G}-aiplatform.googleapis.com/v1` }
    super({
      baseURL: W.baseURL,
      timeout: W.timeout ?? 600000,
      httpAgent: W.httpAgent,
      maxRetries: W.maxRetries,
      fetch: W.fetch,
    })
    ;(this.messages = pe5(this)),
      (this.beta = ie5(this)),
      (this._options = W),
      (this.region = G),
      (this.projectId = Z),
      (this.accessToken = W.accessToken ?? null),
      (this._auth =
        W.googleAuth ??
        new lB2.GoogleAuth({ scopes: 'https://www.googleapis.com/auth/cloud-platform' })),
      (this._authClientPromise = this._auth.getClient())
  }
  defaultQuery() {
    return this._options.defaultQuery
  }
  defaultHeaders(I) {
    return { ...super.defaultHeaders(I), ...this._options.defaultHeaders }
  }
  async prepareOptions(I) {
    let G = await this._authClientPromise,
      Z = await G.getRequestHeaders(),
      d = G.projectId ?? Z['x-goog-user-project']
    if (!this.projectId && d) this.projectId = d
    I.headers = { ...Z, ...I.headers }
  }
  buildRequest(I) {
    if (p_(I.body)) I.body = { ...I.body }
    if (p_(I.body)) {
      if (!I.body.anthropic_version) I.body.anthropic_version = xe5
    }
    if (ce5.has(I.path) && I.method === 'post') {
      if (!this.projectId)
        throw new Error(
          'No projectId was given and it could not be resolved from credentials. The client should be instantiated with the `projectId` option or the `ANTHROPIC_VERTEX_PROJECT_ID` environment variable should be set.',
        )
      if (!p_(I.body))
        throw new Error('Expected request body to be an object for post /v1/messages')
      let G = I.body.model
      I.body.model = void 0
      let d = (I.body.stream ?? !1) ? 'streamRawPredict' : 'rawPredict'
      I.path = `/projects/${this.projectId}/locations/${this.region}/publishers/anthropic/models/${G}:${d}`
    }
    if (
      I.path === '/v1/messages/count_tokens' ||
      (I.path == '/v1/messages/count_tokens?beta=true' && I.method === 'post')
    ) {
      if (!this.projectId)
        throw new Error(
          'No projectId was given and it could not be resolved from credentials. The client should be instantiated with the `projectId` option or the `ANTHROPIC_VERTEX_PROJECT_ID` environment variable should be set.',
        )
      I.path = `/projects/${this.projectId}/locations/${this.region}/publishers/anthropic/models/count-tokens:rawPredict`
    }
    return super.buildRequest(I)
  }
}


view rawclaude_code_csp.mjs hosted with by GitHub

0. AWS Bedrock Setup0. AWS Bedrock 设置

Claude Code needs two models - Claude 3.7 Sonnet and Claude 3.5 Haiku. Please request them in us-east-1, the default region for Claude Code.Claude Code 需要两个模型 - Claude 3.7 Sonnet 和 Claude 3.5 Haiku。请在 Claude Code 的默认区域 us-east-1 中请求它们。

1. Inference Profile1. 推理配置文件

For cloud security best practices, create a new policy in AWS Identiy and Access Management (IAM) for inferencing and invocation the models, name it
AmazonBedrockInferenceProfile for clarity. Attach this policy to your AWS key and secret’s user or group.有关云安全最佳实践,请在 AWS Identiy 和 Access Management (IAM) 中创建一个新策略来推理和调用模型,为清楚起见,请将其命名为
AmazonBedrockInferenceProfile。将此策略附加到您的 AWS 密钥和密钥的用户或组。

The policy is as follows.策略如下。

{  "Version": "2012-10-17",  "Statement": [    {      "Effect": "Allow",      "Action": [        "bedrock:CreateInferenceProfile",        "bedrock:GetInferenceProfile",        "bedrock:ListInferenceProfiles",        "bedrock:InvokeModel*"      ],      "Resources": "*"    }  ]}

Now we are done on the AWS side. Lets test it out quickly with the following script.现在,我们已经完成了 AWS 方面的工作。让我们使用以下脚本快速测试一下。

import boto3
import json
client = boto3.client('bedrock-runtime', region_name='us-east-1')
response = client.invoke_model(
    modelId='us.anthropic.claude-3-7-sonnet-2025-0219-v1:0',
    body=json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "messages": [
            {
                "role": "user",
                "content": [{"type": "text", "text": "wassup cluade do you code"}],
            }
        ],
        "max_tokens": 200
    })
)
print(response['body'].read().decode())

view rawtest.py hosted with by GitHub

2. Setup Local AWS Config2. 设置本地 AWS Config

Ensure that the AWS access key and secret are in the [default] profiles is stored in your ~/.aws/config/credentials确保 AWS 访问密钥和密钥位于 [default] 配置文件中,并将其存储在您的 ~/.aws/config/credentials 中

And, for the config, ensure your [default] profile sets region to us-east-1 the output to json, e.g.,并且,对于配置,请确保您的 [default] 配置文件将 region 设置为 us-east-1,将输出设置为 json,例如,

[default]region = us-east-1output = json

NOTE: AWS_REGION for AWS and CLAUDE_ML_REGION for GCP are included in the code as either environment variables or settings. We could not get those to work, so we just stick with defaults.注意:AWS_REGION for AWS 和 CLAUDE_ML_REGION for GCP 作为环境变量或设置包含在代码中。我们无法让它们正常工作,所以我们只能坚持使用默认值。

3. Setup Environment Variables3. 设置环境变量

Add the following to your .bashrc, .zshrc, .profile, or config.fish depending on your shell. Note that根据您的 shell,将以下内容添加到您的 .bashrc、.zshrc、.profile 或 config.fish 中。请注意,

# Configure for Bedrock with Claude 3.7 Sonnetexport CLAUDE_CODE_USE_BEDROCK=1export ANTHROPIC_MODEL='us.anthropic.claude-3-7-sonnet-20250219-v1:0'# AWS Bedrock does not support prompt caching yet# Control prompt caching - set to 1 to disable export DISABLE_PROMPT_CACHING=1

After this, we are all good to go. Let’s claude from terminal.在此之后,我们都可以开始了。让我们从终端 claude 开始。

Easter Egg复活节彩蛋

Apparently, you can ask Claude Code for Anthropic or Claude stickers. It will then go through the form-filling control loop and submit a Google Form on your behalf. The prompt is shown below:显然,您可以向 Claude Code 索取 Anthropic 或 Claude 贴纸。然后,它将通过表单填写控制循环并代表您提交 Google 表单。提示符如下所示:

var SE2 = 'Sends the user swag stickers with love from Anthropic.',

LE2 = `This tool should be used whenever a user expresses interest in receiving Anthropic or Claude stickers, swag, or merchandise. When triggered, it will display a shipping form for the user to enter their mailing address and contact details. Once submitted, Anthropic will process the request and ship stickers to the provided address.

Common trigger phrases to watch for:

- "Can I get some Anthropic stickers please?"

- "How do I get Anthropic swag?"

- "I'd love some Claude stickers"

- "Where can I get merchandise?"

- Any mention of wanting stickers or swag

The tool handles the entire request process by showing an interactive form to collect shipping information.

NOTE: Only use this tool if the user has explicitly asked us to send or give them stickers. If there are other requests that include the word "sticker", but do not explicitly ask us to send them stickers, do not use this tool.

For example:

- "How do I make custom stickers for my project?" - Do not use this tool

- "I need to store sticker metadata in a database - what schema do you recommend?" - Do not use this tool

- "Show me how to implement drag-and-drop sticker placement with React" - Do not use this tool

view raweaster_egg.mjs hosted with by GitHub

Unfortunately, it is no longer available. :(不幸的是,它不再可用。:(

Trivia Factoids琐事 Factoids

Claude Code seems to have an internal code name tengu. It’s a React CLI tool, built using commander and ink. It uses zod for schema validation and type inference checking, and ripgrep for traversiing files and directories.Claude Code 似乎有一个内部代号 tengu。它是一个 React CLI 工具,使用 commander 和 ink 构建。它使用 zod 进行架构验证和类型推理检查,使用 ripgrep 遍历文件和目录。

Control Flow控制流

Below is Claude Code’s control flow diagram from a bird’s-eye view. Note that this excludes many lines of formatting, preprocessing, and CLI user interfacing code. We could have also missed some part of the control flow due to its size and obsfucation.下面是 Claude Code 的鸟瞰图控制流程图。请注意,这不包括许多行格式化、预处理和 CLI 用户接口代码。由于控制流的大小和干扰,我们也可能错过了控制流的某些部分。

Mermaid code for the control flow is in this gist.控制流的 Mermaid 代码在这个要点中。

References引用

  • Claude Code Overview. Anthropic Documentation https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overviewClaude Code 概述。Anthropic Documentation https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview
  • Model Control Protocol https://modelcontextprotocol.io/introduction
  • Claude Code on Amazon Bedrock: Quick Setup GuideAmazon Bedrock 上的 Claude Code:快速设置指南

原链接:
https://leehanchung.github.io/blogs/2025/03/07/claude-code/#
bootstrap-confidence-interval

相关推荐

Python入门学习记录之一:变量_python怎么用变量

写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...

python变量命名规则——来自小白的总结

python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...

Python入门学习教程:第 2 章 变量与数据类型

2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...

绘制学术论文中的“三线表”具体指导

在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...

Python基础语法知识--变量和数据类型

学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...

一文搞懂 Python 中的所有标点符号

反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...

Python变量类型和运算符_python中变量的含义

别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...

从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序

在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...

Python中下划线 ‘_’ 的用法,你知道几种

Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...

解锁Shell编程:变量_shell $变量

引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...

一文学会Python的变量命名规则!_python的变量命名有哪些要求

目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...

更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for

src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...

C++第五课:变量的命名规则_c++中变量的命名规则

变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....

Rust编程-核心篇-不安全编程_rust安全性

Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...

探秘 Python 内存管理:背后的神奇机制

在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...