Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,45 @@ jobs:

- name: Run tests
run: ./scripts/test

detect_breaking_changes:
timeout-minutes: 10
name: detect-breaking-changes
runs-on: ${{ github.repository == 'stainless-sdks/anthropic-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: |
(github.event_name == 'push' &&
github.ref != 'refs/heads/next' &&
!startsWith(github.ref, 'refs/heads/release-please--')) ||
github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v6

- name: Fetch history for current branch and target branches
run: |
git fetch origin --filter=blob:none --no-tags --depth=2147483647 ${{ github.sha }}
git fetch origin --filter=blob:none --no-tags next main 2>/dev/null || true
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
run: yarn install

- name: Determine base SHA
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "BASE_SHA=${{ github.event.pull_request.base.sha }}" >> $GITHUB_ENV
else
BASE_SHA=$(git merge-base HEAD origin/next 2>/dev/null || git merge-base HEAD origin/main 2>/dev/null || echo "")
echo "BASE_SHA=$BASE_SHA" >> $GITHUB_ENV
fi
- name: Detect breaking changes
if: env.BASE_SHA != ''
run: |
# Try to check out previous versions of the breaking change detection script. This ensures that
# we still detect breaking changes when entire files and their tests are removed.
git checkout "$BASE_SHA" -- ./scripts/detect-breaking-changes 2>/dev/null || true
./scripts/detect-breaking-changes "$BASE_SHA"
2 changes: 1 addition & 1 deletion .github/workflows/create-releases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@v6

- uses: stainless-api/trigger-release-please@v1
- uses: stainless-api/trigger-release-please@bb6677c5a04578eec1ccfd9e1913b5b78ed64c61 # v1.4.0
id: release
with:
repo: ${{ github.event.repository.full_name }}
Expand Down
36 changes: 0 additions & 36 deletions .github/workflows/detect-breaking-changes.yml

This file was deleted.

4 changes: 2 additions & 2 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
".": "0.91.1",
".": "0.92.0",
"packages/vertex-sdk": "0.16.0",
"packages/bedrock-sdk": "0.29.0",
"packages/bedrock-sdk": "0.29.1",
"packages/foundry-sdk": "0.2.3",
"packages/aws-sdk": "0.2.5"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 91
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic%2Fanthropic-2d9a6272c569b37615ae2f2dc675bf9185bc2ea3dc2ecd32eb46b68f263b9924.yml
openapi_spec_hash: 3716f6d62e618fe9018aee00e7c6dd80
config_hash: 9c24b5adcecc3649a6ec0380bd583cdf
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic/anthropic-4175787f21d24cc3d87dcecce2df2469d10f92eee8e4f00af8a6dd36f7e13ffa.yml
openapi_spec_hash: dc43ed54947d427a084a891b7c4a783a
config_hash: 486e52c2d1bedf2dca1e33dcf8132987
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## 0.92.0 (2026-04-30)

Full Changelog: [sdk-v0.91.1...sdk-v0.92.0](https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.91.1...sdk-v0.92.0)

### Features

* **api:** improve Managed Agents APIs ([ca1bf4a](https://github.com/anthropics/anthropic-sdk-typescript/commit/ca1bf4a9b278fddc7f082b1c4f2b3a3e4e20298d))
* support setting headers via env ([32f67d4](https://github.com/anthropics/anthropic-sdk-typescript/commit/32f67d47952b12bb930c8bbfe87ab2ba2aee1882))


### Bug Fixes

* **bedrock:** throw APIError for error events delivered in chunk frames ([#1021](https://github.com/anthropics/anthropic-sdk-typescript/issues/1021)) ([3ae887b](https://github.com/anthropics/anthropic-sdk-typescript/commit/3ae887b89bde1721c75dc9c9812cb9ac191ffc92))


### Chores

* **format:** run eslint and prettier separately ([7ce257c](https://github.com/anthropics/anthropic-sdk-typescript/commit/7ce257c1b1ad9ff4e1cee19e82851bcb65e0e044))
* **internal:** codegen related update ([f08cc77](https://github.com/anthropics/anthropic-sdk-typescript/commit/f08cc771efd596026f4247ecff418e7ef6a3b38a))

## 0.91.1 (2026-04-24)

Full Changelog: [sdk-v0.91.0...sdk-v0.91.1](https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.91.0...sdk-v0.91.1)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@anthropic-ai/sdk",
"version": "0.91.1",
"version": "0.92.0",
"description": "The official TypeScript library for the Anthropic API",
"author": "Anthropic <support@anthropic.com>",
"types": "dist/index.d.ts",
Expand Down
8 changes: 8 additions & 0 deletions packages/bedrock-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.29.1 (2026-04-30)

Full Changelog: [bedrock-sdk-v0.29.0...bedrock-sdk-v0.29.1](https://github.com/anthropics/anthropic-sdk-typescript/compare/bedrock-sdk-v0.29.0...bedrock-sdk-v0.29.1)

### Bug Fixes

* **bedrock:** throw APIError for error events delivered in chunk frames ([#1021](https://github.com/anthropics/anthropic-sdk-typescript/issues/1021)) ([3ae887b](https://github.com/anthropics/anthropic-sdk-typescript/commit/3ae887b89bde1721c75dc9c9812cb9ac191ffc92))

## 0.29.0 (2026-04-23)

Full Changelog: [bedrock-sdk-v0.28.1...bedrock-sdk-v0.29.0](https://github.com/anthropics/anthropic-sdk-typescript/compare/bedrock-sdk-v0.28.1...bedrock-sdk-v0.29.0)
Expand Down
2 changes: 1 addition & 1 deletion packages/bedrock-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@anthropic-ai/bedrock-sdk",
"version": "0.29.0",
"version": "0.29.1",
"description": "The official TypeScript library for the Anthropic Bedrock API",
"author": "Anthropic <support@anthropic.com>",
"types": "dist/index.d.ts",
Expand Down
10 changes: 8 additions & 2 deletions packages/bedrock-sdk/src/core/streaming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class Stream<Item> extends CoreStream<Item> {
}
}

// Note: this function is copied entirely from the core SDK
// Note: this function is adapted from the core SDK
async function* iterator(): AsyncIterator<Item, any, undefined> {
if (consumed) {
throw new Error('Cannot iterate over a consumed stream, use `.tee()` to split the stream.');
Expand All @@ -73,13 +73,19 @@ export class Stream<Item> extends CoreStream<Item> {
try {
for await (const sse of iterMessages()) {
if (sse.event === 'chunk') {
let parsed;
try {
yield JSON.parse(sse.data);
parsed = JSON.parse(sse.data);
} catch (e) {
logger.error(`Could not parse message into JSON:`, sse.data);
logger.error(`From chunk:`, sse.raw);
throw e;
}
if (parsed && typeof parsed === 'object' && parsed.type === 'error') {
// Anthropic-format error delivered inside a Bedrock chunk frame
throw new APIError(undefined, parsed, undefined, response.headers, parsed.error?.type);
}
yield parsed;
}

if (sse.event === 'error') {
Expand Down
59 changes: 59 additions & 0 deletions packages/bedrock-sdk/tests/streaming.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Readable } from 'node:stream';
import { EventStreamMarshaller } from '@smithy/eventstream-serde-node';
import { APIError } from '@anthropic-ai/sdk';
import { Stream, fromUtf8, toUtf8 } from '../src/core/streaming';

function encodeChunkFrame(payload: unknown): ReadableStream {
const marshaller = new EventStreamMarshaller({ utf8Encoder: toUtf8, utf8Decoder: fromUtf8 });
const inner = JSON.stringify(payload);
const body = fromUtf8(JSON.stringify({ bytes: Buffer.from(inner).toString('base64') }));
const serialized = marshaller.serialize(
(async function* () {
yield {
headers: {
':message-type': { type: 'string', value: 'event' },
':event-type': { type: 'string', value: 'chunk' },
':content-type': { type: 'string', value: 'application/json' },
},
body,
};
})(),
(msg: any) => msg,
);
return Readable.toWeb(Readable.from(serialized)) as ReadableStream;
}

describe('Bedrock Stream.fromSSEResponse', () => {
test('throws APIError when a chunk frame contains an Anthropic error payload', async () => {
const response = new Response(
encodeChunkFrame({ type: 'error', error: { type: 'overloaded_error', message: 'test' } }),
);
const stream = Stream.fromSSEResponse(response, new AbortController());

let caught: unknown;
try {
for await (const _ of stream) {
// consume
}
} catch (e) {
caught = e;
}

expect(caught).toBeInstanceOf(APIError);
expect(String(caught)).not.toContain('Unexpected event order');
expect((caught as APIError).type).toBe('overloaded_error');
});

test('yields normal chunk payloads unchanged', async () => {
const response = new Response(
encodeChunkFrame({ type: 'message_start', message: { id: 'msg_1', role: 'assistant' } }),
);
const stream = Stream.fromSSEResponse<any>(response, new AbortController());

const events: any[] = [];
for await (const ev of stream) events.push(ev);

expect(events).toHaveLength(1);
expect(events[0].type).toBe('message_start');
});
});
2 changes: 1 addition & 1 deletion packages/vertex-sdk/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

"@anthropic-ai/sdk@file:../../dist":
# x-release-please-start-version
version "0.91.1"
version "0.92.0"
# x-release-please-end-version
dependencies:
json-schema-to-ts "^3.1.1"
Expand Down
7 changes: 3 additions & 4 deletions scripts/fast-format
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ if ! [ -z "$ESLINT_FILES" ]; then
fi

echo "==> Running prettier --write"
PRETTIER_FILES="$(grep '\.\([mc]?tsx?\|[mc]?jsx?\|json\)$' "$FILE_LIST" || true)"
if ! [ -z "$PRETTIER_FILES" ]; then
echo "$PRETTIER_FILES" | xargs ./node_modules/.bin/prettier \
--write --cache --cache-strategy metadata --no-error-on-unmatched-pattern
if ! [ -z "$FILE_LIST" ]; then
cat "$FILE_LIST" | xargs ./node_modules/.bin/prettier \
--write --cache --cache-strategy metadata --no-error-on-unmatched-pattern --ignore-unknown
fi
9 changes: 8 additions & 1 deletion scripts/utils/postprocess-files.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ async function postprocess() {

// strip out lib="dom", types="node", and types="react" references; these
// are needed at build time, but would pollute the user's TS environment
const transformed = code.replace(
let transformed = code.replace(
/^ *\/\/\/ *<reference +(lib="dom"|types="(node|react)").*?\n/gm,
// replace with same number of characters to avoid breaking source maps
(match) => ' '.repeat(match.length - 1) + '\n',
);

// TypeScript's declaration emitter collapses /** @ts-ignore */ onto the same
// line as the type declaration, which doesn't work. So we convert to // @ts-ignore
// on its own line to properly suppresses errors.
if (file.endsWith('.d.ts') || file.endsWith('.d.mts') || file.endsWith('.d.cts')) {
transformed = transformed.replace(/\/\*\* @ts-ignore\b[^*]*\*\/ /gm, '// @ts-ignore\n');
}

if (transformed !== code) {
console.error(`wrote ${path.relative(process.cwd(), file)}`);
await fs.promises.writeFile(file, transformed, 'utf8');
Expand Down
12 changes: 12 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,18 @@ export class BaseAnthropic {
this.fetch = options.fetch ?? Shims.getDefaultFetch();
this.#encoder = Opts.FallbackEncoder;

const customHeadersEnv = readEnv('ANTHROPIC_CUSTOM_HEADERS');
if (customHeadersEnv) {
const parsed: Record<string, string> = {};
for (const line of customHeadersEnv.split('\n')) {
const colon = line.indexOf(':');
if (colon >= 0) {
parsed[line.substring(0, colon).trim()] = line.substring(colon + 1).trim();
}
}
options.defaultHeaders = { ...parsed, ...options.defaultHeaders };
}

this._options = options;

this.apiKey = typeof apiKey === 'string' ? apiKey : null;
Expand Down
2 changes: 1 addition & 1 deletion src/resources/beta/environments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export interface BetaCloudConfigParams {
}

/**
* Unified Environment resource for both cloud and BYOC environments.
* Unified Environment resource for both cloud and self-hosted environments.
*/
export interface BetaEnvironment {
/**
Expand Down
1 change: 1 addition & 0 deletions src/resources/beta/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export {
type BetaInputJSONDelta,
type BetaInputTokensClearAtLeast,
type BetaInputTokensTrigger,
type BetaIterationsUsage,
type BetaJSONOutputFormat,
type BetaMCPToolConfig,
type BetaMCPToolDefaultConfig,
Expand Down
Loading
Loading