---
title: API 버전 2026-10-21로 마이그레이션
url: https://platform.claude.com/docs/ko/api/migration-2026-10-21
description: "Claude API 통합을 API 버전 2023-06-01에서 2026-10-21로 업그레이드합니다: 설치할 SDK 버전과 적용할 코드 변경 사항을 안내합니다."
---

이 가이드는 API 버전 `2023-06-01`에서 `2026-10-21`로 이전하기 위한 코드 변경 사항을 나열합니다. [업그레이드 단계](https://platform.claude.com/docs/ko/api/migration-2026-10-21#migration-checklist)에서 수행할 작업을 순서대로 설명합니다.

## 업그레이드 단계

<Steps>
  <Step title="2026-10-21로 전환">
    SDK를 사용하는 경우, 요청은 해당 SDK의 메이저 버전이 출시되었을 때 최신이었던 API 버전을 사용합니다. 사용하는 언어에 표시된 버전은 `2026-10-21`을 사용하는 첫 번째 버전이므로 해당 버전으로 업그레이드하세요. SDK 없이 API를 호출하는 경우 `anthropic-version` 헤더를 `2026-10-21`로 설정하세요.

    <Tabs>
      <Tab title="cURL">
        `anthropic-version` 헤더를 `2026-10-21`로 설정하세요:

        ```bash
        curl https://api.anthropic.com/v1/messages \
          -H "x-api-key: $ANTHROPIC_API_KEY" \
          -H "anthropic-version: 2026-10-21" \
          -H "content-type: application/json" \
          -d '{
            "model": "claude-opus-5-5",
            "max_tokens": 1024,
            "messages": [{"role": "user", "content": "Hello, Claude"}]
          }'
        ```
      </Tab>

      <Tab title="CLI">
        `ant` CLI를 버전 2.0.0으로 업그레이드하세요. Homebrew 명령과 릴리스 다운로드는 동일하게 유지됩니다.

        Go는 메이저 버전 2 이상인 모듈의 경로가 해당 버전으로 끝나야 하므로, CLI의 모듈 경로는 이제 `github.com/anthropics/anthropic-cli/v2`입니다. `go install`로 설치하는 경우 경로에 `/v2`를 추가하세요:

        ```bash
        # 변경 전
        go install 'github.com/anthropics/anthropic-cli/cmd/ant@latest'

        # 변경 후
        go install 'github.com/anthropics/anthropic-cli/v2/cmd/ant@latest'
        ```

        이전 경로는 오류나 경고 없이 계속 최신 v1 릴리스를 설치합니다.
      </Tab>

      <Tab title="Python">
        `anthropic` 패키지를 버전 2.0.0으로 업그레이드하세요.
      </Tab>

      <Tab title="TypeScript">
        `@anthropic-ai/sdk` 패키지를 버전 1.0.0으로 업그레이드하세요.

        `@anthropic-ai/bedrock-sdk`, `@anthropic-ai/vertex-sdk`, `@anthropic-ai/foundry-sdk`, `@anthropic-ai/aws-sdk`, `@anthropic-ai/google-cloud-sdk`의 v1은 `@anthropic-ai/sdk`의 v1이 필요하며, 이들의 이전 버전은 1 미만의 버전이 필요합니다. 이 중 하나를 사용하는 경우 같은 업그레이드에서 v1으로 이전하세요. 그렇지 않으면 패키지 관리자가 해당 패키지를 위해 `@anthropic-ai/sdk`의 두 번째 이전 사본을 설치합니다.
      </Tab>

      <Tab title="C#">
        `Anthropic` 패키지를 버전 13.0.0으로 업그레이드하세요.
      </Tab>

      <Tab title="Go">
        모듈 경로가 `github.com/anthropics/anthropic-sdk-go/v2`인 Go SDK 버전 2.0.0으로 업그레이드하세요. Go 모듈의 새 메이저 버전은 새 import 경로를 가지므로, `github.com/anthropics/anthropic-sdk-go` 및 `github.com/anthropics/anthropic-sdk-go/option`과 같은 하위 패키지의 각 import를 `github.com/anthropics/anthropic-sdk-go/v2`로 시작하도록 변경하세요. 그런 다음 `go get github.com/anthropics/anthropic-sdk-go/v2`를 실행하세요.
      </Tab>

      <Tab title="Java">
        `com.anthropic:anthropic-java` 아티팩트를 버전 3.0.0으로 업그레이드하세요.
      </Tab>

      <Tab title="PHP">
        `composer require "anthropic-ai/sdk"`를 실행하여 패키지를 버전 1.0.0으로 업그레이드하세요. `composer update`만으로는 현재 버전 제약 조건 내에 머무릅니다.
      </Tab>

      <Tab title="Ruby">
        `anthropic` gem을 버전 2.0.0으로 업그레이드하세요.
      </Tab>
    </Tabs>

    <Warning>
      Amazon Bedrock에서 `2026-10-21`은 Claude 4.7 이상 모델에서만 사용할 수 있습니다. [Claude on Amazon Bedrock (Opus 4.6 이하)](https://platform.claude.com/docs/ko/build-with-claude/claude-on-amazon-bedrock-legacy)에 나열된 이전 모델을 Bedrock에서 호출하는 경우, 현재 사용 중인 SDK 버전을 유지하거나, API 버전을 직접 설정하는 경우 현재 보내는 버전을 계속 보내세요. 해당 호출을 `2026-10-21`로 이전하려면 먼저 Claude 4.7 이상 모델로 전환하세요.
    </Warning>

    업그레이드는 다음 단계의 수정 사항과 함께 릴리스하세요.
  </Step>

  <Step title="호환성이 깨지는 변경 사항에 맞게 코드 업데이트">
    [호환성이 깨지는 변경 사항](https://platform.claude.com/docs/ko/api/migration-2026-10-21#breaking-changes)을 검토하고, 영향을 받는 각 항목에 맞게 코드를 업데이트하세요. 또한 [새 SDK 또는 CLI 버전에 필요한 코드 변경](https://platform.claude.com/docs/ko/api/migration-2026-10-21#sdk-changes)도 적용하세요.
  </Step>

  <Step title="2026-10-21에 대해 테스트">
    릴리스하기 전에 `2026-10-21`에 대해 통합을 테스트하세요.
  </Step>
</Steps>

## 호환성이 깨지는 변경 사항

### Messages API

이 변경 사항은 Messages API(`POST /v1/messages`)에 대한 요청, [토큰 카운팅](https://platform.claude.com/docs/ko/build-with-claude/token-counting), 그리고 `2026-10-21`로 생성된 [Message Batch](https://platform.claude.com/docs/ko/build-with-claude/batch-processing)의 각 요청에 적용됩니다.

#### assistant 메시지의 document 블록은 오류를 반환합니다

`assistant` 메시지에 `document` 블록을 직접 보내는 경우 영향을 받습니다.

`2026-10-21`에서는 `assistant` 메시지에 `document` 블록을 직접 배치한 요청이 400 오류를 반환합니다. 대신 `user` 메시지로 문서를 보내세요. Claude가 반환한 웹 페치 도구 결과처럼 다른 블록 안에 중첩된 문서는 여전히 허용됩니다.

#### user 메시지의 citations는 오류를 반환합니다

`search_result` 블록 내부를 포함하여 `user` 메시지의 `text` 블록에 `citations`를 보내는 경우 영향을 받습니다.

`2026-10-21`에서는 `user` 메시지에 비어 있지 않은 `citations` 배열이 있는 `text` 블록을 보내는 요청이 400 오류를 반환합니다. 해당 블록에서 `citations`를 제거하세요. 다시 보내는 Claude의 이전 응답과 같이 `assistant` 메시지의 `text` 블록에 있는 citations는 여전히 허용되며, 문서와 검색 결과의 `"citations": {"enabled": true}` 설정도 마찬가지입니다.

#### 샘플링 매개변수가 제거되었습니다

Messages 요청 또는 Message Batch 요청에서 `temperature`, `top_p` 또는 `top_k`를 보내는 경우 영향을 받습니다.

`2026-10-21`에서는 `temperature`, `top_p` 또는 `top_k`를 보내는 요청이 매개변수의 기본값이더라도 400 오류를 반환합니다.

요청에서 세 매개변수를 제거하세요.

최신 메이저 버전부터 SDK와 CLI에는 더 이상 이 세 매개변수가 없습니다.

이러한 매개변수가 없으면 요청은 `temperature` 1.0을 포함한 기본값으로 샘플링하며, 이는 이 매개변수를 생략한 `2023-06-01` 요청과 동일합니다. Claude 4.7 이상 모델처럼 이미 기본값만 허용하는 모델은 이전과 같이 샘플링합니다. Claude Sonnet 4.6처럼 다른 값을 허용하는 모델에서는 더 일관된 출력을 위해 `temperature`를 낮춘 요청이 그 효과를 잃게 됩니다. 이를 대체하는 다른 설정은 없습니다. 요청이 기본값이 아닌 값에 의존하는 경우, 매개변수 전송을 중단하거나 해당 요청을 `2023-06-01`에 유지하세요.

### Admin API 및 Claude Enterprise Analytics API

코드가 다음 표에 있는 Admin API 또는 Claude Enterprise Analytics API 응답 필드를 읽는 경우 영향을 받습니다.

`2026-10-21`에서는 Admin API와 [Claude Enterprise Analytics API](https://platform.claude.com/docs/ko/manage-claude/analytics-api)의 응답에 이름이 변경된 필드의 이전 이름이 더 이상 포함되지 않습니다. 대신 새 이름을 사용하세요.

Admin API:

| 엔드포인트                                                                                                                                                                                                                  | 이전 이름          | 새 이름                                                                                                                           |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| [RBAC 그룹](https://platform.claude.com/docs/ko/api/beta/organization/rbac_groups/list): 생성, 목록 조회, 조회, 업데이트                                                                                                             | `roles`        | `role_ids`                                                                                                                     |
| [RBAC 그룹 멤버](https://platform.claude.com/docs/ko/api/beta/organization/rbac_groups/members/list): 목록 조회 및 추가, 그리고 [멤버 제거](https://platform.claude.com/docs/ko/api/beta/organization/rbac_groups/members/remove)에 대한 응답 | `group_id`     | `rbac_group_id`                                                                                                                |
| [RBAC 역할](https://platform.claude.com/docs/ko/api/beta/organization/rbac_roles/list): 목록 조회 및 조회                                                                                                                       | `name`         | `display_name`                                                                                                                 |
| [조직](https://platform.claude.com/docs/ko/api/organization/rate_limits/list) 및 [워크스페이스](https://platform.claude.com/docs/ko/api/organization/workspaces/rate_limits/list) 속도 제한: 목록 조회, 그리고 워크스페이스의 속도 제한 설정에 대한 응답     | `group_type`   | `group.type`                                                                                                                   |
| [API 키](https://platform.claude.com/docs/ko/api/organization/api_keys/list): 목록 조회, 조회, 업데이트                                                                                                                           | `workspace_id` | `scope` (값이 다름; [API 키의 `workspace_id`](https://platform.claude.com/docs/ko/api/migration-2026-10-21#api-key-workspace-id) 참조) |

Claude Enterprise Analytics API:

| 엔드포인트                                                                                                                                                                                                        | 이전 이름         | 새 이름                  |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | --------------------- |
| 사용자별 [사용량](https://platform.claude.com/docs/ko/api/beta/organization/analytics/user_usage_report/list) 및 [비용](https://platform.claude.com/docs/ko/api/beta/organization/analytics/user_cost_report/list) 보고서 | `actor.email` | `actor.email_address` |
| [활동 요약](https://platform.claude.com/docs/ko/api/beta/organization/analytics/summaries/list)                                                                                                                  | `summaries`   | `data`                |

속도 제한 목록 엔드포인트의 `group_type` 쿼리 매개변수와 API 키 목록 엔드포인트의 `workspace_id` 필터는 변경되지 않았습니다.

#### API 키의 `workspace_id`

코드가 API 키의 `workspace_id`를 읽는 경우 영향을 받습니다.

`2023-06-01`에서 API 키의 `workspace_id`는 키가 바인딩된 워크스페이스의 ID이며, Default Workspace에 바인딩된 키와 하나의 워크스페이스에 바인딩되지 않은 키(모든 워크스페이스 키)의 경우 `null`입니다.

`2026-10-21`에서는 `workspace_id`가 제거되었습니다. 대신 `scope`를 읽으세요. Default Workspace를 포함하여 워크스페이스에 바인딩된 키의 경우 `scope.workspace_id`는 해당 워크스페이스의 실제 ID이며, 모든 워크스페이스 키는 `workspace_id` 없이 `{"type": "organization"}`의 `scope`를 가집니다.

코드가 `null`인 `workspace_id`를 Default Workspace로 처리했다면, 대신 `scope.workspace_id`를 Default Workspace의 ID와 비교하세요. 해당 ID를 찾으려면 `include_default=true`로 [List Workspaces](https://platform.claude.com/docs/ko/api/organization/workspaces/list)를 호출하고 이름이 `"Default"`인 워크스페이스를 가져오세요.

## SDK 및 CLI 변경 사항

이전 SDK 및 CLI 버전은 모든 요청에 `anthropic-version: 2023-06-01`을 보냈습니다. [2026-10-21로 전환](https://platform.claude.com/docs/ko/api/migration-2026-10-21#upgrade)에 있는 버전은 `2026-10-21`을 보냅니다. [호환성이 깨지는 변경 사항](https://platform.claude.com/docs/ko/api/migration-2026-10-21#breaking-changes)의 변경 사항도 이들에 적용됩니다. 제거된 매개변수와 이전 필드 이름은 SDK의 타입과 CLI의 플래그 및 출력에서도 사라졌습니다.

### Amazon Bedrock 및 Google Cloud의 API 버전

Google Cloud's Agent Platform용 SDK 클라이언트는 헤더 대신 요청 본문에 버전을 지정합니다. 이전 버전이 `vertex-2023-10-16`을 보냈던 곳에 `anthropic_version: 2026-10-21`을 보내며, `anthropic-version` 헤더는 보내지 않습니다.

Amazon Bedrock 클라이언트도 마찬가지입니다. 이전 버전이 `bedrock-2023-05-31`을 보냈던 곳에 `anthropic_version: 2026-10-21`을 보내며, `anthropic-version` 헤더는 보내지 않습니다. Claude Opus 4.7보다 오래된 모델은 아직 Bedrock에서 API 버전 `2026-10-21`을 지원하지 않으며, 이를 지정한 요청은 400 오류를 받을 수 있습니다. 이러한 모델 중 하나를 사용하는 경우 당분간 이전 SDK 버전을 유지하거나, 업그레이드한 후 `bedrock-2023-05-31`을 직접 보내세요.

<Tabs>
  <Tab title="Python">
    이는 `AnthropicVertex`, `AsyncAnthropicVertex`, `AnthropicBedrock`, `AsyncAnthropicBedrock`에 적용됩니다.

    `bedrock-2023-05-31`을 보내려면 각 요청에 `extra_body={"anthropic_version": "bedrock-2023-05-31"}`을 전달하세요.
  </Tab>

  <Tab title="TypeScript">
    이는 `AnthropicVertex`와 `AnthropicBedrock`에 적용됩니다. 클라이언트나 요청에 `anthropic-version` 헤더를 설정하면 그 값이 본문에 들어갑니다.

    `bedrock-2023-05-31`을 보내려면 클라이언트나 요청에서 `anthropic-version` 헤더를 `"bedrock-2023-05-31"`로 설정하세요.
  </Tab>

  <Tab title="C#">
    이는 `AnthropicVertexClient`와 `AnthropicBedrockClient`에 적용됩니다. `ClientOptions.ExtraHeaders`를 통해 `anthropic-version` 헤더를 설정하면 그 값이 본문에 들어갑니다.

    `bedrock-2023-05-31`을 보내려면 클라이언트에서 `WithOptions`를 호출하고 `ClientOptions.ExtraHeaders`에서 `anthropic-version`을 `bedrock-2023-05-31`로 설정하세요.
  </Tab>

  <Tab title="Go">
    이는 `vertex` 및 `bedrock` 패키지에 적용됩니다. `option.WithHeader`로 `anthropic-version` 헤더를 설정하면 그 값이 본문에 들어갑니다. `vertex.DefaultVersion`과 `bedrock.DefaultVersion`은 제거되었습니다.

    `bedrock-2023-05-31`을 보내려면 클라이언트나 요청에 `option.WithHeader("anthropic-version", "bedrock-2023-05-31")`을 전달하세요.
  </Tab>

  <Tab title="Java">
    이는 `VertexBackend`와 `BedrockBackend`에 적용됩니다. 클라이언트나 요청에 `anthropic-version` 헤더를 설정하면 그 값이 본문에 들어갑니다.

    `bedrock-2023-05-31`을 보내려면 클라이언트나 요청에서 `anthropic-version` 헤더를 `bedrock-2023-05-31`로 설정하세요.
  </Tab>

  <Tab title="PHP">
    이는 `Anthropic\Vertex\Client`와 `Anthropic\Bedrock\Client`에 적용됩니다.

    `bedrock-2023-05-31`을 보내려면 `requestOptions`에 `'extraBodyParams' => ['anthropic_version' => 'bedrock-2023-05-31']`을 전달하세요.
  </Tab>

  <Tab title="Ruby">
    이는 `Anthropic::VertexClient`와 `Anthropic::BedrockClient`에 적용됩니다. `extra_headers`를 통해 `anthropic-version` 헤더를 설정하면 그 값이 본문에 들어갑니다. `Anthropic::VertexClient::DEFAULT_VERSION`과 `Anthropic::BedrockClient::DEFAULT_VERSION`은 제거되었습니다.

    `bedrock-2023-05-31`을 보내려면 `request_options`에 `extra_headers: {"anthropic-version" => "bedrock-2023-05-31"}`을 전달하세요.
  </Tab>
</Tabs>

### `MessageParam`은 역할별로 하나의 타입을 가진 유니온입니다

이전 버전에서 `MessageParam`은 모든 역할에 대한 하나의 타입이었습니다. 이제 각 역할은 고유한 타입을 가집니다: `UserMessageParam`, `AssistantMessageParam`, `SystemMessageParam`. `BetaMessageParam`도 같은 방식으로 `BetaUserMessageParam`, `BetaAssistantMessageParam`, `BetaSystemMessageParam`으로 분리됩니다. SDK가 보내는 요청은 이전과 동일한 필드와 값을 가집니다.

<Tabs exclude="shell">
  <Tab title="Python">
    `{"role": "user", "content": "Hello"}`처럼 dict 리터럴로 작성된 메시지는 변경할 필요가 없습니다.

    v1에서 `anthropic.types.MessageParam`은 하나의 `TypedDict`였습니다. v2에서는 세 타입의 유니온이며, `anthropic.types.beta.BetaMessageParam`은 해당하는 세 타입의 유니온입니다. 두 이름 모두 `list[MessageParam]`과 같은 어노테이션에서 여전히 작동합니다.

    이제 두 이름 중 하나를 호출하면 `TypeError`가 발생하며, 타입 검사기도 이를 표시합니다. 메시지를 dict로 작성하세요:

    ```python
    # 변경 전
    message = MessageParam(role="user", content="Hello")

    # 변경 후
    message: MessageParam = {"role": "user", "content": "Hello"}
    ```

    두 이름 중 하나를 서브클래싱해도 `TypeError`가 발생합니다. `UserMessageParam`과 같이 해당 역할의 타입을 서브클래싱하세요.

    나머지 변경 사항은 타입 검사에만 영향을 줍니다. `role`이 둘 이상의 역할을 가질 수 있는 변수인 dict는 유니온의 어떤 타입과도 일치하지 않으므로, 한 번에 하나의 역할에 대해 dict를 구성하세요:

    ```python
    # 변경 전
    def to_message(role: Literal["user", "assistant"], text: str) -> MessageParam:
        return {"role": role, "content": text}


    # 변경 후
    def to_message(role: Literal["user", "assistant"], text: str) -> MessageParam:
        if role == "user":
            return {"role": "user", "content": text}
        return {"role": "assistant", "content": text}
    ```

    다음 두 가지는 `BetaMessageParam`에만 적용됩니다:

    * `clear_at`과 `output_config`는 `BetaSystemMessageParam`의 키이므로 user 또는 assistant 메시지는 이를 가질 수 없습니다.
    * `BetaSystemMessageParam`에서 `content`는 선택 사항이므로 pyright가 `message["content"]`를 보고합니다. `message.get("content")`로 읽거나, 먼저 `message["role"]`이 `"system"`이 아닌지 확인하세요.
  </Tab>

  <Tab title="TypeScript">
    `MessageParam`은 하나의 인터페이스였습니다. 이제는 `UserMessageParam | AssistantMessageParam | SystemMessageParam`이며, `BetaMessageParam`은 해당하는 세 타입의 동일한 유니온입니다. 타입만 변경되었습니다. `{ role: "user", content: "Hello, Claude" }`처럼 역할을 명시한 메시지 리터럴은 이전과 같이 타입 검사를 통과하므로 대부분의 코드는 변경할 필요가 없습니다.

    system 타입은 다른 두 타입과 다릅니다. 그 `content`는 문자열 또는 텍스트 블록이며, `beta`에서는 `tool_addition` 및 `tool_removal` 블록도 포함되므로, 그곳에 이미지 블록을 넣으면 더 이상 컴파일되지 않습니다. `beta`에서는 이 타입만 `clear_at`과 `output_config`를 가지며, 그 `content`는 선택 사항입니다.

    모든 역할의 메시지를 처리하는 코드는 콘텐츠 블록을 교체하거나 추가하기 전, 그리고 `clear_at` 또는 `output_config`를 읽기 전에 `role`을 확인해야 합니다:

    ```typescript
    // 변경 전
    const copy: Anthropic.MessageParam = { ...message, content: blocks };

    // 변경 후
    const copy: Anthropic.MessageParam =
      message.role === "system" ? message : { ...message, content: blocks };
    ```

    `BetaMessageParam`의 `content`는 `undefined`일 수 있습니다:

    ```typescript
    // 변경 전
    const types =
      typeof message.content === "string" ? [] : message.content.map((block) => block.type);

    // 변경 후
    const types = Array.isArray(message.content) ? message.content.map((block) => block.type) : [];
    ```

    `BetaMessageParam["content"]` 타입에도 `undefined`가 포함됩니다. user 또는 assistant 메시지의 콘텐츠에는 `BetaMessageContentParam`을 사용하세요.

    인터페이스는 유니온을 확장할 수 없고, 클래스는 유니온을 구현할 수 없습니다. 타입 별칭을 사용하거나, 대신 하나의 역할에 대한 타입을 지정하세요.

    ```typescript
    // 변경 전
    interface StoredMessage extends Anthropic.MessageParam {
      id: string;
    }

    // 변경 후
    type StoredMessage = Anthropic.MessageParam & { id: string };
    ```
  </Tab>

  <Tab title="C#">
    v12에서 `MessageParam`과 `BetaMessageParam`은 `Role`과 `Content`를 설정하는 클래스였습니다. v13에서는 각각 해당 역할에 대한 세 클래스의 유니온이며, `Anthropic.Models.Messages`와 `Anthropic.Models.Beta.Messages`의 `Role` 열거형은 사라졌습니다.

    메시지를 구성할 때는 해당 역할의 클래스를 지정하고 `Role`을 삭제하세요. 각 클래스는 유니온으로 암시적으로 변환됩니다:

    ```csharp
    // 변경 전
    Messages = [new() { Role = Role.User, Content = "Hello, Claude" }],

    // 변경 후
    Messages = [new UserMessageParam { Content = "Hello, Claude" }],
    ```

    `new UserMessageParam("Hello, Claude")`도 작동합니다.

    `Content`를 담는 클래스도 변경됩니다:

    * `MessageParamContent`는 이제 `MessageContentParam`이고, `BetaMessageParamContent`는 이제 `BetaMessageContentParam`입니다.
    * system 메시지는 고유한 콘텐츠 클래스를 가집니다. `SystemMessageParamContent`는 문자열 또는 `TextBlockParam` 목록을 담고, `BetaSystemMessageParamContent`는 문자열 또는 `SystemMessageContentBlock` 목록을 담습니다. `List<ContentBlockParam>` 또는 `List<BetaContentBlockParam>`은 더 이상 이것으로 변환되지 않습니다.
    * `ClearAt`과 `OutputConfig`는 `BetaSystemMessageParam`에만 있습니다.

    메시지를 읽을 때 유니온에는 여전히 `Role`과 `Content`가 있지만 이를 설정할 수는 없으므로, `with` 식은 해당 역할의 클래스에 사용합니다. `Role`은 이제 `MessageParamRole` 또는 `BetaMessageParamRole`을 담습니다. `BetaSystemMessageParam`에서 `Content`가 선택 사항이므로 `BetaMessageParam.Content`는 `null`일 수 있습니다.

    ```csharp
    // 변경 전
    if (message.Role.Value() == Role.Assistant) { }

    // 변경 후
    if (message.Role.Value() == MessageParamRole.Assistant) { }
    ```

    `TryPickUser`, `TryPickAssistant`, `TryPickSystem`, `Switch`, `Match`는 해당 역할의 클래스를 제공합니다.
  </Tab>

  <Tab title="Go">
    v1에서 `MessageParam`은 `Role`과 `Content` 필드를 가진 하나의 구조체였습니다. v2에서는 유니온입니다: `OfUser`는 `*UserMessageParam`을, `OfAssistant`는 `*AssistantMessageParam`을, `OfSystem`은 `*SystemMessageParam`을 담습니다. `BetaMessageParam`도 같은 방식으로 변경됩니다. SDK는 beta system 메시지의 키 순서를 제외하고 이전과 동일한 JSON을 보냅니다.

    `NewUserMessage`, `NewAssistantMessage`, `NewBetaUserMessage`, 그리고 `Message`와 `BetaMessage`의 `ToParam` 메서드는 이전과 같이 작동하므로, 이를 사용해 메시지를 구성하는 코드는 변경할 필요가 없습니다.

    구조체 리터럴은 해당 역할의 타입을 지정합니다. 각 타입이 자체 역할을 마샬링하므로 `Role`은 생략하세요:

    ```go
    // 변경 전
    anthropic.MessageParam{
    	Role:    anthropic.MessageParamRoleAssistant,
    	Content: blocks,
    }

    // 변경 후
    anthropic.MessageParam{OfAssistant: &anthropic.AssistantMessageParam{
    	Content: blocks,
    }}
    ```

    메시지를 읽는 코드는 어떤 필드가 설정되어 있는지 확인합니다:

    ```go
    // 변경 전
    if message.Role == anthropic.MessageParamRoleUser {
    	blocks = message.Content
    }

    // 변경 후
    if message.OfUser != nil {
    	blocks = message.OfUser.Content
    }
    ```

    * `MessageParamRole` 및 `BetaMessageParamRole` 타입과 그 상수는 사라졌습니다. `message.GetRole()`은 역할을 `string`으로 가리키는 포인터를 반환하며, 설정된 필드가 없으면 `nil`을 반환합니다.
    * `ClearAt`과 `OutputConfig`는 `BetaMessageParam`에서 `BetaSystemMessageParam`으로 이동했습니다. `BetaMessageParamClearAt` 타입과 그 상수의 이름은 이제 `BetaSystemMessageParamClearAt`으로 시작합니다.
    * `SystemMessageParam.Content`는 `[]TextBlockParam`입니다. `BetaSystemMessageParam.Content`는 `text`, `tool_addition`, `tool_removal` 블록을 담는 `[]BetaSystemMessageParamContentUnion`입니다. `NewBetaSystemMessage`는 해당 타입의 블록을 받으므로, `anthropic.NewBetaTextBlock("Be brief.")`는 `anthropic.BetaSystemMessageParamContentUnion{OfText: &anthropic.BetaTextBlockParam{Text: "Be brief."}}`가 됩니다.
    * `MessageParam`의 사본은 원본과 동일한 메시지를 가리킵니다. `duplicate.OfUser.Content`를 설정하면 둘 다 변경되며, v1에서는 `duplicate.Content`를 설정하면 사본만 변경되었습니다.
    * `mcp.ToMessage`는 `user` 또는 `assistant` 이외의 역할에 대해 `*mcp.UnsupportedValueError`를 반환합니다. v1은 모든 역할을 메시지에 복사했습니다.
  </Tab>

  <Tab title="Java">
    v2에서 `MessageParam`은 `role`과 `content`를 가진 단일 클래스였습니다. v3에서는 세 클래스의 유니온이며, `MessageParam.Content`는 이제 최상위 `MessageContentParam`입니다. `BetaMessageParam`도 같은 방식으로 변경되며, 그 클래스들은 `Beta` 접두사가 붙은 동일한 이름을 가집니다. SDK가 보내는 JSON은 동일하지만, beta system 메시지에서는 이제 `role`이 `content`보다 앞에 옵니다.

    `String`을 받는 `addUserMessage`, `addAssistantMessage`, `addSystemMessage`, `Message` 또는 `MessageParam`을 받는 `addMessage`, 그리고 `Message.toParam()`은 변경되지 않습니다.

    `MessageParam.builder()`와 `toBuilder()`는 사라졌습니다. 해당 역할의 팩토리 메서드인 `ofUser`, `ofAssistant` 또는 `ofSystem`을 호출하세요:

    ```java
    // 변경 전
    MessageParam message = MessageParam.builder()
        .role(MessageParam.Role.USER)
        .content("Hello, Claude")
        .build();

    // 변경 후
    MessageParam message = MessageParam.ofUser("Hello, Claude");
    ```

    `MessageCreateParams`, `StructuredMessageCreateParams`, `MessageCountTokensParams`, `BatchCreateParams.Request.Params`의 빌더에서 콘텐츠 블록 목록을 받는 메서드의 이름이 변경되었습니다:

    | v2                                 | v2 beta                                       | v3                                        |
    | ---------------------------------- | --------------------------------------------- | ----------------------------------------- |
    | `addUserMessageOfBlockParams`      | `addUserMessageOfBetaContentBlockParams`      | `addUserMessageOfContentBlockParams`      |
    | `addAssistantMessageOfBlockParams` | `addAssistantMessageOfBetaContentBlockParams` | `addAssistantMessageOfContentBlockParams` |
    | `addSystemMessageOfBlockParams`    | `addSystemMessageOfBetaContentBlockParams`    | `addSystemMessageOfBlocks`                |

    콘텐츠 클래스에서 `ofBlockParams`, `blockParams()`, `isBlockParams()`, `asBlockParams()`, 그리고 visitor의 `visitBlockParams`에 있는 `BlockParams`(beta에서는 `BetaContentBlockParams`)는 `ContentBlockParams`가 됩니다.

    system 메시지는 고유한 콘텐츠 클래스인 `SystemMessageParam.Content`를 가지며, 이제 `addSystemMessage`가 이를 받습니다. 그 블록은 `ContentBlockParam`이 아니라 `TextBlockParam`입니다. beta에서는 `ofText`, `ofToolAddition`, `ofToolRemoval`을 가진 `BetaSystemMessageParam.Content.SystemMessageContentBlock`입니다.

    ```java
    // 변경 전
    builder.addSystemMessageOfBlockParams(List.of(ContentBlockParam.ofText(textBlock)));

    // 변경 후
    builder.addSystemMessageOfBlocks(List.of(textBlock));
    ```

    메시지를 읽을 때 `role()`은 변경되지 않습니다. `content()`는 `MessageContentParam`을 반환하며, beta에서는 system 메시지에 콘텐츠가 없을 수 있으므로 `Optional<BetaMessageContentParam>`을 반환합니다. `_role()`, `_content()`, `_additionalProperties()`는 이제 `asUser()`, `asAssistant()` 또는 `asSystem()`이 반환하는 해당 역할의 클래스에 있습니다.
  </Tab>

  <Tab title="PHP">
    클래스는 `Anthropic\Messages`에 있고, beta 클래스는 `Anthropic\Beta\Messages`에 있습니다. 배열로 작성한 메시지는 변경되지 않으며, 여전히 `'role'`이 필요합니다.

    `MessageParam::with()`와 `BetaMessageParam::with()`는 유지되며, `role`에 해당하는 클래스를 반환합니다. 명명된 인수를 사용한 호출은 변경할 필요가 없습니다. 이제 `role`이 첫 번째 매개변수이므로, 위치 인수 호출에서는 `content`와 `role`의 순서를 바꾸거나, `role`을 받지 않는 해당 역할 클래스의 `with()`를 호출하세요. 이전 순서의 인수에 대해 PHP는 PHPStan이 경고하지 않는 `UnhandledMatchError`를 발생시키거나, `content`가 목록이거나 `role`이 열거형 케이스인 경우 `TypeError`를 발생시킵니다.

    ```php
    // 변경 전
    MessageParam::with('Hello, Claude', 'user');

    // 변경 후
    UserMessageParam::with('Hello, Claude');
    ```

    이제 어떤 객체도 `MessageParam`이 아닙니다: `instanceof MessageParam`은 false이며, 매개변수나 반환 타입이 이를 지정하는 곳에서 PHP는 `TypeError`를 발생시킵니다. 대신 세 클래스를 지정하세요:

    ```php
    // 변경 전
    function send(MessageParam $message): void {}

    // 변경 후
    function send(UserMessageParam|AssistantMessageParam|SystemMessageParam $message): void {}
    ```

    * `MessageParam::fromArray()`와 `(new MessageParam)->withContent()`는 "Call to undefined method"를 발생시킵니다. `role`을 자체적으로 설정하는 해당 역할의 클래스에서 호출하세요.
    * `withRole()`은 이제 문자열만 받습니다: `Role` 케이스에 대해 PHP는 `TypeError`를 발생시킵니다. 메시지에 다른 역할을 부여하려면 해당 역할의 클래스를 구성하세요.
    * `clearAt`과 `outputConfig`는 `BetaSystemMessageParam`에만 존재하며, `BetaMessageParam::with()`는 다른 두 역할에 대해 이를 제거합니다. `BetaMessageParam\ClearAt` 열거형은 이제 `BetaSystemMessageParam\ClearAt`입니다.
    * `MessageParam\Content`는 이제 `MessageContentParam`이고, `BetaMessageParam\Content`는 이제 `BetaMessageContentParam`입니다. 이들의 PHPStan 타입도 새 이름을 따릅니다: `ContentShape`는 이제 `MessageContentParamShape`입니다.
    * `'role'`이 `Role` 케이스인 배열은 여전히 작동하지만, 이제 PHPStan이 이를 보고합니다. 문자열로 작성하세요.
  </Tab>

  <Tab title="Ruby">
    해시로 작성한 메시지는 변경되지 않습니다.

    v2에서 `Anthropic::MessageParam`은 `Anthropic::UserMessageParam`, `Anthropic::AssistantMessageParam`, `Anthropic::SystemMessageParam`의 유니온입니다. 같은 방식으로 `Anthropic::Beta::BetaMessageParam`은 해당하는 세 클래스의 유니온입니다.

    `Anthropic::MessageParam.new(role: :user, content: "Hello, Claude")`는 여전히 작동하며, 해당 역할의 클래스 인스턴스를 반환합니다. `role:` 없이 `Anthropic::UserMessageParam.new(content: "Hello, Claude")`처럼 해당 클래스를 직접 구성할 수도 있습니다. 이러한 인스턴스를 구성하거나 검사하는 코드에서는 네 가지가 변경됩니다:

    * `MessageParam.new`는 키워드만 받으므로 해시는 `MessageParam.new(**hash)`로 전달하세요. `role:`이 없거나 세 역할 중 하나가 아니면 `ArgumentError`를 발생시킵니다.
    * `message.is_a?(Anthropic::MessageParam)`은 `false`입니다. `when Anthropic::MessageParam` 분기와 `messages.grep(Anthropic::MessageParam)`은 여전히 일치합니다.
    * `.new`로 구성한 인스턴스는 `to_h`에 `:role`이 없으며, `message[:role]`은 `nil`입니다. `message.role`은 여전히 역할을 반환합니다.
    * `BetaSystemMessageParam`만 `clear_at`과 `output_config`를 가집니다. user 또는 assistant 메시지에서 이들은 `nil`을 반환했지만, 이제는 `NoMethodError`를 발생시킵니다.

    ```ruby
    # 변경 전
    typed = messages.select { _1.is_a?(Anthropic::MessageParam) }
    roles = typed.map { _1[:role] }

    # 변경 후
    typed = messages.grep(Anthropic::MessageParam)
    roles = typed.map(&:role)
    ```

    `Role` 열거형 모듈은 유지됩니다. 다음 상수는 이동했습니다. `Beta`로 시작하는 이름은 `Anthropic::Beta` 아래에 있고, 나머지는 `Anthropic` 아래에 있습니다:

    | 제거됨                         | 대신 사용                                                                          |
    | --------------------------- | ------------------------------------------------------------------------------ |
    | `MessageParam::Content`     | `MessageContentParam`, 또는 system 메시지의 경우 `SystemMessageParam::Content`         |
    | `BetaMessageParam::Content` | `BetaMessageContentParam`, 또는 system 메시지의 경우 `BetaSystemMessageParam::Content` |
    | `BetaMessageParam::ClearAt` | `BetaSystemMessageParam::ClearAt`                                              |

    Sorbet으로 타입 검사를 하는 경우, `MessageParam::OrHash`는 사라졌으며 타입으로서의 `Anthropic::MessageParam`은 더 이상 인스턴스를 허용하지 않습니다. 각각 고유한 `OrHash`를 가진 세 클래스에 대해서는 `Anthropic::MessageParam::Variants`를 사용하세요. RBS에서 `Anthropic::MessageParam`으로 타입이 지정된 값에는 `role`이나 `content`가 없습니다. 메시지의 해시 형식이었으며 이제는 세 클래스의 유니온인 `Anthropic::Models::message_param` 별칭을 사용하세요. beta 이름은 `BetaMessageParam::Variants`와 `Anthropic::Models::Beta::beta_message_param`입니다.
  </Tab>
</Tabs>

### 값이 하나뿐인 enum은 상수가 됩니다

이 변경은 C#, Go, Java, PHP, Ruby SDK와 CLI 플래그 하나에 영향을 줍니다. 이전 버전에서는 하나의 값만 가질 수 있는 필수 필드가 멤버가 하나뿐인 자체 enum 타입을 가졌습니다. 이제 이러한 필드는 상수이며, 해당 enum 타입은 제거되었습니다. SDK가 보내고 읽는 JSON은 동일합니다.

<Tabs exclude="shell:cURL, python, typescript">
  <Tab title="CLI">
    `ant beta:sessions:resources add`에서 `--type`은 선택 사항입니다. 이 명령에서 `--type`이 가질 수 있는 값은 `file`뿐이므로 v2가 이를 대신 보냅니다. 여전히 `--type file`을 전달하는 명령도 계속 작동하므로 변경할 것이 없습니다.
  </Tab>

  <Tab title="C#">
    v12에서는 이러한 `required` 속성이 `BetaManagedAgentsTextBlockType.Text`처럼 멤버가 하나뿐인 enum을 가졌습니다. 거의 모두가 `Anthropic.Models.Beta` 아래 클래스의 `Type` 속성입니다: `Agents`, `DeploymentRuns`, `Deployments`, `Dreams`, `Environments`, `MemoryStores`, `Sessions`, `UserProfiles`, `Vaults`. v13에서 이러한 속성은 `TextBlockParam.Type`이 이미 그랬던 것처럼 생성자가 채워 넣는 `JsonElement`입니다.

    `BetaManagedAgentsGlobToolConfigParams.Type`과 같은 선택적 속성은 enum을 유지합니다. 그중 두 enum은 이름이 새로 바뀌었습니다:

    | v12                                         | v13                                       |
    | ------------------------------------------- | ----------------------------------------- |
    | `BetaManagedAgentsBashToolConfigParamsType` | `Anthropic.Models.Beta.Agents.Type`       |
    | `BetaPackagesType`                          | `Anthropic.Models.Beta.Environments.Type` |

    객체를 생성할 때는 해당 속성을 삭제하세요:

    ```csharp
    // 변경 전
    new BetaManagedAgentsTextBlock
    {
        Type = BetaManagedAgentsTextBlockType.Text,
        Text = "Hello Claude!",
    };

    // 변경 후
    new BetaManagedAgentsTextBlock { Text = "Hello Claude!" };
    ```

    필수 속성이 하나만 남은 클래스는 그 속성을 받는 생성자도 새로 갖게 되므로 `new BetaManagedAgentsTextBlock("Hello Claude!")`도 작동합니다. 필수 속성이 하나도 남지 않은 클래스는 `new BetaManagedAgentsAlwaysAllowPolicy()`로 생성합니다.

    값을 읽을 때는 문자열과 비교하세요:

    ```csharp
    // 변경 전
    if (message.Type.Value() == BetaManagedAgentsAgentMessageEventType.AgentMessage) { }

    // 변경 후
    if (message.Type.GetString() == "agent.message") { }
    ```

    union의 변형을 구분하려면 변경되지 않은 `TryPick*`, `Switch`, `Match` 메서드를 계속 사용하세요.
  </Tab>

  <Tab title="Go">
    이러한 enum 타입과 그 상수의 예로는 `BetaManagedAgentsTextBlockType`과 `BetaManagedAgentsTextBlockTypeText`가 있습니다. 거의 모두가 `client.Beta` 아래 구조체의 `Type` 필드입니다: Agents, Deployments, Deployment Runs, Dreams, Environments, Memory Stores, Sessions, User Profiles, Vaults. v2에서 이러한 필드는 `TextBlockParam.Type`이 이미 그랬던 것처럼 `shared/constant` 패키지의 타입을 사용합니다. `BetaManagedAgentsBashToolConfigParams.Type`과 같은 선택적 필드는 enum을 유지합니다.

    요청에서는 해당 필드를 삭제하세요. 필드를 생략하면 그 하나의 값으로 마샬링됩니다:

    ```go
    // 변경 전
    anthropic.BetaManagedAgentsTextBlockParam{
    	Type: anthropic.BetaManagedAgentsTextBlockTypeText,
    	Text: "Hello Claude!",
    }

    // 변경 후
    anthropic.BetaManagedAgentsTextBlockParam{
    	Text: "Hello Claude!",
    }
    ```

    유일한 필드가 그 `Type`이었던 구조체는 이제 `NewBetaManagedAgentsAlwaysAllowPolicyParam()`과 같은 생성자를 갖습니다. union 멤버로는 빈 구조체에 대한 포인터도 작동합니다: `OfAlwaysAllow: &anthropic.BetaManagedAgentsAlwaysAllowPolicyParam{}`.

    응답에서는 문자열과 비교하세요:

    ```go
    // 변경 전
    switch event.Type {
    case string(anthropic.BetaManagedAgentsAgentMessageEventTypeAgentMessage):
    }

    // 변경 후
    switch event.Type {
    case "agent.message":
    }
    ```

    제거된 타입 중 하나로 선언된 사용자의 변수, 필드 또는 매개변수는 `constant.AgentMessage`와 같은 해당 필드의 새 타입을 사용합니다. `constant.ValueOf[constant.AgentMessage]()`는 그 값을 반환합니다.

    union 생성자도 필드와 함께 변경됩니다. 다음 다섯 개는 `type_` 인수가 없어집니다:

    * `BetaManagedAgentsEventParamsOfUserToolConfirmation`
    * `BetaManagedAgentsEventParamsOfUserDefineOutcome`
    * `BetaManagedAgentsDeploymentInitialEventParamsOfUserDefineOutcome`
    * `BetaManagedAgentsMultiagentRosterEntryParamsOfBetaManagedAgentsAgents`
    * `BetaManagedAgentsMultiagentRosterEntryParamsOfBetaManagedAgentsAdvisors`

    다음 네 개는 다른 인수를 받지 않았으므로 제거되었습니다. `BetaManagedAgentsEventParamsUnion{OfUserInterrupt: &anthropic.BetaManagedAgentsUserInterruptEventParams{}}`처럼 union의 필드를 빈 구조체에 대한 포인터로 설정하세요:

    * `BetaManagedAgentsEventParamsOfUserInterrupt`
    * `BetaManagedAgentsMultiagentRosterEntryParamsOfBetaManagedAgentsMultiagentSelfs`
    * `BetaManagedAgentsCredentialNetworkingParamsOfUnrestricted`
    * `BetaOutputBehaviorParamOfCreateNew`
  </Tab>

  <Tab title="Java">
    이러한 enum의 예로는 멤버가 `TEXT` 하나뿐인 중첩 클래스 `BetaManagedAgentsTextBlock.Type`이 있습니다. 거의 모두가 `com.anthropic.models.beta` 아래 클래스의 `type`입니다: `agents`, `deploymentruns`, `deployments`, `dreams`, `environments`, `memorystores`, `sessions`, `userprofiles`, `vaults`. v3에서 이러한 필드는 `TextBlockParam`의 필드가 이미 그랬던 것처럼 빌더가 채워 넣는 `JsonValue`입니다. `BetaManagedAgentsBashToolConfigParams`의 `type`과 같은 선택적 필드는 enum을 유지합니다.

    객체를 생성할 때는 해당 호출을 삭제하세요:

    ```java
    // 변경 전
    BetaManagedAgentsTextBlock block = BetaManagedAgentsTextBlock.builder()
        .type(BetaManagedAgentsTextBlock.Type.TEXT)
        .text("Hello Claude!")
        .build();

    // 변경 후
    BetaManagedAgentsTextBlock block = BetaManagedAgentsTextBlock.builder()
        .text("Hello Claude!")
        .build();
    ```

    필수 필드가 하나만 남은 클래스는 그 필드를 받는 팩토리 메서드도 새로 갖게 되므로 `BetaManagedAgentsTextBlock.of("Hello Claude!")`도 작동합니다. 필수 필드가 하나도 남지 않은 클래스는 `of(type)`이 없어지고, 그 union은 `ofAlwaysAllow(type)`처럼 enum을 받던 오버로드가 없어집니다. `BetaManagedAgentsAlwaysAllowPolicy.builder().build()`로 생성하세요.

    값을 읽을 때는 `type()`이 제거되었으며 `_type()`이 `com.anthropic.core.JsonValue`를 반환합니다:

    ```java
    // 변경 전
    if (message.type().equals(BetaManagedAgentsAgentMessageEvent.Type.AGENT_MESSAGE)) {}

    // 변경 후
    if (message._type().equals(JsonValue.from("agent.message"))) {}
    ```

    union의 변형을 구분하려면 변경되지 않은 `is*()` 및 `as*()` 메서드와 visitor를 계속 사용하세요.
  </Tab>

  <Tab title="PHP">
    이러한 enum case의 예로는 `Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock\Type::TEXT`가 있습니다. 거의 모두가 `Anthropic\Beta` 아래 Managed Agents 클래스의 `type`입니다. 이러한 속성은 이제 `Anthropic\Messages\TextBlockParam`의 `type`이 이미 그랬던 것처럼 그 하나의 값을 기본값으로 갖는 문자열입니다. `Anthropic\Beta\Environments\BetaPackages`의 `type`과 같은 선택적 속성은 enum을 유지합니다.

    `with()`는 더 이상 `type`을 받지 않습니다. 이를 제거하세요: 남아 있는 `type:`에 대해 PHP는 "Unknown named parameter"를 발생시키며, 위치 기반 호출에서는 그 뒤의 인수들이 한 자리씩 앞으로 이동합니다.

    ```php
    // 변경 전
    ManagedAgentsTextBlock::with(text: 'Hello Claude!', type: Type::TEXT);

    // 변경 후
    ManagedAgentsTextBlock::with(text: 'Hello Claude!');
    ```

    enum case와 비교하던 곳에서는 문자열과 비교하세요:

    ```php
    // 변경 전
    $event->type === Type::AGENT_MESSAGE->value;

    // 변경 후
    $event->type === 'agent.message';
    ```

    * `withType()`과 `$client->beta->sessions->resources->add()`의 `type` 인수는 이제 문자열만 받습니다. `add()`에서는 기본값이 `'file'`이므로 생략할 수 있습니다.
    * 배열로 작성하는 요청은 변경되지 않으며, 여전히 `'type'`이 필요합니다.
  </Tab>

  <Tab title="Ruby">
    이러한 enum 상수의 예로는 `Anthropic::Beta::Sessions::BetaManagedAgentsTextBlock::Type::TEXT`가 있습니다. 거의 모두가 `Anthropic::Beta` 아래 Managed Agents 클래스의 `type`입니다. v2에서 이러한 필드는 `Anthropic::TextBlockParam`의 `type`이 이미 그랬던 것처럼 상수로 선언됩니다. `Anthropic::Beta::BetaManagedAgentsGlobToolConfigParams`의 `type`과 같은 선택적 필드는 enum을 유지합니다.

    제거된 상수는 해당 심볼로 바꾸세요:

    ```ruby
    # 변경 전
    event.type == Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent::Type::AGENT_MESSAGE

    # 변경 후
    event.type == :"agent.message"
    ```

    해시로 작성하는 요청은 변경되지 않으며, 여전히 `type`이 필요합니다:

    ```ruby
    client.beta.sessions.events.send_(
      session.id,
      events: [{type: "user.message", content: [{type: "text", text: "Hello Claude!"}]}]
    )
    ```

    모델 인스턴스를 생성할 때 `type:`에는 이제 기본값이 있으므로 생략할 수 있습니다: `Anthropic::Beta::Sessions::BetaManagedAgentsTextBlock.new(text: "Hello Claude!")`. `client.beta.sessions.resources.add`의 `type:` 키워드도 마찬가지입니다.

    Sorbet으로 타입 검사를 하는 경우, 이러한 모듈의 `Type::OrSymbol` 및 `Type::TaggedSymbol` 별칭도 함께 제거되었으며 필드는 `Symbol`입니다. `OrSymbol`은 `String`도 허용했으므로 `.new(type: "text")`는 더 이상 타입 검사를 통과하지 않습니다. 키워드를 제거하거나 `:text`를 전달하세요. RBS에서는 각 클래스의 `type_` 별칭이 제거되었으며, 필드는 `:text`와 같은 리터럴입니다.
  </Tab>
</Tabs>

### 도구 러너에서 클라이언트 측 압축이 제거되었습니다

이 변경은 TypeScript 및 Ruby SDK에 영향을 줍니다. 도구 러너의 클라이언트 측 "compaction"(압축)은 제거되었으며, 대신 클라이언트의 추가 요청 없이 API 내부에서 대화를 요약하는 서버 측 압축을 사용합니다.

<Tabs exclude="shell, python, csharp, go, java, php">
  <Tab title="TypeScript">
    `compactionControl` 옵션과 `@anthropic-ai/sdk/lib/tools/CompactionControl` 모듈이 제거되었습니다. 이 옵션은 v0.129.0에서 작동을 멈췄으며, 이를 전달하면 `AnthropicError`가 발생했습니다. 이 옵션은 params 타입에 없으므로 TypeScript는 이를 알 수 없는 속성으로 보고합니다.

    토큰 임계값에서 계속 자동으로 압축하려면:

    ```typescript
    // 변경 전
    const runner = client.beta.messages.toolRunner({
      // ...
      compactionControl: { enabled: true, contextTokenThreshold: 100_000 }
    });

    // 변경 후
    const runner = client.beta.messages.toolRunner({
      // ...
      betas: ["compact-2026-01-12"],
      context_management: {
        edits: [{ type: "compact_20260112", trigger: { type: "input_tokens", value: 100_000 } }]
      }
    });
    ```

    대화를 압축할 시점을 직접 결정하려면 [`runner.compactBeforeNextTurn()`](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/helpers.md#compaction)을 호출하세요.
  </Tab>

  <Tab title="Ruby">
    `compaction_control:` 옵션이 제거되었습니다. 이 옵션은 v1.74.0에서 작동을 멈췄으며, 이를 전달하면 `ArgumentError`가 발생했습니다.

    토큰 임계값에서 계속 자동으로 압축하려면:

    ```ruby
    # 변경 전
    runner = client.beta.messages.tool_runner(
      # ...
      compaction_control: {enabled: true, context_token_threshold: 100_000}
    )

    # 변경 후
    runner = client.beta.messages.tool_runner(
      # ...
      betas: ["compact-2026-01-12"],
      context_management: {
        edits: [{type: :compact_20260112, trigger: {type: :input_tokens, value: 100_000}}]
      }
    )
    ```

    대화를 압축할 시점을 직접 결정하려면 러너에서 [`#compact_before_next_turn`](https://github.com/anthropics/anthropic-sdk-ruby/blob/main/helpers.md#compact_before_next_turn---compact-the-conversation)을 호출하세요.
  </Tab>
</Tabs>

트리거 임계값은 최소 50,000 토큰이어야 합니다. 다른 옵션(`pause_after_compaction`, 사용자 지정 `instructions`)은 [압축](https://platform.claude.com/docs/ko/build-with-claude/compaction-threshold)을 참조하세요.

### Text Completions가 제거되었습니다

레거시 Text Completions API가 TypeScript, Go, Java, Ruby SDK와 CLI에서 제거되었습니다. 최신 모델과 기능은 이를 지원하지 않습니다. 대신 [Messages API](https://platform.claude.com/docs/ko/api/messages)를 사용하세요.

<Tabs exclude="shell:cURL, python, csharp, php">
  <Tab title="CLI">
    `ant completions create` 명령이 제거되었습니다.

    ```bash
    # 변경 전
    ant completions create \
      --model "$MODEL" \
      --max-tokens-to-sample 1024 \
      --prompt $'\n\nHuman: Hello, Claude\n\nAssistant:'

    # 변경 후
    ant messages create \
      --model "$MODEL" \
      --max-tokens 1024 \
      --message '{role: user, content: "Hello, Claude"}'
    ```

    응답 텍스트는 `completion` 필드에서 `content.0.text`로 이동하므로, `--transform completion`을 전달하던 스크립트는 대신 `--transform content.0.text`를 전달합니다.

    `ant messages create`도 `--stream`을 받지만, 그 이벤트는 형태가 다릅니다: 텍스트는 `content_block_delta` 이벤트의 `delta.text`로 도착하므로 `--transform content.0.text`는 스트림에 적용되지 않습니다.
  </Tab>

  <Tab title="TypeScript">
    `client.completions`가 `Completions` 리소스 클래스 및 `Completion`, `CompletionCreateParams`, `CompletionCreateParamsNonStreaming`, `CompletionCreateParamsStreaming` 타입과 함께 제거되었습니다. `AnthropicBedrock`에도 더 이상 `completions` 속성이 없습니다. Text Completions 프롬프트에서만 사용되던 `HUMAN_PROMPT` 및 `AI_PROMPT` 상수도 export와 클라이언트의 정적 속성 모두에서 제거되었습니다.

    ```typescript
    // 변경 전
    const completion = await client.completions.create({
      model,
      max_tokens_to_sample: 1024,
      prompt: "\n\nHuman: Hello, Claude\n\nAssistant:"
    });
    console.log(completion.completion);

    // 변경 후
    const message = await client.messages.create({
      model,
      max_tokens: 1024,
      messages: [{ role: "user", content: "Hello, Claude" }]
    });
    console.log(message.content);
    ```

    `client.completions.create({ ..., stream: true })`는 `client.messages.create({ ..., stream: true })` 또는 `client.messages.stream({ ... })`가 됩니다.
  </Tab>

  <Tab title="Go">
    `client.Completions`가 `CompletionService`, `NewCompletionService`, `CompletionNewParams`, `Completion`과 함께 제거되었습니다. `aws.Client`에도 더 이상 `Completions` 필드가 없습니다. `bedrock.DefaultEndpoints`는 더 이상 `/v1/complete`를 나열하지 않습니다.

    ```go
    // 변경 전
    completion, err := client.Completions.New(ctx, anthropic.CompletionNewParams{
    	Model:             model,
    	MaxTokensToSample: 1024,
    	Prompt:            "\n\nHuman: Hello, Claude\n\nAssistant:",
    })
    fmt.Println(completion.Completion)

    // 변경 후
    message, err := client.Messages.New(ctx, anthropic.MessageNewParams{
    	Model:     model,
    	MaxTokens: 1024,
    	Messages: []anthropic.MessageParam{
    		anthropic.NewUserMessage(anthropic.NewTextBlock("Hello, Claude")),
    	},
    })
    fmt.Println(message.Content[0].Text)
    ```

    `client.Completions.NewStreaming`은 `client.Messages.NewStreaming`이 됩니다.
  </Tab>

  <Tab title="Java">
    `client.completions()`가 `AnthropicClient` 및 `AnthropicClientAsync`에서 `CompletionService`, `CompletionServiceAsync`, `com.anthropic.models.completions` 패키지(`CompletionCreateParams` 및 `Completion`)와 함께 제거되었습니다.

    ```java
    // 변경 전
    CompletionCreateParams params = CompletionCreateParams.builder()
        .model(model)
        .maxTokensToSample(1024)
        .prompt("\n\nHuman: Hello, Claude\n\nAssistant:")
        .build();

    System.out.println(client.completions().create(params).completion());

    // 변경 후
    MessageCreateParams params = MessageCreateParams.builder()
        .model(model)
        .maxTokens(1024)
        .addUserMessage("Hello, Claude")
        .build();

    client.messages().create(params).content().stream()
        .flatMap(contentBlock -> contentBlock.text().stream())
        .forEach(textBlock -> System.out.println(textBlock.text()));
    ```

    `client.completions().createStreaming`은 `client.messages().createStreaming`이 됩니다.
  </Tab>

  <Tab title="Ruby">
    `client.completions`가 `Anthropic::Resources::Completions`, `Anthropic::CompletionCreateParams`, `Anthropic::Completion`과 함께 제거되었습니다. `Anthropic::BedrockClient`에도 더 이상 `completions` reader가 없습니다. `completions`가 `NotImplementedError`를 발생시키던 `Anthropic::BedrockMantleClient` 및 `Anthropic::GoogleCloudClient`에서는 해당 메서드가 더 이상 존재하지 않습니다.

    ```ruby
    # 변경 전
    completion = client.completions.create(
      model: model,
      max_tokens_to_sample: 1024,
      prompt: "\n\nHuman: Hello, Claude\n\nAssistant:"
    )
    puts(completion.completion)

    # 변경 후
    message = client.messages.create(
      model: model,
      max_tokens: 1024,
      messages: [{role: "user", content: "Hello, Claude"}]
    )
    puts(message.content)
    ```

    `client.completions.create_streaming`은 `client.messages.stream`이 됩니다.
  </Tab>
</Tabs>

### 베타가 아닌 Models 메서드에서 `betas`가 제거되었습니다

베타가 아닌 Models 메서드는 더 이상 `betas` (csharp, go: `Betas`; java: `.addBeta()`)를 받지 않으며, `ant models` 명령은 더 이상 `--beta`를 받지 않습니다. 베타 헤더를 보내려면 `client.beta.models` (csharp, go: `client.Beta.Models`; java: `client.beta().models()`; php: `$client->beta->models`)에서 같은 메서드를 호출하거나, CLI에서 `ant beta:models`를 사용하세요. SDK에서 이러한 메서드는 `BetaModelInfo` (ruby: `Anthropic::Beta::BetaModelInfo`)를 반환하며, 베타가 아닌 메서드는 `ModelInfo` (ruby: `Anthropic::ModelInfo`)를 반환합니다.

<Tabs exclude="shell:cURL">
  <Tab title="CLI">
    ```bash
    # 변경 전
    ant models list --beta "$BETA"

    # 변경 후
    ant beta:models list --beta "$BETA"
    ```
  </Tab>

  <Tab title="Python">
    `client.models.retrieve()` 및 `client.models.list()`는 더 이상 `betas`를 받지 않으며(이를 전달하면 `TypeError`가 발생하고 타입 검사기가 이를 표시합니다), `anthropic.types.ModelListParams`에는 더 이상 `betas` 키가 없습니다.

    ```python
    # 변경 전
    page = client.models.list(betas=[beta])

    # 변경 후
    page = client.beta.models.list(betas=[beta])
    ```
  </Tab>

  <Tab title="TypeScript">
    `Anthropic.ModelRetrieveParams` 및 `Anthropic.ModelListParams`에는 더 이상 `betas` 속성이 없습니다.

    ```typescript
    // 변경 전
    const page = await client.models.list({ betas: [beta] });

    // 변경 후
    const page = await client.beta.models.list({ betas: [beta] });
    ```
  </Tab>

  <Tab title="C#">
    `Anthropic.Models.Models`의 `ModelRetrieveParams` 및 `ModelListParams`에는 더 이상 `Betas` 속성이 없습니다. `client.Beta.Models`의 메서드는 `Anthropic.Models.Beta.Models`에 있는 같은 이름의 클래스를 받습니다.

    ```csharp
    // 변경 전
    using Anthropic.Models.Models;

    var page = await client.Models.List(new ModelListParams { Betas = [beta] });

    // 변경 후
    using Anthropic.Models.Beta.Models;

    var page = await client.Beta.Models.List(new ModelListParams { Betas = [beta] });
    ```
  </Tab>

  <Tab title="Go">
    `ModelGetParams` 및 `ModelListParams`에는 더 이상 `Betas` 필드가 없습니다.

    ```go
    // 변경 전
    page, err := client.Models.List(ctx, anthropic.ModelListParams{
    	Betas: []anthropic.AnthropicBeta{beta},
    })

    // 변경 후
    page, err := client.Beta.Models.List(ctx, anthropic.BetaModelListParams{
    	Betas: []anthropic.AnthropicBeta{beta},
    })
    ```
  </Tab>

  <Tab title="Java">
    `com.anthropic.models.models`의 `ModelRetrieveParams` 및 `ModelListParams`에는 더 이상 `betas()`가 없으며, 그 빌더에도 더 이상 `betas` 및 `addBeta`가 없습니다. `client.beta().models()`의 메서드는 `com.anthropic.models.beta.models`에 있는 같은 이름의 클래스를 받습니다.

    ```java
    // 변경 전
    import com.anthropic.models.models.ModelListPage;
    import com.anthropic.models.models.ModelListParams;

    ModelListPage page = client.models().list(ModelListParams.builder().addBeta(beta).build());

    // 변경 후
    import com.anthropic.models.beta.models.ModelListPage;
    import com.anthropic.models.beta.models.ModelListParams;

    ModelListPage page = client.beta().models().list(ModelListParams.builder().addBeta(beta).build());
    ```
  </Tab>

  <Tab title="PHP">
    `$client->models->retrieve()` 및 `$client->models->list()`는 더 이상 `betas`를 받지 않으며(이를 전달하면 `Error: Unknown named parameter $betas`가 발생합니다), `Anthropic\Models\ModelRetrieveParams` 및 `Anthropic\Models\ModelListParams`에는 더 이상 `betas` 속성이 없습니다.

    ```php
    // 변경 전
    $page = $client->models->list(betas: [$beta]);

    // 변경 후
    $page = $client->beta->models->list(betas: [$beta]);
    ```

    인수를 위치 기반으로 전달하는 경우, 두 메서드 모두에서 `workspaceID`와 `requestOptions`가 각각 한 자리씩 앞으로 이동합니다.
  </Tab>

  <Tab title="Ruby">
    `client.models.retrieve` 및 `client.models.list`는 더 이상 `betas:`를 받지 않으며, `Anthropic::ModelRetrieveParams` 및 `Anthropic::ModelListParams`에는 더 이상 `betas` 필드가 없습니다.

    ```ruby
    # 변경 전
    page = client.models.list(betas: [beta])

    # 변경 후
    page = client.beta.models.list(betas: [beta])
    ```

    `client.models`에 `betas:`를 전달해도 오류가 발생하지는 않지만, 더 이상 `anthropic-beta` 헤더를 설정하지 않습니다.
  </Tab>
</Tabs>

### API 키는 `Authorization: Bearer`로 전송됩니다

SDK와 CLI는 API 키를 `X-Api-Key` 헤더 대신 `Authorization: Bearer <key>`로 전송하므로, `X-Api-Key`를 읽거나 설정하는 프록시 또는 게이트웨이는 `Authorization`을 사용하도록 변경하거나 [키를 직접 `X-Api-Key`로 보내세요](https://platform.claude.com/docs/ko/api/migration-2026-10-21#sdk-proxy-x-api-key). Claude API는 두 헤더 중 어느 쪽의 키든 허용하므로, API와 직접 통신하는 프로그램은 변경할 필요가 없습니다.

```text wrap
# Before
X-Api-Key: <key>

# After
Authorization: Bearer <key>
```

<Tabs>
  <Tab title="CLI">
    이는 `ANTHROPIC_API_KEY`에 있는 키와 `--api-key-stdin`으로 파이프된 키에 적용됩니다.

    `--debug`를 사용하면 요청 로그에 `X-Api-Key: <REDACTED>`가 표시되던 곳에 이제 `Authorization: Bearer <REDACTED>`가 표시됩니다.
  </Tab>

  <Tab title="Python">
    `Authorization`은 `auth_token`이 이미 사용하는 헤더입니다.

    이는 `Anthropic` 및 `AsyncAnthropic`의 `api_key` 인수와 `ANTHROPIC_API_KEY` 환경 변수, 그리고 `AnthropicAWS`의 `api_key` 및 `ANTHROPIC_AWS_API_KEY`에 적용됩니다. `AnthropicFoundry`는 여전히 키를 `x-api-key`로 보내며, `AnthropicBedrockMantle`은 이미 bearer 토큰을 보냈습니다.
  </Tab>

  <Tab title="TypeScript">
    `Authorization`은 `authToken` 옵션이 이미 사용하는 헤더입니다.

    이는 `apiKey` 옵션, `ANTHROPIC_API_KEY` 환경 변수, 그리고 `@anthropic-ai/aws-sdk`의 `apiKey` 및 `ANTHROPIC_AWS_API_KEY`에 적용됩니다. `@anthropic-ai/foundry-sdk`의 `apiKey`는 여전히 `X-Api-Key`로 전송되며, `@anthropic-ai/bedrock-sdk`의 `apiKey`는 이미 bearer 토큰이었습니다.

    `x-api-key` 요청 헤더에서 키를 읽는 미들웨어나 사용자 지정 `fetch`는 대신 `authorization`을 읽어야 하며, 여기서 키는 `Bearer `뒤에 옵니다.
  </Tab>

  <Tab title="C#">
    `Authorization`은 `AuthToken`이 이미 사용하는 헤더입니다.

    이는 `AnthropicClient` 및 `ClientOptions`의 `ApiKey`와 `ANTHROPIC_API_KEY` 환경 변수에 적용됩니다. v13에 의존하는 `Anthropic.Aws` 릴리스에서는 `AwsClientOptions`의 `ApiKey`와 `ANTHROPIC_AWS_API_KEY`에도 적용됩니다. `AnthropicFoundryApiKeyCredentials`는 여전히 키를 `x-api-key`로 보내며, `MantleAwsClientOptions`의 `ApiKey`는 이미 bearer 토큰이었습니다.
  </Tab>

  <Tab title="Go">
    이는 `option.WithAPIKey`, `ANTHROPIC_API_KEY` 환경 변수, 그리고 `aws.ClientConfig`의 `APIKey`(또는 `ANTHROPIC_AWS_API_KEY`)에 적용됩니다. `foundry.ClientConfig`의 `APIKey`(또는 `ANTHROPIC_FOUNDRY_API_KEY`)는 여전히 `X-Api-Key`로 전송되며, `bedrock.MantleClientConfig`의 `APIKey`는 이미 bearer 토큰이었습니다.
  </Tab>

  <Tab title="Java">
    `Authorization`은 `authToken`이 이미 사용하는 헤더입니다.

    이는 `AnthropicOkHttpClient`, `AnthropicOkHttpClientAsync`, `AnthropicBackend` 빌더의 `apiKey`, `ANTHROPIC_API_KEY` 환경 변수, 그리고 `anthropic.apiKey` 시스템 속성에 적용됩니다. `FoundryBackend` 빌더의 `apiKey`는 여전히 `x-api-key`로 전송됩니다. `AwsBackend`, `BedrockBackend`, `BedrockMantleBackend` 빌더의 `apiKey`는 이미 bearer 토큰이었습니다.

    인터셉터는 이제 `X-Api-Key` 대신 `Authorization`에서 키를 보게 됩니다.
  </Tab>

  <Tab title="PHP">
    `Authorization`은 `authToken`이 이미 사용하는 헤더입니다.

    이는 `Anthropic\Client`의 `apiKey` 인수와 `ANTHROPIC_API_KEY` 환경 변수, 그리고 `Anthropic\Aws\Client`의 `apiKey` 및 `ANTHROPIC_AWS_API_KEY`에 적용됩니다. `Anthropic\Foundry\Client`는 여전히 키를 `x-api-key`로 보내며, `Anthropic\Bedrock\MantleClient`는 이미 bearer 토큰을 보냈습니다.
  </Tab>

  <Tab title="Ruby">
    `Authorization`은 `auth_token:`이 이미 사용하는 헤더입니다.

    이는 `Anthropic::Client`의 `api_key:` 인수와 `ANTHROPIC_API_KEY` 환경 변수, 그리고 `Anthropic::AWSClient`의 `api_key:` 및 `ANTHROPIC_AWS_API_KEY`에 적용됩니다. `Anthropic::BedrockMantleClient`는 이미 bearer 토큰을 보냈습니다.

    SDK는 다른 origin으로의 리디렉션을 따를 때 `Authorization`을 제거하며, 여기에는 같은 호스트에서 `http`에서 `https`로의 리디렉션도 포함됩니다. 이제 그 경우에도 키가 제거됩니다.
  </Tab>
</Tabs>

#### 프록시 또는 게이트웨이가 `X-Api-Key`를 읽는 경우

<Tabs exclude="shell:cURL">
  <Tab title="CLI">
    `--base-url` 또는 `ANTHROPIC_BASE_URL`이 `ant`를 `X-Api-Key`를 읽는 프록시나 게이트웨이로 향하게 하는 경우, 해당 프록시나 게이트웨이가 `Authorization`에서 키를 읽도록 변경하세요. `ant`에는 사용자 지정 헤더를 추가하는 플래그나 환경 변수가 없으므로 `X-Api-Key`를 보낼 수 없습니다.
  </Tab>

  <Tab title="Python">
    HTTP 클라이언트의 `auth` 함수로 키를 다시 옮기세요. 이 함수는 재시도를 포함하여 클라이언트가 보내는 모든 요청에서 실행됩니다:

    ```python
    import httpx2
    from anthropic import Anthropic, DefaultHttpxClient


    def send_x_api_key(request: httpx2.Request) -> httpx2.Request:
        if request.headers.get("Authorization") == f"Bearer {api_key}":
            del request.headers["Authorization"]
            request.headers["X-Api-Key"] = api_key
        return request


    client = Anthropic(api_key=api_key, http_client=DefaultHttpxClient(auth=send_x_api_key))
    ```

    `AsyncAnthropic`은 `http_client=DefaultAsyncHttpxClient(auth=send_x_api_key)`에서 같은 함수를 받습니다.
  </Tab>

  <Tab title="TypeScript">
    헤더를 직접 설정하세요. `Authorization: null`은 키가 그쪽으로도 전송되는 것을 막습니다:

    ```typescript
    const client = new Anthropic({
      apiKey,
      defaultHeaders: { "X-Api-Key": apiKey, Authorization: null }
    });
    ```

    프록시가 자격 증명을 추가하고 클라이언트에는 자격 증명이 없는 경우, v0에서는 `defaultHeaders`에 `"X-Api-Key": null` 또는 `Authorization: null` 중 하나로 이를 지정할 수 있었습니다. v1은 `Authorization: null`만 허용합니다.

    environment work poller와 worker는 자체 키를 받으므로, 자체 요청에서 `X-Api-Key` 및 `Authorization` 기본 헤더를 제외합니다.
  </Tab>

  <Tab title="C#">
    `ExtraHeaders`로 헤더를 직접 설정하세요. `ApiKey`와 `AuthToken`을 `null`로 설정하면 `ANTHROPIC_API_KEY` 또는 `ANTHROPIC_AUTH_TOKEN`에서 찾은 자격 증명이 전송되는 것도 막을 수 있습니다:

    ```csharp
    AnthropicClient client = new(
        new ClientOptions
        {
            ApiKey = null,
            AuthToken = null,
            ExtraHeaders = new Dictionary<string, string> { ["X-Api-Key"] = apiKey },
        }
    );
    ```
  </Tab>

  <Tab title="Go">
    헤더를 직접 설정하세요. `option.WithHeaderDel`은 `ANTHROPIC_API_KEY`에서 찾은 키가 전송되는 것도 막습니다:

    ```go
    client := anthropic.NewClient(
    	option.WithHeader("X-Api-Key", apiKey),
    	option.WithHeaderDel("Authorization"),
    )
    ```

    `environments.WorkPoller`와 `environments.EnvironmentWorker`는 자체 키를 받으므로, 자체 요청에서 직접 설정한 `X-Api-Key`를 제외합니다.
  </Tab>

  <Tab title="Java">
    `apiKey`를 호출하는 대신 헤더를 직접 설정하세요:

    ```java
    AnthropicClient client = AnthropicOkHttpClient.builder()
        .putHeader("X-Api-Key", apiKey)
        .build();
    ```
  </Tab>

  <Tab title="PHP">
    미들웨어로 키를 다시 옮기세요:

    ```php
    use Anthropic\Client;
    use Psr\Http\Message\RequestInterface;
    use Psr\Http\Message\ResponseInterface;

    $sendXApiKey = fn (RequestInterface $request, callable $next): ResponseInterface => $next(
        $request->withoutHeader('Authorization')->withHeader('X-Api-Key', $apiKey)
    );

    $client = new Client(apiKey: $apiKey, requestOptions: ['middleware' => [$sendXApiKey]]);
    ```

    이를 위해 클라이언트의 `extraHeaders`를 사용하지 마세요. 자체 `extraHeaders`가 있는 요청은 클라이언트의 것을 대체하며, 베타 헤더가 필요한 `$client->beta` 아래의 모든 엔드포인트에는 자체 `extraHeaders`가 있습니다.
  </Tab>

  <Tab title="Ruby">
    미들웨어로 키를 다시 옮기세요:

    ```ruby
    send_x_api_key = lambda do |req, nxt|
      next nxt.call(req) unless req.headers["authorization"] == "Bearer #{api_key}"
      nxt.call(req.with(headers: {**req.headers.except("authorization"), "x-api-key" => api_key}))
    end

    client = Anthropic::Client.new(api_key: api_key, middleware: send_x_api_key)
    ```

    첫 번째 줄은 다른 origin으로 리디렉션된 요청처럼 키를 포함하지 않는 요청은 그대로 둡니다.

    `Anthropic::AWSClient`는 `middleware:` 인수를 받지 않습니다. 대신 각 요청에 `request_options: {middleware: send_x_api_key}`로 미들웨어를 전달하세요.
  </Tab>
</Tabs>

#### 요청에서 `X-Api-Key`를 설정하거나 제거한 경우

이 변경은 Python, TypeScript, Go, PHP, Ruby SDK에 영향을 줍니다.

요청이 인증 토큰만 보내도록 `X-Api-Key`를 제거했다면, 해당 코드를 변경하는 대신 삭제하세요. `Authorization`을 제거하면 토큰이 제거되기 때문입니다. [클라이언트는 하나의 자격 증명을 보유하므로](https://platform.claude.com/docs/ko/api/migration-2026-10-21#sdk-one-credential) 그것이 토큰인지 확인하세요: 코드에서 아무것도 전달하지 않고 `ANTHROPIC_API_KEY`와 `ANTHROPIC_AUTH_TOKEN`이 모두 설정되어 있으면 클라이언트는 키를 사용합니다.

<Tabs exclude="shell, csharp, java">
  <Tab title="Python">
    요청에서 키를 제외하기 위해 `extra_headers={"X-Api-Key": omit}`를 전달하는 코드는 더 이상 그렇게 동작하지 않습니다. 대신 `extra_headers={"Authorization": omit}`를 전달하세요.

    `extra_headers={"X-Api-Key": other_key}`는 더 이상 클라이언트의 키를 대체하지 않습니다: 두 키가 모두 전송됩니다. 하나의 요청에 다른 키를 보내려면 `extra_headers={"Authorization": f"Bearer {other_key}"}`를 전달하세요.
  </Tab>

  <Tab title="TypeScript">
    요청 옵션의 `headers: { "X-Api-Key": otherKey }`는 더 이상 클라이언트의 키를 대체하지 않습니다: 두 키가 모두 전송됩니다. 하나의 요청에 다른 키를 보내려면 ``headers: { Authorization: `Bearer $\{otherKey}` }``를 전달하세요.
  </Tab>

  <Tab title="Go">
    `option.WithHeaderDel("X-Api-Key")`는 더 이상 요청에서 키를 제외하지 않습니다. 대신 `Authorization`을 삭제하세요:

    ```go
    // 변경 전
    client.Messages.New(ctx, params, option.WithHeaderDel("X-Api-Key"))

    // 변경 후
    client.Messages.New(ctx, params, option.WithHeaderDel("Authorization"))
    ```

    `option.WithHeader("X-Api-Key", otherKey)`는 더 이상 클라이언트의 키를 대체하지 않습니다: 두 키가 모두 전송됩니다. 하나의 요청에 다른 키를 보내려면 `option.WithAPIKey(otherKey)`를 전달하세요.
  </Tab>

  <Tab title="PHP">
    `'extraHeaders' => ['X-Api-Key' => null]`은 더 이상 요청에서 키를 제외하지 않습니다. 자격 증명 없이 요청을 보내려면 대신 `Authorization`을 `null`로 설정하거나, 클라이언트 전체에 대해 이렇게 했다면 미들웨어에서 제거하세요.

    `'extraHeaders' => ['X-Api-Key' => $otherKey]`는 더 이상 클라이언트의 키를 대체하지 않습니다: 두 키가 모두 전송됩니다. 하나의 요청에 다른 키를 보내려면 `Authorization`을 `"Bearer {$otherKey}"`로 설정하세요.
  </Tab>

  <Tab title="Ruby">
    `extra_headers: {"x-api-key" => nil}`은 더 이상 요청에서 키를 제외하지 않습니다. 대신 `"authorization"`을 `nil`로 설정하세요. 하나의 요청에 다른 키를 보내려면 `"x-api-key"`가 아니라 `"authorization"`을 `"Bearer #{other_key}"`로 설정하세요.
  </Tab>
</Tabs>

### 클라이언트는 하나의 자격 증명을 보유합니다

이제 API 키와 인증 토큰이 하나의 헤더를 공유하므로, SDK 클라이언트는 하나의 자격 증명을 보유합니다. 코드에서 아무것도 전달하지 않으면 [자격 증명 우선순위](https://platform.claude.com/docs/ko/manage-claude/wif-reference#credential-precedence) 순서를 따릅니다.

<Tabs exclude="shell">
  <Tab title="Python">
    v1은 클라이언트가 API 키와 인증 토큰을 모두 가지고 있을 때 각각 별도의 헤더로 둘 다 전송했습니다. 자격 증명은 `api_key`, `auth_token`, `credentials`, `config`, `profile` 중 하나입니다.

    * **최대 하나만 전달하세요.** 생성자에서, 또는 한 번의 `copy()`나 `with_options()` 호출에서 두 개 이상을 전달하면 `ValueError`가 발생합니다. `None`은 개수에 포함되지 않습니다. v1은 `TypeError`를 발생시켰으며, 그것도 `credentials`, `config`, `profile` 중 두 개를 전달한 경우에만 발생시켰습니다.
    * **전달한 것이 유일한 자격 증명입니다.** v1과 마찬가지로, 클라이언트는 환경이나 디스크에서 다른 자격 증명을 찾지 않습니다.
    * **아무것도 전달하지 않으면, 다음 중 설정된 첫 번째 항목만 사용됩니다:** `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_PROFILE`이 지정하는 프로필, 워크로드 아이덴티티 페더레이션 변수, 디스크의 활성 프로필(`active_config` 파일이 지정하는 프로필, 없으면 `default`). 처음 두 항목이 모두 설정되어 있으면 클라이언트는 경고를 한 번 기록합니다. v1은 `ANTHROPIC_CONFIG_DIR`이 설정되어 있거나 `active_config` 파일이 존재할 때 페더레이션 변수보다 활성 프로필을 먼저 사용했습니다. 계속 활성 프로필을 사용하려면 `ANTHROPIC_PROFILE`을 설정하세요.
    * **`copy()`와 `with_options()`는 대체합니다.** 전달한 자격 증명은 종류에 관계없이 클라이언트 자체의 자격 증명을 대체합니다. 이전 자격 증명의 config나 profile에서 온 기본 URL과 헤더는 함께 제거되고, 새 자격 증명의 것이 사용됩니다. 직접 전달한 기본 URL은 유지됩니다.

    ```python
    client = Anthropic(api_key=key, auth_token=token)

    # 이전: `X-Api-Key: <key>` 및 `Authorization: Bearer <token>`을 함께 전송했습니다
    # 이후: `ValueError`를 발생시킵니다
    ```

    플랫폼 클라이언트는 자체 규칙을 유지합니다. `AnthropicAWS`는 `api_key`와 함께 `auth_token`을 받아도 오류가 발생하지 않으며, 키를 전송합니다.

    자세한 내용은 [`_client.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_client.py)에 있는 `Anthropic.__init__`과 `Anthropic.copy`의 docstring을 참조하세요.

    예를 들어 게이트웨이용 토큰과 그 뒤의 API용 키처럼 둘 다 전송하는 방식에 의존했다면, 토큰을 `auth_token`으로 전달하고 `default_headers`에 `X-Api-Key`를 설정하세요. 게이트웨이가 요청을 전달하기 전에 `Authorization` 헤더를 제거하도록 하세요. Claude API는 요청당 하나의 자격 증명을 기대합니다.
  </Tab>

  <Tab title="TypeScript">
    v0에서는 API 키와 인증 토큰을 모두 가진 클라이언트가 각각 별도의 헤더로 둘 다 전송했습니다. 자격 증명은 `apiKey`, `authToken`, `credentials`, `config`, `profile` 중 하나입니다.

    * **최대 하나만 전달하세요.** `new Anthropic()`에서, 또는 한 번의 `withOptions()` 호출에서 두 개 이상을 전달하면 `TypeError`가 발생합니다. `null`과 `undefined`는 개수에 포함되지 않습니다.
    * **전달한 것이 유일한 자격 증명입니다.** 클라이언트는 환경이나 디스크에서 다른 자격 증명을 찾지 않습니다.
    * **아무것도 전달하지 않으면, 다음 중 첫 번째 항목이 사용됩니다:** `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_PROFILE`이 지정하는 프로필, 워크로드 아이덴티티 페더레이션 변수, 디스크의 활성 프로필(`active_config` 파일이 지정하는 프로필, 없으면 `default`). 처음 두 항목이 모두 설정되어 있으면 클라이언트는 경고를 한 번 기록합니다. v0에서는 활성 프로필이 페더레이션 변수보다 먼저였습니다. 존재하지 않는 프로필을 지정하는 `ANTHROPIC_PROFILE`은 v0에서는 건너뛰었지만, 이제는 첫 번째 요청에서 `AnthropicError`가 발생합니다. 인수 없이 호출한 `loadConfig()`도 같은 순서를 따르며 같은 오류를 발생시킵니다.
    * **`withOptions`는 대체합니다.** 전달한 자격 증명은 복사하는 클라이언트의 자격 증명을 대체하므로, `client.withOptions({ authToken })`에 더 이상 `apiKey: null`을 함께 지정할 필요가 없습니다.
    * **플랫폼 클라이언트는 해당 플랫폼의 자격 증명만 받습니다.** AWS, Bedrock, Foundry 클라이언트와 `AnthropicVertex`는 인증에 사용하지 않는 자격 증명 옵션에 대해 `AnthropicError`를 발생시키며, 이는 `AnthropicGoogleCloud`가 이미 하던 방식과 같습니다. AWS 및 Bedrock 클라이언트에서 `apiKey: null`은 이제 키를 지우므로, 클라이언트는 AWS 자격 증명으로 서명합니다. `AnthropicBedrock`은 키를 `client.apiKey`에 보관하며, v0에서는 `client.authToken`에 보관했습니다.

    ```typescript
    // 이전: API 키를 전송하고 `credentials`를 무시했습니다
    const client = new Anthropic({ apiKey, credentials });

    // 이후: 위 줄에서 TypeError가 발생합니다
    const client = new Anthropic({ credentials });
    ```

    [`ClientOptions`](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/src/client.ts)의 doc comment에서 각 옵션의 동작을 설명하며, 해당 플랫폼 클라이언트 각각의 생성자에 있는 doc comment에는 거부하는 옵션이 나열되어 있습니다.

    예를 들어 게이트웨이용 토큰과 그 뒤의 API용 키처럼 둘 다 전송하는 방식에 의존했다면, `defaultHeaders`에 `X-Api-Key`를 설정하고 `authToken`은 유지하세요. 게이트웨이가 요청을 전달하기 전에 `Authorization` 헤더를 제거하도록 하세요. Claude API는 요청당 하나의 자격 증명을 기대합니다.
  </Tab>

  <Tab title="C#">
    v12에서는 API 키와 인증 토큰을 모두 가진 클라이언트가 각각 별도의 헤더로 둘 다 전송했습니다. 자격 증명은 `ApiKey`, `AuthToken`, `ClientOptions.Credentials` 중 하나입니다.

    * **두 개를 전달하면 오류입니다.** 두 번째 자격 증명을 설정하면 `ArgumentException`이 발생합니다. `null`은 개수에 포함되지 않으므로, 직접 만든 `ClientOptions`에서 자격 증명을 교체하려면 먼저 이전 자격 증명을 `null`로 설정하세요.
    * **하나를 전달하면 그것을 사용하고 환경은 무시합니다.** 자격 증명 환경 변수나 디스크의 프로필을 읽지 않습니다. 마찬가지로, `AnthropicCredentials.Resolve(profile: "name")`은 이제 `ANTHROPIC_API_KEY`나 `ANTHROPIC_AUTH_TOKEN`이 설정되어 있어도 해당 프로필의 자격 증명을 반환합니다.
    * **아무것도 전달하지 않으면 환경에서 처음 일치하는 항목을 사용합니다:** `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_PROFILE`, 워크로드 아이덴티티 페더레이션 변수, 그다음 디스크의 활성 프로필. 비어 있는 `ANTHROPIC_API_KEY`나 `ANTHROPIC_AUTH_TOKEN`은 설정되지 않은 것으로 간주됩니다. 처음 두 항목이 모두 설정되어 있으면 stderr에 경고가 한 번 출력됩니다. 클라이언트는 처음 사용될 때 확인하므로, 존재하지 않는 `ANTHROPIC_PROFILE`은 이제 생성자 대신 첫 번째 요청에서 예외를 발생시킵니다.
    * **`WithOptions`는 대체합니다.** modifier에서 전달한 자격 증명은 종류에 관계없이 클라이언트의 자격 증명을 대체하므로, `AuthToken = token`에 더 이상 `ApiKey = null`을 함께 지정할 필요가 없습니다. 아무것도 전달하지 않으면, modifier가 새 `ClientOptions`를 반환하더라도 복사본은 클라이언트의 자격 증명, `BaseUrl`, `ExtraHeaders`를 유지합니다.

    ```csharp
    // 이전: 둘 다 각각 별도의 헤더로 전송했습니다
    AnthropicClient client = new() { ApiKey = apiKey, AuthToken = token };

    // 이후: 위 줄에서 ArgumentException이 발생합니다
    AnthropicClient client = new() { AuthToken = token };
    ```

    자세한 내용은 [`ClientOptions`](https://github.com/anthropics/anthropic-sdk-csharp/blob/main/src/Anthropic/Core/ClientOptions.cs)의 해당 세 속성에 대한 XML 문서를 참조하세요.

    클라우드 플랫폼 클라이언트는 생성 시 사용한 자격 증명을 유지합니다. Bedrock, Bedrock Mantle, Foundry, Google Cloud, AWS 클라이언트와 `AnthropicVertexClient`는 생성 시점에 인증 방식을 결정하며, 대부분 이를 위해 `Authorization` 헤더를 사용합니다. v13에 의존하는 이 패키지들의 릴리스는 `WithOptions`를 통해 설정한 `ApiKey`나 `AuthToken`을 무시합니다. `AnthropicAwsClient`에서 다른 키를 사용하려면 `AwsClientOptions`에 `ApiKey`를 지정하여 새 클라이언트를 생성하세요.

    예를 들어 게이트웨이용 토큰과 그 뒤의 API용 키처럼 둘 다 전송하는 방식에 의존했다면, `ExtraHeaders`로 `X-Api-Key`를 설정하고 `AuthToken`은 유지하세요. 게이트웨이가 요청을 전달하기 전에 `Authorization` 헤더를 제거하도록 하세요. Claude API는 요청당 하나의 자격 증명을 기대합니다.
  </Tab>

  <Tab title="Go">
    v1에서는 API 키와 인증 토큰을 모두 가진 클라이언트가 각각 별도의 헤더로 둘 다 전송했습니다. 자격 증명은 `option.WithAPIKey`, `option.WithAuthToken`, `option.WithConfig`, `option.WithProfile`, `option.WithFederationTokenProvider` 중 하나에서 옵니다.

    * **`anthropic.NewClient`에 이 중 두 개를 전달하면 오류입니다.** `NewClient`는 오류를 반환하지 않으므로, 클라이언트가 보내는 모든 요청이 해당 오류로 실패합니다. `NewClient`는 이미 `anthropic.DefaultClientOptions()`를 적용하므로, 그 결과를 추가로 전달하지 마세요. 그렇게 하면 환경에서 찾은 자격 증명이 직접 전달한 것으로 간주됩니다.
    * **이 중 하나는 그대로 사용됩니다.** 환경이나 디스크의 프로필에서 자격 증명을 읽지 않습니다. v1에서는 `ANTHROPIC_API_KEY`와 `ANTHROPIC_AUTH_TOKEN`이 마지막 세 가지보다 우선했습니다.
    * **아무것도 없으면, 다음 중 설정된 첫 번째 항목이 사용되며,** 순서는 v1과 같습니다: `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_PROFILE`, 워크로드 아이덴티티 페더레이션 변수, 디스크의 활성 프로필. 처음 두 항목이 모두 설정되어 있으면 SDK는 경고를 한 번 기록합니다.
    * **요청에 이 중 하나를 지정하면 해당 요청에 대해 클라이언트의 자격 증명을 대체하므로,** `option.WithAuthToken`에 더 이상 `option.WithHeaderDel("X-Api-Key")`를 함께 지정할 필요가 없습니다.

    ```go
    // 이전: API 키가 전송되고 경고가 로그에 기록되었습니다
    client := anthropic.NewClient(
    	option.WithAPIKey(apiKey),
    	option.WithProfile("work"),
    )

    // 이후: 위 클라이언트의 모든 요청이 실패하므로 원하는 것을 전달하세요
    client := anthropic.NewClient(option.WithAPIKey(apiKey))
    ```

    v1이 기록하던 경고가 없어졌으므로, 이를 억제하던 `option.WithConfigQuiet`는 이제 `option.WithConfig`와 같은 동작을 하며 지원 중단되었습니다.

    자세한 내용은 [`client.go`](https://github.com/anthropics/anthropic-sdk-go/blob/main/client.go)에 있는 `anthropic.NewClient`와 `anthropic.DefaultClientOptions`의 doc comment를 참조하세요.

    예를 들어 게이트웨이용 토큰과 그 뒤의 API용 키처럼 둘 다 전송하는 방식에 의존했다면, `option.WithHeader`로 `X-Api-Key`를 설정하고 `option.WithAuthToken`은 유지하세요. 게이트웨이가 요청을 전달하기 전에 `Authorization` 헤더를 제거하도록 하세요. Claude API는 요청당 하나의 자격 증명을 기대합니다.

    `ANTHROPIC_CUSTOM_HEADERS`와 `ANTHROPIC_WEBHOOK_SIGNING_KEY`는 이제 `anthropic.NewClient`가 생성하는 모든 클라이언트에 적용됩니다. v1에서는 환경과 디스크의 프로필 어디에도 자격 증명이 없을 때만 읽혔습니다.
  </Tab>

  <Tab title="Java">
    v2에서는 API 키와 인증 토큰을 모두 가진 클라이언트가 각각 별도의 헤더로 둘 다 전송했습니다. 자격 증명은 `AnthropicOkHttpClient`, `AnthropicOkHttpClientAsync`, `AnthropicBackend` 빌더의 `apiKey`, `authToken`, `configurationProvider` 중 하나입니다.

    * **최대 하나만 설정하세요.** 하나의 빌더에 두 개를 설정하면 `build()`가 해당 항목들을 명시한 `IllegalStateException`을 발생시킵니다. `null`이나 빈 `Optional`은 개수에 포함되지 않습니다.
    * **설정한 것이 유일한 자격 증명입니다.** `fromEnv()`는 그 전에 호출하든 후에 호출하든 환경이나 디스크의 프로필에서 자격 증명을 가져오지 않습니다. v2에서는 `fromEnv()`가 찾은 키나 토큰이 함께, 또는 대신 전송될 수 있었습니다.
    * **아무것도 설정하지 않으면, `fromEnv()`는 다음 중 처음 찾은 항목을 사용합니다:** `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_PROFILE`, 워크로드 아이덴티티 페더레이션 변수, 디스크의 활성 프로필. 처음 두 항목이 모두 설정되어 있으면 `System.err`에 경고가 한 번 출력됩니다. `anthropic.apiKey`와 `anthropic.authToken` 시스템 속성은 환경으로 간주됩니다. 변수나 시스템 속성에 있는 빈 키나 토큰은 설정되지 않은 것으로 간주됩니다. v2에서는 `fromEnv()`가 빈 값을 키나 토큰으로 사용했습니다.

    ```java
    // 이전: 둘 다 전송되었습니다. v3에서는 build()가 IllegalStateException을 발생시킵니다
    AnthropicClient client = AnthropicOkHttpClient.builder()
        .apiKey(apiKey)
        .authToken(authToken)
        .build();

    // 이후
    AnthropicClient client = AnthropicOkHttpClient.builder()
        .apiKey(apiKey)
        .build();
    ```

    자세한 내용은 해당 빌더의 `fromEnv()` 문서를 참조하세요.

    예를 들어 게이트웨이용 토큰과 그 뒤의 API용 키처럼 둘 다 전송하는 방식에 의존했다면, 두 헤더를 직접 설정하세요:

    ```java
    AnthropicClient client = AnthropicOkHttpClient.builder()
        .putHeader("Authorization", "Bearer " + gatewayToken)
        .putHeader("X-Api-Key", apiKey)
        .build();
    ```

    게이트웨이가 요청을 전달하기 전에 `Authorization` 헤더를 제거하도록 하세요. Claude API는 요청당 하나의 자격 증명을 기대합니다.
  </Tab>

  <Tab title="PHP">
    이전 버전은 클라이언트가 API 키와 인증 토큰을 모두 가지고 있을 때 각각 별도의 헤더로 둘 다 전송했습니다. `Anthropic\Client`는 `apiKey`, `authToken`, `credentials` 중 하나에서 하나의 자격 증명을 받습니다:

    * 이 중 두 개 이상을 전달하면 `\InvalidArgumentException`이 발생합니다. `null`만 전달하지 않은 것으로 간주됩니다. 빈 문자열은 전달한 것으로 간주되므로, `new Client(apiKey: '')`는 자격 증명을 전송하지 않습니다.
    * 하나를 전달하면 그것을 사용하며, 환경이나 디스크의 프로필에서 자격 증명을 읽지 않습니다. `ANTHROPIC_API_KEY`가 설정된 상태에서 `new Client(authToken: $token)`은 토큰을 전송합니다. 이전 버전은 환경의 키도 함께 전송했습니다.
    * 아무것도 전달하지 않으면 다음 중 설정된 첫 번째 항목을 사용합니다: `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_PROFILE`이 지정하는 프로필, 워크로드 아이덴티티 페더레이션 변수, 디스크의 활성 프로필(`active_config` 파일이 지정하는 프로필, 없으면 `default`). 이전 버전은 페더레이션 변수보다 활성 프로필을 먼저 사용했으며, `active_config` 파일이 없으면 프로필을 사용하지 않았습니다. 또한 존재하지 않거나 유효하지 않은 프로필을 지정하는 `ANTHROPIC_PROFILE`은 건너뛰었습니다. 이 경우 이제 `new Client()`가 `Anthropic\Core\Exceptions\AnthropicException`을 발생시킵니다. `ANTHROPIC_API_KEY`와 `ANTHROPIC_AUTH_TOKEN`이 모두 설정되어 있으면, 클라이언트는 키를 전송하고 `authToken` 속성은 비어 있습니다. 이렇게 생성된 첫 번째 클라이언트는 또한 프로세스당 한 번(웹 서버에서는 요청당 한 번) `error_log()`로 경고를 기록합니다: `Anthropic: ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN are both set. Using ANTHROPIC_API_KEY.` 이를 중지하려면 사용하지 않는 변수를 설정 해제하세요.

    ```php
    // 이전: 키를 X-Api-Key로, 토큰을 Authorization으로 전송했습니다.
    // 이후: "Pass at most one of `apiKey`, `authToken`, or `credentials`. Received `apiKey`, `authToken`." 오류를 발생시킵니다.
    $client = new Client(apiKey: $key, authToken: $token);
    ```

    예를 들어 게이트웨이용 토큰과 그 뒤의 API용 키처럼 둘 다 전송하는 방식에 의존했다면, 토큰을 `authToken`으로 전달하고 [프록시나 게이트웨이가 `X-Api-Key`를 읽는 경우](https://platform.claude.com/docs/ko/api/migration-2026-10-21#sdk-proxy-x-api-key)에 있는 것과 같은 미들웨어에서 `withoutHeader` 호출 없이 `X-Api-Key`를 추가하세요. 게이트웨이가 요청을 전달하기 전에 `Authorization` 헤더를 제거하도록 하세요. Claude API는 요청당 하나의 자격 증명을 기대합니다.
  </Tab>

  <Tab title="Ruby">
    `Anthropic::Client.new`의 자격 증명 인수는 `api_key:`, `auth_token:`, `credentials:`, `config:`입니다. `nil` 인수는 전달하지 않은 것으로 간주됩니다. 플랫폼 클라이언트는 자체 규칙을 유지합니다.

    * **두 개 이상 전달한 경우:** `Anthropic::Client.new`가 `ArgumentError`를 발생시킵니다. 이전 버전은 `credentials:`와 `config:`를 함께 전달한 경우에만 오류를 발생시켰고, 그 외에는 키가 있으면 키를, 그다음 토큰을 전송했습니다.
    * **하나를 전달한 경우:** 클라이언트는 그것을 사용하며, 환경이나 디스크의 프로필에 있는 자격 증명으로 대체하지 않습니다.
    * **아무것도 전달하지 않은 경우:** 클라이언트는 다음 중 처음 찾은 항목을 사용합니다: `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_PROFILE`, 워크로드 아이덴티티 페더레이션 변수, 디스크의 활성 프로필. 순서는 바뀌지 않았지만, `ANTHROPIC_API_KEY`와 `ANTHROPIC_AUTH_TOKEN`이 모두 설정되어 있으면 이제 `client.auth_token`은 `nil`입니다. 비어 있는 `ANTHROPIC_API_KEY`나 `ANTHROPIC_AUTH_TOKEN`은 이제 설정되지 않은 것으로 간주되며, 이전 버전에서는 비어 있는 `ANTHROPIC_API_KEY`가 토큰과 그 이후의 모든 항목을 가렸습니다.

    자격 증명을 전달하지 않았고 `ANTHROPIC_API_KEY`와 `ANTHROPIC_AUTH_TOKEN`이 모두 설정되어 있으면, SDK는 또한 프로세스당 한 번 `Kernel#warn`을 통해 표준 오류에 경고를 출력합니다: `Anthropic: ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN are both set. Using ANTHROPIC_API_KEY.` 이를 없애려면 사용하지 않는 변수를 설정 해제하세요.

    ```ruby
    # 이전: 키를 전송하고 토큰은 무시했습니다.
    # 이후: ArgumentError, "Pass at most one of `api_key:`, `auth_token:`, `credentials:`, or `config:`. Received `api_key:`, `auth_token:`."
    Anthropic::Client.new(api_key: api_key, auth_token: auth_token)

    # 전송하려는 것 하나만 전달하세요.
    Anthropic::Client.new(api_key: api_key)
    ```
  </Tab>
</Tabs>

### 하나의 SDK 또는 CLI의 변경 사항

이 변경 사항들은 각각 하나의 SDK 또는 CLI에 영향을 줍니다.

<Tabs exclude="shell:cURL, python, typescript, go, ruby">
  <Tab title="CLI">
    **`--api-key`와 `--auth-token`이 제거되었습니다.** 명령줄의 값은 셸 기록과 프로세스 목록에 노출되므로, `ant`는 더 이상 API 키나 인증 토큰을 플래그 값으로 받지 않습니다. 두 플래그 모두 v1.27.0부터 지원 중단 경고를 출력해 왔습니다. 여전히 이 중 하나를 전달하는 명령은 `flag provided but not defined`와 함께 중지됩니다.

    | 제거됨                    | 대신 사용                                                      |
    | ---------------------- | ---------------------------------------------------------- |
    | `--api-key <key>`      | `ANTHROPIC_API_KEY`, `--api-key-stdin` 또는 `ant auth login` |
    | `--auth-token <token>` | `ANTHROPIC_AUTH_TOKEN` 또는 `--auth-token-stdin`             |

    ```bash
    # 변경 전
    ant --api-key "$KEY" models list

    # 변경 후, 환경 변수에서 가져오기
    export ANTHROPIC_API_KEY="$KEY"
    ant models list

    # 변경 후, 시크릿 관리자에서 가져오기
    op read op://vault/anthropic/api-key | ant --api-key-stdin models list
    ```

    `--api-key-stdin`과 `--auth-token-stdin`은 표준 입력 전체를 읽으므로, 이 중 하나를 사용하는 명령은 요청 본문을 플래그에서 가져옵니다.

    `ant auth status`, `ant apply`의 첫 실행 프롬프트, 그리고 여러 인증 소스에 대한 안내는 이제 이 자격 증명을 `ANTHROPIC_API_KEY`와 `ANTHROPIC_AUTH_TOKEN`으로 표시하며, 이전에는 `--api-key / ANTHROPIC_API_KEY`와 `--auth-token / ANTHROPIC_AUTH_TOKEN`으로 출력했습니다.
  </Tab>

  <Tab title="C#">
    **유니온의 `Type`은 enum입니다.** v12에서는 `ContentBlock.Type`이나 `RawMessageStreamEvent.Type`과 같은 유니온 클래스의 `Type` 속성이 `JsonElement`였습니다. v13에서는 `ApiEnum<string, T>`이며, 여기서 `T`는 `ContentBlockType`처럼 각 variant마다 하나의 멤버를 가진 새 enum입니다. `BetaMemoryTool20250818Command.Command`처럼 일부 유니온은 대신 `Name`이나 `Command`로 구분되며, 해당 속성도 같은 방식으로 변경됩니다. `TextBlock.Type`과 같은 variant 클래스의 `Type`은 여전히 `JsonElement`입니다.

    ```csharp
    // 변경 전
    if (block.Type.GetString() == "tool_use") { }

    // 변경 후
    if (block.Type.Value() == ContentBlockType.ToolUse) { }
    ```

    `block.Type.Raw()`는 이 버전의 SDK에 enum 멤버가 없는 문자열을 포함하여 문자열을 반환합니다.

    **`IChatClient`는 샘플링 옵션을 무시합니다.** `IChatClient` 어댑터(`AsIChatClient()`)는 이제 `ChatOptions.Temperature`, `ChatOptions.TopK`, `ChatOptions.TopP`를 무시합니다. [샘플링 매개변수가 제거되었습니다](https://platform.claude.com/docs/ko/api/migration-2026-10-21#sampling-parameters)를 참조하세요.
  </Tab>

  <Tab title="Java">
    **이제 `Optional`을 반환하는 getter.** `AnthropicBackend`의 `apiKey()`와 `authToken()`은 이제 `Optional<String>`을 반환하며, 이는 `AwsBackend`와 `BedrockMantleBackend`의 `apiKey()`가 이미 하던 방식과 같습니다. v2에서는 각각 `String`을 반환했으며, 백엔드에 해당 종류의 자격 증명이 없으면 `null`이었습니다.

    ```java
    // 변경 전
    String apiKey = backend.apiKey();
    if (apiKey != null) {}

    // 변경 후
    Optional<String> apiKey = backend.apiKey();
    if (apiKey.isPresent()) {}
    ```

    다음 getter들도 이제 `Optional`을 반환합니다. v2에서는 각각 값 자체를 반환했으며, 값이 없으면 `null`이었습니다:

    * `BedrockBackend`의 `apiKey()`와 `awsCredentialsProvider()`
    * `McpResourceFile`의 `filename()`과 `mimeType()`
    * `CredentialSource`의 `detail()`
    * `HttpRequest`의 `body()`
    * `FoundryBackend`의 `resource()`(이전의 `getResource()`)
    * `RequestOptions`의 `responseValidation()`, `timeout()`, `followRedirects()`, `fallbackState()`, `openTelemetry()`(이전의 `getResponseValidation()`, `getTimeout()`, `getFollowRedirects()`, `getFallbackState()`, `getOpenTelemetry()`)

    ```java
    // 변경 전
    String filename = file.filename();
    if (filename != null) {}
    String resource = backend.getResource();

    // 변경 후
    Optional<String> filename = file.filename();
    if (filename.isPresent()) {}
    Optional<String> resource = backend.resource();
    ```

    `FoundryBackend`의 `getBaseUrl()`이 제거되었습니다. 요청이 전송되는 URL을 반환하는 `baseUrl()`을 호출하세요. 이는 설정한 기본 URL이거나 리소스로부터 생성된 URL이며, `/anthropic`으로 끝납니다.

    `AnthropicBackend`의 `getBaseUrl()`도 제거되었습니다. 같은 값을 반환하는 `baseUrl()`을 호출하세요.

    **`HttpRequest`에는 기본 URL이 필요합니다.** 인터셉터 테스트처럼 `HttpRequest`를 직접 생성하는 경우, 기본 URL을 설정하세요. 기본 URL이 없으면 이제 `build()`가 `IllegalStateException`을 발생시킵니다. v2에서는 `baseUrl()`이 `null`인 요청을 반환했습니다. SDK가 생성하는 요청에는 이미 기본 URL이 있었습니다.

    ```java
    // 변경 전
    HttpRequest request = HttpRequest.builder()
        .method(HttpMethod.GET)
        .build();

    // 변경 후
    HttpRequest request = HttpRequest.builder()
        .method(HttpMethod.GET)
        .baseUrl("https://api.anthropic.com")
        .build();
    ```

    `baseUrl()`은 여전히 `String`을 반환하며, 이제 절대 `null`이 아닙니다. 빌더에서 `baseUrl(Optional<String>)`은 제거되었고 `baseUrl(String)`은 더 이상 `null`을 허용하지 않습니다.

    **인터셉터가 `anthropic-version`을 볼 수 있습니다.** 이제 클라이언트는 인터셉터가 실행되기 전에 기본 `anthropic-version` 헤더를 추가합니다. v2에서는 백엔드가 인터셉터 실행 후에 추가했습니다. 인터셉터가 자체 버전을 설정하는 경우, `putHeader`는 이제 두 번째 값을 추가하므로 `replaceHeaders`를 호출하세요:

    ```java
    // 변경 전
    request.toBuilder().putHeader("anthropic-version", version).build();

    // 변경 후
    request.toBuilder().replaceHeaders("anthropic-version", version).build();
    ```
  </Tab>

  <Tab title="PHP">
    **전달한 enum case는 해당 값으로 다시 읽힙니다.** `with()`와 `withAllowedCallers()` 같은 setter는 여전히 enum case 또는 그 값을 받습니다. 이전 버전은 case를 전달한 그대로 유지했습니다. v1은 case의 값을 유지하며, 이는 속성 타입이 이미 선언하고 있는 것입니다. SDK가 응답으로부터 생성하는 객체는 변경되지 않으며, SDK가 전송하는 JSON도 동일합니다. 속성을 다시 읽어 case와 비교하는 경우, 이제 비교 결과는 false이며 아무 예외도 발생하지 않으므로 case의 값과 비교하세요:

    ```php
    $tool = CodeExecutionTool20250825::with(allowedCallers: [AllowedCaller::DIRECT]);

    // 변경 전
    in_array(AllowedCaller::DIRECT, $tool->allowedCallers, true);

    // 변경 후
    in_array(AllowedCaller::DIRECT->value, $tool->allowedCallers, true);
    ```
  </Tab>
</Tabs>

### 라이선스는 Apache 2.0입니다

이 버전부터 SDK와 CLI는 Apache License, Version 2.0에 따라 라이선스가 부여됩니다. 이전 버전은 MIT License로 유지됩니다. 코드 변경은 필요하지 않습니다. 의존성의 라이선스를 추적하고 있다면 해당 항목을 업데이트하세요.

* **TypeScript:** 플랫폼 패키지(`@anthropic-ai/bedrock-sdk`, `@anthropic-ai/vertex-sdk`, `@anthropic-ai/foundry-sdk`, `@anthropic-ai/aws-sdk`, `@anthropic-ai/google-cloud-sdk`)는 각자의 1.0.0 릴리스에서 라이선스가 변경됩니다.
* **C#:** 다른 패키지(`Anthropic.Bedrock`, `Anthropic.Vertex`, `Anthropic.Foundry`, `Anthropic.Aws`, `Anthropic.GoogleCloud`, `Anthropic.Mcp`)는 각자의 1.0.0 릴리스에서 라이선스가 변경됩니다.
* **Java:** 이 변경은 모든 `com.anthropic` 아티팩트에 적용됩니다.
