Skip to content
Closed
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
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ CHANGELOG.md

# don't format tsc output, will break source maps
/dist
/packages/*/dist
13 changes: 6 additions & 7 deletions packages/bedrock-sdk/build
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,16 @@ node scripts/postprocess-dist-package-json.cjs

# build to .js/.mjs/.d.ts files
npm exec tsc-multi
# we need to add exports = module.exports = Anthropic TypeScript to index.js;
# No way to get that from index.ts because it would cause compile errors
# we need to patch index.js so that `new module.exports()` works for cjs backwards
# compat. No way to get that from index.ts because it would cause compile errors
# when building .mjs
DIST_PATH=./dist node ../../scripts/utils/fix-index-exports.cjs

# with "moduleResolution": "nodenext", if ESM resolves to index.d.ts,
# it'll have TS errors on the default import. But if it resolves to
# index.d.mts the default import will work (even though both files have
# the same export default statement)
cp dist/index.d.ts dist/index.d.mts
cp tsconfig.dist-src.json dist/src/tsconfig.json
cp src/internal/shim-types.d.ts dist/internal/shim-types.d.ts
cp src/internal/shim-types.d.ts dist/internal/shim-types.d.mts
mkdir -p dist/internal/shims
cp src/internal/shims/*.{mjs,js,d.ts,d.mts} dist/internal/shims

DIST_PATH=./dist PKG_IMPORT_PATH=@anthropic-ai/bedrock-sdk/ node ../../scripts/utils/postprocess-files.cjs

Expand Down
3 changes: 2 additions & 1 deletion packages/bedrock-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@smithy/util-base64": "^2.0.0"
},
"devDependencies": {
"@types/node": "^20.17.6",
"@types/jest": "^29.4.0",
"@typescript-eslint/eslint-plugin": "^6.7.0",
"@typescript-eslint/parser": "^6.7.0",
Expand All @@ -46,7 +47,7 @@
"ts-jest": "^29.1.0",
"ts-morph": "^19.0.0",
"ts-node": "^10.5.0",
"tsc-multi": "^1.1.0",
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.3/tsc-multi.tgz",
"tsconfig-paths": "^4.0.0",
"typescript": "^4.8.2"
},
Expand Down
81 changes: 34 additions & 47 deletions packages/bedrock-sdk/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import * as Core from '@anthropic-ai/sdk/core';
import { BaseAnthropic, ClientOptions as CoreClientOptions } from '@anthropic-ai/sdk/client';
import * as Resources from '@anthropic-ai/sdk/resources/index';
import * as API from '@anthropic-ai/sdk/index';
import { getAuthHeaders } from './auth';
import { Stream } from './streaming';
import { getAuthHeaders } from './core/auth';
import { Stream } from './core/streaming';
import { readEnv } from './internal/utils/env';
import { FinalRequestOptions } from './internal/request-options';
import { isObj } from './internal/utils/values';
import { buildHeaders, type HeadersLike } from './internal/headers';
import { FinalizedRequestInit } from './internal/types';
import type { Fetch } from './internal/builtin-types';
import type { MergedRequestInit } from './internal/types';

export { BaseAnthropic } from '@anthropic-ai/sdk/client';

const DEFAULT_VERSION = 'bedrock-2023-05-31';
const MODEL_ENDPOINTS = new Set<string>(['/v1/complete', '/v1/messages', '/v1/messages?beta=true']);

export type ClientOptions = Omit<API.ClientOptions, 'apiKey' | 'authToken'> & {
export type ClientOptions = Omit<CoreClientOptions, 'apiKey' | 'authToken'> & {
awsSecretKey?: string | null | undefined;
awsAccessKey?: string | null | undefined;

Expand All @@ -19,14 +27,12 @@ export type ClientOptions = Omit<API.ClientOptions, 'apiKey' | 'authToken'> & {
};

/** API Client for interfacing with the Anthropic Bedrock API. */
export class AnthropicBedrock extends Core.APIClient {
export class AnthropicBedrock extends BaseAnthropic {
awsSecretKey: string | null;
awsAccessKey: string | null;
awsRegion: string;
awsSessionToken: string | null;

private _options: ClientOptions;

/**
* API Client for interfacing with the Anthropic Bedrock API.
*
Expand All @@ -36,37 +42,25 @@ export class AnthropicBedrock extends Core.APIClient {
* @param {string | null | undefined} [opts.awsSessionToken]
* @param {string} [opts.baseURL=process.env['ANTHROPIC_BEDROCK_BASE_URL'] ?? https://bedrock-runtime.${this.awsRegion}.amazonaws.com] - Override the default base URL for the API.
* @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
* @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.
* @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
* @param {MergedRequestInit} [opts.fetchOptions] - Additional `RequestInit` options to be passed to `fetch` calls.
* @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
* @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
* @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.
* @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.
* @param {HeadersLike} opts.defaultHeaders - Default headers to include with every request to the API.
* @param {Record<string, string | undefined>} opts.defaultQuery - Default query parameters to include with every request to the API.
* @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.
*/
constructor({
baseURL = Core.readEnv('ANTHROPIC_BEDROCK_BASE_URL'),
awsRegion = readEnv('AWS_REGION') ?? 'us-east-1',
baseURL = readEnv('ANTHROPIC_BEDROCK_BASE_URL') ?? `https://bedrock-runtime.${awsRegion}.amazonaws.com`,
awsSecretKey = null,
awsAccessKey = null,
awsRegion = Core.readEnv('AWS_REGION') ?? 'us-east-1',
awsSessionToken = null,
...opts
}: ClientOptions = {}) {
const options: ClientOptions = {
awsSecretKey,
awsAccessKey,
awsRegion,
awsSessionToken,
...opts,
baseURL: baseURL || `https://bedrock-runtime.${awsRegion}.amazonaws.com`,
};

super({
baseURL: options.baseURL!,
timeout: options.timeout ?? 600000 /* 10 minutes */,
httpAgent: options.httpAgent,
maxRetries: options.maxRetries,
fetch: options.fetch,
baseURL,
...opts,
});
this._options = options;

this.awsSecretKey = awsSecretKey;
this.awsAccessKey = awsAccessKey;
Expand All @@ -78,20 +72,13 @@ export class AnthropicBedrock extends Core.APIClient {
completions: Resources.Completions = new Resources.Completions(this);
beta: BetaResource = makeBetaResource(this);

protected override defaultQuery(): Core.DefaultQuery | undefined {
return this._options.defaultQuery;
}

protected override defaultHeaders(opts: Core.FinalRequestOptions): Core.Headers {
return {
...super.defaultHeaders(opts),
...this._options.defaultHeaders,
};
protected override validateHeaders() {
// auth validation is handled in prepareRequest since it needs to be async
}

protected override async prepareRequest(
request: RequestInit,
{ url, options }: { url: string; options: Core.FinalRequestOptions },
request: FinalizedRequestInit,
{ url, options }: { url: string; options: FinalRequestOptions },
): Promise<void> {
const regionName = this.awsRegion;
if (!regionName) {
Expand All @@ -107,37 +94,37 @@ export class AnthropicBedrock extends Core.APIClient {
awsSecretKey: this.awsSecretKey,
awsSessionToken: this.awsSessionToken,
});
request.headers = { ...request.headers, ...headers };
request.headers = buildHeaders([headers, request.headers]).values;
}

override buildRequest(options: Core.FinalRequestOptions<unknown>): {
req: RequestInit;
override buildRequest(options: FinalRequestOptions): {
req: FinalizedRequestInit;
url: string;
timeout: number;
} {
options.__streamClass = Stream;

if (Core.isObj(options.body)) {
if (isObj(options.body)) {
// create a shallow copy of the request body so that code that mutates it later
// doesn't mutate the original user-provided object
options.body = { ...options.body };
}

if (Core.isObj(options.body)) {
if (isObj(options.body)) {
if (!options.body['anthropic_version']) {
options.body['anthropic_version'] = DEFAULT_VERSION;
}

if (options.headers && !options.body['anthropic_beta']) {
const betas = Core.getHeader(options.headers, 'anthropic-beta');
const betas = buildHeaders([options.headers]).values.get('anthropic-beta');
if (betas != null) {
options.body['anthropic_beta'] = betas.split(',');
}
}
}

if (MODEL_ENDPOINTS.has(options.path) && options.method === 'post') {
if (!Core.isObj(options.body)) {
if (!isObj(options.body)) {
throw new Error('Expected request body to be an object for post /v1/messages');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { SignatureV4 } from '@smithy/signature-v4';
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
import { HttpRequest } from '@smithy/protocol-http';
import { Sha256 } from '@aws-crypto/sha256-js';
import type { RequestInit } from '@anthropic-ai/sdk/_shims/index';

type AuthProps = {
url: string;
Expand Down
1 change: 1 addition & 0 deletions packages/bedrock-sdk/src/core/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '@anthropic-ai/sdk/core/error';
1 change: 1 addition & 0 deletions packages/bedrock-sdk/src/core/pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '@anthropic-ai/sdk/core/pagination';
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ import { EventStreamMarshaller } from '@smithy/eventstream-serde-node';
import { fromBase64, toBase64 } from '@smithy/util-base64';
import { streamCollector } from '@smithy/fetch-http-handler';
import { EventStreamSerdeContext, SerdeContext } from '@smithy/types';
import {
Stream as CoreStream,
readableStreamAsyncIterable,
ServerSentEvent,
} from '@anthropic-ai/sdk/streaming';
import { Stream as CoreStream, ServerSentEvent } from '@anthropic-ai/sdk/streaming';
import { AnthropicError } from '@anthropic-ai/sdk/error';
import { APIError } from '@anthropic-ai/sdk';
import { createResponseHeaders, safeJSON } from '@anthropic-ai/sdk/core';
import { de_ResponseStream } from './AWS_restJson1';
import { de_ResponseStream } from '../AWS_restJson1';
import { ReadableStreamToAsyncIterable } from '../internal/shims';
import { safeJSON } from '../internal/utils/values';

type Bytes = string | ArrayBuffer | Uint8Array | Buffer | null | undefined;

Expand Down Expand Up @@ -42,7 +39,7 @@ export class Stream<Item> extends CoreStream<Item> {
throw new AnthropicError(`Attempted to iterate over a response with no body`);
}

const responseBodyIter = readableStreamAsyncIterable<Bytes>(response.body);
const responseBodyIter = ReadableStreamToAsyncIterable<Bytes>(response.body);
const eventStream = de_ResponseStream(responseBodyIter, getMinimalSerdeContext());
for await (const event of eventStream) {
if (event.chunk && event.chunk.bytes) {
Expand Down Expand Up @@ -84,7 +81,7 @@ export class Stream<Item> extends CoreStream<Item> {
const errJSON = safeJSON(errText);
const errMessage = errJSON ? undefined : errText;

throw APIError.generate(undefined, errJSON, errMessage, createResponseHeaders(response.headers));
throw APIError.generate(undefined, errJSON, errMessage, response.headers);
}
}
done = true;
Expand Down
6 changes: 2 additions & 4 deletions packages/bedrock-sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
import { AnthropicBedrock } from './client';

export default AnthropicBedrock;
export { AnthropicBedrock };
export * from './client';
export { AnthropicBedrock as default } from './client';
1 change: 1 addition & 0 deletions packages/bedrock-sdk/src/internal
2 changes: 1 addition & 1 deletion packages/bedrock-sdk/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "./tsconfig.json",
"include": ["dist/src"],
"exclude": [],
"exclude": ["dist/src/internal/detect-platform.ts"],
"compilerOptions": {
"rootDir": "./dist/src",
"paths": {
Expand Down
4 changes: 2 additions & 2 deletions packages/bedrock-sdk/tsconfig.dist-src.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
// via declaration maps
"include": ["index.ts"],
"compilerOptions": {
"target": "es2015",
"lib": ["DOM"],
"target": "ES2015",
"lib": ["DOM", "DOM.Iterable", "ES2018"],
"moduleResolution": "node"
}
}
2 changes: 1 addition & 1 deletion packages/bedrock-sdk/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"include": ["src", "tests", "examples"],
"exclude": [],
"exclude": ["dist/src/internal/detect-platform.ts"],
"compilerOptions": {
"target": "es2020",
"lib": ["es2020"],
Expand Down
Loading