├── .devcontainer └── devcontainer.json ├── .github ├── CODEOWNERS └── workflows │ ├── ci.yml │ ├── create-releases.yml │ ├── publish-npm.yml │ └── release-doctor.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── .release-please-manifest.json ├── .stats.yml ├── Brewfile ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── MIGRATION.md ├── README.md ├── SECURITY.md ├── api.md ├── bin ├── check-release-environment ├── cli ├── migration-config.json ├── publish-npm └── replace-internal-symlinks ├── eslint.config.mjs ├── examples ├── .keep ├── batch-results.ts ├── cancellation.ts ├── count-tokens.ts ├── demo.ts ├── mcp.ts ├── raw-streaming.ts ├── streaming.ts ├── thinking-stream.ts ├── thinking.ts ├── tools-streaming.ts ├── tools.ts ├── web-search-stream.ts └── web-search.ts ├── helpers.md ├── jest.config.ts ├── package.json ├── packages ├── bedrock-sdk │ ├── CHANGELOG.md │ ├── README.md │ ├── build │ ├── examples │ │ ├── demo.ts │ │ └── streaming.ts │ ├── jest.config.ts │ ├── package.json │ ├── scripts │ │ └── postprocess-dist-package-json.cjs │ ├── src │ │ ├── AWS_restJson1.ts │ │ ├── client.ts │ │ ├── core │ │ │ ├── auth.ts │ │ │ ├── error.ts │ │ │ ├── pagination.ts │ │ │ └── streaming.ts │ │ ├── index.ts │ │ └── internal │ ├── tests │ │ └── client.test.ts │ ├── tsc-multi.json │ ├── tsconfig.build.json │ ├── tsconfig.deno.json │ ├── tsconfig.dist-src.json │ ├── tsconfig.json │ └── yarn.lock └── vertex-sdk │ ├── CHANGELOG.md │ ├── README.md │ ├── build │ ├── examples │ └── vertex.ts │ ├── package.json │ ├── scripts │ └── postprocess-dist-package-json.cjs │ ├── src │ ├── client.ts │ ├── core │ │ ├── error.ts │ │ ├── pagination.ts │ │ └── streaming.ts │ ├── index.ts │ └── internal │ ├── tsc-multi.json │ ├── tsconfig.build.json │ ├── tsconfig.deno.json │ ├── tsconfig.dist-src.json │ ├── tsconfig.json │ └── yarn.lock ├── release-please-config.json ├── scripts ├── bootstrap ├── build ├── build-all ├── format ├── lint ├── mock ├── publish-packages.ts ├── test └── utils │ ├── attw-report.cjs │ ├── check-is-in-git-install.sh │ ├── check-version.cjs │ ├── fix-index-exports.cjs │ ├── git-swap.sh │ ├── make-dist-package-json.cjs │ ├── postprocess-files.cjs │ └── upload-artifact.sh ├── src ├── _vendor │ └── partial-json-parser │ │ ├── README.md │ │ └── parser.ts ├── api-promise.ts ├── client.ts ├── core │ ├── README.md │ ├── api-promise.ts │ ├── error.ts │ ├── pagination.ts │ ├── resource.ts │ ├── streaming.ts │ └── uploads.ts ├── error.ts ├── index.ts ├── internal │ ├── README.md │ ├── builtin-types.ts │ ├── constants.ts │ ├── decoders │ │ ├── jsonl.ts │ │ └── line.ts │ ├── detect-platform.ts │ ├── errors.ts │ ├── headers.ts │ ├── parse.ts │ ├── request-options.ts │ ├── shim-types.ts │ ├── shims.ts │ ├── stream-utils.ts │ ├── to-file.ts │ ├── types.ts │ ├── uploads.ts │ ├── utils.ts │ └── utils │ │ ├── base64.ts │ │ ├── bytes.ts │ │ ├── env.ts │ │ ├── log.ts │ │ ├── path.ts │ │ ├── sleep.ts │ │ ├── uuid.ts │ │ └── values.ts ├── lib │ ├── .keep │ ├── BetaMessageStream.ts │ └── MessageStream.ts ├── pagination.ts ├── resource.ts ├── resources.ts ├── resources │ ├── beta.ts │ ├── beta │ │ ├── beta.ts │ │ ├── files.ts │ │ ├── index.ts │ │ ├── messages.ts │ │ ├── messages │ │ │ ├── batches.ts │ │ │ ├── index.ts │ │ │ └── messages.ts │ │ └── models.ts │ ├── completions.ts │ ├── index.ts │ ├── messages.ts │ ├── messages │ │ ├── batches.ts │ │ ├── index.ts │ │ └── messages.ts │ ├── models.ts │ ├── shared.ts │ └── top-level.ts ├── streaming.ts ├── uploads.ts └── version.ts ├── tests ├── api-resources │ ├── MessageStream.test.ts │ ├── beta │ │ ├── files.test.ts │ │ ├── messages │ │ │ ├── batches.test.ts │ │ │ └── messages.test.ts │ │ └── models.test.ts │ ├── completions.test.ts │ ├── messages │ │ ├── batches.test.ts │ │ └── messages.test.ts │ └── models.test.ts ├── base64.test.ts ├── buildHeaders.test.ts ├── form.test.ts ├── index.test.ts ├── internal │ └── decoders │ │ └── line.test.ts ├── lib │ ├── TracksToolInput.test.ts │ └── partial-json.test.ts ├── path.test.ts ├── responses.test.ts ├── streaming.test.ts ├── stringifyQuery.test.ts ├── uploads.test.ts └── utils │ └── typing.ts ├── tsc-multi.json ├── tsconfig.build.json ├── tsconfig.deno.json ├── tsconfig.dist-src.json ├── tsconfig.json └── yarn.lock /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/debian 3 | { 4 | "name": "Development", 5 | "image": "mcr.microsoft.com/devcontainers/typescript-node:latest", 6 | "features": { 7 | "ghcr.io/devcontainers/features/node:1": {} 8 | }, 9 | "postCreateCommand": "yarn install", 10 | "customizations": { 11 | "vscode": { 12 | "extensions": ["esbenp.prettier-vscode"] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This file is used to automatically assign reviewers to PRs 2 | # For more information see: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 3 | 4 | * @anthropics/sdk 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches-ignore: 5 | - 'generated' 6 | - 'codegen/**' 7 | - 'integrated/**' 8 | - 'stl-preview-head/**' 9 | - 'stl-preview-base/**' 10 | 11 | jobs: 12 | lint: 13 | timeout-minutes: 10 14 | name: lint 15 | runs-on: ${{ github.repository == 'stainless-sdks/anthropic-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Set up Node 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: '20' 23 | 24 | - name: Bootstrap 25 | run: ./scripts/bootstrap 26 | 27 | - name: Update internal symlinks in third party packages 28 | run: ./bin/replace-internal-symlinks 29 | 30 | - name: run build all 31 | # this is needed so that sub packages can work (they depend on `dist` in the root folder) 32 | run: ./scripts/build-all 33 | 34 | - name: Check types 35 | run: ./scripts/lint 36 | 37 | build: 38 | timeout-minutes: 5 39 | name: build 40 | runs-on: ${{ github.repository == 'stainless-sdks/anthropic-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} 41 | permissions: 42 | contents: read 43 | id-token: write 44 | steps: 45 | - uses: actions/checkout@v4 46 | 47 | - name: Set up Node 48 | uses: actions/setup-node@v4 49 | with: 50 | node-version: '20' 51 | 52 | - name: Bootstrap 53 | run: ./scripts/bootstrap 54 | 55 | - name: Update internal symlinks in third party packages 56 | run: ./bin/replace-internal-symlinks 57 | 58 | - name: run build all 59 | run: ./scripts/build-all 60 | 61 | - name: Get GitHub OIDC Token 62 | if: github.repository == 'stainless-sdks/anthropic-typescript' 63 | id: github-oidc 64 | uses: actions/github-script@v6 65 | with: 66 | script: core.setOutput('github_token', await core.getIDToken()); 67 | 68 | - name: Upload tarball 69 | if: github.repository == 'stainless-sdks/anthropic-typescript' 70 | env: 71 | URL: https://pkg.stainless.com/s 72 | AUTH: ${{ steps.github-oidc.outputs.github_token }} 73 | SHA: ${{ github.sha }} 74 | run: ./scripts/utils/upload-artifact.sh 75 | test: 76 | timeout-minutes: 10 77 | name: test 78 | runs-on: ${{ github.repository == 'stainless-sdks/anthropic-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} 79 | steps: 80 | - uses: actions/checkout@v4 81 | 82 | - name: Set up Node 83 | uses: actions/setup-node@v4 84 | with: 85 | node-version: '20' 86 | 87 | - name: Bootstrap 88 | run: ./scripts/bootstrap 89 | 90 | - name: Update internal symlinks in third party packages 91 | run: ./bin/replace-internal-symlinks 92 | 93 | - name: run build all 94 | # this is needed so that sub packages can work (they depend on `dist` in the root folder) 95 | run: ./scripts/build-all 96 | 97 | - name: Run tests 98 | run: ./scripts/test 99 | -------------------------------------------------------------------------------- /.github/workflows/create-releases.yml: -------------------------------------------------------------------------------- 1 | name: Create releases 2 | on: 3 | schedule: 4 | - cron: '0 5 * * *' # every day at 5am UTC 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | release: 11 | name: release 12 | if: github.ref == 'refs/heads/main' && github.repository == 'anthropics/anthropic-sdk-typescript' 13 | runs-on: ubuntu-latest 14 | environment: production-release 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - uses: stainless-api/trigger-release-please@v1 20 | id: release 21 | with: 22 | repo: ${{ github.event.repository.full_name }} 23 | stainless-api-key: ${{ secrets.STAINLESS_API_KEY }} 24 | 25 | - name: Set up Node 26 | if: ${{ steps.release.outputs.releases_created }} 27 | uses: actions/setup-node@v3 28 | with: 29 | node-version: '20' 30 | 31 | - name: Install dependencies 32 | if: ${{ steps.release.outputs.releases_created }} 33 | run: | 34 | yarn install 35 | 36 | - name: Update internal symlinks in third party packages 37 | run: ./bin/replace-internal-symlinks 38 | 39 | - name: Publish to NPM 40 | if: ${{ steps.release.outputs.releases_created }} 41 | run: | 42 | yarn tsn scripts/publish-packages.ts 43 | 44 | env: 45 | DATA: ${{ toJSON(steps.release.outputs) }} 46 | NPM_TOKEN: ${{ secrets.ANTHROPIC_NPM_TOKEN || secrets.NPM_TOKEN }} 47 | -------------------------------------------------------------------------------- /.github/workflows/publish-npm.yml: -------------------------------------------------------------------------------- 1 | # workflow for re-running publishing to NPM in case it fails for some reason 2 | # you can run this workflow by navigating to https://www.github.com/anthropics/anthropic-sdk-typescript/actions/workflows/publish-npm.yml 3 | name: Publish NPM 4 | on: 5 | 6 | 7 | workflow_dispatch: 8 | inputs: 9 | path: 10 | description: The path to run the release in, e.g. '.' or 'packages/vertex-sdk' 11 | required: true 12 | 13 | jobs: 14 | publish: 15 | name: publish 16 | runs-on: ubuntu-latest 17 | environment: production-release 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: Set up Node 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: '20' 26 | 27 | - name: Install dependencies 28 | run: | 29 | yarn install 30 | 31 | - name: Update internal symlinks in third party packages 32 | run: ./bin/replace-internal-symlinks 33 | 34 | - name: Publish to NPM 35 | run: | 36 | yarn tsn scripts/publish-packages.ts '{ "paths_released": "[\"${{ github.event.inputs.path }}\"]" }' 37 | env: 38 | NPM_TOKEN: ${{ secrets.ANTHROPIC_NPM_TOKEN || secrets.NPM_TOKEN }} 39 | -------------------------------------------------------------------------------- /.github/workflows/release-doctor.yml: -------------------------------------------------------------------------------- 1 | name: Release Doctor 2 | on: 3 | push: 4 | branches: 5 | - main 6 | workflow_dispatch: 7 | 8 | jobs: 9 | release_doctor: 10 | name: release doctor 11 | runs-on: ubuntu-latest 12 | environment: production-release 13 | if: github.repository == 'anthropics/anthropic-sdk-typescript' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Check release environment 19 | run: | 20 | bash ./bin/check-release-environment 21 | env: 22 | STAINLESS_API_KEY: ${{ secrets.STAINLESS_API_KEY }} 23 | NPM_TOKEN: ${{ secrets.ANTHROPIC_NPM_TOKEN || secrets.NPM_TOKEN }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .prism.log 2 | node_modules 3 | yarn-error.log 4 | codegen.log 5 | Brewfile.lock.json 6 | dist 7 | dist-deno 8 | /*.tgz 9 | .idea/ 10 | 11 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | CHANGELOG.md 2 | /ecosystem-tests/*/** 3 | /node_modules 4 | /deno 5 | 6 | # don't format tsc output, will break source maps 7 | /dist 8 | /packages/*/dist 9 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "experimentalTernaries": true, 4 | "printWidth": 110, 5 | "singleQuote": true, 6 | "trailingComma": "all" 7 | } 8 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "0.53.0", 3 | "packages/vertex-sdk": "0.11.4", 4 | "packages/bedrock-sdk": "0.22.1" 5 | } 6 | -------------------------------------------------------------------------------- /.stats.yml: -------------------------------------------------------------------------------- 1 | configured_endpoints: 26 2 | openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic%2Fanthropic-a7b84017aa1126ad99443296dcd81ab2b53f1c346014b92096226cf993f30502.yml 3 | openapi_spec_hash: 58d4e72c7906bd8a680ab17b99de6215 4 | config_hash: b08362db009c073fa7b1c154969cb200 5 | -------------------------------------------------------------------------------- /Brewfile: -------------------------------------------------------------------------------- 1 | brew "node" 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Setting up the environment 2 | 3 | This repository uses [`yarn@v1`](https://classic.yarnpkg.com/lang/en/docs/install). 4 | Other package managers may work but are not officially supported for development. 5 | 6 | To set up the repository, run: 7 | 8 | ```sh 9 | $ yarn 10 | $ yarn build 11 | ``` 12 | 13 | This will install all the required dependencies and build output files to `dist/`. 14 | 15 | ## Modifying/Adding code 16 | 17 | Most of the SDK is generated code. Modifications to code will be persisted between generations, but may 18 | result in merge conflicts between manual patches and changes from the generator. The generator will never 19 | modify the contents of the `src/lib/` and `examples/` directories. 20 | 21 | ## Adding and running examples 22 | 23 | All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. 24 | 25 | ```ts 26 | // add an example to examples/.ts 27 | 28 | #!/usr/bin/env -S npm run tsn -T 29 | … 30 | ``` 31 | 32 | ```sh 33 | $ chmod +x examples/.ts 34 | # run the example against your api 35 | $ yarn tsn -T examples/.ts 36 | ``` 37 | 38 | ## Using the repository from source 39 | 40 | If you’d like to use the repository from source, you can either install from git or link to a cloned repository: 41 | 42 | To install via git: 43 | 44 | ```sh 45 | $ npm install git+ssh://git@github.com:anthropics/anthropic-sdk-typescript.git 46 | ``` 47 | 48 | Alternatively, to link a local copy of the repo: 49 | 50 | ```sh 51 | # Clone 52 | $ git clone https://www.github.com/anthropics/anthropic-sdk-typescript 53 | $ cd anthropic-sdk-typescript 54 | 55 | # With yarn 56 | $ yarn link 57 | $ cd ../my-package 58 | $ yarn link @anthropic-ai/sdk 59 | 60 | # With pnpm 61 | $ pnpm link --global 62 | $ cd ../my-package 63 | $ pnpm link -—global @anthropic-ai/sdk 64 | ``` 65 | 66 | ## Running tests 67 | 68 | Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. 69 | 70 | ```sh 71 | $ npx prism mock path/to/your/openapi.yml 72 | ``` 73 | 74 | ```sh 75 | $ yarn run test 76 | ``` 77 | 78 | ## Linting and formatting 79 | 80 | This repository uses [prettier](https://www.npmjs.com/package/prettier) and 81 | [eslint](https://www.npmjs.com/package/eslint) to format the code in the repository. 82 | 83 | To lint: 84 | 85 | ```sh 86 | $ yarn lint 87 | ``` 88 | 89 | To format and fix all lint issues automatically: 90 | 91 | ```sh 92 | $ yarn fix 93 | ``` 94 | 95 | ## Publishing and releases 96 | 97 | Changes made to this repository via the automated release PR pipeline should publish to npm automatically. If 98 | the changes aren't made through the automated pipeline, you may want to make releases manually. 99 | 100 | ### Publish with a GitHub workflow 101 | 102 | You can release to package managers by using [the `Publish NPM` GitHub action](https://www.github.com/anthropics/anthropic-sdk-typescript/actions/workflows/publish-npm.yml). This requires a setup organization or repository secret to be set up. 103 | 104 | ### Publish manually 105 | 106 | If you need to manually release a package, you can run the `bin/publish-npm` script with an `NPM_TOKEN` set on 107 | the environment. 108 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 Anthropic, PBC. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting Security Issues 4 | 5 | This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. 6 | 7 | To report a security issue, please contact the Stainless team at security@stainless.com. 8 | 9 | ## Responsible Disclosure 10 | 11 | We appreciate the efforts of security researchers and individuals who help us maintain the security of 12 | SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible 13 | disclosure practices by allowing us a reasonable amount of time to investigate and address the issue 14 | before making any information public. 15 | 16 | ## Reporting Non-SDK Related Security Issues 17 | 18 | If you encounter security issues that are not directly related to SDKs but pertain to the services 19 | or products provided by Anthropic, please follow the respective company's security reporting guidelines. 20 | 21 | ### Anthropic Terms and Policies 22 | 23 | Please contact support@anthropic.com for any questions or concerns regarding the security of our services. 24 | 25 | --- 26 | 27 | Thank you for helping us keep the SDKs and systems they interact with secure. 28 | -------------------------------------------------------------------------------- /bin/check-release-environment: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | errors=() 4 | 5 | if [ -z "${STAINLESS_API_KEY}" ]; then 6 | errors+=("The STAINLESS_API_KEY secret has not been set. Please contact Stainless for an API key & set it in your organization secrets on GitHub.") 7 | fi 8 | 9 | if [ -z "${NPM_TOKEN}" ]; then 10 | errors+=("The ANTHROPIC_NPM_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets") 11 | fi 12 | 13 | lenErrors=${#errors[@]} 14 | 15 | if [[ lenErrors -gt 0 ]]; then 16 | echo -e "Found the following errors in the release environment:\n" 17 | 18 | for error in "${errors[@]}"; do 19 | echo -e "- $error\n" 20 | done 21 | 22 | exit 1 23 | fi 24 | 25 | echo "The environment is ready to push releases!" 26 | 27 | -------------------------------------------------------------------------------- /bin/cli: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { spawnSync } = require('child_process'); 4 | 5 | const commands = { 6 | migrate: { 7 | description: 8 | 'Run migrations to update your code using @anthropic-ai/sdk@0.41 to be compatible with @anthropic-ai/sdk@0.50', 9 | fn: () => { 10 | const result = spawnSync( 11 | 'npx', 12 | [ 13 | '-y', 14 | 'https://github.com/stainless-api/migrate-ts/releases/download/0.0.2/stainless-api-migrate-0.0.2-6.tgz', 15 | '--migrationConfig', 16 | require.resolve('./migration-config.json'), 17 | ...process.argv.slice(3), 18 | ], 19 | { stdio: 'inherit' }, 20 | ); 21 | if (result.status !== 0) { 22 | process.exit(result.status); 23 | } 24 | }, 25 | }, 26 | }; 27 | 28 | function exitWithHelp() { 29 | console.log(`Usage: anthropic-ai-sdk `); 30 | console.log(); 31 | console.log('Subcommands:'); 32 | 33 | for (const [name, info] of Object.entries(commands)) { 34 | console.log(` ${name} ${info.description}`); 35 | } 36 | 37 | console.log(); 38 | process.exit(1); 39 | } 40 | 41 | if (process.argv.length < 3) { 42 | exitWithHelp(); 43 | } 44 | 45 | const commandName = process.argv[2]; 46 | 47 | const command = commands[commandName]; 48 | if (!command) { 49 | console.log(`Unknown subcommand ${commandName}.`); 50 | exitWithHelp(); 51 | } 52 | 53 | command.fn(); 54 | -------------------------------------------------------------------------------- /bin/migration-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "pkg": "@anthropic-ai/sdk", 3 | "githubRepo": "https://github.com/anthropics/anthropic-sdk-typescript", 4 | "clientClass": "Anthropic", 5 | "baseClientClass": "BaseAnthropic", 6 | "methods": [] 7 | } 8 | -------------------------------------------------------------------------------- /bin/publish-npm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN" 6 | 7 | yarn build 8 | cd dist 9 | 10 | # Get latest version from npm 11 | # 12 | # If the package doesn't exist, yarn will return 13 | # {"type":"error","data":"Received invalid response from npm."} 14 | # where .data.version doesn't exist so LAST_VERSION will be an empty string. 15 | LAST_VERSION="$(yarn info --json 2> /dev/null | jq -r '.data.version')" 16 | 17 | # Get current version from package.json 18 | VERSION="$(node -p "require('./package.json').version")" 19 | 20 | # Check if current version is pre-release (e.g. alpha / beta / rc) 21 | CURRENT_IS_PRERELEASE=false 22 | if [[ "$VERSION" =~ -([a-zA-Z]+) ]]; then 23 | CURRENT_IS_PRERELEASE=true 24 | CURRENT_TAG="${BASH_REMATCH[1]}" 25 | fi 26 | 27 | # Check if last version is a stable release 28 | LAST_IS_STABLE_RELEASE=true 29 | if [[ -z "$LAST_VERSION" || "$LAST_VERSION" =~ -([a-zA-Z]+) ]]; then 30 | LAST_IS_STABLE_RELEASE=false 31 | fi 32 | 33 | # Use a corresponding alpha/beta tag if there already is a stable release and we're publishing a prerelease. 34 | if $CURRENT_IS_PRERELEASE && $LAST_IS_STABLE_RELEASE; then 35 | TAG="$CURRENT_TAG" 36 | else 37 | TAG="latest" 38 | fi 39 | 40 | # Publish with the appropriate tag 41 | yarn publish --access public --tag "$TAG" 42 | -------------------------------------------------------------------------------- /bin/replace-internal-symlinks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | # This script replaces "internal" symlinks in the bedrock and vertex packages 6 | # with the actual folder contents by copying the entire directory. 7 | 8 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 9 | ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" 10 | 11 | PACKAGES=("bedrock-sdk" "vertex-sdk") 12 | 13 | for package in "${PACKAGES[@]}"; do 14 | PACKAGE_DIR="$ROOT_DIR/packages/$package" 15 | INTERNAL_SYMLINK="$PACKAGE_DIR/src/internal" 16 | 17 | if [ -L "$INTERNAL_SYMLINK" ]; then 18 | echo "Processing $package..." 19 | 20 | # Remove the symlink 21 | rm "$INTERNAL_SYMLINK" 22 | 23 | # Create the directory 24 | mkdir -p "$INTERNAL_SYMLINK" 25 | 26 | # Copy the contents from the source internal directory 27 | cp -R "$ROOT_DIR/src/internal/"* "$INTERNAL_SYMLINK/" 28 | 29 | echo "Replaced symlink with directory in $package" 30 | else 31 | echo "No 'internal' symlink found in $package or it's not a symlink" 32 | fi 33 | done 34 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import tseslint from 'typescript-eslint'; 3 | import unusedImports from 'eslint-plugin-unused-imports'; 4 | import prettier from 'eslint-plugin-prettier'; 5 | 6 | export default tseslint.config( 7 | { 8 | languageOptions: { 9 | parser: tseslint.parser, 10 | parserOptions: { sourceType: 'module' }, 11 | }, 12 | files: ['**/*.ts', '**/*.mts', '**/*.cts', '**/*.js', '**/*.mjs', '**/*.cjs'], 13 | ignores: ['dist/'], 14 | plugins: { 15 | '@typescript-eslint': tseslint.plugin, 16 | 'unused-imports': unusedImports, 17 | prettier, 18 | }, 19 | rules: { 20 | 'no-unused-vars': 'off', 21 | 'prettier/prettier': 'error', 22 | 'unused-imports/no-unused-imports': 'error', 23 | 'no-restricted-imports': [ 24 | 'error', 25 | { 26 | patterns: [ 27 | { 28 | regex: '^@anthropic-ai/sdk(/.*)?', 29 | message: 'Use a relative import, not a package import.', 30 | }, 31 | ], 32 | }, 33 | ], 34 | }, 35 | }, 36 | { 37 | files: ['tests/**', 'examples/**', 'packages/**'], 38 | rules: { 39 | 'no-restricted-imports': 'off', 40 | }, 41 | }, 42 | ); 43 | -------------------------------------------------------------------------------- /examples/.keep: -------------------------------------------------------------------------------- 1 | File generated from our OpenAPI spec by Stainless. 2 | 3 | This directory can be used to store example files demonstrating usage of this SDK. 4 | It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. 5 | -------------------------------------------------------------------------------- /examples/batch-results.ts: -------------------------------------------------------------------------------- 1 | import Anthropic from '@anthropic-ai/sdk/index'; 2 | 3 | const anthropic = new Anthropic(); 4 | 5 | async function main() { 6 | const batch_id = process.argv[2]; 7 | if (!batch_id) { 8 | throw new Error('must specify a message batch ID, `yarn tsn examples/batch-results.ts msgbatch_123`'); 9 | } 10 | 11 | console.log(`fetching results for ${batch_id}`); 12 | 13 | const results = await anthropic.beta.messages.batches.results(batch_id); 14 | 15 | for await (const result of results) { 16 | console.log(result); 17 | } 18 | } 19 | 20 | main(); 21 | -------------------------------------------------------------------------------- /examples/cancellation.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | const client = new Anthropic(); 5 | 6 | /** 7 | * This script demonstrates two ways of cancelling a stream, 8 | * by racing to see whether some Rust code prints "unwrap" 9 | * before 1.5 seconds or not. 10 | * 11 | * The most common is simply to `break` from the loop, 12 | * but you can also call `stream.controller.abort()` from outside the loop 13 | * if you need to. 14 | */ 15 | async function main() { 16 | const question = 'Hey Claude! How can I recursively list all files in a directory in Rust?'; 17 | 18 | const stream = await client.messages.create({ 19 | model: 'claude-3-5-sonnet-latest', 20 | stream: true, 21 | max_tokens: 500, 22 | messages: [{ role: 'user', content: question }], 23 | }); 24 | 25 | // If you need to, you can cancel a stream from outside the iterator 26 | // by calling "stream.controller.abort()" 27 | const timeout = setTimeout(() => { 28 | console.log('\nCancelling after 1.5 seconds.'); 29 | stream.controller.abort(); 30 | }, 1500); 31 | 32 | for await (const event of stream) { 33 | if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') { 34 | process.stdout.write(event.delta.text); 35 | 36 | // Most typically, you can cancel the stream by using "break" 37 | if (event.delta.text.includes('unwrap')) { 38 | console.log('\nCancelling after seeing "unwrap".'); 39 | clearTimeout(timeout); 40 | break; 41 | } 42 | } 43 | } 44 | } 45 | 46 | main(); 47 | -------------------------------------------------------------------------------- /examples/count-tokens.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY 6 | 7 | async function main() { 8 | const result = await client.messages.countTokens({ 9 | messages: [ 10 | { 11 | role: 'user', 12 | content: 'Hey Claude!?', 13 | }, 14 | ], 15 | model: 'claude-3-5-sonnet-latest', 16 | }); 17 | console.dir(result); 18 | } 19 | 20 | main(); 21 | -------------------------------------------------------------------------------- /examples/demo.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY 6 | 7 | async function main() { 8 | const result = await client.messages.create({ 9 | messages: [ 10 | { 11 | role: 'user', 12 | content: 'Hey Claude!?', 13 | }, 14 | ], 15 | model: 'claude-3-5-sonnet-latest', 16 | max_tokens: 1024, 17 | }); 18 | console.dir(result); 19 | } 20 | 21 | main(); 22 | -------------------------------------------------------------------------------- /examples/mcp.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const anthropic = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY 6 | 7 | const main = async () => { 8 | const stream = anthropic.beta.messages.stream( 9 | { 10 | model: 'claude-3-7-sonnet-20250219', 11 | max_tokens: 1000, 12 | mcp_servers: [ 13 | { 14 | type: 'url', 15 | url: 'http://example-server.modelcontextprotocol.io/sse', 16 | name: 'example', 17 | authorization_token: 'YOUR_TOKEN', 18 | tool_configuration: { 19 | // Optional, defaults to allowing all tools 20 | enabled: true, // Optional 21 | allowed_tools: ['echo', 'add'], // Optional 22 | }, 23 | }, 24 | ], 25 | messages: [ 26 | { 27 | role: 'user', 28 | content: 'Calculate 1+2', 29 | }, 30 | ], 31 | }, 32 | { 33 | headers: { 34 | 'anthropic-beta': 'mcp-client-2025-04-04', 35 | }, 36 | }, 37 | ); 38 | for await (const event of stream) { 39 | if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') { 40 | process.stdout.write(event.delta.text); 41 | } 42 | } 43 | process.stdout.write('\n'); 44 | }; 45 | main(); 46 | -------------------------------------------------------------------------------- /examples/raw-streaming.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY 6 | 7 | async function main() { 8 | const stream = await client.messages.create({ 9 | model: 'claude-3-5-sonnet-latest', 10 | stream: true, 11 | max_tokens: 500, 12 | messages: [ 13 | { 14 | role: 'user', 15 | content: 'Hey Claude!', 16 | }, 17 | ], 18 | }); 19 | 20 | for await (const event of stream) { 21 | if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') { 22 | process.stdout.write(event.delta.text); 23 | } 24 | } 25 | process.stdout.write('\n'); 26 | } 27 | 28 | main(); 29 | -------------------------------------------------------------------------------- /examples/streaming.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY 6 | 7 | async function main() { 8 | const stream = client.messages 9 | .stream({ 10 | messages: [ 11 | { 12 | role: 'user', 13 | content: `Hey Claude! How can I recursively list all files in a directory in Rust?`, 14 | }, 15 | ], 16 | model: 'claude-3-5-sonnet-latest', 17 | max_tokens: 1024, 18 | }) 19 | // Once a content block is fully streamed, this event will fire 20 | .on('contentBlock', (content) => console.log('contentBlock', content)) 21 | // Once a message is fully streamed, this event will fire 22 | .on('message', (message) => console.log('message', message)); 23 | 24 | for await (const event of stream) { 25 | console.log('event', event); 26 | } 27 | 28 | const message = await stream.finalMessage(); 29 | console.log('finalMessage', message); 30 | } 31 | 32 | main().catch((err) => { 33 | console.error(err); 34 | process.exit(1); 35 | }); 36 | -------------------------------------------------------------------------------- /examples/thinking-stream.ts: -------------------------------------------------------------------------------- 1 | import Anthropic from '@anthropic-ai/sdk'; 2 | 3 | const client = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY 4 | 5 | async function main() { 6 | let thinkingState = 'not-started'; 7 | 8 | const stream = client.messages 9 | .stream({ 10 | model: 'claude-3-7-sonnet-20250219', 11 | max_tokens: 3200, 12 | thinking: { type: 'enabled', budget_tokens: 1600 }, 13 | messages: [{ role: 'user', content: 'Create a haiku about Anthropic.' }], 14 | }) 15 | .on('thinking', (thinking) => { 16 | if (thinkingState === 'not-started') { 17 | console.log('Thinking:\n---------'); 18 | thinkingState = 'started'; 19 | } 20 | 21 | process.stdout.write(thinking); 22 | }) 23 | .on('text', (text) => { 24 | if (thinkingState !== 'finished') { 25 | console.log('\n\nText:\n-----'); 26 | thinkingState = 'finished'; 27 | } 28 | process.stdout.write(text); 29 | }); 30 | 31 | const finalMessage = await stream.finalMessage(); 32 | console.log('\n\nFinal message object:\n--------------------', finalMessage); 33 | } 34 | 35 | main(); 36 | -------------------------------------------------------------------------------- /examples/thinking.ts: -------------------------------------------------------------------------------- 1 | import Anthropic from '@anthropic-ai/sdk'; 2 | 3 | const client = new Anthropic(); 4 | 5 | async function main() { 6 | const message = await client.messages.create({ 7 | model: 'claude-3-7-sonnet-20250219', 8 | max_tokens: 3200, 9 | thinking: { type: 'enabled', budget_tokens: 1600 }, 10 | messages: [{ role: 'user', content: 'Create a haiku about Anthropic.' }], 11 | }); 12 | 13 | for (const block of message.content) { 14 | if (block.type === 'thinking') { 15 | console.log(`Thinking: ${block.thinking}`); 16 | } else if (block.type === 'text') { 17 | console.log(`Text: ${block.text}`); 18 | } 19 | } 20 | } 21 | 22 | main(); 23 | -------------------------------------------------------------------------------- /examples/tools-streaming.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | import { inspect } from 'util'; 5 | 6 | // gets API Key from environment variable ANTHROPIC_API_KEY 7 | const client = new Anthropic(); 8 | 9 | async function main() { 10 | const stream = client.messages 11 | .stream({ 12 | messages: [ 13 | { 14 | role: 'user', 15 | content: `What is the weather in SF?`, 16 | }, 17 | ], 18 | tools: [ 19 | { 20 | name: 'get_weather', 21 | description: 'Get the weather at a specific location', 22 | input_schema: { 23 | type: 'object', 24 | properties: { 25 | location: { type: 'string', description: 'The city and state, e.g. San Francisco, CA' }, 26 | unit: { 27 | type: 'string', 28 | enum: ['celsius', 'fahrenheit'], 29 | description: 'Unit for the output', 30 | }, 31 | }, 32 | required: ['location'], 33 | }, 34 | }, 35 | ], 36 | model: 'claude-3-5-sonnet-latest', 37 | max_tokens: 1024, 38 | }) 39 | // When a JSON content block delta is encountered this 40 | // event will be fired with the delta and the currently accumulated object 41 | .on('inputJson', (delta, snapshot) => { 42 | console.log(`delta: ${delta}`); 43 | console.log(`snapshot: ${inspect(snapshot)}`); 44 | console.log(); 45 | }); 46 | 47 | await stream.done(); 48 | } 49 | 50 | main(); 51 | -------------------------------------------------------------------------------- /examples/tools.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | import assert from 'node:assert'; 5 | 6 | const client = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY 7 | 8 | async function main() { 9 | const userMessage: Anthropic.MessageParam = { 10 | role: 'user', 11 | content: 'What is the weather in SF?', 12 | }; 13 | const tools: Anthropic.Tool[] = [ 14 | { 15 | name: 'get_weather', 16 | description: 'Get the weather for a specific location', 17 | input_schema: { 18 | type: 'object', 19 | properties: { location: { type: 'string' } }, 20 | }, 21 | }, 22 | ]; 23 | 24 | const message = await client.messages.create({ 25 | model: 'claude-3-5-sonnet-latest', 26 | max_tokens: 1024, 27 | messages: [userMessage], 28 | tools, 29 | }); 30 | console.log('Initial response:'); 31 | console.dir(message, { depth: 4 }); 32 | 33 | assert(message.stop_reason === 'tool_use'); 34 | 35 | const tool = message.content.find( 36 | (content): content is Anthropic.ToolUseBlock => content.type === 'tool_use', 37 | ); 38 | assert(tool); 39 | 40 | const result = await client.messages.create({ 41 | model: 'claude-3-5-sonnet-latest', 42 | max_tokens: 1024, 43 | messages: [ 44 | userMessage, 45 | { role: message.role, content: message.content }, 46 | { 47 | role: 'user', 48 | content: [ 49 | { 50 | type: 'tool_result', 51 | tool_use_id: tool.id, 52 | content: 'The weather is 73f', 53 | }, 54 | ], 55 | }, 56 | ], 57 | tools, 58 | }); 59 | console.log('\nFinal response'); 60 | console.dir(result, { depth: 4 }); 61 | } 62 | 63 | main(); 64 | -------------------------------------------------------------------------------- /examples/web-search-stream.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic(); 6 | 7 | async function main() { 8 | console.log('Claude with Web Search (Streaming)'); 9 | console.log('=================================='); 10 | 11 | // Create a stream with web search enabled 12 | const stream = client.messages 13 | .stream({ 14 | model: 'claude-3-5-sonnet-latest', 15 | max_tokens: 1024, 16 | messages: [ 17 | { 18 | role: 'user', 19 | content: "What's the weather in New York?", 20 | }, 21 | ], 22 | tools: [ 23 | { 24 | name: 'web_search', 25 | type: 'web_search_20250305', 26 | }, 27 | ], 28 | }) 29 | .on('text', (text) => { 30 | // Print text as it arrives 31 | process.stdout.write(text); 32 | }) 33 | .on('streamEvent', (event) => { 34 | // Track when web search is being used 35 | if (event.type === 'content_block_start' && event.content_block.type === 'web_search_tool_result') { 36 | process.stdout.write('\n[Web search started...]'); 37 | } 38 | }); 39 | 40 | // Wait for the stream to complete 41 | const message = await stream.finalMessage(); 42 | 43 | console.log('\n\nFinal usage statistics:'); 44 | console.log(`Input tokens: ${message.usage.input_tokens}`); 45 | console.log(`Output tokens: ${message.usage.output_tokens}`); 46 | 47 | if (message.usage.server_tool_use) { 48 | console.log(`Web search requests: ${message.usage.server_tool_use.web_search_requests}`); 49 | } else { 50 | console.log('No web search requests recorded in usage'); 51 | } 52 | 53 | // Display message content types for debugging 54 | console.log('\nMessage Content Types:'); 55 | message.content.forEach((block, i) => { 56 | console.log(`Content Block ${i + 1}: Type = ${block.type}`); 57 | }); 58 | 59 | // Show full message for debugging 60 | console.log('\nComplete message structure:'); 61 | console.dir(message, { depth: 4 }); 62 | } 63 | 64 | main().catch(console.error); 65 | -------------------------------------------------------------------------------- /examples/web-search.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic(); 6 | 7 | async function main() { 8 | console.log('Web Search Example'); 9 | console.log('================='); 10 | 11 | // Create a message with web search enabled 12 | const message = await client.messages.create({ 13 | model: 'claude-3-5-sonnet-latest', 14 | max_tokens: 1024, 15 | messages: [ 16 | { 17 | role: 'user', 18 | content: 19 | "What's the current weather in San Francisco? Please search the web for up-to-date information.", 20 | }, 21 | ], 22 | tools: [ 23 | { 24 | name: 'web_search', 25 | type: 'web_search_20250305', 26 | }, 27 | ], 28 | }); 29 | 30 | // Print the full response 31 | console.log('\nFull response:'); 32 | console.dir(message, { depth: 4 }); 33 | 34 | // Extract and print the content 35 | console.log('\nResponse content:'); 36 | for (const contentBlock of message.content) { 37 | if (contentBlock.type === 'text') { 38 | console.log(contentBlock.text); 39 | } 40 | } 41 | 42 | // Print usage information 43 | console.log('\nUsage statistics:'); 44 | console.log(`Input tokens: ${message.usage.input_tokens}`); 45 | console.log(`Output tokens: ${message.usage.output_tokens}`); 46 | 47 | if (message.usage.server_tool_use) { 48 | console.log(`Web search requests: ${message.usage.server_tool_use.web_search_requests}`); 49 | } 50 | } 51 | 52 | main().catch(console.error); 53 | -------------------------------------------------------------------------------- /helpers.md: -------------------------------------------------------------------------------- 1 | # Message Helpers 2 | 3 | ## Streaming Responses 4 | 5 | ```ts 6 | anthropic.messages.stream({ … }, options?): MessageStream 7 | ``` 8 | 9 | `anthropic.messages.stream()` returns a `MessageStream`, which emits events, has an async 10 | iterator, and exposes helper methods to accumulate stream events into a convenient shape and make it easy to reason 11 | about the conversation. 12 | 13 | Alternatively, you can use `anthropic.messages.create({ stream: true, … })` which returns an async 14 | iterable of the chunks in the stream and uses less memory (most notably, it does not accumulate a message 15 | object for you). 16 | 17 | If you need to cancel a stream, you can `break` from a `for await` loop or call `stream.abort()`. 18 | 19 | See an example of streaming helpers in action in [`examples/streaming.ts`](examples/streaming.ts). 20 | 21 | ## MessageStream API 22 | 23 | ### Events 24 | 25 | #### `.on('connect', () => …)` 26 | 27 | The first event that is fired when the connection with the Anthropic API is established. 28 | 29 | #### `.on('streamEvent', (event: MessageStreamEvent, snapshot: Message) => …)` 30 | 31 | The event fired when a stream event is received from the API. Not fired when it is not streaming. The snapshot 32 | returns an accumulated `Message` which is progressively built-up over events. 33 | 34 | #### `.on('text', (textDelta: string, textSnapshot: string) => …)` 35 | 36 | The event fired when a text delta is sent by the API. The second parameter returns a `textSnapshot`. 37 | 38 | #### `.on('inputJson', (patialJson: string, jsonSnapshot: unknown) => …)` 39 | 40 | The event fired when a json delta is sent by the API. The second parameter returns a `jsonSnapshot`. 41 | 42 | #### `.on('message', (message: Message) => …)` 43 | 44 | The event fired when a message is done being streamed by the API. Corresponds to the `message_stop` SSE event. 45 | 46 | #### `.on('contentBlock', (content: ContentBlock) => …)` 47 | 48 | The event fired when a content block is done being streamed by the API. Corresponds to the 49 | `content_block_stop` SSE event. 50 | 51 | #### `.on('finalMessage', (message: Message) => …)` 52 | 53 | The event fired for the final message. Currently this is equivalent to the `message` event, but is fired after 54 | it. 55 | 56 | #### `.on('error', (error: AnthropicError) => …)` 57 | 58 | The event fired when an error is encountered while streaming. 59 | 60 | #### `.on('abort', (error: APIUserAbortError) => …)` 61 | 62 | The event fired when the stream receives a signal to abort. 63 | 64 | #### `.on('end', () => …)` 65 | 66 | The last event fired in the stream. 67 | 68 | ### Methods 69 | 70 | #### `.abort()` 71 | 72 | Aborts the runner and the streaming request, equivalent to `.controller.abort()`. Calling `.abort()` on a 73 | `MessageStream` will also abort any in-flight network requests. 74 | 75 | #### `await .done()` 76 | 77 | An empty promise which resolves when the stream is done. 78 | 79 | #### `.currentMessage` 80 | 81 | Returns the current state of the message that is being accumulated, or `undefined` if there is no such 82 | message. 83 | 84 | #### `await .finalMessage()` 85 | 86 | A promise which resolves with the last message received from the API. Throws if no such message exists. 87 | 88 | #### `await .finalText()` 89 | 90 | A promise which resolves with the text of the last message received from the API. 91 | 92 | ### Fields 93 | 94 | #### `.messages` 95 | 96 | A mutable array of all messages in the conversation. 97 | 98 | #### `.controller` 99 | 100 | The underlying `AbortController` for the runner. 101 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { JestConfigWithTsJest } from 'ts-jest'; 2 | 3 | const config: JestConfigWithTsJest = { 4 | preset: 'ts-jest/presets/default-esm', 5 | testEnvironment: 'node', 6 | transform: { 7 | '^.+\\.(t|j)sx?$': ['@swc/jest', { sourceMaps: 'inline' }], 8 | }, 9 | moduleNameMapper: { 10 | '^@anthropic-ai/sdk$': '/src/index.ts', 11 | '^@anthropic-ai/sdk/(.*)$': '/src/$1', 12 | }, 13 | modulePathIgnorePatterns: [ 14 | '/ecosystem-tests/', 15 | '/dist/', 16 | '/deno/', 17 | '/deno_tests/', 18 | '/packages/', 19 | ], 20 | testPathIgnorePatterns: ['scripts'], 21 | }; 22 | 23 | export default config; 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@anthropic-ai/sdk", 3 | "version": "0.53.0", 4 | "description": "The official TypeScript library for the Anthropic API", 5 | "author": "Anthropic ", 6 | "types": "dist/index.d.ts", 7 | "main": "dist/index.js", 8 | "type": "commonjs", 9 | "repository": "github:anthropics/anthropic-sdk-typescript", 10 | "license": "MIT", 11 | "packageManager": "yarn@1.22.22", 12 | "files": [ 13 | "**/*" 14 | ], 15 | "private": false, 16 | "scripts": { 17 | "test": "./scripts/test", 18 | "build": "./scripts/build-all", 19 | "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", 20 | "format": "./scripts/format", 21 | "prepare": "if ./scripts/utils/check-is-in-git-install.sh; then ./scripts/build && ./scripts/utils/git-swap.sh; fi", 22 | "tsn": "ts-node -r tsconfig-paths/register", 23 | "lint": "./scripts/lint", 24 | "fix": "./scripts/format" 25 | }, 26 | "dependencies": {}, 27 | "devDependencies": { 28 | "@arethetypeswrong/cli": "^0.17.0", 29 | "@swc/core": "^1.3.102", 30 | "@swc/jest": "^0.2.29", 31 | "@types/jest": "^29.4.0", 32 | "@types/node": "^20.17.6", 33 | "typescript-eslint": "8.31.1", 34 | "@typescript-eslint/eslint-plugin": "8.31.1", 35 | "@typescript-eslint/parser": "8.31.1", 36 | "eslint": "^9.20.1", 37 | "eslint-plugin-prettier": "^5.4.1", 38 | "eslint-plugin-unused-imports": "^4.1.4", 39 | "iconv-lite": "^0.6.3", 40 | "jest": "^29.4.0", 41 | "prettier": "^3.0.0", 42 | "publint": "^0.2.12", 43 | "ts-jest": "^29.1.0", 44 | "ts-node": "^10.5.0", 45 | "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz", 46 | "tsconfig-paths": "^4.0.0", 47 | "typescript": "5.8.3" 48 | }, 49 | "imports": { 50 | "@anthropic-ai/sdk": ".", 51 | "@anthropic-ai/sdk/*": "./src/*" 52 | }, 53 | "bin": { 54 | "anthropic-ai-sdk": "bin/cli" 55 | }, 56 | "exports": { 57 | ".": { 58 | "import": "./dist/index.mjs", 59 | "require": "./dist/index.js" 60 | }, 61 | "./*.mjs": { 62 | "default": "./dist/*.mjs" 63 | }, 64 | "./*.js": { 65 | "default": "./dist/*.js" 66 | }, 67 | "./*": { 68 | "import": "./dist/*.mjs", 69 | "require": "./dist/*.js" 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/README.md: -------------------------------------------------------------------------------- 1 | # Anthropic Bedrock TypeScript API Library 2 | 3 | [![NPM version](https://img.shields.io/npm/v/@anthropic-ai/bedrock-sdk.svg)](https://npmjs.org/package/@anthropic-ai/bedrock-sdk) 4 | 5 | This library provides convenient access to the Anthropic Bedrock API. 6 | 7 | For the non-Bedrock Anthropic API at api.anthropic.com, see [`@anthropic-ai/sdk`](https://github.com/anthropics/anthropic-sdk-typescript). 8 | 9 | ## Installation 10 | 11 | ```sh 12 | npm install @anthropic-ai/bedrock-sdk 13 | ``` 14 | 15 | ## Usage 16 | 17 | 18 | ```js 19 | import { AnthropicBedrock } from '@anthropic-ai/bedrock-sdk'; 20 | 21 | // Note: this assumes you have configured AWS credentials in a way 22 | // that the AWS Node SDK will recognise, typicaly a shared `~/.aws/credentials` 23 | // file or `AWS_ACCESS_KEY_ID` & `AWS_SECRET_ACCESS_KEY` environment variables. 24 | // 25 | // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html 26 | const client = new AnthropicBedrock(); 27 | 28 | async function main() { 29 | const message = await client.messages.create({ 30 | model: 'anthropic.claude-3-5-sonnet-20241022-v2:0', 31 | messages: [ 32 | { 33 | role: 'user', 34 | content: 'Hello!', 35 | }, 36 | ], 37 | max_tokens: 1024, 38 | }); 39 | console.log(message); 40 | } 41 | 42 | main(); 43 | ``` 44 | 45 | For more details on how to use the SDK, see the [README.md for the main Anthropic SDK](https://github.com/anthropics/anthropic-sdk-typescript/tree/main#anthropic-typescript-api-library) which this library extends. 46 | 47 | ## Requirements 48 | 49 | TypeScript >= 4.5 is supported. 50 | 51 | The following runtimes are supported: 52 | 53 | - Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. 54 | - Deno v1.28.0 or higher, using `import { AnthropicBedrock } from "npm:@anthropic-ai/bedrock-sdk"`. 55 | - Bun 1.0 or later. 56 | - Cloudflare Workers. 57 | - Vercel Edge Runtime. 58 | - Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). 59 | - Nitro v2.6 or greater. 60 | 61 | Note that React Native is not supported at this time. 62 | 63 | If you are interested in other runtime environments, please open or upvote an issue on GitHub. 64 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exuo pipefail 3 | 4 | rm -rf dist; mkdir dist 5 | 6 | # Copy src to dist/src and build from dist/src into dist, so that 7 | # the source map for index.js.map will refer to ./src/index.ts etc 8 | cp -rp src README.md dist 9 | 10 | for file in LICENSE; do 11 | if [ -e "../../${file}" ]; then cp "../../${file}" dist; fi 12 | done 13 | 14 | for file in CHANGELOG.md; do 15 | if [ -e "${file}" ]; then cp "${file}" dist; fi 16 | done 17 | 18 | # this converts the export map paths for the dist directory 19 | # and does a few other minor things 20 | PKG_JSON_PATH=../../packages/bedrock-sdk/package.json node ../../scripts/utils/make-dist-package-json.cjs > dist/package.json 21 | 22 | # updates the `@anthropic-ai/sdk` dependency to point to NPM 23 | node scripts/postprocess-dist-package-json.cjs 24 | 25 | # build to .js/.mjs/.d.ts files 26 | npm exec tsc-multi 27 | # we need to patch index.js so that `new module.exports()` works for cjs backwards 28 | # compat. No way to get that from index.ts because it would cause compile errors 29 | # when building .mjs 30 | DIST_PATH=./dist node ../../scripts/utils/fix-index-exports.cjs 31 | 32 | cp tsconfig.dist-src.json dist/src/tsconfig.json 33 | 34 | DIST_PATH=./dist PKG_IMPORT_PATH=@anthropic-ai/bedrock-sdk/ node ../../scripts/utils/postprocess-files.cjs 35 | 36 | # make sure that nothing crashes when we require the output CJS or 37 | # import the output ESM 38 | (cd dist && node -e 'require("@anthropic-ai/bedrock-sdk")') 39 | (cd dist && node -e 'import("@anthropic-ai/bedrock-sdk")' --input-type=module) 40 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/examples/demo.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import { AnthropicBedrock } from '@anthropic-ai/bedrock-sdk'; 4 | 5 | // Note: this assumes you have configured AWS credentials in a way 6 | // that the AWS Node SDK will recognise, typicaly a shared `~/.aws/credentials` 7 | // file or `AWS_ACCESS_KEY_ID` & `AWS_SECRET_ACCESS_KEY` environment variables. 8 | // 9 | // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html 10 | const anthropic = new AnthropicBedrock(); 11 | 12 | async function main() { 13 | const message = await anthropic.messages.create({ 14 | model: 'anthropic.claude-3-5-sonnet-20241022-v2:0', 15 | messages: [ 16 | { 17 | role: 'user', 18 | content: 'Hello!', 19 | }, 20 | ], 21 | max_tokens: 1024, 22 | }); 23 | console.log(message); 24 | } 25 | 26 | main(); 27 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/examples/streaming.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import { AnthropicBedrock } from '@anthropic-ai/bedrock-sdk'; 4 | 5 | // Note: this assumes you have configured AWS credentials in a way 6 | // that the AWS Node SDK will recognise, typicaly a shared `~/.aws/credentials` 7 | // file or `AWS_ACCESS_KEY_ID` & `AWS_SECRET_ACCESS_KEY` environment variables. 8 | // 9 | // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html 10 | const client = new AnthropicBedrock(); 11 | 12 | async function main() { 13 | const stream = await client.messages.create({ 14 | model: 'anthropic.claude-3-5-sonnet-20241022-v2:0', 15 | messages: [ 16 | { 17 | role: 'user', 18 | content: 'Hello!', 19 | }, 20 | ], 21 | max_tokens: 1024, 22 | stream: true, 23 | }); 24 | 25 | for await (const event of stream) { 26 | if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') { 27 | process.stdout.write(event.delta.text); 28 | } 29 | } 30 | process.stdout.write('\n'); 31 | } 32 | 33 | main(); 34 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { JestConfigWithTsJest } from 'ts-jest'; 2 | 3 | const config: JestConfigWithTsJest = { 4 | preset: 'ts-jest/presets/default-esm', 5 | testEnvironment: 'node', 6 | transform: { 7 | '^.+\\.(t|j)sx?$': ['@swc/jest', { sourceMaps: 'inline' }], 8 | }, 9 | moduleNameMapper: { 10 | '^@anthropic-ai/bedrock-sdk$': '/src/index.ts', 11 | '^@anthropic-ai/bedrock-sdk/(.*)$': '/src/$1', 12 | }, 13 | modulePathIgnorePatterns: ['/dist/', '/deno/'], 14 | testPathIgnorePatterns: ['scripts'], 15 | }; 16 | 17 | export default config; 18 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@anthropic-ai/bedrock-sdk", 3 | "version": "0.22.1", 4 | "description": "The official TypeScript library for the Anthropic Bedrock API", 5 | "author": "Anthropic ", 6 | "types": "dist/index.d.ts", 7 | "main": "dist/index.js", 8 | "type": "commonjs", 9 | "repository": "github:anthropics/anthropic-sdk-typescript", 10 | "license": "MIT", 11 | "packageManager": "yarn@1.22.21", 12 | "private": false, 13 | "scripts": { 14 | "test": "jest", 15 | "build": "bash ./build", 16 | "prepack": "echo 'to pack, run yarn build && (cd dist; yarn pack)' && exit 1", 17 | "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", 18 | "format": "prettier --write --cache --cache-strategy metadata . !dist", 19 | "prepare": "if [ $(basename $(dirname $PWD)) = 'node_modules' ]; then npm run build; fi", 20 | "tsn": "ts-node -r tsconfig-paths/register", 21 | "lint": "eslint --ext ts,js .", 22 | "fix": "eslint --fix --ext ts,js ." 23 | }, 24 | "dependencies": { 25 | "@anthropic-ai/sdk": "file:../../dist/", 26 | "@aws-crypto/sha256-js": "^4.0.0", 27 | "@aws-sdk/client-bedrock-runtime": "^3.797.0", 28 | "@aws-sdk/credential-providers": "^3.796.0", 29 | "@smithy/eventstream-serde-node": "^2.0.10", 30 | "@smithy/fetch-http-handler": "^2.2.1", 31 | "@smithy/protocol-http": "^3.0.6", 32 | "@smithy/signature-v4": "^3.1.1", 33 | "@smithy/smithy-client": "^2.1.9", 34 | "@smithy/types": "^2.3.4", 35 | "@smithy/util-base64": "^2.0.0" 36 | }, 37 | "devDependencies": { 38 | "@swc/core": "^1.3.101", 39 | "@swc/jest": "^0.2.29", 40 | "@types/node": "^20.17.6", 41 | "@types/jest": "^29.4.0", 42 | "@typescript-eslint/eslint-plugin": "^6.7.0", 43 | "@typescript-eslint/parser": "^6.7.0", 44 | "eslint": "^8.49.0", 45 | "eslint-plugin-prettier": "^5.0.1", 46 | "eslint-plugin-unused-imports": "^3.0.0", 47 | "jest": "^29.4.0", 48 | "prettier": "^3.0.0", 49 | "ts-jest": "^29.1.0", 50 | "ts-morph": "^19.0.0", 51 | "ts-node": "^10.5.0", 52 | "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.3/tsc-multi.tgz", 53 | "tsconfig-paths": "^4.0.0", 54 | "typescript": "^4.8.2" 55 | }, 56 | "imports": { 57 | "@anthropic-ai/bedrock-sdk": ".", 58 | "@anthropic-ai/bedrock-sdk/*": "./src/*" 59 | }, 60 | "exports": { 61 | ".": { 62 | "require": { 63 | "types": "./dist/index.d.ts", 64 | "default": "./dist/index.js" 65 | }, 66 | "types": "./dist/index.d.mts", 67 | "default": "./dist/index.mjs" 68 | }, 69 | "./*.mjs": { 70 | "types": "./dist/*.d.ts", 71 | "default": "./dist/*.mjs" 72 | }, 73 | "./*.js": { 74 | "types": "./dist/*.d.ts", 75 | "default": "./dist/*.js" 76 | }, 77 | "./*": { 78 | "types": "./dist/*.d.ts", 79 | "require": "./dist/*.js", 80 | "default": "./dist/*.mjs" 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/scripts/postprocess-dist-package-json.cjs: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const pkgJson = require('../dist/package.json'); 3 | 4 | for (const dep in pkgJson.dependencies) { 5 | // ensure we point to NPM instead of a local directory 6 | if (dep === '@anthropic-ai/sdk') { 7 | pkgJson.dependencies[dep] = '>=0.50.3 <1'; 8 | } 9 | } 10 | 11 | fs.writeFileSync('dist/package.json', JSON.stringify(pkgJson, null, 2)); 12 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/src/core/auth.ts: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import { SignatureV4 } from '@smithy/signature-v4'; 3 | import { fromNodeProviderChain } from '@aws-sdk/credential-providers'; 4 | import { HttpRequest } from '@smithy/protocol-http'; 5 | import { Sha256 } from '@aws-crypto/sha256-js'; 6 | 7 | type AuthProps = { 8 | url: string; 9 | regionName: string; 10 | awsAccessKey: string | null | undefined; 11 | awsSecretKey: string | null | undefined; 12 | awsSessionToken: string | null | undefined; 13 | }; 14 | 15 | export const getAuthHeaders = async (req: RequestInit, props: AuthProps): Promise> => { 16 | assert(req.method, 'Expected request method property to be set'); 17 | 18 | const providerChain = fromNodeProviderChain(); 19 | 20 | const credentials = await withTempEnv( 21 | () => { 22 | // Temporarily set the appropriate environment variables if we've been 23 | // explicitly given credentials so that the credentials provider can 24 | // resolve them. 25 | // 26 | // Note: the environment provider is only not run first if the `AWS_PROFILE` 27 | // environment variable is set. 28 | // https://github.com/aws/aws-sdk-js-v3/blob/44a18a34b2c93feccdfcd162928d13e6dbdcaf30/packages/credential-provider-node/src/defaultProvider.ts#L49 29 | if (props.awsAccessKey) { 30 | process.env['AWS_ACCESS_KEY_ID'] = props.awsAccessKey; 31 | } 32 | if (props.awsSecretKey) { 33 | process.env['AWS_SECRET_ACCESS_KEY'] = props.awsSecretKey; 34 | } 35 | if (props.awsSessionToken) { 36 | process.env['AWS_SESSION_TOKEN'] = props.awsSessionToken; 37 | } 38 | }, 39 | () => providerChain(), 40 | ); 41 | 42 | const signer = new SignatureV4({ 43 | service: 'bedrock', 44 | region: props.regionName, 45 | credentials, 46 | sha256: Sha256, 47 | }); 48 | 49 | const url = new URL(props.url); 50 | 51 | const headers = 52 | !req.headers ? {} 53 | : Symbol.iterator in req.headers ? 54 | Object.fromEntries(Array.from(req.headers).map((header) => [...header])) 55 | : { ...req.headers }; 56 | 57 | // The connection header may be stripped by a proxy somewhere, so the receiver 58 | // of this message may not see this header, so we remove it from the set of headers 59 | // that are signed. 60 | delete headers['connection']; 61 | headers['host'] = url.hostname; 62 | 63 | const request = new HttpRequest({ 64 | method: req.method.toUpperCase(), 65 | protocol: url.protocol, 66 | path: url.pathname, 67 | headers, 68 | body: req.body, 69 | }); 70 | 71 | const signed = await signer.sign(request); 72 | return signed.headers; 73 | }; 74 | 75 | const withTempEnv = async (updateEnv: () => void, fn: () => Promise): Promise => { 76 | const previousEnv = { ...process.env }; 77 | 78 | try { 79 | updateEnv(); 80 | return await fn(); 81 | } finally { 82 | process.env = previousEnv; 83 | } 84 | }; 85 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/src/core/error.ts: -------------------------------------------------------------------------------- 1 | export * from '@anthropic-ai/sdk/core/error'; 2 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/src/core/pagination.ts: -------------------------------------------------------------------------------- 1 | export * from '@anthropic-ai/sdk/core/pagination'; 2 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/src/core/streaming.ts: -------------------------------------------------------------------------------- 1 | import { EventStreamMarshaller } from '@smithy/eventstream-serde-node'; 2 | import { fromBase64, toBase64 } from '@smithy/util-base64'; 3 | import { streamCollector } from '@smithy/fetch-http-handler'; 4 | import { EventStreamSerdeContext, SerdeContext } from '@smithy/types'; 5 | import { Stream as CoreStream, ServerSentEvent } from '@anthropic-ai/sdk/streaming'; 6 | import { AnthropicError } from '@anthropic-ai/sdk/error'; 7 | import { APIError } from '@anthropic-ai/sdk'; 8 | import { de_ResponseStream } from '../AWS_restJson1'; 9 | import { ReadableStreamToAsyncIterable } from '../internal/shims'; 10 | import { safeJSON } from '../internal/utils/values'; 11 | 12 | type Bytes = string | ArrayBuffer | Uint8Array | Buffer | null | undefined; 13 | 14 | export const toUtf8 = (input: Uint8Array): string => new TextDecoder('utf-8').decode(input); 15 | export const fromUtf8 = (input: string): Uint8Array => new TextEncoder().encode(input); 16 | 17 | // `de_ResponseStream` parses a Bedrock response stream and emits events as they are found. 18 | // It requires a "context" argument which has many fields, but for what we're using it for 19 | // it only needs this. 20 | export const getMinimalSerdeContext = (): SerdeContext & EventStreamSerdeContext => { 21 | const marshaller = new EventStreamMarshaller({ utf8Encoder: toUtf8, utf8Decoder: fromUtf8 }); 22 | return { 23 | base64Decoder: fromBase64, 24 | base64Encoder: toBase64, 25 | utf8Decoder: fromUtf8, 26 | utf8Encoder: toUtf8, 27 | eventStreamMarshaller: marshaller, 28 | streamCollector: streamCollector, 29 | } as unknown as SerdeContext & EventStreamSerdeContext; 30 | }; 31 | 32 | export class Stream extends CoreStream { 33 | static override fromSSEResponse(response: Response, controller: AbortController) { 34 | let consumed = false; 35 | 36 | async function* iterMessages(): AsyncGenerator { 37 | if (!response.body) { 38 | controller.abort(); 39 | throw new AnthropicError(`Attempted to iterate over a response with no body`); 40 | } 41 | 42 | const responseBodyIter = ReadableStreamToAsyncIterable(response.body); 43 | const eventStream = de_ResponseStream(responseBodyIter, getMinimalSerdeContext()); 44 | for await (const event of eventStream) { 45 | if (event.chunk && event.chunk.bytes) { 46 | const s = toUtf8(event.chunk.bytes); 47 | yield { event: 'chunk', data: s, raw: [] }; 48 | } else if (event.internalServerException) { 49 | yield { event: 'error', data: 'InternalServerException', raw: [] }; 50 | } else if (event.modelStreamErrorException) { 51 | yield { event: 'error', data: 'ModelStreamErrorException', raw: [] }; 52 | } else if (event.validationException) { 53 | yield { event: 'error', data: 'ValidationException', raw: [] }; 54 | } else if (event.throttlingException) { 55 | yield { event: 'error', data: 'ThrottlingException', raw: [] }; 56 | } 57 | } 58 | } 59 | 60 | // Note: this function is copied entirely from the core SDK 61 | async function* iterator(): AsyncIterator { 62 | if (consumed) { 63 | throw new Error('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); 64 | } 65 | consumed = true; 66 | let done = false; 67 | try { 68 | for await (const sse of iterMessages()) { 69 | if (sse.event === 'chunk') { 70 | try { 71 | yield JSON.parse(sse.data); 72 | } catch (e) { 73 | console.error(`Could not parse message into JSON:`, sse.data); 74 | console.error(`From chunk:`, sse.raw); 75 | throw e; 76 | } 77 | } 78 | 79 | if (sse.event === 'error') { 80 | const errText = sse.data; 81 | const errJSON = safeJSON(errText); 82 | const errMessage = errJSON ? undefined : errText; 83 | 84 | throw APIError.generate(undefined, errJSON, errMessage, response.headers); 85 | } 86 | } 87 | done = true; 88 | } catch (e) { 89 | // If the user calls `stream.controller.abort()`, we should exit without throwing. 90 | if (isAbortError(e)) return; 91 | throw e; 92 | } finally { 93 | // If the user `break`s, abort the ongoing request. 94 | if (!done) controller.abort(); 95 | } 96 | } 97 | 98 | return new Stream(iterator, controller); 99 | } 100 | } 101 | 102 | function isAbortError(err: unknown) { 103 | return ( 104 | typeof err === 'object' && 105 | err !== null && 106 | // Spec-compliant fetch implementations 107 | (('name' in err && (err as any).name === 'AbortError') || 108 | // Expo fetch 109 | ('message' in err && String((err as any).message).includes('FetchRequestCanceledException'))) 110 | ); 111 | } 112 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './client'; 2 | export { AnthropicBedrock as default } from './client'; 3 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/src/internal: -------------------------------------------------------------------------------- 1 | ../../../src/internal -------------------------------------------------------------------------------- /packages/bedrock-sdk/tests/client.test.ts: -------------------------------------------------------------------------------- 1 | // Mock the client to allow for a more integration-style test 2 | // We're mocking specific parts of the AnthropicBedrock client to avoid 3 | // dependencies while still testing the integration behavior 4 | 5 | // Mock specific parts of the client 6 | jest.mock('../src/core/auth', () => ({ 7 | getAuthHeaders: jest.fn().mockResolvedValue({}), 8 | })); 9 | 10 | // Create a mock fetch function 11 | const mockFetch = jest.fn().mockImplementation(() => { 12 | return Promise.resolve({ 13 | ok: true, 14 | status: 200, 15 | statusText: 'OK', 16 | headers: new Headers({ 'content-type': 'application/json' }), 17 | json: () => Promise.resolve({}), 18 | text: () => Promise.resolve('{}'), 19 | }); 20 | }); 21 | 22 | // Store original fetch function 23 | const originalFetch = global.fetch; 24 | 25 | describe('Bedrock model ARN URL encoding integration test', () => { 26 | beforeEach(() => { 27 | // Replace global fetch with our mock 28 | global.fetch = mockFetch; 29 | // Clear mock history 30 | mockFetch.mockClear(); 31 | }); 32 | 33 | afterEach(() => { 34 | // Restore original fetch 35 | global.fetch = originalFetch; 36 | }); 37 | 38 | test('properly encodes model ARNs with slashes in URL path', async () => { 39 | // Import the client - do this inside the test to ensure mocks are set up first 40 | const { AnthropicBedrock } = require('../src'); 41 | 42 | // Create client instance 43 | const client = new AnthropicBedrock({ 44 | awsRegion: 'us-east-1', 45 | baseURL: 'http://localhost:4010', 46 | }); 47 | 48 | // Model ARN with slashes that needs encoding 49 | const modelArn = 50 | 'arn:aws:bedrock:us-east-2:1234:inference-profile/us.anthropic.claude-3-7-sonnet-20250219-v1:0'; 51 | 52 | // Make a request to trigger the URL construction with the ARN 53 | try { 54 | await client.messages.create({ 55 | model: modelArn, 56 | max_tokens: 1024, 57 | messages: [{ content: 'Test message', role: 'user' }], 58 | }); 59 | } catch (e) { 60 | // We expect errors due to mocking - we're just interested in the URL construction 61 | } 62 | 63 | // Verify that fetch was called 64 | expect(mockFetch).toHaveBeenCalled(); 65 | 66 | // Get the URL that was passed to fetch 67 | const fetchUrl = mockFetch.mock.calls[0][0]; 68 | 69 | // Expected URL with properly encoded ARN (slash encoded as %2F) 70 | const expectedUrl = 71 | 'http://localhost:4010/model/arn:aws:bedrock:us-east-2:1234:inference-profile%2Fus.anthropic.claude-3-7-sonnet-20250219-v1:0/invoke'; 72 | 73 | // Verify the exact URL matches what we expect 74 | expect(fetchUrl).toBe(expectedUrl); 75 | }); 76 | 77 | test('properly constructs URL path for normal model names', async () => { 78 | // Import the client - do this inside the test to ensure mocks are set up first 79 | const { AnthropicBedrock } = require('../src'); 80 | 81 | // Create client instance 82 | const client = new AnthropicBedrock({ 83 | awsRegion: 'us-east-1', 84 | baseURL: 'http://localhost:4010', 85 | }); 86 | 87 | // Regular model name (still contains characters that need encoding) 88 | const modelName = 'anthropic.claude-3-sonnet-20240229-v1:0'; 89 | 90 | // Make a request to trigger the URL construction 91 | try { 92 | await client.messages.create({ 93 | model: modelName, 94 | max_tokens: 1024, 95 | messages: [{ content: 'Test message', role: 'user' }], 96 | }); 97 | } catch (e) { 98 | // We expect errors due to mocking - we're just interested in the URL construction 99 | } 100 | 101 | // Verify that fetch was called 102 | expect(mockFetch).toHaveBeenCalled(); 103 | 104 | // Get the URL that was passed to fetch 105 | const fetchUrl = mockFetch.mock.calls[0][0]; 106 | 107 | // Expected URL with properly encoded model name 108 | const expectedUrl = 'http://localhost:4010/model/anthropic.claude-3-sonnet-20240229-v1:0/invoke'; 109 | 110 | // Verify the exact URL matches what we expect 111 | expect(fetchUrl).toBe(expectedUrl); 112 | }); 113 | }); 114 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/tsc-multi.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { "extname": ".js", "module": "commonjs" }, 4 | { "extname": ".mjs", "module": "esnext" } 5 | ], 6 | "projects": ["tsconfig.build.json"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["dist/src"], 4 | "exclude": ["dist/src/internal/detect-platform.ts"], 5 | "compilerOptions": { 6 | "rootDir": "./dist/src", 7 | "paths": { 8 | "@anthropic-ai/bedrock-sdk/*": ["src/*"], 9 | "@anthropic-ai/bedrock-sdk": ["src/index.ts"] 10 | }, 11 | "noEmit": false, 12 | "declaration": true, 13 | "declarationMap": true, 14 | "outDir": "dist", 15 | "pretty": true, 16 | "sourceMap": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/tsconfig.deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["deno"], 4 | "exclude": [], 5 | "compilerOptions": { 6 | "rootDir": "./deno", 7 | "lib": ["es2020", "DOM"], 8 | "paths": { 9 | "@anthropic-ai/bedrock-sdk/*": ["src/*"], 10 | "@anthropic-ai/bedrock-sdk": ["src/index.ts"] 11 | }, 12 | "noEmit": true, 13 | "declaration": true, 14 | "declarationMap": true, 15 | "outDir": "deno", 16 | "pretty": true, 17 | "sourceMap": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/tsconfig.dist-src.json: -------------------------------------------------------------------------------- 1 | { 2 | // this config is included in the published src directory to prevent TS errors 3 | // from appearing when users go to source, and VSCode opens the source .ts file 4 | // via declaration maps 5 | "include": ["index.ts"], 6 | "compilerOptions": { 7 | "target": "ES2015", 8 | "lib": ["DOM", "DOM.Iterable", "ES2018"], 9 | "moduleResolution": "node" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/bedrock-sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src", "tests", "examples"], 3 | "exclude": ["dist/src/internal/detect-platform.ts"], 4 | "compilerOptions": { 5 | "target": "es2020", 6 | "lib": ["es2020"], 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "esModuleInterop": true, 10 | "baseUrl": "./", 11 | "paths": { 12 | "@anthropic-ai/bedrock-sdk/*": ["src/*"], 13 | "@anthropic-ai/bedrock-sdk": ["src/index.ts"] 14 | }, 15 | "noEmit": true, 16 | 17 | "resolveJsonModule": true, 18 | 19 | "forceConsistentCasingInFileNames": true, 20 | 21 | "strict": true, 22 | "noImplicitAny": true, 23 | "strictNullChecks": true, 24 | "strictFunctionTypes": true, 25 | "strictBindCallApply": true, 26 | "strictPropertyInitialization": true, 27 | "noImplicitThis": true, 28 | "noImplicitReturns": true, 29 | "alwaysStrict": true, 30 | "exactOptionalPropertyTypes": true, 31 | "noUncheckedIndexedAccess": true, 32 | "noImplicitOverride": true, 33 | "noPropertyAccessFromIndexSignature": true, 34 | 35 | "skipLibCheck": true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/vertex-sdk/README.md: -------------------------------------------------------------------------------- 1 | # Anthropic Vertex TypeScript API Library 2 | 3 | [![NPM version](https://img.shields.io/npm/v/@anthropic-ai/vertex-sdk.svg)](https://npmjs.org/package/@anthropic-ai/vertex-sdk) 4 | 5 | This library provides convenient access to the Anthropic Vertex API. 6 | 7 | For the non-Vertex Anthropic API at api.anthropic.com, see [`@anthropic-ai/sdk`](https://github.com/anthropics/anthropic-sdk-typescript). 8 | 9 | ## Installation 10 | 11 | ```sh 12 | npm install @anthropic-ai/vertex-sdk 13 | ``` 14 | 15 | ## Usage 16 | 17 | 18 | ```js 19 | import { AnthropicVertex } from '@anthropic-ai/vertex-sdk'; 20 | 21 | // Reads from the `CLOUD_ML_REGION` & `ANTHROPIC_VERTEX_PROJECT_ID` environment variables. 22 | // Additionally goes through the standard `google-auth-library` flow. 23 | const client = new AnthropicVertex(); 24 | 25 | async function main() { 26 | const result = await client.messages.create({ 27 | messages: [ 28 | { 29 | role: 'user', 30 | content: 'Hey Claude!', 31 | }, 32 | ], 33 | model: 'claude-3-5-sonnet-v2@20241022', 34 | max_tokens: 300, 35 | }); 36 | console.log(JSON.stringify(result, null, 2)); 37 | } 38 | 39 | main(); 40 | ``` 41 | 42 | For more details on how to use the SDK, see the [README.md for the main Anthropic SDK](https://github.com/anthropics/anthropic-sdk-typescript/tree/main#anthropic-typescript-api-library) which this library extends. 43 | 44 | ## Requirements 45 | 46 | TypeScript >= 4.5 is supported. 47 | 48 | The following runtimes are supported: 49 | 50 | - Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. 51 | - Deno v1.28.0 or higher, using `import { AnthropicVertex } from "npm:@anthropic-ai/vertex-sdk"`. 52 | - Bun 1.0 or later. 53 | - Cloudflare Workers. 54 | - Vercel Edge Runtime. 55 | - Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). 56 | - Nitro v2.6 or greater. 57 | 58 | Note that React Native is not supported at this time. 59 | 60 | If you are interested in other runtime environments, please open or upvote an issue on GitHub. 61 | -------------------------------------------------------------------------------- /packages/vertex-sdk/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exuo pipefail 3 | 4 | rm -rf dist; mkdir dist 5 | 6 | # Copy src to dist/src and build from dist/src into dist, so that 7 | # the source map for index.js.map will refer to ./src/index.ts etc 8 | cp -rp src README.md dist 9 | 10 | for file in LICENSE; do 11 | if [ -e "../../${file}" ]; then cp "../../${file}" dist; fi 12 | done 13 | 14 | for file in CHANGELOG.md; do 15 | if [ -e "${file}" ]; then cp "${file}" dist; fi 16 | done 17 | 18 | # this converts the export map paths for the dist directory 19 | # and does a few other minor things 20 | PKG_JSON_PATH=../../packages/vertex-sdk/package.json node ../../scripts/utils/make-dist-package-json.cjs > dist/package.json 21 | 22 | # updates the `@anthropic-ai/sdk` dependency to point to NPM 23 | node scripts/postprocess-dist-package-json.cjs 24 | 25 | # build to .js/.mjs/.d.ts files 26 | npm exec tsc-multi 27 | # we need to patch index.js so that `new module.exports()` works for cjs backwards 28 | # compat. No way to get that from index.ts because it would cause compile errors 29 | # when building .mjs 30 | DIST_PATH=./dist node ../../scripts/utils/fix-index-exports.cjs 31 | 32 | cp tsconfig.dist-src.json dist/src/tsconfig.json 33 | 34 | DIST_PATH=./dist PKG_IMPORT_PATH=@anthropic-ai/vertex-sdk/ node ../../scripts/utils/postprocess-files.cjs 35 | 36 | # make sure that nothing crashes when we require the output CJS or 37 | # import the output ESM 38 | (cd dist && node -e 'require("@anthropic-ai/vertex-sdk")') 39 | (cd dist && node -e 'import("@anthropic-ai/vertex-sdk")' --input-type=module) 40 | -------------------------------------------------------------------------------- /packages/vertex-sdk/examples/vertex.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S npm run tsn -T 2 | 3 | import { AnthropicVertex } from '@anthropic-ai/vertex-sdk'; 4 | 5 | // Reads from the `CLOUD_ML_REGION` & `ANTHROPIC_VERTEX_PROJECT_ID` 6 | // environment variables. 7 | const client = new AnthropicVertex(); 8 | 9 | async function main() { 10 | const result = await client.messages.create({ 11 | messages: [ 12 | { 13 | role: 'user', 14 | content: 'Hello!', 15 | }, 16 | ], 17 | model: 'claude-3-5-sonnet-v2@20241022', 18 | max_tokens: 300, 19 | }); 20 | console.log(JSON.stringify(result, null, 2)); 21 | } 22 | 23 | main().catch((err) => { 24 | console.error(err); 25 | process.exit(1); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/vertex-sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@anthropic-ai/vertex-sdk", 3 | "version": "0.11.4", 4 | "description": "The official TypeScript library for the Anthropic Vertex API", 5 | "author": "Anthropic ", 6 | "types": "dist/index.d.ts", 7 | "main": "dist/index.js", 8 | "type": "commonjs", 9 | "repository": "github:anthropics/anthropic-sdk-typescript", 10 | "license": "MIT", 11 | "packageManager": "yarn@1.22.21", 12 | "private": false, 13 | "scripts": { 14 | "test": "echo 'no tests defined yet' && exit 1", 15 | "build": "bash ./build", 16 | "prepack": "echo 'to pack, run yarn build && (cd dist; yarn pack)' && exit 1", 17 | "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", 18 | "format": "prettier --write --cache --cache-strategy metadata . !dist", 19 | "prepare": "if [ $(basename $(dirname $PWD)) = 'node_modules' ]; then npm run build; fi", 20 | "tsn": "ts-node -r tsconfig-paths/register", 21 | "lint": "eslint --ext ts,js .", 22 | "fix": "eslint --fix --ext ts,js ." 23 | }, 24 | "dependencies": { 25 | "@anthropic-ai/sdk": "file:../../dist/", 26 | "google-auth-library": "^9.4.2" 27 | }, 28 | "devDependencies": { 29 | "@types/node": "^20.17.6", 30 | "@types/jest": "^29.4.0", 31 | "@typescript-eslint/eslint-plugin": "^6.7.0", 32 | "@typescript-eslint/parser": "^6.7.0", 33 | "eslint": "^8.49.0", 34 | "eslint-plugin-prettier": "^5.0.1", 35 | "eslint-plugin-unused-imports": "^3.0.0", 36 | "jest": "^29.4.0", 37 | "prettier": "^3.0.0", 38 | "ts-jest": "^29.1.0", 39 | "ts-morph": "^19.0.0", 40 | "ts-node": "^10.5.0", 41 | "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.3/tsc-multi.tgz", 42 | "tsconfig-paths": "^4.0.0", 43 | "typescript": "^4.8.2" 44 | }, 45 | "imports": { 46 | "@anthropic-ai/vertex-sdk": ".", 47 | "@anthropic-ai/vertex-sdk/*": "./src/*" 48 | }, 49 | "exports": { 50 | ".": { 51 | "require": { 52 | "types": "./dist/index.d.ts", 53 | "default": "./dist/index.js" 54 | }, 55 | "types": "./dist/index.d.mts", 56 | "default": "./dist/index.mjs" 57 | }, 58 | "./*.mjs": { 59 | "types": "./dist/*.d.ts", 60 | "default": "./dist/*.mjs" 61 | }, 62 | "./*.js": { 63 | "types": "./dist/*.d.ts", 64 | "default": "./dist/*.js" 65 | }, 66 | "./*": { 67 | "types": "./dist/*.d.ts", 68 | "require": "./dist/*.js", 69 | "default": "./dist/*.mjs" 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/vertex-sdk/scripts/postprocess-dist-package-json.cjs: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const pkgJson = require('../dist/package.json'); 3 | 4 | for (const dep in pkgJson.dependencies) { 5 | // ensure we point to NPM instead of a local directory 6 | if (dep === '@anthropic-ai/sdk') { 7 | pkgJson.dependencies[dep] = '>=0.50.3 <1'; 8 | } 9 | } 10 | 11 | fs.writeFileSync('dist/package.json', JSON.stringify(pkgJson, null, 2)); 12 | -------------------------------------------------------------------------------- /packages/vertex-sdk/src/core/error.ts: -------------------------------------------------------------------------------- 1 | export * from '@anthropic-ai/sdk/core/error'; 2 | -------------------------------------------------------------------------------- /packages/vertex-sdk/src/core/pagination.ts: -------------------------------------------------------------------------------- 1 | export * from '@anthropic-ai/sdk/core/pagination'; 2 | -------------------------------------------------------------------------------- /packages/vertex-sdk/src/core/streaming.ts: -------------------------------------------------------------------------------- 1 | export * from '@anthropic-ai/sdk/core/streaming'; 2 | -------------------------------------------------------------------------------- /packages/vertex-sdk/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './client'; 2 | export { AnthropicVertex as default } from './client'; 3 | -------------------------------------------------------------------------------- /packages/vertex-sdk/src/internal: -------------------------------------------------------------------------------- 1 | ../../../src/internal -------------------------------------------------------------------------------- /packages/vertex-sdk/tsc-multi.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { "extname": ".js", "module": "commonjs" }, 4 | { "extname": ".mjs", "module": "esnext" } 5 | ], 6 | "projects": ["tsconfig.build.json"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/vertex-sdk/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["dist/src"], 4 | "exclude": ["dist/src/internal/detect-platform.ts"], 5 | "compilerOptions": { 6 | "rootDir": "./dist/src", 7 | "paths": { 8 | "@anthropic-ai/vertex-sdk/*": ["src/*"], 9 | "@anthropic-ai/vertex-sdk": ["src/index.ts"] 10 | }, 11 | "noEmit": false, 12 | "declaration": true, 13 | "declarationMap": true, 14 | "outDir": "dist", 15 | "pretty": true, 16 | "sourceMap": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/vertex-sdk/tsconfig.deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["deno"], 4 | "exclude": [], 5 | "compilerOptions": { 6 | "rootDir": "./deno", 7 | "lib": ["es2020", "DOM"], 8 | "paths": { 9 | "@anthropic-ai/vertex-sdk/*": ["src/*"], 10 | "@anthropic-ai/vertex-sdk": ["src/index.ts"] 11 | }, 12 | "noEmit": true, 13 | "declaration": true, 14 | "declarationMap": true, 15 | "outDir": "deno", 16 | "pretty": true, 17 | "sourceMap": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/vertex-sdk/tsconfig.dist-src.json: -------------------------------------------------------------------------------- 1 | { 2 | // this config is included in the published src directory to prevent TS errors 3 | // from appearing when users go to source, and VSCode opens the source .ts file 4 | // via declaration maps 5 | "include": ["index.ts"], 6 | "compilerOptions": { 7 | "target": "es2015", 8 | "lib": ["DOM"], 9 | "moduleResolution": "node" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/vertex-sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src", "tests", "examples"], 3 | "exclude": ["dist/src/internal/detect-platform.ts"], 4 | "compilerOptions": { 5 | "target": "es2020", 6 | "lib": ["es2020"], 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "esModuleInterop": true, 10 | "baseUrl": "./", 11 | "paths": { 12 | "@anthropic-ai/vertex-sdk/*": ["src/*"], 13 | "@anthropic-ai/vertex-sdk": ["src/index.ts"] 14 | }, 15 | "noEmit": true, 16 | 17 | "resolveJsonModule": true, 18 | 19 | "forceConsistentCasingInFileNames": true, 20 | 21 | "strict": true, 22 | "noImplicitAny": true, 23 | "strictNullChecks": true, 24 | "strictFunctionTypes": true, 25 | "strictBindCallApply": true, 26 | "strictPropertyInitialization": true, 27 | "noImplicitThis": true, 28 | "noImplicitReturns": true, 29 | "alwaysStrict": true, 30 | "exactOptionalPropertyTypes": true, 31 | "noUncheckedIndexedAccess": true, 32 | "noImplicitOverride": true, 33 | "noPropertyAccessFromIndexSignature": true, 34 | 35 | "skipLibCheck": true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | ".": {}, 4 | "packages/vertex-sdk": {}, 5 | "packages/bedrock-sdk": {} 6 | }, 7 | "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", 8 | "include-v-in-tag": true, 9 | "include-component-in-tag": true, 10 | "versioning": "prerelease", 11 | "prerelease": true, 12 | "bump-minor-pre-major": true, 13 | "bump-patch-for-minor-pre-major": false, 14 | "pull-request-header": "Automated Release PR", 15 | "pull-request-title-pattern": "release: ${version}", 16 | "changelog-sections": [ 17 | { 18 | "type": "feat", 19 | "section": "Features" 20 | }, 21 | { 22 | "type": "fix", 23 | "section": "Bug Fixes" 24 | }, 25 | { 26 | "type": "perf", 27 | "section": "Performance Improvements" 28 | }, 29 | { 30 | "type": "revert", 31 | "section": "Reverts" 32 | }, 33 | { 34 | "type": "chore", 35 | "section": "Chores" 36 | }, 37 | { 38 | "type": "docs", 39 | "section": "Documentation" 40 | }, 41 | { 42 | "type": "style", 43 | "section": "Styles" 44 | }, 45 | { 46 | "type": "refactor", 47 | "section": "Refactors" 48 | }, 49 | { 50 | "type": "test", 51 | "section": "Tests", 52 | "hidden": true 53 | }, 54 | { 55 | "type": "build", 56 | "section": "Build System" 57 | }, 58 | { 59 | "type": "ci", 60 | "section": "Continuous Integration", 61 | "hidden": true 62 | } 63 | ], 64 | "release-type": "node", 65 | "extra-files": [ 66 | "src/version.ts", 67 | "README.md", 68 | "packages/vertex-sdk/yarn.lock", 69 | "packages/bedrock-sdk/yarn.lock" 70 | ] 71 | } 72 | -------------------------------------------------------------------------------- /scripts/bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then 8 | brew bundle check >/dev/null 2>&1 || { 9 | echo "==> Installing Homebrew dependencies…" 10 | brew bundle 11 | } 12 | fi 13 | 14 | echo "==> Installing Node dependencies…" 15 | 16 | PACKAGE_MANAGER=$(command -v yarn >/dev/null 2>&1 && echo "yarn" || echo "npm") 17 | 18 | $PACKAGE_MANAGER install 19 | -------------------------------------------------------------------------------- /scripts/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exuo pipefail 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | node scripts/utils/check-version.cjs 8 | 9 | # Build into dist and will publish the package from there, 10 | # so that src/resources/foo.ts becomes /resources/foo.js 11 | # This way importing from `"@anthropic-ai/sdk/resources/foo"` works 12 | # even with `"moduleResolution": "node"` 13 | 14 | rm -rf dist; mkdir dist 15 | # Copy src to dist/src and build from dist/src into dist, so that 16 | # the source map for index.js.map will refer to ./src/index.ts etc 17 | cp -rp src README.md dist 18 | for file in LICENSE CHANGELOG.md; do 19 | if [ -e "${file}" ]; then cp "${file}" dist; fi 20 | done 21 | if [ -e "bin/cli" ]; then 22 | mkdir -p dist/bin 23 | cp -p "bin/cli" dist/bin/; 24 | fi 25 | if [ -e "bin/migration-config.json" ]; then 26 | mkdir -p dist/bin 27 | cp -p "bin/migration-config.json" dist/bin/; 28 | fi 29 | # this converts the export map paths for the dist directory 30 | # and does a few other minor things 31 | node scripts/utils/make-dist-package-json.cjs > dist/package.json 32 | 33 | # build to .js/.mjs/.d.ts files 34 | npm exec tsc-multi 35 | # we need to patch index.js so that `new module.exports()` works for cjs backwards 36 | # compat. No way to get that from index.ts because it would cause compile errors 37 | # when building .mjs 38 | node scripts/utils/fix-index-exports.cjs 39 | cp tsconfig.dist-src.json dist/src/tsconfig.json 40 | 41 | node scripts/utils/postprocess-files.cjs 42 | 43 | # make sure that nothing crashes when we require the output CJS or 44 | # import the output ESM 45 | (cd dist && node -e 'require("@anthropic-ai/sdk")') 46 | (cd dist && node -e 'import("@anthropic-ai/sdk")' --input-type=module) 47 | 48 | if [ -e ./scripts/build-deno ] 49 | then 50 | ./scripts/build-deno 51 | fi 52 | -------------------------------------------------------------------------------- /scripts/build-all: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exuo pipefail 3 | 4 | # build the core SDK package an all sub-packages 5 | 6 | bash ./scripts/build 7 | 8 | for dir in packages/*; do 9 | if [ -d "$dir" ]; then 10 | (cd "$dir" && yarn install && yarn build) 11 | fi 12 | done 13 | -------------------------------------------------------------------------------- /scripts/format: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | echo "==> Running eslint --fix" 8 | ./node_modules/.bin/eslint --fix . 9 | 10 | echo "==> Running prettier --write" 11 | # format things eslint didn't 12 | ./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' 13 | -------------------------------------------------------------------------------- /scripts/lint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | echo "==> Running eslint" 8 | ./node_modules/.bin/eslint . 9 | 10 | echo "==> Building" 11 | ./scripts/build 12 | 13 | echo "==> Checking types" 14 | ./node_modules/typescript/bin/tsc 15 | 16 | echo "==> Running Are The Types Wrong?" 17 | ./node_modules/.bin/attw --pack dist -f json >.attw.json || true 18 | node scripts/utils/attw-report.cjs 19 | 20 | echo "==> Running publint" 21 | ./node_modules/.bin/publint dist 22 | -------------------------------------------------------------------------------- /scripts/mock: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | if [[ -n "$1" && "$1" != '--'* ]]; then 8 | URL="$1" 9 | shift 10 | else 11 | URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" 12 | fi 13 | 14 | # Check if the URL is empty 15 | if [ -z "$URL" ]; then 16 | echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" 17 | exit 1 18 | fi 19 | 20 | echo "==> Starting mock server with URL ${URL}" 21 | 22 | # Run prism mock on the given spec 23 | if [ "$1" == "--daemon" ]; then 24 | npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & 25 | 26 | # Wait for server to come online 27 | echo -n "Waiting for server" 28 | while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do 29 | echo -n "." 30 | sleep 0.1 31 | done 32 | 33 | if grep -q "✖ fatal" ".prism.log"; then 34 | cat .prism.log 35 | exit 1 36 | fi 37 | 38 | echo 39 | else 40 | npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" 41 | fi 42 | -------------------------------------------------------------------------------- /scripts/publish-packages.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Called from the `create-releases.yml` workflow with the output 3 | * of the release please action as the first argument. 4 | * 5 | * Example JSON input: 6 | * 7 | * ```json 8 | { 9 | "releases_created": "true", 10 | "release_created": "true", 11 | "id": "137967744", 12 | "name": "sdk: v0.14.5", 13 | "tag_name": "sdk-v0.14.5", 14 | "sha": "7cc2ba5c694e76a117f731d4cf0b06f8b8361f2e", 15 | "body": "## 0.14.5 (2024-01-22)\n\n...", 16 | "html_url": "https://github.com/$org/$repo/releases/tag/sdk-v0.14.5", 17 | "draft": "false", 18 | "upload_url": "https://uploads.github.com/repos/$org/$repo/releases/137967744/assets{?name,label}", 19 | "path": ".", 20 | "version": "0.14.5", 21 | "major": "0", 22 | "minor": "14", 23 | "patch": "5", 24 | "packages/additional-sdk--release_created": "true", 25 | "packages/additional-sdk--id": "137967756", 26 | "packages/additional-sdk--name": "additional-sdk: v0.5.2", 27 | "packages/additional-sdk--tag_name": "additional-sdk-v0.5.2", 28 | "packages/additional-sdk--sha": "7cc2ba5c694e76a117f731d4cf0b06f8b8361f2e", 29 | "packages/additional-sdk--body": "## 0.5.2 (2024-01-22)\n\n...", 30 | "packages/additional-sdk--html_url": "https://github.com/$org/$repo/releases/tag/additional-sdk-v0.5.2", 31 | "packages/additional-sdk--draft": "false", 32 | "packages/additional-sdk--upload_url": "https://uploads.github.com/repos/$org/$repo/releases/137967756/assets{?name,label}", 33 | "packages/additional-sdk--path": "packages/additional-sdk", 34 | "packages/additional-sdk--version": "0.5.2", 35 | "packages/additional-sdk--major": "0", 36 | "packages/additional-sdk--minor": "5", 37 | "packages/additional-sdk--patch": "2", 38 | "paths_released": "[\".\",\"packages/additional-sdk\"]" 39 | } 40 | ``` 41 | */ 42 | 43 | import { execSync } from 'child_process'; 44 | import path from 'path'; 45 | 46 | function main() { 47 | const data = process.argv[2] ?? process.env['DATA']; 48 | if (!data) { 49 | throw new Error(`Usage: publish-packages.ts '{"json": "obj"}'`); 50 | } 51 | 52 | const rootDir = path.join(__dirname, '..'); 53 | console.log('root dir', rootDir); 54 | console.log(`publish-packages called with ${data}`); 55 | 56 | const outputs = JSON.parse(data); 57 | 58 | const rawPaths = outputs.paths_released; 59 | 60 | if (!rawPaths) { 61 | console.error(JSON.stringify(outputs, null, 2)); 62 | throw new Error('Expected outputs to contain a truthy `paths_released` property'); 63 | } 64 | if (typeof rawPaths !== 'string') { 65 | console.error(JSON.stringify(outputs, null, 2)); 66 | throw new Error('Expected outputs `paths_released` property to be a JSON string'); 67 | } 68 | 69 | const paths = JSON.parse(rawPaths); 70 | if (!Array.isArray(paths)) { 71 | console.error(JSON.stringify(outputs, null, 2)); 72 | throw new Error('Expected outputs `paths_released` property to be an array'); 73 | } 74 | if (!paths.length) { 75 | console.error(JSON.stringify(outputs, null, 2)); 76 | throw new Error('Expected outputs `paths_released` property to contain at least one entry'); 77 | } 78 | 79 | const publishScriptPath = path.join(rootDir, 'bin', 'publish-npm'); 80 | console.log('Using publish script at', publishScriptPath); 81 | 82 | console.log('Ensuring root package is built'); 83 | console.log(`$ yarn build`); 84 | execSync(`yarn build`, { cwd: rootDir, encoding: 'utf8', stdio: 'inherit' }); 85 | 86 | for (const relPackagePath of paths) { 87 | console.log('\n'); 88 | 89 | const packagePath = path.join(rootDir, relPackagePath); 90 | console.log(`Publishing in directory: ${packagePath}`); 91 | 92 | console.log(`$ yarn install`); 93 | execSync(`yarn install`, { cwd: packagePath, encoding: 'utf8', stdio: 'inherit' }); 94 | 95 | console.log(`$ bash ${publishScriptPath}`); 96 | execSync(`bash ${publishScriptPath}`, { cwd: packagePath, encoding: 'utf8', stdio: 'inherit' }); 97 | } 98 | 99 | console.log('Finished publishing packages'); 100 | } 101 | 102 | main(); 103 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | RED='\033[0;31m' 8 | GREEN='\033[0;32m' 9 | YELLOW='\033[0;33m' 10 | NC='\033[0m' # No Color 11 | 12 | function prism_is_running() { 13 | curl --silent "http://localhost:4010" >/dev/null 2>&1 14 | } 15 | 16 | kill_server_on_port() { 17 | pids=$(lsof -t -i tcp:"$1" || echo "") 18 | if [ "$pids" != "" ]; then 19 | kill "$pids" 20 | echo "Stopped $pids." 21 | fi 22 | } 23 | 24 | function is_overriding_api_base_url() { 25 | [ -n "$TEST_API_BASE_URL" ] 26 | } 27 | 28 | if ! is_overriding_api_base_url && ! prism_is_running ; then 29 | # When we exit this script, make sure to kill the background mock server process 30 | trap 'kill_server_on_port 4010' EXIT 31 | 32 | # Start the dev server 33 | ./scripts/mock --daemon 34 | fi 35 | 36 | if is_overriding_api_base_url ; then 37 | echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" 38 | echo 39 | elif ! prism_is_running ; then 40 | echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" 41 | echo -e "running against your OpenAPI spec." 42 | echo 43 | echo -e "To run the server, pass in the path or url of your OpenAPI" 44 | echo -e "spec to the prism command:" 45 | echo 46 | echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" 47 | echo 48 | 49 | exit 1 50 | else 51 | echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" 52 | echo 53 | fi 54 | 55 | echo "==> Running tests" 56 | ./node_modules/.bin/jest "$@" 57 | -------------------------------------------------------------------------------- /scripts/utils/attw-report.cjs: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const problems = Object.values(JSON.parse(fs.readFileSync('.attw.json', 'utf-8')).problems) 3 | .flat() 4 | .filter( 5 | (problem) => 6 | !( 7 | // This is intentional, if the user specifies .mjs they get ESM. 8 | ( 9 | (problem.kind === 'CJSResolvesToESM' && problem.entrypoint.endsWith('.mjs')) || 10 | // This is intentional for backwards compat reasons. 11 | (problem.kind === 'MissingExportEquals' && problem.implementationFileName.endsWith('/index.js')) || 12 | // this is intentional, we deliberately attempt to import types that may not exist from parent node_modules 13 | // folders to better support various runtimes without triggering automatic type acquisition. 14 | (problem.kind === 'InternalResolutionError' && problem.moduleSpecifier.includes('node_modules')) 15 | ) 16 | ), 17 | ); 18 | fs.unlinkSync('.attw.json'); 19 | if (problems.length) { 20 | process.stdout.write('The types are wrong!\n' + JSON.stringify(problems, null, 2) + '\n'); 21 | process.exitCode = 1; 22 | } else { 23 | process.stdout.write('Types ok!\n'); 24 | } 25 | -------------------------------------------------------------------------------- /scripts/utils/check-is-in-git-install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Check if you happen to call prepare for a repository that's already in node_modules. 3 | [ "$(basename "$(dirname "$PWD")")" = 'node_modules' ] || 4 | # The name of the containing directory that 'npm` uses, which looks like 5 | # $HOME/.npm/_cacache/git-cloneXXXXXX 6 | [ "$(basename "$(dirname "$PWD")")" = 'tmp' ] || 7 | # The name of the containing directory that 'yarn` uses, which looks like 8 | # $(yarn cache dir)/.tmp/XXXXX 9 | [ "$(basename "$(dirname "$PWD")")" = '.tmp' ] 10 | -------------------------------------------------------------------------------- /scripts/utils/check-version.cjs: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const main = () => { 5 | const pkg = require('../../package.json'); 6 | const version = pkg['version']; 7 | if (!version) throw 'The version property is not set in the package.json file'; 8 | if (typeof version !== 'string') { 9 | throw `Unexpected type for the package.json version field; got ${typeof version}, expected string`; 10 | } 11 | 12 | const versionFile = path.resolve(__dirname, '..', '..', 'src', 'version.ts'); 13 | const contents = fs.readFileSync(versionFile, 'utf8'); 14 | const output = contents.replace(/(export const VERSION = ')(.*)(')/g, `$1${version}$3`); 15 | fs.writeFileSync(versionFile, output); 16 | }; 17 | 18 | if (require.main === module) { 19 | main(); 20 | } 21 | -------------------------------------------------------------------------------- /scripts/utils/fix-index-exports.cjs: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const indexJs = 5 | process.env['DIST_PATH'] ? 6 | path.resolve(process.env['DIST_PATH'], 'index.js') 7 | : path.resolve(__dirname, '..', '..', 'dist', 'index.js'); 8 | 9 | let before = fs.readFileSync(indexJs, 'utf8'); 10 | let after = before.replace( 11 | /^(\s*Object\.defineProperty\s*\(exports,\s*["']__esModule["'].+)$/m, 12 | `exports = module.exports = function (...args) { 13 | return new exports.default(...args) 14 | } 15 | $1`.replace(/^ /gm, ''), 16 | ); 17 | fs.writeFileSync(indexJs, after, 'utf8'); 18 | -------------------------------------------------------------------------------- /scripts/utils/git-swap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exuo pipefail 3 | # the package is published to NPM from ./dist 4 | # we want the final file structure for git installs to match the npm installs, so we 5 | 6 | # delete everything except ./dist and ./node_modules 7 | find . -maxdepth 1 -mindepth 1 ! -name 'dist' ! -name 'node_modules' -exec rm -rf '{}' + 8 | 9 | # move everything from ./dist to . 10 | mv dist/* . 11 | 12 | # delete the now-empty ./dist 13 | rmdir dist 14 | -------------------------------------------------------------------------------- /scripts/utils/make-dist-package-json.cjs: -------------------------------------------------------------------------------- 1 | const pkgJson = require(process.env['PKG_JSON_PATH'] || '../../package.json'); 2 | 3 | function processExportMap(m) { 4 | for (const key in m) { 5 | const value = m[key]; 6 | if (typeof value === 'string') m[key] = value.replace(/^\.\/dist\//, './'); 7 | else processExportMap(value); 8 | } 9 | } 10 | processExportMap(pkgJson.exports); 11 | 12 | for (const key of ['types', 'main', 'module']) { 13 | if (typeof pkgJson[key] === 'string') pkgJson[key] = pkgJson[key].replace(/^(\.\/)?dist\//, './'); 14 | } 15 | 16 | delete pkgJson.devDependencies; 17 | delete pkgJson.scripts.prepack; 18 | delete pkgJson.scripts.prepublishOnly; 19 | delete pkgJson.scripts.prepare; 20 | 21 | console.log(JSON.stringify(pkgJson, null, 2)); 22 | -------------------------------------------------------------------------------- /scripts/utils/postprocess-files.cjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | const distDir = 6 | process.env['DIST_PATH'] ? 7 | path.resolve(process.env['DIST_PATH']) 8 | : path.resolve(__dirname, '..', '..', 'dist'); 9 | 10 | async function* walk(dir) { 11 | for await (const d of await fs.promises.opendir(dir)) { 12 | const entry = path.join(dir, d.name); 13 | if (d.isDirectory()) yield* walk(entry); 14 | else if (d.isFile()) yield entry; 15 | } 16 | } 17 | 18 | async function postprocess() { 19 | for await (const file of walk(distDir)) { 20 | if (!/(\.d)?[cm]?ts$/.test(file)) continue; 21 | 22 | const code = await fs.promises.readFile(file, 'utf8'); 23 | 24 | // strip out lib="dom", types="node", and types="react" references; these 25 | // are needed at build time, but would pollute the user's TS environment 26 | const transformed = code.replace( 27 | /^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n', 30 | ); 31 | 32 | if (transformed !== code) { 33 | console.error(`wrote ${path.relative(process.cwd(), file)}`); 34 | await fs.promises.writeFile(file, transformed, 'utf8'); 35 | } 36 | } 37 | 38 | const newExports = { 39 | '.': { 40 | require: { 41 | types: './index.d.ts', 42 | default: './index.js', 43 | }, 44 | types: './index.d.mts', 45 | default: './index.mjs', 46 | }, 47 | }; 48 | 49 | for (const entry of await fs.promises.readdir(distDir, { withFileTypes: true })) { 50 | if (entry.isDirectory() && entry.name !== 'src' && entry.name !== 'internal' && entry.name !== 'bin') { 51 | const subpath = './' + entry.name; 52 | newExports[subpath + '/*.mjs'] = { 53 | default: subpath + '/*.mjs', 54 | }; 55 | newExports[subpath + '/*.js'] = { 56 | default: subpath + '/*.js', 57 | }; 58 | newExports[subpath + '/*'] = { 59 | import: subpath + '/*.mjs', 60 | require: subpath + '/*.js', 61 | }; 62 | } else if (entry.isFile() && /\.[cm]?js$/.test(entry.name)) { 63 | const { name, ext } = path.parse(entry.name); 64 | const subpathWithoutExt = './' + name; 65 | const subpath = './' + entry.name; 66 | newExports[subpathWithoutExt] ||= { import: undefined, require: undefined }; 67 | const isModule = ext[1] === 'm'; 68 | if (isModule) { 69 | newExports[subpathWithoutExt].import = subpath; 70 | } else { 71 | newExports[subpathWithoutExt].require = subpath; 72 | } 73 | newExports[subpath] = { 74 | default: subpath, 75 | }; 76 | } 77 | } 78 | await fs.promises.writeFile( 79 | 'dist/package.json', 80 | JSON.stringify( 81 | Object.assign( 82 | /** @type {Record} */ ( 83 | JSON.parse(await fs.promises.readFile('dist/package.json', 'utf-8')) 84 | ), 85 | { 86 | exports: newExports, 87 | }, 88 | ), 89 | null, 90 | 2, 91 | ), 92 | ); 93 | } 94 | postprocess(); 95 | -------------------------------------------------------------------------------- /scripts/utils/upload-artifact.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exuo pipefail 3 | 4 | RESPONSE=$(curl -X POST "$URL" \ 5 | -H "Authorization: Bearer $AUTH" \ 6 | -H "Content-Type: application/json") 7 | 8 | SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') 9 | 10 | if [[ "$SIGNED_URL" == "null" ]]; then 11 | echo -e "\033[31mFailed to get signed URL.\033[0m" 12 | exit 1 13 | fi 14 | 15 | UPLOAD_RESPONSE=$(tar -cz dist | curl -v -X PUT \ 16 | -H "Content-Type: application/gzip" \ 17 | --data-binary @- "$SIGNED_URL" 2>&1) 18 | 19 | if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then 20 | echo -e "\033[32mUploaded build to Stainless storage.\033[0m" 21 | echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/anthropic-typescript/$SHA'\033[0m" 22 | else 23 | echo -e "\033[31mFailed to upload artifact.\033[0m" 24 | exit 1 25 | fi 26 | -------------------------------------------------------------------------------- /src/_vendor/partial-json-parser/README.md: -------------------------------------------------------------------------------- 1 | # Partial JSON Parser 2 | 3 | Vendored from https://www.npmjs.com/package/partial-json-parser and updated to use TypeScript. 4 | -------------------------------------------------------------------------------- /src/api-promise.ts: -------------------------------------------------------------------------------- 1 | /** @deprecated Import from ./core/api-promise instead */ 2 | export * from './core/api-promise'; 3 | -------------------------------------------------------------------------------- /src/core/README.md: -------------------------------------------------------------------------------- 1 | # `core` 2 | 3 | This directory holds public modules implementing non-resource-specific SDK functionality. 4 | -------------------------------------------------------------------------------- /src/core/api-promise.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { type BaseAnthropic } from '../client'; 4 | 5 | import { type PromiseOrValue } from '../internal/types'; 6 | import { 7 | type APIResponseProps, 8 | type WithRequestID, 9 | defaultParseResponse, 10 | addRequestID, 11 | } from '../internal/parse'; 12 | 13 | /** 14 | * A subclass of `Promise` providing additional helper methods 15 | * for interacting with the SDK. 16 | */ 17 | export class APIPromise extends Promise> { 18 | private parsedPromise: Promise> | undefined; 19 | #client: BaseAnthropic; 20 | 21 | constructor( 22 | client: BaseAnthropic, 23 | private responsePromise: Promise, 24 | private parseResponse: ( 25 | client: BaseAnthropic, 26 | props: APIResponseProps, 27 | ) => PromiseOrValue> = defaultParseResponse, 28 | ) { 29 | super((resolve) => { 30 | // this is maybe a bit weird but this has to be a no-op to not implicitly 31 | // parse the response body; instead .then, .catch, .finally are overridden 32 | // to parse the response 33 | resolve(null as any); 34 | }); 35 | this.#client = client; 36 | } 37 | 38 | _thenUnwrap(transform: (data: T, props: APIResponseProps) => U): APIPromise { 39 | return new APIPromise(this.#client, this.responsePromise, async (client, props) => 40 | addRequestID(transform(await this.parseResponse(client, props), props), props.response), 41 | ); 42 | } 43 | 44 | /** 45 | * Gets the raw `Response` instance instead of parsing the response 46 | * data. 47 | * 48 | * If you want to parse the response body but still get the `Response` 49 | * instance, you can use {@link withResponse()}. 50 | * 51 | * 👋 Getting the wrong TypeScript type for `Response`? 52 | * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` 53 | * to your `tsconfig.json`. 54 | */ 55 | asResponse(): Promise { 56 | return this.responsePromise.then((p) => p.response); 57 | } 58 | 59 | /** 60 | * Gets the parsed response data, the raw `Response` instance and the ID of the request, 61 | * returned via the `request-id` header which is useful for debugging requests and resporting 62 | * issues to Anthropic. 63 | * 64 | * If you just want to get the raw `Response` instance without parsing it, 65 | * you can use {@link asResponse()}. 66 | * 67 | * 👋 Getting the wrong TypeScript type for `Response`? 68 | * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` 69 | * to your `tsconfig.json`. 70 | */ 71 | async withResponse(): Promise<{ data: T; response: Response; request_id: string | null | undefined }> { 72 | const [data, response] = await Promise.all([this.parse(), this.asResponse()]); 73 | return { data, response, request_id: response.headers.get('request-id') }; 74 | } 75 | 76 | private parse(): Promise> { 77 | if (!this.parsedPromise) { 78 | this.parsedPromise = this.responsePromise.then( 79 | (data) => this.parseResponse(this.#client, data) as any as Promise>, 80 | ); 81 | } 82 | return this.parsedPromise; 83 | } 84 | 85 | override then, TResult2 = never>( 86 | onfulfilled?: ((value: WithRequestID) => TResult1 | PromiseLike) | undefined | null, 87 | onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null, 88 | ): Promise { 89 | return this.parse().then(onfulfilled, onrejected); 90 | } 91 | 92 | override catch( 93 | onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null, 94 | ): Promise | TResult> { 95 | return this.parse().catch(onrejected); 96 | } 97 | 98 | override finally(onfinally?: (() => void) | undefined | null): Promise> { 99 | return this.parse().finally(onfinally); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/core/error.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { castToError } from '../internal/errors'; 4 | 5 | export class AnthropicError extends Error {} 6 | 7 | export class APIError< 8 | TStatus extends number | undefined = number | undefined, 9 | THeaders extends Headers | undefined = Headers | undefined, 10 | TError extends Object | undefined = Object | undefined, 11 | > extends AnthropicError { 12 | /** HTTP status for the response that caused the error */ 13 | readonly status: TStatus; 14 | /** HTTP headers for the response that caused the error */ 15 | readonly headers: THeaders; 16 | /** JSON body of the response that caused the error */ 17 | readonly error: TError; 18 | 19 | readonly requestID: string | null | undefined; 20 | 21 | constructor(status: TStatus, error: TError, message: string | undefined, headers: THeaders) { 22 | super(`${APIError.makeMessage(status, error, message)}`); 23 | this.status = status; 24 | this.headers = headers; 25 | this.requestID = headers?.get('request-id'); 26 | this.error = error; 27 | } 28 | 29 | private static makeMessage(status: number | undefined, error: any, message: string | undefined) { 30 | const msg = 31 | error?.message ? 32 | typeof error.message === 'string' ? 33 | error.message 34 | : JSON.stringify(error.message) 35 | : error ? JSON.stringify(error) 36 | : message; 37 | 38 | if (status && msg) { 39 | return `${status} ${msg}`; 40 | } 41 | if (status) { 42 | return `${status} status code (no body)`; 43 | } 44 | if (msg) { 45 | return msg; 46 | } 47 | return '(no status code or body)'; 48 | } 49 | 50 | static generate( 51 | status: number | undefined, 52 | errorResponse: Object | undefined, 53 | message: string | undefined, 54 | headers: Headers | undefined, 55 | ): APIError { 56 | if (!status || !headers) { 57 | return new APIConnectionError({ message, cause: castToError(errorResponse) }); 58 | } 59 | 60 | const error = errorResponse as Record; 61 | 62 | if (status === 400) { 63 | return new BadRequestError(status, error, message, headers); 64 | } 65 | 66 | if (status === 401) { 67 | return new AuthenticationError(status, error, message, headers); 68 | } 69 | 70 | if (status === 403) { 71 | return new PermissionDeniedError(status, error, message, headers); 72 | } 73 | 74 | if (status === 404) { 75 | return new NotFoundError(status, error, message, headers); 76 | } 77 | 78 | if (status === 409) { 79 | return new ConflictError(status, error, message, headers); 80 | } 81 | 82 | if (status === 422) { 83 | return new UnprocessableEntityError(status, error, message, headers); 84 | } 85 | 86 | if (status === 429) { 87 | return new RateLimitError(status, error, message, headers); 88 | } 89 | 90 | if (status >= 500) { 91 | return new InternalServerError(status, error, message, headers); 92 | } 93 | 94 | return new APIError(status, error, message, headers); 95 | } 96 | } 97 | 98 | export class APIUserAbortError extends APIError { 99 | constructor({ message }: { message?: string } = {}) { 100 | super(undefined, undefined, message || 'Request was aborted.', undefined); 101 | } 102 | } 103 | 104 | export class APIConnectionError extends APIError { 105 | constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) { 106 | super(undefined, undefined, message || 'Connection error.', undefined); 107 | // in some environments the 'cause' property is already declared 108 | // @ts-ignore 109 | if (cause) this.cause = cause; 110 | } 111 | } 112 | 113 | export class APIConnectionTimeoutError extends APIConnectionError { 114 | constructor({ message }: { message?: string } = {}) { 115 | super({ message: message ?? 'Request timed out.' }); 116 | } 117 | } 118 | 119 | export class BadRequestError extends APIError<400, Headers> {} 120 | 121 | export class AuthenticationError extends APIError<401, Headers> {} 122 | 123 | export class PermissionDeniedError extends APIError<403, Headers> {} 124 | 125 | export class NotFoundError extends APIError<404, Headers> {} 126 | 127 | export class ConflictError extends APIError<409, Headers> {} 128 | 129 | export class UnprocessableEntityError extends APIError<422, Headers> {} 130 | 131 | export class RateLimitError extends APIError<429, Headers> {} 132 | 133 | export class InternalServerError extends APIError {} 134 | -------------------------------------------------------------------------------- /src/core/resource.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { BaseAnthropic } from '../client'; 4 | 5 | export class APIResource { 6 | protected _client: BaseAnthropic; 7 | 8 | constructor(client: BaseAnthropic) { 9 | this._client = client; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/core/uploads.ts: -------------------------------------------------------------------------------- 1 | export { type Uploadable } from '../internal/uploads'; 2 | export { toFile, type ToFileInput } from '../internal/to-file'; 3 | -------------------------------------------------------------------------------- /src/error.ts: -------------------------------------------------------------------------------- 1 | /** @deprecated Import from ./core/error instead */ 2 | export * from './core/error'; 3 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export { Anthropic as default } from './client'; 4 | 5 | export { type Uploadable, toFile } from './core/uploads'; 6 | export { APIPromise } from './core/api-promise'; 7 | export { BaseAnthropic, Anthropic, type ClientOptions, HUMAN_PROMPT, AI_PROMPT } from './client'; 8 | export { PagePromise } from './core/pagination'; 9 | export { 10 | AnthropicError, 11 | APIError, 12 | APIConnectionError, 13 | APIConnectionTimeoutError, 14 | APIUserAbortError, 15 | NotFoundError, 16 | ConflictError, 17 | RateLimitError, 18 | BadRequestError, 19 | AuthenticationError, 20 | InternalServerError, 21 | PermissionDeniedError, 22 | UnprocessableEntityError, 23 | } from './core/error'; 24 | -------------------------------------------------------------------------------- /src/internal/README.md: -------------------------------------------------------------------------------- 1 | # `internal` 2 | 3 | The modules in this directory are not importable outside this package and will change between releases. 4 | -------------------------------------------------------------------------------- /src/internal/builtin-types.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export type Fetch = (input: string | URL | Request, init?: RequestInit) => Promise; 4 | 5 | /** 6 | * An alias to the builtin `RequestInit` type so we can 7 | * easily alias it in import statements if there are name clashes. 8 | * 9 | * https://developer.mozilla.org/docs/Web/API/RequestInit 10 | */ 11 | type _RequestInit = RequestInit; 12 | 13 | /** 14 | * An alias to the builtin `Response` type so we can 15 | * easily alias it in import statements if there are name clashes. 16 | * 17 | * https://developer.mozilla.org/docs/Web/API/Response 18 | */ 19 | type _Response = Response; 20 | 21 | /** 22 | * The type for the first argument to `fetch`. 23 | * 24 | * https://developer.mozilla.org/docs/Web/API/Window/fetch#resource 25 | */ 26 | type _RequestInfo = Request | URL | string; 27 | 28 | /** 29 | * The type for constructing `RequestInit` Headers. 30 | * 31 | * https://developer.mozilla.org/docs/Web/API/RequestInit#setting_headers 32 | */ 33 | type _HeadersInit = RequestInit['headers']; 34 | 35 | /** 36 | * The type for constructing `RequestInit` body. 37 | * 38 | * https://developer.mozilla.org/docs/Web/API/RequestInit#body 39 | */ 40 | type _BodyInit = RequestInit['body']; 41 | 42 | /** 43 | * An alias to the builtin `Array` type so we can 44 | * easily alias it in import statements if there are name clashes. 45 | */ 46 | type _Array = Array; 47 | 48 | /** 49 | * An alias to the builtin `Record` type so we can 50 | * easily alias it in import statements if there are name clashes. 51 | */ 52 | type _Record = Record; 53 | 54 | export type { 55 | _Array as Array, 56 | _BodyInit as BodyInit, 57 | _HeadersInit as HeadersInit, 58 | _Record as Record, 59 | _RequestInfo as RequestInfo, 60 | _RequestInit as RequestInit, 61 | _Response as Response, 62 | }; 63 | 64 | /** 65 | * A copy of the builtin `EndingType` type as it isn't fully supported in certain 66 | * environments and attempting to reference the global version will error. 67 | * 68 | * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L27941 69 | */ 70 | type EndingType = 'native' | 'transparent'; 71 | 72 | /** 73 | * A copy of the builtin `BlobPropertyBag` type as it isn't fully supported in certain 74 | * environments and attempting to reference the global version will error. 75 | * 76 | * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L154 77 | * https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#options 78 | */ 79 | export interface BlobPropertyBag { 80 | endings?: EndingType; 81 | type?: string; 82 | } 83 | 84 | /** 85 | * A copy of the builtin `FilePropertyBag` type as it isn't fully supported in certain 86 | * environments and attempting to reference the global version will error. 87 | * 88 | * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L503 89 | * https://developer.mozilla.org/en-US/docs/Web/API/File/File#options 90 | */ 91 | export interface FilePropertyBag extends BlobPropertyBag { 92 | lastModified?: number; 93 | } 94 | -------------------------------------------------------------------------------- /src/internal/constants.ts: -------------------------------------------------------------------------------- 1 | // File containing shared constants 2 | 3 | /** 4 | * Model-specific timeout constraints for non-streaming requests 5 | */ 6 | export const MODEL_NONSTREAMING_TOKENS: Record = { 7 | 'claude-opus-4-20250514': 8192, 8 | 'claude-opus-4-0': 8192, 9 | 'claude-4-opus-20250514': 8192, 10 | 'anthropic.claude-opus-4-20250514-v1:0': 8192, 11 | 'claude-opus-4@20250514': 8192, 12 | }; 13 | -------------------------------------------------------------------------------- /src/internal/decoders/jsonl.ts: -------------------------------------------------------------------------------- 1 | import { AnthropicError } from '../../core/error'; 2 | import { ReadableStreamToAsyncIterable } from '../shims'; 3 | import { LineDecoder, type Bytes } from './line'; 4 | 5 | export class JSONLDecoder { 6 | controller: AbortController; 7 | 8 | constructor( 9 | private iterator: AsyncIterableIterator, 10 | controller: AbortController, 11 | ) { 12 | this.controller = controller; 13 | } 14 | 15 | private async *decoder(): AsyncIterator { 16 | const lineDecoder = new LineDecoder(); 17 | for await (const chunk of this.iterator) { 18 | for (const line of lineDecoder.decode(chunk)) { 19 | yield JSON.parse(line); 20 | } 21 | } 22 | 23 | for (const line of lineDecoder.flush()) { 24 | yield JSON.parse(line); 25 | } 26 | } 27 | 28 | [Symbol.asyncIterator](): AsyncIterator { 29 | return this.decoder(); 30 | } 31 | 32 | static fromResponse(response: Response, controller: AbortController): JSONLDecoder { 33 | if (!response.body) { 34 | controller.abort(); 35 | if ( 36 | typeof (globalThis as any).navigator !== 'undefined' && 37 | (globalThis as any).navigator.product === 'ReactNative' 38 | ) { 39 | throw new AnthropicError( 40 | `The default react-native fetch implementation does not support streaming. Please use expo/fetch: https://docs.expo.dev/versions/latest/sdk/expo/#expofetch-api`, 41 | ); 42 | } 43 | throw new AnthropicError(`Attempted to iterate over a response with no body`); 44 | } 45 | 46 | return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/internal/decoders/line.ts: -------------------------------------------------------------------------------- 1 | import { concatBytes, decodeUTF8, encodeUTF8 } from '../utils/bytes'; 2 | 3 | export type Bytes = string | ArrayBuffer | Uint8Array | null | undefined; 4 | 5 | /** 6 | * A re-implementation of httpx's `LineDecoder` in Python that handles incrementally 7 | * reading lines from text. 8 | * 9 | * https://github.com/encode/httpx/blob/920333ea98118e9cf617f246905d7b202510941c/httpx/_decoders.py#L258 10 | */ 11 | export class LineDecoder { 12 | // prettier-ignore 13 | static NEWLINE_CHARS = new Set(['\n', '\r']); 14 | static NEWLINE_REGEXP = /\r\n|[\n\r]/g; 15 | 16 | #buffer: Uint8Array; 17 | #carriageReturnIndex: number | null; 18 | 19 | constructor() { 20 | this.#buffer = new Uint8Array(); 21 | this.#carriageReturnIndex = null; 22 | } 23 | 24 | decode(chunk: Bytes): string[] { 25 | if (chunk == null) { 26 | return []; 27 | } 28 | 29 | const binaryChunk = 30 | chunk instanceof ArrayBuffer ? new Uint8Array(chunk) 31 | : typeof chunk === 'string' ? encodeUTF8(chunk) 32 | : chunk; 33 | 34 | this.#buffer = concatBytes([this.#buffer, binaryChunk]); 35 | 36 | const lines: string[] = []; 37 | let patternIndex; 38 | while ((patternIndex = findNewlineIndex(this.#buffer, this.#carriageReturnIndex)) != null) { 39 | if (patternIndex.carriage && this.#carriageReturnIndex == null) { 40 | // skip until we either get a corresponding `\n`, a new `\r` or nothing 41 | this.#carriageReturnIndex = patternIndex.index; 42 | continue; 43 | } 44 | 45 | // we got double \r or \rtext\n 46 | if ( 47 | this.#carriageReturnIndex != null && 48 | (patternIndex.index !== this.#carriageReturnIndex + 1 || patternIndex.carriage) 49 | ) { 50 | lines.push(decodeUTF8(this.#buffer.subarray(0, this.#carriageReturnIndex - 1))); 51 | this.#buffer = this.#buffer.subarray(this.#carriageReturnIndex); 52 | this.#carriageReturnIndex = null; 53 | continue; 54 | } 55 | 56 | const endIndex = 57 | this.#carriageReturnIndex !== null ? patternIndex.preceding - 1 : patternIndex.preceding; 58 | 59 | const line = decodeUTF8(this.#buffer.subarray(0, endIndex)); 60 | lines.push(line); 61 | 62 | this.#buffer = this.#buffer.subarray(patternIndex.index); 63 | this.#carriageReturnIndex = null; 64 | } 65 | 66 | return lines; 67 | } 68 | 69 | flush(): string[] { 70 | if (!this.#buffer.length) { 71 | return []; 72 | } 73 | return this.decode('\n'); 74 | } 75 | } 76 | 77 | /** 78 | * This function searches the buffer for the end patterns, (\r or \n) 79 | * and returns an object with the index preceding the matched newline and the 80 | * index after the newline char. `null` is returned if no new line is found. 81 | * 82 | * ```ts 83 | * findNewLineIndex('abc\ndef') -> { preceding: 2, index: 3 } 84 | * ``` 85 | */ 86 | function findNewlineIndex( 87 | buffer: Uint8Array, 88 | startIndex: number | null, 89 | ): { preceding: number; index: number; carriage: boolean } | null { 90 | const newline = 0x0a; // \n 91 | const carriage = 0x0d; // \r 92 | 93 | for (let i = startIndex ?? 0; i < buffer.length; i++) { 94 | if (buffer[i] === newline) { 95 | return { preceding: i, index: i + 1, carriage: false }; 96 | } 97 | 98 | if (buffer[i] === carriage) { 99 | return { preceding: i, index: i + 1, carriage: true }; 100 | } 101 | } 102 | 103 | return null; 104 | } 105 | 106 | export function findDoubleNewlineIndex(buffer: Uint8Array): number { 107 | // This function searches the buffer for the end patterns (\r\r, \n\n, \r\n\r\n) 108 | // and returns the index right after the first occurrence of any pattern, 109 | // or -1 if none of the patterns are found. 110 | const newline = 0x0a; // \n 111 | const carriage = 0x0d; // \r 112 | 113 | for (let i = 0; i < buffer.length - 1; i++) { 114 | if (buffer[i] === newline && buffer[i + 1] === newline) { 115 | // \n\n 116 | return i + 2; 117 | } 118 | if (buffer[i] === carriage && buffer[i + 1] === carriage) { 119 | // \r\r 120 | return i + 2; 121 | } 122 | if ( 123 | buffer[i] === carriage && 124 | buffer[i + 1] === newline && 125 | i + 3 < buffer.length && 126 | buffer[i + 2] === carriage && 127 | buffer[i + 3] === newline 128 | ) { 129 | // \r\n\r\n 130 | return i + 4; 131 | } 132 | } 133 | 134 | return -1; 135 | } 136 | -------------------------------------------------------------------------------- /src/internal/errors.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export function isAbortError(err: unknown) { 4 | return ( 5 | typeof err === 'object' && 6 | err !== null && 7 | // Spec-compliant fetch implementations 8 | (('name' in err && (err as any).name === 'AbortError') || 9 | // Expo fetch 10 | ('message' in err && String((err as any).message).includes('FetchRequestCanceledException'))) 11 | ); 12 | } 13 | 14 | export const castToError = (err: any): Error => { 15 | if (err instanceof Error) return err; 16 | if (typeof err === 'object' && err !== null) { 17 | try { 18 | if (Object.prototype.toString.call(err) === '[object Error]') { 19 | // @ts-ignore - not all envs have native support for cause yet 20 | const error = new Error(err.message, err.cause ? { cause: err.cause } : {}); 21 | if (err.stack) error.stack = err.stack; 22 | // @ts-ignore - not all envs have native support for cause yet 23 | if (err.cause && !error.cause) error.cause = err.cause; 24 | if (err.name) error.name = err.name; 25 | return error; 26 | } 27 | } catch {} 28 | try { 29 | return new Error(JSON.stringify(err)); 30 | } catch {} 31 | } 32 | return new Error(err); 33 | }; 34 | -------------------------------------------------------------------------------- /src/internal/headers.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | type HeaderValue = string | undefined | null; 4 | export type HeadersLike = 5 | | Headers 6 | | readonly HeaderValue[][] 7 | | Record 8 | | undefined 9 | | null 10 | | NullableHeaders; 11 | 12 | const brand_privateNullableHeaders = Symbol.for('brand.privateNullableHeaders') as symbol & { 13 | description: 'brand.privateNullableHeaders'; 14 | }; 15 | 16 | /** 17 | * @internal 18 | * Users can pass explicit nulls to unset default headers. When we parse them 19 | * into a standard headers type we need to preserve that information. 20 | */ 21 | export type NullableHeaders = { 22 | /** Brand check, prevent users from creating a NullableHeaders. */ 23 | [_: typeof brand_privateNullableHeaders]: true; 24 | /** Parsed headers. */ 25 | values: Headers; 26 | /** Set of lowercase header names explicitly set to null. */ 27 | nulls: Set; 28 | }; 29 | 30 | const isArray = Array.isArray as (val: unknown) => val is readonly unknown[]; 31 | 32 | function* iterateHeaders(headers: HeadersLike): IterableIterator { 33 | if (!headers) return; 34 | 35 | if (brand_privateNullableHeaders in headers) { 36 | const { values, nulls } = headers as NullableHeaders; 37 | yield* values.entries(); 38 | for (const name of nulls) { 39 | yield [name, null]; 40 | } 41 | return; 42 | } 43 | 44 | let shouldClear = false; 45 | let iter: Iterable; 46 | if (headers instanceof Headers) { 47 | iter = headers.entries(); 48 | } else if (isArray(headers)) { 49 | iter = headers; 50 | } else { 51 | shouldClear = true; 52 | iter = Object.entries(headers ?? {}); 53 | } 54 | for (let row of iter) { 55 | const name = row[0]; 56 | if (typeof name !== 'string') throw new TypeError('expected header name to be a string'); 57 | const values = isArray(row[1]) ? row[1] : [row[1]]; 58 | let didClear = false; 59 | for (const value of values) { 60 | if (value === undefined) continue; 61 | 62 | // Objects keys always overwrite older headers, they never append. 63 | // Yield a null to clear the header before adding the new values. 64 | if (shouldClear && !didClear) { 65 | didClear = true; 66 | yield [name, null]; 67 | } 68 | yield [name, value]; 69 | } 70 | } 71 | } 72 | 73 | export const buildHeaders = (newHeaders: HeadersLike[]): NullableHeaders => { 74 | const targetHeaders = new Headers(); 75 | const nullHeaders = new Set(); 76 | for (const headers of newHeaders) { 77 | const seenHeaders = new Set(); 78 | for (const [name, value] of iterateHeaders(headers)) { 79 | const lowerName = name.toLowerCase(); 80 | if (!seenHeaders.has(lowerName)) { 81 | targetHeaders.delete(name); 82 | seenHeaders.add(lowerName); 83 | } 84 | if (value === null) { 85 | targetHeaders.delete(name); 86 | nullHeaders.add(lowerName); 87 | } else { 88 | targetHeaders.append(name, value); 89 | nullHeaders.delete(lowerName); 90 | } 91 | } 92 | } 93 | return { [brand_privateNullableHeaders]: true, values: targetHeaders, nulls: nullHeaders }; 94 | }; 95 | 96 | export const isEmptyHeaders = (headers: HeadersLike) => { 97 | for (const _ of iterateHeaders(headers)) return false; 98 | return true; 99 | }; 100 | -------------------------------------------------------------------------------- /src/internal/parse.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import type { FinalRequestOptions } from './request-options'; 4 | import { Stream } from '../core/streaming'; 5 | import { type BaseAnthropic } from '../client'; 6 | import { formatRequestDetails, loggerFor } from './utils/log'; 7 | import type { AbstractPage } from '../core/pagination'; 8 | 9 | export type APIResponseProps = { 10 | response: Response; 11 | options: FinalRequestOptions; 12 | controller: AbortController; 13 | requestLogID: string; 14 | retryOfRequestLogID: string | undefined; 15 | startTime: number; 16 | }; 17 | 18 | export async function defaultParseResponse( 19 | client: BaseAnthropic, 20 | props: APIResponseProps, 21 | ): Promise> { 22 | const { response, requestLogID, retryOfRequestLogID, startTime } = props; 23 | const body = await (async () => { 24 | if (props.options.stream) { 25 | loggerFor(client).debug('response', response.status, response.url, response.headers, response.body); 26 | 27 | // Note: there is an invariant here that isn't represented in the type system 28 | // that if you set `stream: true` the response type must also be `Stream` 29 | 30 | if (props.options.__streamClass) { 31 | return props.options.__streamClass.fromSSEResponse(response, props.controller) as any; 32 | } 33 | 34 | return Stream.fromSSEResponse(response, props.controller) as any; 35 | } 36 | 37 | // fetch refuses to read the body when the status code is 204. 38 | if (response.status === 204) { 39 | return null as T; 40 | } 41 | 42 | if (props.options.__binaryResponse) { 43 | return response as unknown as T; 44 | } 45 | 46 | const contentType = response.headers.get('content-type'); 47 | const mediaType = contentType?.split(';')[0]?.trim(); 48 | const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json'); 49 | if (isJSON) { 50 | const json = await response.json(); 51 | return addRequestID(json as T, response); 52 | } 53 | 54 | const text = await response.text(); 55 | return text as unknown as T; 56 | })(); 57 | loggerFor(client).debug( 58 | `[${requestLogID}] response parsed`, 59 | formatRequestDetails({ 60 | retryOfRequestLogID, 61 | url: response.url, 62 | status: response.status, 63 | body, 64 | durationMs: Date.now() - startTime, 65 | }), 66 | ); 67 | return body; 68 | } 69 | 70 | export type WithRequestID = 71 | T extends Array | Response | AbstractPage ? T 72 | : T extends Record ? T & { _request_id?: string | null } 73 | : T; 74 | 75 | export function addRequestID(value: T, response: Response): WithRequestID { 76 | if (!value || typeof value !== 'object' || Array.isArray(value)) { 77 | return value as WithRequestID; 78 | } 79 | 80 | return Object.defineProperty(value, '_request_id', { 81 | value: response.headers.get('request-id'), 82 | enumerable: false, 83 | }) as WithRequestID; 84 | } 85 | -------------------------------------------------------------------------------- /src/internal/request-options.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { NullableHeaders } from './headers'; 4 | 5 | import type { BodyInit } from './builtin-types'; 6 | import { Stream } from '../core/streaming'; 7 | import type { HTTPMethod, MergedRequestInit } from './types'; 8 | import { type HeadersLike } from './headers'; 9 | 10 | export type FinalRequestOptions = RequestOptions & { method: HTTPMethod; path: string }; 11 | 12 | export type RequestOptions = { 13 | method?: HTTPMethod; 14 | path?: string; 15 | query?: object | undefined | null; 16 | body?: unknown; 17 | headers?: HeadersLike; 18 | maxRetries?: number; 19 | stream?: boolean | undefined; 20 | timeout?: number; 21 | fetchOptions?: MergedRequestInit; 22 | signal?: AbortSignal | undefined | null; 23 | idempotencyKey?: string; 24 | 25 | __binaryResponse?: boolean | undefined; 26 | __streamClass?: typeof Stream; 27 | }; 28 | 29 | export type EncodedContent = { bodyHeaders: HeadersLike; body: BodyInit }; 30 | export type RequestEncoder = (request: { headers: NullableHeaders; body: unknown }) => EncodedContent; 31 | 32 | export const FallbackEncoder: RequestEncoder = ({ headers, body }) => { 33 | return { 34 | bodyHeaders: { 35 | 'content-type': 'application/json', 36 | }, 37 | body: JSON.stringify(body), 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /src/internal/shim-types.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | /** 4 | * Shims for types that we can't always rely on being available globally. 5 | * 6 | * Note: these only exist at the type-level, there is no corresponding runtime 7 | * version for any of these symbols. 8 | */ 9 | 10 | type NeverToAny = T extends never ? any : T; 11 | 12 | /** @ts-ignore */ 13 | type _DOMReadableStream = globalThis.ReadableStream; 14 | 15 | /** @ts-ignore */ 16 | type _NodeReadableStream = import('stream/web').ReadableStream; 17 | 18 | type _ConditionalNodeReadableStream = 19 | typeof globalThis extends { ReadableStream: any } ? never : _NodeReadableStream; 20 | 21 | type _ReadableStream = NeverToAny< 22 | | ([0] extends [1 & _DOMReadableStream] ? never : _DOMReadableStream) 23 | | ([0] extends [1 & _ConditionalNodeReadableStream] ? never : _ConditionalNodeReadableStream) 24 | >; 25 | 26 | export type { _ReadableStream as ReadableStream }; 27 | -------------------------------------------------------------------------------- /src/internal/shims.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | /** 4 | * This module provides internal shims and utility functions for environments where certain Node.js or global types may not be available. 5 | * 6 | * These are used to ensure we can provide a consistent behaviour between different JavaScript environments and good error 7 | * messages in cases where an environment isn't fully supported. 8 | */ 9 | 10 | import type { Fetch } from './builtin-types'; 11 | import type { ReadableStream } from './shim-types'; 12 | 13 | export function getDefaultFetch(): Fetch { 14 | if (typeof fetch !== 'undefined') { 15 | return fetch as any; 16 | } 17 | 18 | throw new Error( 19 | '`fetch` is not defined as a global; Either pass `fetch` to the client, `new Anthropic({ fetch })` or polyfill the global, `globalThis.fetch = fetch`', 20 | ); 21 | } 22 | 23 | type ReadableStreamArgs = ConstructorParameters; 24 | 25 | export function makeReadableStream(...args: ReadableStreamArgs): ReadableStream { 26 | const ReadableStream = (globalThis as any).ReadableStream; 27 | if (typeof ReadableStream === 'undefined') { 28 | // Note: All of the platforms / runtimes we officially support already define 29 | // `ReadableStream` as a global, so this should only ever be hit on unsupported runtimes. 30 | throw new Error( 31 | '`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`', 32 | ); 33 | } 34 | 35 | return new ReadableStream(...args); 36 | } 37 | 38 | export function ReadableStreamFrom(iterable: Iterable | AsyncIterable): ReadableStream { 39 | let iter: AsyncIterator | Iterator = 40 | Symbol.asyncIterator in iterable ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator](); 41 | 42 | return makeReadableStream({ 43 | start() {}, 44 | async pull(controller: any) { 45 | const { done, value } = await iter.next(); 46 | if (done) { 47 | controller.close(); 48 | } else { 49 | controller.enqueue(value); 50 | } 51 | }, 52 | async cancel() { 53 | await iter.return?.(); 54 | }, 55 | }); 56 | } 57 | 58 | /** 59 | * Most browsers don't yet have async iterable support for ReadableStream, 60 | * and Node has a very different way of reading bytes from its "ReadableStream". 61 | * 62 | * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490 63 | */ 64 | export function ReadableStreamToAsyncIterable(stream: any): AsyncIterableIterator { 65 | if (stream[Symbol.asyncIterator]) return stream; 66 | 67 | const reader = stream.getReader(); 68 | return { 69 | async next() { 70 | try { 71 | const result = await reader.read(); 72 | if (result?.done) reader.releaseLock(); // release lock when stream becomes closed 73 | return result; 74 | } catch (e) { 75 | reader.releaseLock(); // release lock when stream becomes errored 76 | throw e; 77 | } 78 | }, 79 | async return() { 80 | const cancelPromise = reader.cancel(); 81 | reader.releaseLock(); 82 | await cancelPromise; 83 | return { done: true, value: undefined }; 84 | }, 85 | [Symbol.asyncIterator]() { 86 | return this; 87 | }, 88 | }; 89 | } 90 | 91 | /** 92 | * Cancels a ReadableStream we don't need to consume. 93 | * See https://undici.nodejs.org/#/?id=garbage-collection 94 | */ 95 | export async function CancelReadableStream(stream: any): Promise { 96 | if (stream === null || typeof stream !== 'object') return; 97 | 98 | if (stream[Symbol.asyncIterator]) { 99 | await stream[Symbol.asyncIterator]().return?.(); 100 | return; 101 | } 102 | 103 | const reader = stream.getReader(); 104 | const cancelPromise = reader.cancel(); 105 | reader.releaseLock(); 106 | await cancelPromise; 107 | } 108 | -------------------------------------------------------------------------------- /src/internal/stream-utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Most browsers don't yet have async iterable support for ReadableStream, 3 | * and Node has a very different way of reading bytes from its "ReadableStream". 4 | * 5 | * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490 6 | */ 7 | export function ReadableStreamToAsyncIterable(stream: any): AsyncIterableIterator { 8 | if (stream[Symbol.asyncIterator]) return stream; 9 | 10 | const reader = stream.getReader(); 11 | return { 12 | async next() { 13 | try { 14 | const result = await reader.read(); 15 | if (result?.done) reader.releaseLock(); // release lock when stream becomes closed 16 | return result; 17 | } catch (e) { 18 | reader.releaseLock(); // release lock when stream becomes errored 19 | throw e; 20 | } 21 | }, 22 | async return() { 23 | const cancelPromise = reader.cancel(); 24 | reader.releaseLock(); 25 | await cancelPromise; 26 | return { done: true, value: undefined }; 27 | }, 28 | [Symbol.asyncIterator]() { 29 | return this; 30 | }, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/internal/utils.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export * from './utils/values'; 4 | export * from './utils/base64'; 5 | export * from './utils/env'; 6 | export * from './utils/log'; 7 | export * from './utils/uuid'; 8 | export * from './utils/sleep'; 9 | -------------------------------------------------------------------------------- /src/internal/utils/base64.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { AnthropicError } from '../../core/error'; 4 | import { encodeUTF8 } from './bytes'; 5 | 6 | export const toBase64 = (data: string | Uint8Array | null | undefined): string => { 7 | if (!data) return ''; 8 | 9 | if (typeof (globalThis as any).Buffer !== 'undefined') { 10 | return (globalThis as any).Buffer.from(data).toString('base64'); 11 | } 12 | 13 | if (typeof data === 'string') { 14 | data = encodeUTF8(data); 15 | } 16 | 17 | if (typeof btoa !== 'undefined') { 18 | return btoa(String.fromCharCode.apply(null, data as any)); 19 | } 20 | 21 | throw new AnthropicError('Cannot generate base64 string; Expected `Buffer` or `btoa` to be defined'); 22 | }; 23 | 24 | export const fromBase64 = (str: string): Uint8Array => { 25 | if (typeof (globalThis as any).Buffer !== 'undefined') { 26 | const buf = (globalThis as any).Buffer.from(str, 'base64'); 27 | return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); 28 | } 29 | 30 | if (typeof atob !== 'undefined') { 31 | const bstr = atob(str); 32 | const buf = new Uint8Array(bstr.length); 33 | for (let i = 0; i < bstr.length; i++) { 34 | buf[i] = bstr.charCodeAt(i); 35 | } 36 | return buf; 37 | } 38 | 39 | throw new AnthropicError('Cannot decode base64 string; Expected `Buffer` or `atob` to be defined'); 40 | }; 41 | -------------------------------------------------------------------------------- /src/internal/utils/bytes.ts: -------------------------------------------------------------------------------- 1 | export function concatBytes(buffers: Uint8Array[]): Uint8Array { 2 | let length = 0; 3 | for (const buffer of buffers) { 4 | length += buffer.length; 5 | } 6 | const output = new Uint8Array(length); 7 | let index = 0; 8 | for (const buffer of buffers) { 9 | output.set(buffer, index); 10 | index += buffer.length; 11 | } 12 | 13 | return output; 14 | } 15 | 16 | let encodeUTF8_: (str: string) => Uint8Array; 17 | export function encodeUTF8(str: string) { 18 | let encoder; 19 | return ( 20 | encodeUTF8_ ?? 21 | ((encoder = new (globalThis as any).TextEncoder()), (encodeUTF8_ = encoder.encode.bind(encoder))) 22 | )(str); 23 | } 24 | 25 | let decodeUTF8_: (bytes: Uint8Array) => string; 26 | export function decodeUTF8(bytes: Uint8Array) { 27 | let decoder; 28 | return ( 29 | decodeUTF8_ ?? 30 | ((decoder = new (globalThis as any).TextDecoder()), (decodeUTF8_ = decoder.decode.bind(decoder))) 31 | )(bytes); 32 | } 33 | -------------------------------------------------------------------------------- /src/internal/utils/env.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | /** 4 | * Read an environment variable. 5 | * 6 | * Trims beginning and trailing whitespace. 7 | * 8 | * Will return undefined if the environment variable doesn't exist or cannot be accessed. 9 | */ 10 | export const readEnv = (env: string): string | undefined => { 11 | if (typeof (globalThis as any).process !== 'undefined') { 12 | return (globalThis as any).process.env?.[env]?.trim() ?? undefined; 13 | } 14 | if (typeof (globalThis as any).Deno !== 'undefined') { 15 | return (globalThis as any).Deno.env?.get?.(env)?.trim(); 16 | } 17 | return undefined; 18 | }; 19 | -------------------------------------------------------------------------------- /src/internal/utils/log.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { hasOwn } from './values'; 4 | import { type BaseAnthropic } from '../../client'; 5 | import { RequestOptions } from '../request-options'; 6 | 7 | type LogFn = (message: string, ...rest: unknown[]) => void; 8 | export type Logger = { 9 | error: LogFn; 10 | warn: LogFn; 11 | info: LogFn; 12 | debug: LogFn; 13 | }; 14 | export type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug'; 15 | 16 | const levelNumbers = { 17 | off: 0, 18 | error: 200, 19 | warn: 300, 20 | info: 400, 21 | debug: 500, 22 | }; 23 | 24 | export const parseLogLevel = ( 25 | maybeLevel: string | undefined, 26 | sourceName: string, 27 | client: BaseAnthropic, 28 | ): LogLevel | undefined => { 29 | if (!maybeLevel) { 30 | return undefined; 31 | } 32 | if (hasOwn(levelNumbers, maybeLevel)) { 33 | return maybeLevel; 34 | } 35 | loggerFor(client).warn( 36 | `${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify( 37 | Object.keys(levelNumbers), 38 | )}`, 39 | ); 40 | return undefined; 41 | }; 42 | 43 | function noop() {} 44 | 45 | function makeLogFn(fnLevel: keyof Logger, logger: Logger | undefined, logLevel: LogLevel) { 46 | if (!logger || levelNumbers[fnLevel] > levelNumbers[logLevel]) { 47 | return noop; 48 | } else { 49 | // Don't wrap logger functions, we want the stacktrace intact! 50 | return logger[fnLevel].bind(logger); 51 | } 52 | } 53 | 54 | const noopLogger = { 55 | error: noop, 56 | warn: noop, 57 | info: noop, 58 | debug: noop, 59 | }; 60 | 61 | let cachedLoggers = new WeakMap(); 62 | 63 | export function loggerFor(client: BaseAnthropic): Logger { 64 | const logger = client.logger; 65 | const logLevel = client.logLevel ?? 'off'; 66 | if (!logger) { 67 | return noopLogger; 68 | } 69 | 70 | const cachedLogger = cachedLoggers.get(logger); 71 | if (cachedLogger && cachedLogger[0] === logLevel) { 72 | return cachedLogger[1]; 73 | } 74 | 75 | const levelLogger = { 76 | error: makeLogFn('error', logger, logLevel), 77 | warn: makeLogFn('warn', logger, logLevel), 78 | info: makeLogFn('info', logger, logLevel), 79 | debug: makeLogFn('debug', logger, logLevel), 80 | }; 81 | 82 | cachedLoggers.set(logger, [logLevel, levelLogger]); 83 | 84 | return levelLogger; 85 | } 86 | 87 | export const formatRequestDetails = (details: { 88 | options?: RequestOptions | undefined; 89 | headers?: Headers | Record | undefined; 90 | retryOfRequestLogID?: string | undefined; 91 | retryOf?: string | undefined; 92 | url?: string | undefined; 93 | status?: number | undefined; 94 | method?: string | undefined; 95 | durationMs?: number | undefined; 96 | message?: unknown; 97 | body?: unknown; 98 | }) => { 99 | if (details.options) { 100 | details.options = { ...details.options }; 101 | delete details.options['headers']; // redundant + leaks internals 102 | } 103 | if (details.headers) { 104 | details.headers = Object.fromEntries( 105 | (details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map( 106 | ([name, value]) => [ 107 | name, 108 | ( 109 | name.toLowerCase() === 'x-api-key' || 110 | name.toLowerCase() === 'authorization' || 111 | name.toLowerCase() === 'cookie' || 112 | name.toLowerCase() === 'set-cookie' 113 | ) ? 114 | '***' 115 | : value, 116 | ], 117 | ), 118 | ); 119 | } 120 | if ('retryOfRequestLogID' in details) { 121 | if (details.retryOfRequestLogID) { 122 | details.retryOf = details.retryOfRequestLogID; 123 | } 124 | delete details.retryOfRequestLogID; 125 | } 126 | return details; 127 | }; 128 | -------------------------------------------------------------------------------- /src/internal/utils/path.ts: -------------------------------------------------------------------------------- 1 | import { AnthropicError } from '../../core/error'; 2 | 3 | /** 4 | * Percent-encode everything that isn't safe to have in a path without encoding safe chars. 5 | * 6 | * Taken from https://datatracker.ietf.org/doc/html/rfc3986#section-3.3: 7 | * > unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 8 | * > sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" 9 | * > pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 10 | */ 11 | export function encodeURIPath(str: string) { 12 | return str.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent); 13 | } 14 | 15 | export const createPathTagFunction = (pathEncoder = encodeURIPath) => 16 | function path(statics: readonly string[], ...params: readonly unknown[]): string { 17 | // If there are no params, no processing is needed. 18 | if (statics.length === 1) return statics[0]!; 19 | 20 | let postPath = false; 21 | const path = statics.reduce((previousValue, currentValue, index) => { 22 | if (/[?#]/.test(currentValue)) { 23 | postPath = true; 24 | } 25 | return ( 26 | previousValue + 27 | currentValue + 28 | (index === params.length ? '' : (postPath ? encodeURIComponent : pathEncoder)(String(params[index]))) 29 | ); 30 | }, ''); 31 | 32 | const pathOnly = path.split(/[?#]/, 1)[0]!; 33 | const invalidSegments = []; 34 | const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi; 35 | let match; 36 | 37 | // Find all invalid segments 38 | while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) { 39 | invalidSegments.push({ 40 | start: match.index, 41 | length: match[0].length, 42 | }); 43 | } 44 | 45 | if (invalidSegments.length > 0) { 46 | let lastEnd = 0; 47 | const underline = invalidSegments.reduce((acc, segment) => { 48 | const spaces = ' '.repeat(segment.start - lastEnd); 49 | const arrows = '^'.repeat(segment.length); 50 | lastEnd = segment.start + segment.length; 51 | return acc + spaces + arrows; 52 | }, ''); 53 | 54 | throw new AnthropicError( 55 | `Path parameters result in path with invalid segments:\n${path}\n${underline}`, 56 | ); 57 | } 58 | 59 | return path; 60 | }; 61 | 62 | /** 63 | * URI-encodes path params and ensures no unsafe /./ or /../ path segments are introduced. 64 | */ 65 | export const path = createPathTagFunction(encodeURIPath); 66 | -------------------------------------------------------------------------------- /src/internal/utils/sleep.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); 4 | -------------------------------------------------------------------------------- /src/internal/utils/uuid.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | /** 4 | * https://stackoverflow.com/a/2117523 5 | */ 6 | export let uuid4 = function () { 7 | const { crypto } = globalThis as any; 8 | if (crypto?.randomUUID) { 9 | uuid4 = crypto.randomUUID.bind(crypto); 10 | return crypto.randomUUID(); 11 | } 12 | const u8 = new Uint8Array(1); 13 | const randomByte = crypto ? () => crypto.getRandomValues(u8)[0]! : () => (Math.random() * 0xff) & 0xff; 14 | return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) => 15 | (+c ^ (randomByte() & (15 >> (+c / 4)))).toString(16), 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /src/internal/utils/values.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { AnthropicError } from '../../core/error'; 4 | 5 | // https://url.spec.whatwg.org/#url-scheme-string 6 | const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i; 7 | 8 | export const isAbsoluteURL = (url: string): boolean => { 9 | return startsWithSchemeRegexp.test(url); 10 | }; 11 | 12 | /** Returns an object if the given value isn't an object, otherwise returns as-is */ 13 | export function maybeObj(x: unknown): object { 14 | if (typeof x !== 'object') { 15 | return {}; 16 | } 17 | 18 | return x ?? {}; 19 | } 20 | 21 | // https://stackoverflow.com/a/34491287 22 | export function isEmptyObj(obj: Object | null | undefined): boolean { 23 | if (!obj) return true; 24 | for (const _k in obj) return false; 25 | return true; 26 | } 27 | 28 | // https://eslint.org/docs/latest/rules/no-prototype-builtins 29 | export function hasOwn(obj: T, key: PropertyKey): key is keyof T { 30 | return Object.prototype.hasOwnProperty.call(obj, key); 31 | } 32 | 33 | export function isObj(obj: unknown): obj is Record { 34 | return obj != null && typeof obj === 'object' && !Array.isArray(obj); 35 | } 36 | 37 | export const ensurePresent = (value: T | null | undefined): T => { 38 | if (value == null) { 39 | throw new AnthropicError(`Expected a value to be given but received ${value} instead.`); 40 | } 41 | 42 | return value; 43 | }; 44 | 45 | export const validatePositiveInteger = (name: string, n: unknown): number => { 46 | if (typeof n !== 'number' || !Number.isInteger(n)) { 47 | throw new AnthropicError(`${name} must be an integer`); 48 | } 49 | if (n < 0) { 50 | throw new AnthropicError(`${name} must be a positive integer`); 51 | } 52 | return n; 53 | }; 54 | 55 | export const coerceInteger = (value: unknown): number => { 56 | if (typeof value === 'number') return Math.round(value); 57 | if (typeof value === 'string') return parseInt(value, 10); 58 | 59 | throw new AnthropicError(`Could not coerce ${value} (type: ${typeof value}) into a number`); 60 | }; 61 | 62 | export const coerceFloat = (value: unknown): number => { 63 | if (typeof value === 'number') return value; 64 | if (typeof value === 'string') return parseFloat(value); 65 | 66 | throw new AnthropicError(`Could not coerce ${value} (type: ${typeof value}) into a number`); 67 | }; 68 | 69 | export const coerceBoolean = (value: unknown): boolean => { 70 | if (typeof value === 'boolean') return value; 71 | if (typeof value === 'string') return value === 'true'; 72 | return Boolean(value); 73 | }; 74 | 75 | export const maybeCoerceInteger = (value: unknown): number | undefined => { 76 | if (value === undefined) { 77 | return undefined; 78 | } 79 | return coerceInteger(value); 80 | }; 81 | 82 | export const maybeCoerceFloat = (value: unknown): number | undefined => { 83 | if (value === undefined) { 84 | return undefined; 85 | } 86 | return coerceFloat(value); 87 | }; 88 | 89 | export const maybeCoerceBoolean = (value: unknown): boolean | undefined => { 90 | if (value === undefined) { 91 | return undefined; 92 | } 93 | return coerceBoolean(value); 94 | }; 95 | 96 | export const safeJSON = (text: string) => { 97 | try { 98 | return JSON.parse(text); 99 | } catch (err) { 100 | return undefined; 101 | } 102 | }; 103 | -------------------------------------------------------------------------------- /src/lib/.keep: -------------------------------------------------------------------------------- 1 | File generated from our OpenAPI spec by Stainless. 2 | 3 | This directory can be used to store custom files to expand the SDK. 4 | It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. 5 | -------------------------------------------------------------------------------- /src/pagination.ts: -------------------------------------------------------------------------------- 1 | /** @deprecated Import from ./core/pagination instead */ 2 | export * from './core/pagination'; 3 | -------------------------------------------------------------------------------- /src/resource.ts: -------------------------------------------------------------------------------- 1 | /** @deprecated Import from ./core/resource instead */ 2 | export * from './core/resource'; 3 | -------------------------------------------------------------------------------- /src/resources.ts: -------------------------------------------------------------------------------- 1 | export * from './resources/index'; 2 | -------------------------------------------------------------------------------- /src/resources/beta.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export * from './beta/index'; 4 | -------------------------------------------------------------------------------- /src/resources/beta/index.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export { 4 | Beta, 5 | type AnthropicBeta, 6 | type BetaAPIError, 7 | type BetaAuthenticationError, 8 | type BetaBillingError, 9 | type BetaError, 10 | type BetaErrorResponse, 11 | type BetaGatewayTimeoutError, 12 | type BetaInvalidRequestError, 13 | type BetaNotFoundError, 14 | type BetaOverloadedError, 15 | type BetaPermissionError, 16 | type BetaRateLimitError, 17 | } from './beta'; 18 | export { 19 | Files, 20 | type DeletedFile, 21 | type FileMetadata, 22 | type FileListParams, 23 | type FileDeleteParams, 24 | type FileDownloadParams, 25 | type FileRetrieveMetadataParams, 26 | type FileUploadParams, 27 | type FileMetadataPage, 28 | } from './files'; 29 | export { 30 | Messages, 31 | type BetaBase64ImageSource, 32 | type BetaBase64PDFBlock, 33 | type BetaBase64PDFSource, 34 | type BetaCacheControlEphemeral, 35 | type BetaCacheCreation, 36 | type BetaCitationCharLocation, 37 | type BetaCitationCharLocationParam, 38 | type BetaCitationContentBlockLocation, 39 | type BetaCitationContentBlockLocationParam, 40 | type BetaCitationPageLocation, 41 | type BetaCitationPageLocationParam, 42 | type BetaCitationWebSearchResultLocationParam, 43 | type BetaCitationsConfigParam, 44 | type BetaCitationsDelta, 45 | type BetaCitationsWebSearchResultLocation, 46 | type BetaCodeExecutionOutputBlock, 47 | type BetaCodeExecutionOutputBlockParam, 48 | type BetaCodeExecutionResultBlock, 49 | type BetaCodeExecutionResultBlockParam, 50 | type BetaCodeExecutionTool20250522, 51 | type BetaCodeExecutionToolResultBlock, 52 | type BetaCodeExecutionToolResultBlockContent, 53 | type BetaCodeExecutionToolResultBlockParam, 54 | type BetaCodeExecutionToolResultBlockParamContent, 55 | type BetaCodeExecutionToolResultError, 56 | type BetaCodeExecutionToolResultErrorCode, 57 | type BetaCodeExecutionToolResultErrorParam, 58 | type BetaContainer, 59 | type BetaContainerUploadBlock, 60 | type BetaContainerUploadBlockParam, 61 | type BetaContentBlock, 62 | type BetaContentBlockParam, 63 | type BetaContentBlockSource, 64 | type BetaContentBlockSourceContent, 65 | type BetaFileDocumentSource, 66 | type BetaFileImageSource, 67 | type BetaImageBlockParam, 68 | type BetaInputJSONDelta, 69 | type BetaMCPToolResultBlock, 70 | type BetaMCPToolUseBlock, 71 | type BetaMCPToolUseBlockParam, 72 | type BetaMessage, 73 | type BetaMessageDeltaUsage, 74 | type BetaMessageParam, 75 | type BetaMessageTokensCount, 76 | type BetaMetadata, 77 | type BetaPlainTextSource, 78 | type BetaRawContentBlockDelta, 79 | type BetaRawContentBlockDeltaEvent, 80 | type BetaRawContentBlockStartEvent, 81 | type BetaRawContentBlockStopEvent, 82 | type BetaRawMessageDeltaEvent, 83 | type BetaRawMessageStartEvent, 84 | type BetaRawMessageStopEvent, 85 | type BetaRawMessageStreamEvent, 86 | type BetaRedactedThinkingBlock, 87 | type BetaRedactedThinkingBlockParam, 88 | type BetaRequestMCPServerToolConfiguration, 89 | type BetaRequestMCPServerURLDefinition, 90 | type BetaRequestMCPToolResultBlockParam, 91 | type BetaServerToolUsage, 92 | type BetaServerToolUseBlock, 93 | type BetaServerToolUseBlockParam, 94 | type BetaSignatureDelta, 95 | type BetaStopReason, 96 | type BetaTextBlock, 97 | type BetaTextBlockParam, 98 | type BetaTextCitation, 99 | type BetaTextCitationParam, 100 | type BetaTextDelta, 101 | type BetaThinkingBlock, 102 | type BetaThinkingBlockParam, 103 | type BetaThinkingConfigDisabled, 104 | type BetaThinkingConfigEnabled, 105 | type BetaThinkingConfigParam, 106 | type BetaThinkingDelta, 107 | type BetaTool, 108 | type BetaToolBash20241022, 109 | type BetaToolBash20250124, 110 | type BetaToolChoice, 111 | type BetaToolChoiceAny, 112 | type BetaToolChoiceAuto, 113 | type BetaToolChoiceNone, 114 | type BetaToolChoiceTool, 115 | type BetaToolComputerUse20241022, 116 | type BetaToolComputerUse20250124, 117 | type BetaToolResultBlockParam, 118 | type BetaToolTextEditor20241022, 119 | type BetaToolTextEditor20250124, 120 | type BetaToolTextEditor20250429, 121 | type BetaToolUnion, 122 | type BetaToolUseBlock, 123 | type BetaToolUseBlockParam, 124 | type BetaURLImageSource, 125 | type BetaURLPDFSource, 126 | type BetaUsage, 127 | type BetaWebSearchResultBlock, 128 | type BetaWebSearchResultBlockParam, 129 | type BetaWebSearchTool20250305, 130 | type BetaWebSearchToolRequestError, 131 | type BetaWebSearchToolResultBlock, 132 | type BetaWebSearchToolResultBlockContent, 133 | type BetaWebSearchToolResultBlockParam, 134 | type BetaWebSearchToolResultBlockParamContent, 135 | type BetaWebSearchToolResultError, 136 | type BetaWebSearchToolResultErrorCode, 137 | type MessageCreateParams, 138 | type MessageCreateParamsNonStreaming, 139 | type MessageCreateParamsStreaming, 140 | type MessageCountTokensParams, 141 | } from './messages/index'; 142 | export { 143 | Models, 144 | type BetaModelInfo, 145 | type ModelRetrieveParams, 146 | type ModelListParams, 147 | type BetaModelInfosPage, 148 | } from './models'; 149 | -------------------------------------------------------------------------------- /src/resources/beta/messages.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export * from './messages/index'; 4 | -------------------------------------------------------------------------------- /src/resources/beta/messages/index.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export { 4 | Batches, 5 | type BetaDeletedMessageBatch, 6 | type BetaMessageBatch, 7 | type BetaMessageBatchCanceledResult, 8 | type BetaMessageBatchErroredResult, 9 | type BetaMessageBatchExpiredResult, 10 | type BetaMessageBatchIndividualResponse, 11 | type BetaMessageBatchRequestCounts, 12 | type BetaMessageBatchResult, 13 | type BetaMessageBatchSucceededResult, 14 | type BatchCreateParams, 15 | type BatchRetrieveParams, 16 | type BatchListParams, 17 | type BatchDeleteParams, 18 | type BatchCancelParams, 19 | type BatchResultsParams, 20 | type BetaMessageBatchesPage, 21 | } from './batches'; 22 | export { 23 | Messages, 24 | type BetaBase64ImageSource, 25 | type BetaBase64PDFBlock, 26 | type BetaBase64PDFSource, 27 | type BetaCacheControlEphemeral, 28 | type BetaCacheCreation, 29 | type BetaCitationCharLocation, 30 | type BetaCitationCharLocationParam, 31 | type BetaCitationContentBlockLocation, 32 | type BetaCitationContentBlockLocationParam, 33 | type BetaCitationPageLocation, 34 | type BetaCitationPageLocationParam, 35 | type BetaCitationWebSearchResultLocationParam, 36 | type BetaCitationsConfigParam, 37 | type BetaCitationsDelta, 38 | type BetaCitationsWebSearchResultLocation, 39 | type BetaCodeExecutionOutputBlock, 40 | type BetaCodeExecutionOutputBlockParam, 41 | type BetaCodeExecutionResultBlock, 42 | type BetaCodeExecutionResultBlockParam, 43 | type BetaCodeExecutionTool20250522, 44 | type BetaCodeExecutionToolResultBlock, 45 | type BetaCodeExecutionToolResultBlockContent, 46 | type BetaCodeExecutionToolResultBlockParam, 47 | type BetaCodeExecutionToolResultBlockParamContent, 48 | type BetaCodeExecutionToolResultError, 49 | type BetaCodeExecutionToolResultErrorCode, 50 | type BetaCodeExecutionToolResultErrorParam, 51 | type BetaContainer, 52 | type BetaContainerUploadBlock, 53 | type BetaContainerUploadBlockParam, 54 | type BetaContentBlock, 55 | type BetaContentBlockParam, 56 | type BetaContentBlockSource, 57 | type BetaContentBlockSourceContent, 58 | type BetaFileDocumentSource, 59 | type BetaFileImageSource, 60 | type BetaImageBlockParam, 61 | type BetaInputJSONDelta, 62 | type BetaMCPToolResultBlock, 63 | type BetaMCPToolUseBlock, 64 | type BetaMCPToolUseBlockParam, 65 | type BetaMessage, 66 | type BetaMessageDeltaUsage, 67 | type BetaMessageParam, 68 | type BetaMessageTokensCount, 69 | type BetaMetadata, 70 | type BetaPlainTextSource, 71 | type BetaRawContentBlockDelta, 72 | type BetaRawContentBlockDeltaEvent, 73 | type BetaRawContentBlockStartEvent, 74 | type BetaRawContentBlockStopEvent, 75 | type BetaRawMessageDeltaEvent, 76 | type BetaRawMessageStartEvent, 77 | type BetaRawMessageStopEvent, 78 | type BetaRawMessageStreamEvent, 79 | type BetaRedactedThinkingBlock, 80 | type BetaRedactedThinkingBlockParam, 81 | type BetaRequestMCPServerToolConfiguration, 82 | type BetaRequestMCPServerURLDefinition, 83 | type BetaRequestMCPToolResultBlockParam, 84 | type BetaServerToolUsage, 85 | type BetaServerToolUseBlock, 86 | type BetaServerToolUseBlockParam, 87 | type BetaSignatureDelta, 88 | type BetaStopReason, 89 | type BetaTextBlock, 90 | type BetaTextBlockParam, 91 | type BetaTextCitation, 92 | type BetaTextCitationParam, 93 | type BetaTextDelta, 94 | type BetaThinkingBlock, 95 | type BetaThinkingBlockParam, 96 | type BetaThinkingConfigDisabled, 97 | type BetaThinkingConfigEnabled, 98 | type BetaThinkingConfigParam, 99 | type BetaThinkingDelta, 100 | type BetaTool, 101 | type BetaToolBash20241022, 102 | type BetaToolBash20250124, 103 | type BetaToolChoice, 104 | type BetaToolChoiceAny, 105 | type BetaToolChoiceAuto, 106 | type BetaToolChoiceNone, 107 | type BetaToolChoiceTool, 108 | type BetaToolComputerUse20241022, 109 | type BetaToolComputerUse20250124, 110 | type BetaToolResultBlockParam, 111 | type BetaToolTextEditor20241022, 112 | type BetaToolTextEditor20250124, 113 | type BetaToolTextEditor20250429, 114 | type BetaToolUnion, 115 | type BetaToolUseBlock, 116 | type BetaToolUseBlockParam, 117 | type BetaURLImageSource, 118 | type BetaURLPDFSource, 119 | type BetaUsage, 120 | type BetaWebSearchResultBlock, 121 | type BetaWebSearchResultBlockParam, 122 | type BetaWebSearchTool20250305, 123 | type BetaWebSearchToolRequestError, 124 | type BetaWebSearchToolResultBlock, 125 | type BetaWebSearchToolResultBlockContent, 126 | type BetaWebSearchToolResultBlockParam, 127 | type BetaWebSearchToolResultBlockParamContent, 128 | type BetaWebSearchToolResultError, 129 | type BetaWebSearchToolResultErrorCode, 130 | type MessageCreateParams, 131 | type MessageCreateParamsNonStreaming, 132 | type MessageCreateParamsStreaming, 133 | type MessageCountTokensParams, 134 | type BetaMessageStreamParams, 135 | } from './messages'; 136 | -------------------------------------------------------------------------------- /src/resources/beta/models.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../../core/resource'; 4 | import * as BetaAPI from './beta'; 5 | import { APIPromise } from '../../core/api-promise'; 6 | import { Page, type PageParams, PagePromise } from '../../core/pagination'; 7 | import { buildHeaders } from '../../internal/headers'; 8 | import { RequestOptions } from '../../internal/request-options'; 9 | import { path } from '../../internal/utils/path'; 10 | 11 | export class Models extends APIResource { 12 | /** 13 | * Get a specific model. 14 | * 15 | * The Models API response can be used to determine information about a specific 16 | * model or resolve a model alias to a model ID. 17 | * 18 | * @example 19 | * ```ts 20 | * const betaModelInfo = await client.beta.models.retrieve( 21 | * 'model_id', 22 | * ); 23 | * ``` 24 | */ 25 | retrieve( 26 | modelID: string, 27 | params: ModelRetrieveParams | null | undefined = {}, 28 | options?: RequestOptions, 29 | ): APIPromise { 30 | const { betas } = params ?? {}; 31 | return this._client.get(path`/v1/models/${modelID}?beta=true`, { 32 | ...options, 33 | headers: buildHeaders([ 34 | { ...(betas?.toString() != null ? { 'anthropic-beta': betas?.toString() } : undefined) }, 35 | options?.headers, 36 | ]), 37 | }); 38 | } 39 | 40 | /** 41 | * List available models. 42 | * 43 | * The Models API response can be used to determine which models are available for 44 | * use in the API. More recently released models are listed first. 45 | * 46 | * @example 47 | * ```ts 48 | * // Automatically fetches more pages as needed. 49 | * for await (const betaModelInfo of client.beta.models.list()) { 50 | * // ... 51 | * } 52 | * ``` 53 | */ 54 | list( 55 | params: ModelListParams | null | undefined = {}, 56 | options?: RequestOptions, 57 | ): PagePromise { 58 | const { betas, ...query } = params ?? {}; 59 | return this._client.getAPIList('/v1/models?beta=true', Page, { 60 | query, 61 | ...options, 62 | headers: buildHeaders([ 63 | { ...(betas?.toString() != null ? { 'anthropic-beta': betas?.toString() } : undefined) }, 64 | options?.headers, 65 | ]), 66 | }); 67 | } 68 | } 69 | 70 | export type BetaModelInfosPage = Page; 71 | 72 | export interface BetaModelInfo { 73 | /** 74 | * Unique model identifier. 75 | */ 76 | id: string; 77 | 78 | /** 79 | * RFC 3339 datetime string representing the time at which the model was released. 80 | * May be set to an epoch value if the release date is unknown. 81 | */ 82 | created_at: string; 83 | 84 | /** 85 | * A human-readable name for the model. 86 | */ 87 | display_name: string; 88 | 89 | /** 90 | * Object type. 91 | * 92 | * For Models, this is always `"model"`. 93 | */ 94 | type: 'model'; 95 | } 96 | 97 | export interface ModelRetrieveParams { 98 | /** 99 | * Optional header to specify the beta version(s) you want to use. 100 | */ 101 | betas?: Array; 102 | } 103 | 104 | export interface ModelListParams extends PageParams { 105 | /** 106 | * Header param: Optional header to specify the beta version(s) you want to use. 107 | */ 108 | betas?: Array; 109 | } 110 | 111 | export declare namespace Models { 112 | export { 113 | type BetaModelInfo as BetaModelInfo, 114 | type BetaModelInfosPage as BetaModelInfosPage, 115 | type ModelRetrieveParams as ModelRetrieveParams, 116 | type ModelListParams as ModelListParams, 117 | }; 118 | } 119 | -------------------------------------------------------------------------------- /src/resources/index.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export * from './shared'; 4 | export { 5 | Beta, 6 | type AnthropicBeta, 7 | type BetaAPIError, 8 | type BetaAuthenticationError, 9 | type BetaBillingError, 10 | type BetaError, 11 | type BetaErrorResponse, 12 | type BetaGatewayTimeoutError, 13 | type BetaInvalidRequestError, 14 | type BetaNotFoundError, 15 | type BetaOverloadedError, 16 | type BetaPermissionError, 17 | type BetaRateLimitError, 18 | } from './beta/beta'; 19 | export { 20 | Completions, 21 | type Completion, 22 | type CompletionCreateParams, 23 | type CompletionCreateParamsNonStreaming, 24 | type CompletionCreateParamsStreaming, 25 | } from './completions'; 26 | export { 27 | Messages, 28 | type Base64ImageSource, 29 | type Base64PDFSource, 30 | type CacheControlEphemeral, 31 | type CitationCharLocation, 32 | type CitationCharLocationParam, 33 | type CitationContentBlockLocation, 34 | type CitationContentBlockLocationParam, 35 | type CitationPageLocation, 36 | type CitationPageLocationParam, 37 | type CitationWebSearchResultLocationParam, 38 | type CitationsConfigParam, 39 | type CitationsDelta, 40 | type CitationsWebSearchResultLocation, 41 | type ContentBlock, 42 | type ContentBlockParam, 43 | type ContentBlockStartEvent, 44 | type ContentBlockStopEvent, 45 | type ContentBlockSource, 46 | type ContentBlockSourceContent, 47 | type DocumentBlockParam, 48 | type ImageBlockParam, 49 | type InputJSONDelta, 50 | type Message, 51 | type MessageCountTokensTool, 52 | type MessageDeltaEvent, 53 | type MessageDeltaUsage, 54 | type MessageParam, 55 | type MessageStreamParams, 56 | type MessageTokensCount, 57 | type Metadata, 58 | type Model, 59 | type PlainTextSource, 60 | type RawContentBlockDelta, 61 | type RawContentBlockDeltaEvent, 62 | type RawContentBlockStartEvent, 63 | type RawContentBlockStopEvent, 64 | type RawMessageDeltaEvent, 65 | type RawMessageStartEvent, 66 | type RawMessageStopEvent, 67 | type RawMessageStreamEvent, 68 | type RedactedThinkingBlock, 69 | type RedactedThinkingBlockParam, 70 | type ServerToolUsage, 71 | type ServerToolUseBlock, 72 | type ServerToolUseBlockParam, 73 | type SignatureDelta, 74 | type StopReason, 75 | type TextBlock, 76 | type TextBlockParam, 77 | type TextCitation, 78 | type TextCitationParam, 79 | type TextDelta, 80 | type ThinkingBlock, 81 | type ThinkingBlockParam, 82 | type ThinkingConfigDisabled, 83 | type ThinkingConfigEnabled, 84 | type ThinkingConfigParam, 85 | type ThinkingDelta, 86 | type Tool, 87 | type ToolBash20250124, 88 | type ToolChoice, 89 | type ToolChoiceAny, 90 | type ToolChoiceAuto, 91 | type ToolChoiceNone, 92 | type ToolChoiceTool, 93 | type ToolResultBlockParam, 94 | type ToolTextEditor20250124, 95 | type ToolUnion, 96 | type ToolUseBlock, 97 | type ToolUseBlockParam, 98 | type URLImageSource, 99 | type URLPDFSource, 100 | type Usage, 101 | type WebSearchResultBlock, 102 | type WebSearchResultBlockParam, 103 | type WebSearchTool20250305, 104 | type WebSearchToolRequestError, 105 | type WebSearchToolResultBlock, 106 | type WebSearchToolResultBlockContent, 107 | type WebSearchToolResultBlockParam, 108 | type WebSearchToolResultBlockParamContent, 109 | type WebSearchToolResultError, 110 | type MessageCreateParams, 111 | type MessageCreateParamsNonStreaming, 112 | type MessageCreateParamsStreaming, 113 | type MessageCountTokensParams, 114 | } from './messages/messages'; 115 | export { 116 | Models, 117 | type ModelInfo, 118 | type ModelRetrieveParams, 119 | type ModelListParams, 120 | type ModelInfosPage, 121 | } from './models'; 122 | -------------------------------------------------------------------------------- /src/resources/messages.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export * from './messages/index'; 4 | -------------------------------------------------------------------------------- /src/resources/messages/index.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export { 4 | Batches, 5 | type DeletedMessageBatch, 6 | type MessageBatch, 7 | type MessageBatchCanceledResult, 8 | type MessageBatchErroredResult, 9 | type MessageBatchExpiredResult, 10 | type MessageBatchIndividualResponse, 11 | type MessageBatchRequestCounts, 12 | type MessageBatchResult, 13 | type MessageBatchSucceededResult, 14 | type BatchCreateParams, 15 | type BatchListParams, 16 | type MessageBatchesPage, 17 | } from './batches'; 18 | export { 19 | Messages, 20 | type Base64ImageSource, 21 | type Base64PDFSource, 22 | type CacheControlEphemeral, 23 | type CitationCharLocation, 24 | type CitationCharLocationParam, 25 | type CitationContentBlockLocation, 26 | type CitationContentBlockLocationParam, 27 | type CitationPageLocation, 28 | type CitationPageLocationParam, 29 | type CitationWebSearchResultLocationParam, 30 | type CitationsConfigParam, 31 | type CitationsDelta, 32 | type CitationsWebSearchResultLocation, 33 | type ContentBlock, 34 | type ContentBlockParam, 35 | type ContentBlockStartEvent, 36 | type ContentBlockStopEvent, 37 | type ContentBlockSource, 38 | type ContentBlockSourceContent, 39 | type DocumentBlockParam, 40 | type ImageBlockParam, 41 | type InputJSONDelta, 42 | type Message, 43 | type MessageCountTokensTool, 44 | type MessageDeltaEvent, 45 | type MessageDeltaUsage, 46 | type MessageParam, 47 | type MessageTokensCount, 48 | type Metadata, 49 | type Model, 50 | type PlainTextSource, 51 | type RawContentBlockDelta, 52 | type RawContentBlockDeltaEvent, 53 | type RawContentBlockStartEvent, 54 | type RawContentBlockStopEvent, 55 | type RawMessageDeltaEvent, 56 | type RawMessageStartEvent, 57 | type RawMessageStopEvent, 58 | type RawMessageStreamEvent, 59 | type RedactedThinkingBlock, 60 | type RedactedThinkingBlockParam, 61 | type ServerToolUsage, 62 | type ServerToolUseBlock, 63 | type ServerToolUseBlockParam, 64 | type SignatureDelta, 65 | type StopReason, 66 | type TextBlock, 67 | type TextBlockParam, 68 | type TextCitation, 69 | type TextCitationParam, 70 | type TextDelta, 71 | type ThinkingBlock, 72 | type ThinkingBlockParam, 73 | type ThinkingConfigDisabled, 74 | type ThinkingConfigEnabled, 75 | type ThinkingConfigParam, 76 | type ThinkingDelta, 77 | type Tool, 78 | type ToolBash20250124, 79 | type ToolChoice, 80 | type ToolChoiceAny, 81 | type ToolChoiceAuto, 82 | type ToolChoiceNone, 83 | type ToolChoiceTool, 84 | type ToolResultBlockParam, 85 | type ToolTextEditor20250124, 86 | type ToolUnion, 87 | type ToolUseBlock, 88 | type ToolUseBlockParam, 89 | type URLImageSource, 90 | type URLPDFSource, 91 | type Usage, 92 | type WebSearchResultBlock, 93 | type WebSearchResultBlockParam, 94 | type WebSearchTool20250305, 95 | type WebSearchToolRequestError, 96 | type WebSearchToolResultBlock, 97 | type WebSearchToolResultBlockContent, 98 | type WebSearchToolResultBlockParam, 99 | type WebSearchToolResultBlockParamContent, 100 | type WebSearchToolResultError, 101 | type MessageStreamEvent, 102 | type MessageStartEvent, 103 | type MessageStopEvent, 104 | type ContentBlockDeltaEvent, 105 | type MessageCreateParams, 106 | type MessageCreateParamsBase, 107 | type MessageCreateParamsNonStreaming, 108 | type MessageCreateParamsStreaming, 109 | type MessageCountTokensParams, 110 | } from './messages'; 111 | -------------------------------------------------------------------------------- /src/resources/models.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../core/resource'; 4 | import * as BetaAPI from './beta/beta'; 5 | import { APIPromise } from '../core/api-promise'; 6 | import { Page, type PageParams, PagePromise } from '../core/pagination'; 7 | import { buildHeaders } from '../internal/headers'; 8 | import { RequestOptions } from '../internal/request-options'; 9 | import { path } from '../internal/utils/path'; 10 | 11 | export class Models extends APIResource { 12 | /** 13 | * Get a specific model. 14 | * 15 | * The Models API response can be used to determine information about a specific 16 | * model or resolve a model alias to a model ID. 17 | */ 18 | retrieve( 19 | modelID: string, 20 | params: ModelRetrieveParams | null | undefined = {}, 21 | options?: RequestOptions, 22 | ): APIPromise { 23 | const { betas } = params ?? {}; 24 | return this._client.get(path`/v1/models/${modelID}`, { 25 | ...options, 26 | headers: buildHeaders([ 27 | { ...(betas?.toString() != null ? { 'anthropic-beta': betas?.toString() } : undefined) }, 28 | options?.headers, 29 | ]), 30 | }); 31 | } 32 | 33 | /** 34 | * List available models. 35 | * 36 | * The Models API response can be used to determine which models are available for 37 | * use in the API. More recently released models are listed first. 38 | */ 39 | list( 40 | params: ModelListParams | null | undefined = {}, 41 | options?: RequestOptions, 42 | ): PagePromise { 43 | const { betas, ...query } = params ?? {}; 44 | return this._client.getAPIList('/v1/models', Page, { 45 | query, 46 | ...options, 47 | headers: buildHeaders([ 48 | { ...(betas?.toString() != null ? { 'anthropic-beta': betas?.toString() } : undefined) }, 49 | options?.headers, 50 | ]), 51 | }); 52 | } 53 | } 54 | 55 | export type ModelInfosPage = Page; 56 | 57 | export interface ModelInfo { 58 | /** 59 | * Unique model identifier. 60 | */ 61 | id: string; 62 | 63 | /** 64 | * RFC 3339 datetime string representing the time at which the model was released. 65 | * May be set to an epoch value if the release date is unknown. 66 | */ 67 | created_at: string; 68 | 69 | /** 70 | * A human-readable name for the model. 71 | */ 72 | display_name: string; 73 | 74 | /** 75 | * Object type. 76 | * 77 | * For Models, this is always `"model"`. 78 | */ 79 | type: 'model'; 80 | } 81 | 82 | export interface ModelRetrieveParams { 83 | /** 84 | * Optional header to specify the beta version(s) you want to use. 85 | */ 86 | betas?: Array; 87 | } 88 | 89 | export interface ModelListParams extends PageParams { 90 | /** 91 | * Header param: Optional header to specify the beta version(s) you want to use. 92 | */ 93 | betas?: Array; 94 | } 95 | 96 | export declare namespace Models { 97 | export { 98 | type ModelInfo as ModelInfo, 99 | type ModelInfosPage as ModelInfosPage, 100 | type ModelRetrieveParams as ModelRetrieveParams, 101 | type ModelListParams as ModelListParams, 102 | }; 103 | } 104 | -------------------------------------------------------------------------------- /src/resources/shared.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export interface APIErrorObject { 4 | message: string; 5 | 6 | type: 'api_error'; 7 | } 8 | 9 | export interface AuthenticationError { 10 | message: string; 11 | 12 | type: 'authentication_error'; 13 | } 14 | 15 | export interface BillingError { 16 | message: string; 17 | 18 | type: 'billing_error'; 19 | } 20 | 21 | export type ErrorObject = 22 | | InvalidRequestError 23 | | AuthenticationError 24 | | BillingError 25 | | PermissionError 26 | | NotFoundError 27 | | RateLimitError 28 | | GatewayTimeoutError 29 | | APIErrorObject 30 | | OverloadedError; 31 | 32 | export interface ErrorResponse { 33 | error: ErrorObject; 34 | 35 | type: 'error'; 36 | } 37 | 38 | export interface GatewayTimeoutError { 39 | message: string; 40 | 41 | type: 'timeout_error'; 42 | } 43 | 44 | export interface InvalidRequestError { 45 | message: string; 46 | 47 | type: 'invalid_request_error'; 48 | } 49 | 50 | export interface NotFoundError { 51 | message: string; 52 | 53 | type: 'not_found_error'; 54 | } 55 | 56 | export interface OverloadedError { 57 | message: string; 58 | 59 | type: 'overloaded_error'; 60 | } 61 | 62 | export interface PermissionError { 63 | message: string; 64 | 65 | type: 'permission_error'; 66 | } 67 | 68 | export interface RateLimitError { 69 | message: string; 70 | 71 | type: 'rate_limit_error'; 72 | } 73 | -------------------------------------------------------------------------------- /src/resources/top-level.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export {}; 4 | -------------------------------------------------------------------------------- /src/streaming.ts: -------------------------------------------------------------------------------- 1 | /** @deprecated Import from ./core/streaming instead */ 2 | export * from './core/streaming'; 3 | -------------------------------------------------------------------------------- /src/uploads.ts: -------------------------------------------------------------------------------- 1 | /** @deprecated Import from ./core/uploads instead */ 2 | export * from './core/uploads'; 3 | -------------------------------------------------------------------------------- /src/version.ts: -------------------------------------------------------------------------------- 1 | export const VERSION = '0.53.0'; // x-release-please-version 2 | -------------------------------------------------------------------------------- /tests/api-resources/beta/files.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Anthropic, { toFile } from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic({ 6 | apiKey: 'my-anthropic-api-key', 7 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 8 | }); 9 | 10 | describe('resource files', () => { 11 | test('list', async () => { 12 | const responsePromise = client.beta.files.list(); 13 | const rawResponse = await responsePromise.asResponse(); 14 | expect(rawResponse).toBeInstanceOf(Response); 15 | const response = await responsePromise; 16 | expect(response).not.toBeInstanceOf(Response); 17 | const dataAndResponse = await responsePromise.withResponse(); 18 | expect(dataAndResponse.data).toBe(response); 19 | expect(dataAndResponse.response).toBe(rawResponse); 20 | }); 21 | 22 | test('list: request options and params are passed correctly', async () => { 23 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 24 | await expect( 25 | client.beta.files.list( 26 | { after_id: 'after_id', before_id: 'before_id', limit: 1, betas: ['string'] }, 27 | { path: '/_stainless_unknown_path' }, 28 | ), 29 | ).rejects.toThrow(Anthropic.NotFoundError); 30 | }); 31 | 32 | test('delete', async () => { 33 | const responsePromise = client.beta.files.delete('file_id'); 34 | const rawResponse = await responsePromise.asResponse(); 35 | expect(rawResponse).toBeInstanceOf(Response); 36 | const response = await responsePromise; 37 | expect(response).not.toBeInstanceOf(Response); 38 | const dataAndResponse = await responsePromise.withResponse(); 39 | expect(dataAndResponse.data).toBe(response); 40 | expect(dataAndResponse.response).toBe(rawResponse); 41 | }); 42 | 43 | test('delete: request options and params are passed correctly', async () => { 44 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 45 | await expect( 46 | client.beta.files.delete('file_id', { betas: ['string'] }, { path: '/_stainless_unknown_path' }), 47 | ).rejects.toThrow(Anthropic.NotFoundError); 48 | }); 49 | 50 | test('download: request options and params are passed correctly', async () => { 51 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 52 | await expect( 53 | client.beta.files.download('file_id', { betas: ['string'] }, { path: '/_stainless_unknown_path' }), 54 | ).rejects.toThrow(Anthropic.NotFoundError); 55 | }); 56 | 57 | test('retrieveMetadata', async () => { 58 | const responsePromise = client.beta.files.retrieveMetadata('file_id'); 59 | const rawResponse = await responsePromise.asResponse(); 60 | expect(rawResponse).toBeInstanceOf(Response); 61 | const response = await responsePromise; 62 | expect(response).not.toBeInstanceOf(Response); 63 | const dataAndResponse = await responsePromise.withResponse(); 64 | expect(dataAndResponse.data).toBe(response); 65 | expect(dataAndResponse.response).toBe(rawResponse); 66 | }); 67 | 68 | test('retrieveMetadata: request options and params are passed correctly', async () => { 69 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 70 | await expect( 71 | client.beta.files.retrieveMetadata( 72 | 'file_id', 73 | { betas: ['string'] }, 74 | { path: '/_stainless_unknown_path' }, 75 | ), 76 | ).rejects.toThrow(Anthropic.NotFoundError); 77 | }); 78 | 79 | test('upload: only required params', async () => { 80 | const responsePromise = client.beta.files.upload({ 81 | file: await toFile(Buffer.from('# my file contents'), 'README.md'), 82 | }); 83 | const rawResponse = await responsePromise.asResponse(); 84 | expect(rawResponse).toBeInstanceOf(Response); 85 | const response = await responsePromise; 86 | expect(response).not.toBeInstanceOf(Response); 87 | const dataAndResponse = await responsePromise.withResponse(); 88 | expect(dataAndResponse.data).toBe(response); 89 | expect(dataAndResponse.response).toBe(rawResponse); 90 | }); 91 | 92 | test('upload: required and optional params', async () => { 93 | const response = await client.beta.files.upload({ 94 | file: await toFile(Buffer.from('# my file contents'), 'README.md'), 95 | betas: ['string'], 96 | }); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /tests/api-resources/beta/models.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic({ 6 | apiKey: 'my-anthropic-api-key', 7 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 8 | }); 9 | 10 | describe('resource models', () => { 11 | test('retrieve', async () => { 12 | const responsePromise = client.beta.models.retrieve('model_id'); 13 | const rawResponse = await responsePromise.asResponse(); 14 | expect(rawResponse).toBeInstanceOf(Response); 15 | const response = await responsePromise; 16 | expect(response).not.toBeInstanceOf(Response); 17 | const dataAndResponse = await responsePromise.withResponse(); 18 | expect(dataAndResponse.data).toBe(response); 19 | expect(dataAndResponse.response).toBe(rawResponse); 20 | }); 21 | 22 | test('retrieve: request options and params are passed correctly', async () => { 23 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 24 | await expect( 25 | client.beta.models.retrieve('model_id', { betas: ['string'] }, { path: '/_stainless_unknown_path' }), 26 | ).rejects.toThrow(Anthropic.NotFoundError); 27 | }); 28 | 29 | test('retrieve: request options and params are passed correctly', async () => { 30 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 31 | await expect( 32 | client.beta.models.retrieve('model_id', { betas: ['string'] }, { path: '/_stainless_unknown_path' }), 33 | ).rejects.toThrow(Anthropic.NotFoundError); 34 | }); 35 | 36 | test('list', async () => { 37 | const responsePromise = client.beta.models.list(); 38 | const rawResponse = await responsePromise.asResponse(); 39 | expect(rawResponse).toBeInstanceOf(Response); 40 | const response = await responsePromise; 41 | expect(response).not.toBeInstanceOf(Response); 42 | const dataAndResponse = await responsePromise.withResponse(); 43 | expect(dataAndResponse.data).toBe(response); 44 | expect(dataAndResponse.response).toBe(rawResponse); 45 | }); 46 | 47 | test('list: request options and params are passed correctly', async () => { 48 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 49 | await expect( 50 | client.beta.models.list( 51 | { after_id: 'after_id', before_id: 'before_id', limit: 1, betas: ['string'] }, 52 | { path: '/_stainless_unknown_path' }, 53 | ), 54 | ).rejects.toThrow(Anthropic.NotFoundError); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /tests/api-resources/completions.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic({ 6 | apiKey: 'my-anthropic-api-key', 7 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 8 | }); 9 | 10 | describe('resource completions', () => { 11 | test('create: only required params', async () => { 12 | const responsePromise = client.completions.create({ 13 | max_tokens_to_sample: 256, 14 | model: 'claude-3-7-sonnet-latest', 15 | prompt: '\n\nHuman: Hello, world!\n\nAssistant:', 16 | }); 17 | const rawResponse = await responsePromise.asResponse(); 18 | expect(rawResponse).toBeInstanceOf(Response); 19 | const response = await responsePromise; 20 | expect(response).not.toBeInstanceOf(Response); 21 | const dataAndResponse = await responsePromise.withResponse(); 22 | expect(dataAndResponse.data).toBe(response); 23 | expect(dataAndResponse.response).toBe(rawResponse); 24 | }); 25 | 26 | test('create: required and optional params', async () => { 27 | const response = await client.completions.create({ 28 | max_tokens_to_sample: 256, 29 | model: 'claude-3-7-sonnet-latest', 30 | prompt: '\n\nHuman: Hello, world!\n\nAssistant:', 31 | metadata: { user_id: '13803d75-b4b5-4c3e-b2a2-6f21399b021b' }, 32 | stop_sequences: ['string'], 33 | stream: false, 34 | temperature: 1, 35 | top_k: 5, 36 | top_p: 0.7, 37 | betas: ['string'], 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /tests/api-resources/models.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Anthropic from '@anthropic-ai/sdk'; 4 | 5 | const client = new Anthropic({ 6 | apiKey: 'my-anthropic-api-key', 7 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 8 | }); 9 | 10 | describe('resource models', () => { 11 | test('retrieve', async () => { 12 | const responsePromise = client.models.retrieve('model_id'); 13 | const rawResponse = await responsePromise.asResponse(); 14 | expect(rawResponse).toBeInstanceOf(Response); 15 | const response = await responsePromise; 16 | expect(response).not.toBeInstanceOf(Response); 17 | const dataAndResponse = await responsePromise.withResponse(); 18 | expect(dataAndResponse.data).toBe(response); 19 | expect(dataAndResponse.response).toBe(rawResponse); 20 | }); 21 | 22 | test('retrieve: request options and params are passed correctly', async () => { 23 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 24 | await expect( 25 | client.models.retrieve('model_id', { betas: ['string'] }, { path: '/_stainless_unknown_path' }), 26 | ).rejects.toThrow(Anthropic.NotFoundError); 27 | }); 28 | 29 | test('retrieve: request options and params are passed correctly', async () => { 30 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 31 | await expect( 32 | client.models.retrieve('model_id', { betas: ['string'] }, { path: '/_stainless_unknown_path' }), 33 | ).rejects.toThrow(Anthropic.NotFoundError); 34 | }); 35 | 36 | test('list', async () => { 37 | const responsePromise = client.models.list(); 38 | const rawResponse = await responsePromise.asResponse(); 39 | expect(rawResponse).toBeInstanceOf(Response); 40 | const response = await responsePromise; 41 | expect(response).not.toBeInstanceOf(Response); 42 | const dataAndResponse = await responsePromise.withResponse(); 43 | expect(dataAndResponse.data).toBe(response); 44 | expect(dataAndResponse.response).toBe(rawResponse); 45 | }); 46 | 47 | test('list: request options and params are passed correctly', async () => { 48 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 49 | await expect( 50 | client.models.list( 51 | { after_id: 'after_id', before_id: 'before_id', limit: 1, betas: ['string'] }, 52 | { path: '/_stainless_unknown_path' }, 53 | ), 54 | ).rejects.toThrow(Anthropic.NotFoundError); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /tests/base64.test.ts: -------------------------------------------------------------------------------- 1 | import { fromBase64, toBase64 } from '@anthropic-ai/sdk/internal/utils/base64'; 2 | 3 | describe.each(['Buffer', 'atob'])('with %s', (mode) => { 4 | let originalBuffer: BufferConstructor; 5 | beforeAll(() => { 6 | if (mode === 'atob') { 7 | originalBuffer = globalThis.Buffer; 8 | // @ts-expect-error Can't assign undefined to BufferConstructor 9 | delete globalThis.Buffer; 10 | } 11 | }); 12 | afterAll(() => { 13 | if (mode === 'atob') { 14 | globalThis.Buffer = originalBuffer; 15 | } 16 | }); 17 | test('toBase64', () => { 18 | const testCases = [ 19 | { 20 | input: 'hello world', 21 | expected: 'aGVsbG8gd29ybGQ=', 22 | }, 23 | { 24 | input: new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), 25 | expected: 'aGVsbG8gd29ybGQ=', 26 | }, 27 | { 28 | input: undefined, 29 | expected: '', 30 | }, 31 | { 32 | input: new Uint8Array([ 33 | 229, 102, 215, 230, 65, 22, 46, 87, 243, 176, 99, 99, 31, 174, 8, 242, 83, 142, 169, 64, 122, 123, 34 | 193, 71, 35 | ]), 36 | expected: '5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH', 37 | }, 38 | { 39 | input: '✓', 40 | expected: '4pyT', 41 | }, 42 | { 43 | input: new Uint8Array([226, 156, 147]), 44 | expected: '4pyT', 45 | }, 46 | ]; 47 | 48 | testCases.forEach(({ input, expected }) => { 49 | expect(toBase64(input)).toBe(expected); 50 | }); 51 | }); 52 | 53 | test('fromBase64', () => { 54 | const testCases = [ 55 | { 56 | input: 'aGVsbG8gd29ybGQ=', 57 | expected: new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), 58 | }, 59 | { 60 | input: '', 61 | expected: new Uint8Array([]), 62 | }, 63 | { 64 | input: '5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH', 65 | expected: new Uint8Array([ 66 | 229, 102, 215, 230, 65, 22, 46, 87, 243, 176, 99, 99, 31, 174, 8, 242, 83, 142, 169, 64, 122, 123, 67 | 193, 71, 68 | ]), 69 | }, 70 | { 71 | input: '4pyT', 72 | expected: new Uint8Array([226, 156, 147]), 73 | }, 74 | ]; 75 | 76 | testCases.forEach(({ input, expected }) => { 77 | expect(fromBase64(input)).toEqual(expected); 78 | }); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /tests/buildHeaders.test.ts: -------------------------------------------------------------------------------- 1 | import { inspect } from 'node:util'; 2 | import { buildHeaders, type HeadersLike, type NullableHeaders } from '@anthropic-ai/sdk/internal/headers'; 3 | 4 | function inspectNullableHeaders(headers: NullableHeaders) { 5 | return `NullableHeaders {${[ 6 | ...[...headers.values.entries()].map(([name, value]) => ` ${inspect(name)}: ${inspect(value)}`), 7 | ...[...headers.nulls].map((name) => ` ${inspect(name)}: null`), 8 | ].join(', ')} }`; 9 | } 10 | 11 | describe('buildHeaders', () => { 12 | const cases: [HeadersLike[], string][] = [ 13 | [[new Headers({ 'content-type': 'text/plain' })], `NullableHeaders { 'content-type': 'text/plain' }`], 14 | [ 15 | [ 16 | { 17 | 'content-type': 'text/plain', 18 | }, 19 | { 20 | 'Content-Type': undefined, 21 | }, 22 | ], 23 | `NullableHeaders { 'content-type': 'text/plain' }`, 24 | ], 25 | [ 26 | [ 27 | { 28 | 'content-type': 'text/plain', 29 | }, 30 | { 31 | 'Content-Type': null, 32 | }, 33 | ], 34 | `NullableHeaders { 'content-type': null }`, 35 | ], 36 | [ 37 | [ 38 | { 39 | cookie: 'name1=value1', 40 | Cookie: 'name2=value2', 41 | }, 42 | ], 43 | `NullableHeaders { 'cookie': 'name2=value2' }`, 44 | ], 45 | [ 46 | [ 47 | { 48 | cookie: 'name1=value1', 49 | Cookie: undefined, 50 | }, 51 | ], 52 | `NullableHeaders { 'cookie': 'name1=value1' }`, 53 | ], 54 | [ 55 | [ 56 | { 57 | cookie: ['name1=value1', 'name2=value2'], 58 | }, 59 | ], 60 | `NullableHeaders { 'cookie': 'name1=value1; name2=value2' }`, 61 | ], 62 | [ 63 | [ 64 | { 65 | 'x-foo': ['name1=value1', 'name2=value2'], 66 | }, 67 | ], 68 | `NullableHeaders { 'x-foo': 'name1=value1, name2=value2' }`, 69 | ], 70 | [ 71 | [ 72 | [ 73 | ['cookie', 'name1=value1'], 74 | ['cookie', 'name2=value2'], 75 | ['Cookie', 'name3=value3'], 76 | ], 77 | ], 78 | `NullableHeaders { 'cookie': 'name1=value1; name2=value2; name3=value3' }`, 79 | ], 80 | [[undefined], `NullableHeaders { }`], 81 | [[null], `NullableHeaders { }`], 82 | ]; 83 | for (const [input, expected] of cases) { 84 | test(expected, () => { 85 | expect(inspectNullableHeaders(buildHeaders(input))).toEqual(expected); 86 | }); 87 | } 88 | }); 89 | -------------------------------------------------------------------------------- /tests/form.test.ts: -------------------------------------------------------------------------------- 1 | import { multipartFormRequestOptions, createForm } from '@anthropic-ai/sdk/internal/uploads'; 2 | import { toFile } from '@anthropic-ai/sdk/core/uploads'; 3 | 4 | describe('form data validation', () => { 5 | test('valid values do not error', async () => { 6 | await multipartFormRequestOptions( 7 | { 8 | body: { 9 | foo: 'foo', 10 | string: 1, 11 | bool: true, 12 | file: await toFile(Buffer.from('some-content')), 13 | blob: new Blob(['Some content'], { type: 'text/plain' }), 14 | }, 15 | }, 16 | fetch, 17 | ); 18 | }); 19 | 20 | test('null', async () => { 21 | await expect(() => 22 | multipartFormRequestOptions( 23 | { 24 | body: { 25 | null: null, 26 | }, 27 | }, 28 | fetch, 29 | ), 30 | ).rejects.toThrow(TypeError); 31 | }); 32 | 33 | test('undefined is stripped', async () => { 34 | const form = await createForm( 35 | { 36 | foo: undefined, 37 | bar: 'baz', 38 | }, 39 | fetch, 40 | ); 41 | expect(form.has('foo')).toBe(false); 42 | expect(form.get('bar')).toBe('baz'); 43 | }); 44 | 45 | test('nested undefined property is stripped', async () => { 46 | const form = await createForm( 47 | { 48 | bar: { 49 | baz: undefined, 50 | }, 51 | }, 52 | fetch, 53 | ); 54 | expect(Array.from(form.entries())).toEqual([]); 55 | 56 | const form2 = await createForm( 57 | { 58 | bar: { 59 | foo: 'string', 60 | baz: undefined, 61 | }, 62 | }, 63 | fetch, 64 | ); 65 | expect(Array.from(form2.entries())).toEqual([['bar[foo]', 'string']]); 66 | }); 67 | 68 | test('nested undefined array item is stripped', async () => { 69 | const form = await createForm( 70 | { 71 | bar: [undefined, undefined], 72 | }, 73 | fetch, 74 | ); 75 | expect(Array.from(form.entries())).toEqual([]); 76 | 77 | const form2 = await createForm( 78 | { 79 | bar: [undefined, 'foo'], 80 | }, 81 | fetch, 82 | ); 83 | expect(Array.from(form2.entries())).toEqual([['bar[]', 'foo']]); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /tests/lib/TracksToolInput.test.ts: -------------------------------------------------------------------------------- 1 | import { ContentBlock } from '../../src/resources/messages'; 2 | 3 | import { TracksToolInput } from '@anthropic-ai/sdk/lib/MessageStream'; 4 | import { TracksToolInput as BetaTracksToolInput } from '@anthropic-ai/sdk/lib/BetaMessageStream'; 5 | import { BetaContentBlock } from '@anthropic-ai/sdk/resources/beta'; 6 | 7 | /** 8 | * This test ensures that our TracksToolInput type includes all content block types that have an input property. 9 | * If any new content block types with input properties are added, they should be added to the TracksToolInput types. 10 | */ 11 | 12 | describe('TracksToolInput type', () => { 13 | describe('Regular MessageStream', () => { 14 | type ContentBlockWithInput = Extract; 15 | 16 | it('TracksToolInput includes all content block types with input properties', () => { 17 | type Test = ContentBlockWithInput extends TracksToolInput ? true : false; 18 | const test: Test = true; 19 | expect(test).toBe(true); 20 | }); 21 | 22 | it('all TracksToolInput types should have an input property', () => { 23 | type Test2 = TracksToolInput extends ContentBlockWithInput ? true : false; 24 | const test2: Test2 = true; 25 | expect(test2).toBe(true); 26 | }); 27 | }); 28 | 29 | describe('Beta MessageStream', () => { 30 | type BetaContentBlockWithInput = Extract; 31 | 32 | it('TracksToolInput includes all content block types with input properties', () => { 33 | type Test = BetaContentBlockWithInput extends BetaTracksToolInput ? true : false; 34 | const test: Test = true; 35 | expect(test).toBe(true); 36 | }); 37 | 38 | it('all BetaTracksToolInput types should have an input property', () => { 39 | type Test2 = BetaTracksToolInput extends BetaContentBlockWithInput ? true : false; 40 | const test2: Test2 = true; 41 | expect(test2).toBe(true); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /tests/lib/partial-json.test.ts: -------------------------------------------------------------------------------- 1 | import { partialParse } from '@anthropic-ai/sdk/_vendor/partial-json-parser/parser'; 2 | 3 | describe('partialParse', () => { 4 | test('a valid complete JSON string', () => { 5 | expect(partialParse(`{"foo": "bar", "thing": "baz"}`)).toEqual({ foo: 'bar', thing: 'baz' }); 6 | }); 7 | 8 | test('a valid partial JSON string', () => { 9 | expect(partialParse(`{"foo": "bar", "thing": "`)).toEqual({ foo: 'bar' }); 10 | }); 11 | 12 | test('empty JSON object', () => { 13 | expect(partialParse(`{}`)).toEqual({}); 14 | }); 15 | 16 | test('incomplete nested JSON object', () => { 17 | expect(partialParse(`{"foo": {"bar": "baz"}`)).toEqual({ foo: { bar: 'baz' } }); 18 | }); 19 | 20 | test('complete nested JSON object', () => { 21 | expect(partialParse(`{"foo": {"bar": "baz"}}`)).toEqual({ foo: { bar: 'baz' } }); 22 | }); 23 | 24 | test('JSON array with incomplete object', () => { 25 | expect(partialParse(`{"foo": [{"bar": "baz"}`)).toEqual({ foo: [{ bar: 'baz' }] }); 26 | }); 27 | 28 | test('JSON array with complete objects', () => { 29 | expect(partialParse(`{"foo": [{"bar": "baz"}, {"qux": "quux"}]}`)).toEqual({ 30 | foo: [{ bar: 'baz' }, { qux: 'quux' }], 31 | }); 32 | }); 33 | 34 | test('string with escaped characters', () => { 35 | expect(partialParse(`{"foo": "bar\\\"baz"}`)).toEqual({ foo: 'bar"baz' }); 36 | }); 37 | 38 | test('string with incomplete escape sequence', () => { 39 | expect(partialParse(`{"foo": "bar\\`)).toEqual({}); 40 | }); 41 | 42 | test('invalid JSON string gracefully', () => { 43 | expect(partialParse(`{"foo": "bar", "thing": "baz"`)).toEqual({ foo: 'bar', thing: 'baz' }); 44 | }); 45 | 46 | test('JSON string with null value', () => { 47 | expect(partialParse(`{"foo": null, "bar": "baz"}`)).toEqual({ foo: null, bar: 'baz' }); 48 | }); 49 | 50 | test('JSON string with number values', () => { 51 | expect(partialParse(`{"foo": 123, "bar": 45.67}`)).toEqual({ foo: 123, bar: 45.67 }); 52 | }); 53 | 54 | test('JSON string with boolean values', () => { 55 | expect(partialParse(`{"foo": true, "bar": false}`)).toEqual({ foo: true, bar: false }); 56 | }); 57 | 58 | test('JSON string with mixed data types', () => { 59 | expect(partialParse(`{"foo": "bar", "baz": 123, "qux": true, "quux": null}`)).toEqual({ 60 | foo: 'bar', 61 | baz: 123, 62 | qux: true, 63 | quux: null, 64 | }); 65 | }); 66 | 67 | test('JSON string with partial literal tokens', () => { 68 | expect(partialParse(`{"foo": "bar", "baz": nul`)).toEqual({ foo: 'bar' }); 69 | expect(partialParse(`{"foo": "bar", "baz": tr`)).toEqual({ foo: 'bar' }); 70 | expect(partialParse(`{"foo": "bar", "baz": truee`)).toEqual({ foo: 'bar' }); 71 | expect(partialParse(`{"foo": "bar", "baz": fal`)).toEqual({ foo: 'bar' }); 72 | }); 73 | 74 | test('deeply nested JSON objects', () => { 75 | expect(partialParse(`{"a": {"b": {"c": {"d": "e"}}}}`)).toEqual({ a: { b: { c: { d: 'e' } } } }); 76 | }); 77 | 78 | test('deeply nested partial JSON objects', () => { 79 | expect(partialParse(`{"a": {"b": {"c": {"d": "e`)).toEqual({ a: { b: { c: {} } } }); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /tests/responses.test.ts: -------------------------------------------------------------------------------- 1 | import { APIPromise } from '@anthropic-ai/sdk/api-promise'; 2 | import Anthropic from '@anthropic-ai/sdk/index'; 3 | import { compareType } from './utils/typing'; 4 | 5 | const client = new Anthropic({ apiKey: 'dummy' }); 6 | 7 | describe('request id', () => { 8 | test('types', () => { 9 | compareType>, string>(true); 10 | compareType>, number>(true); 11 | compareType>, null>(true); 12 | compareType>, void>(true); 13 | compareType>, Response>(true); 14 | compareType>, Response>(true); 15 | compareType>, { foo: string } & { _request_id?: string | null }>( 16 | true, 17 | ); 18 | compareType>>, Array<{ foo: string }>>(true); 19 | }); 20 | 21 | test('withResponse', async () => { 22 | const client = new Anthropic({ 23 | apiKey: 'dummy', 24 | fetch: async () => 25 | new Response(JSON.stringify({ id: 'bar' }), { 26 | headers: { 'request-id': 'req_xxx', 'content-type': 'application/json' }, 27 | }), 28 | }); 29 | 30 | const { 31 | data: message, 32 | response, 33 | request_id, 34 | } = await client.messages 35 | .create({ messages: [], model: 'claude-3-opus-20240229', max_tokens: 1024 }) 36 | .withResponse(); 37 | 38 | expect(request_id).toBe('req_xxx'); 39 | expect(response.headers.get('request-id')).toBe('req_xxx'); 40 | expect(message.id).toBe('bar'); 41 | expect(JSON.stringify(message)).toBe('{"id":"bar"}'); 42 | }); 43 | 44 | test('object response', async () => { 45 | const client = new Anthropic({ 46 | apiKey: 'dummy', 47 | fetch: async () => 48 | new Response(JSON.stringify({ id: 'bar' }), { 49 | headers: { 'request-id': 'req_xxx', 'content-type': 'application/json' }, 50 | }), 51 | }); 52 | 53 | const rsp = await client.messages.create({ 54 | messages: [], 55 | model: 'claude-3-opus-20240229', 56 | max_tokens: 1024, 57 | }); 58 | expect(rsp.id).toBe('bar'); 59 | expect(rsp._request_id).toBe('req_xxx'); 60 | expect(JSON.stringify(rsp)).toBe('{"id":"bar"}'); 61 | }); 62 | 63 | test('envelope response', async () => { 64 | const promise = new APIPromise<{ data: { foo: string } }>( 65 | client, 66 | (async () => { 67 | return { 68 | response: new Response(JSON.stringify({ data: { foo: 'bar' } }), { 69 | headers: { 'request-id': 'req_xxx', 'content-type': 'application/json' }, 70 | }), 71 | controller: {} as any, 72 | options: {} as any, 73 | requestLogID: 'log_000000', 74 | retryOfRequestLogID: undefined, 75 | startTime: Date.now(), 76 | }; 77 | })(), 78 | )._thenUnwrap((d) => d.data); 79 | 80 | const rsp = await promise; 81 | expect(rsp.foo).toBe('bar'); 82 | expect(rsp._request_id).toBe('req_xxx'); 83 | }); 84 | 85 | test('page response', async () => { 86 | const client = new Anthropic({ 87 | apiKey: 'dummy', 88 | fetch: async () => 89 | new Response(JSON.stringify({ data: [{ foo: 'bar' }] }), { 90 | headers: { 'request-id': 'req_xxx', 'content-type': 'application/json' }, 91 | }), 92 | }); 93 | 94 | const page = await client.beta.messages.batches.list(); 95 | expect(page.data).toMatchObject([{ foo: 'bar' }]); 96 | expect((page as any)._request_id).toBeUndefined(); 97 | }); 98 | 99 | test('array response', async () => { 100 | const promise = new APIPromise>( 101 | client, 102 | (async () => { 103 | return { 104 | response: new Response(JSON.stringify([{ foo: 'bar' }]), { 105 | headers: { 'request-id': 'req_xxx', 'content-type': 'application/json' }, 106 | }), 107 | controller: {} as any, 108 | options: {} as any, 109 | requestLogID: 'log_000000', 110 | retryOfRequestLogID: undefined, 111 | startTime: Date.now(), 112 | }; 113 | })(), 114 | ); 115 | 116 | const rsp = await promise; 117 | expect(rsp.length).toBe(1); 118 | expect(rsp[0]).toMatchObject({ foo: 'bar' }); 119 | expect((rsp as any)._request_id).toBeUndefined(); 120 | }); 121 | 122 | test('string response', async () => { 123 | const promise = new APIPromise( 124 | client, 125 | (async () => { 126 | return { 127 | response: new Response('hello world', { 128 | headers: { 'request-id': 'req_xxx', 'content-type': 'application/text' }, 129 | }), 130 | controller: {} as any, 131 | options: {} as any, 132 | requestLogID: 'log_000000', 133 | retryOfRequestLogID: undefined, 134 | startTime: Date.now(), 135 | }; 136 | })(), 137 | ); 138 | 139 | const result = await promise; 140 | expect(result).toBe('hello world'); 141 | expect((result as any)._request_id).toBeUndefined(); 142 | }); 143 | }); 144 | -------------------------------------------------------------------------------- /tests/stringifyQuery.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { Anthropic } from '@anthropic-ai/sdk'; 4 | 5 | const { stringifyQuery } = Anthropic.prototype as any; 6 | 7 | describe(stringifyQuery, () => { 8 | for (const [input, expected] of [ 9 | [{ a: '1', b: 2, c: true }, 'a=1&b=2&c=true'], 10 | [{ a: null, b: false, c: undefined }, 'a=&b=false'], 11 | [{ 'a/b': 1.28341 }, `${encodeURIComponent('a/b')}=1.28341`], 12 | [ 13 | { 'a/b': 'c/d', 'e=f': 'g&h' }, 14 | `${encodeURIComponent('a/b')}=${encodeURIComponent('c/d')}&${encodeURIComponent( 15 | 'e=f', 16 | )}=${encodeURIComponent('g&h')}`, 17 | ], 18 | ]) { 19 | it(`${JSON.stringify(input)} -> ${expected}`, () => { 20 | expect(stringifyQuery(input)).toEqual(expected); 21 | }); 22 | } 23 | 24 | for (const value of [[], {}, new Date()]) { 25 | it(`${JSON.stringify(value)} -> `, () => { 26 | expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); 27 | }); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /tests/utils/typing.ts: -------------------------------------------------------------------------------- 1 | type Equal = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? true : false; 2 | 3 | export const expectType = (_expression: T): void => { 4 | return; 5 | }; 6 | 7 | export const compareType = (_expression: Equal): void => { 8 | return; 9 | }; 10 | -------------------------------------------------------------------------------- /tsc-multi.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { "extname": ".js", "module": "commonjs", "shareHelpers": "internal/tslib.js" }, 4 | { "extname": ".mjs", "module": "esnext", "shareHelpers": "internal/tslib.mjs" } 5 | ], 6 | "projects": ["tsconfig.build.json"] 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["dist/src"], 4 | "exclude": [], 5 | "compilerOptions": { 6 | "rootDir": "./dist/src", 7 | "paths": { 8 | "@anthropic-ai/sdk/*": ["dist/src/*"], 9 | "@anthropic-ai/sdk": ["dist/src/index.ts"] 10 | }, 11 | "noEmit": false, 12 | "declaration": true, 13 | "declarationMap": true, 14 | "outDir": "dist", 15 | "pretty": true, 16 | "sourceMap": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["dist-deno"], 4 | "exclude": [], 5 | "compilerOptions": { 6 | "rootDir": "./dist-deno", 7 | "lib": ["es2020", "DOM"], 8 | "noEmit": true, 9 | "declaration": true, 10 | "declarationMap": true, 11 | "outDir": "dist-deno", 12 | "pretty": true, 13 | "sourceMap": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.dist-src.json: -------------------------------------------------------------------------------- 1 | { 2 | // this config is included in the published src directory to prevent TS errors 3 | // from appearing when users go to source, and VSCode opens the source .ts file 4 | // via declaration maps 5 | "include": ["index.ts"], 6 | "compilerOptions": { 7 | "target": "ES2015", 8 | "lib": ["DOM", "DOM.Iterable", "ES2018"], 9 | "moduleResolution": "node" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src", "tests", "examples"], 3 | "exclude": [], 4 | "compilerOptions": { 5 | "target": "es2020", 6 | "lib": ["es2020"], 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "esModuleInterop": true, 10 | "baseUrl": "./", 11 | "paths": { 12 | "@anthropic-ai/sdk/*": ["src/*"], 13 | "@anthropic-ai/sdk": ["src/index.ts"] 14 | }, 15 | "noEmit": true, 16 | 17 | "resolveJsonModule": true, 18 | 19 | "forceConsistentCasingInFileNames": true, 20 | 21 | "strict": true, 22 | "noImplicitAny": true, 23 | "strictNullChecks": true, 24 | "strictFunctionTypes": true, 25 | "strictBindCallApply": true, 26 | "strictPropertyInitialization": true, 27 | "noImplicitThis": true, 28 | "noImplicitReturns": true, 29 | "alwaysStrict": true, 30 | "exactOptionalPropertyTypes": true, 31 | "noUncheckedIndexedAccess": true, 32 | "noImplicitOverride": true, 33 | "noPropertyAccessFromIndexSignature": true, 34 | "isolatedModules": false, 35 | 36 | "skipLibCheck": true 37 | } 38 | } 39 | --------------------------------------------------------------------------------