UNPKG

@anthropic-ai/sdk

Version:

The official TypeScript library for the Anthropic API

602 lines 31 kB
"use strict"; var _BetaMessageStream_instances, _BetaMessageStream_currentMessageSnapshot, _BetaMessageStream_params, _BetaMessageStream_connectedPromise, _BetaMessageStream_resolveConnectedPromise, _BetaMessageStream_rejectConnectedPromise, _BetaMessageStream_endPromise, _BetaMessageStream_resolveEndPromise, _BetaMessageStream_rejectEndPromise, _BetaMessageStream_listeners, _BetaMessageStream_ended, _BetaMessageStream_errored, _BetaMessageStream_aborted, _BetaMessageStream_catchingPromiseCreated, _BetaMessageStream_response, _BetaMessageStream_request_id, _BetaMessageStream_logger, _BetaMessageStream_getFinalMessage, _BetaMessageStream_getFinalText, _BetaMessageStream_handleError, _BetaMessageStream_beginRequest, _BetaMessageStream_addStreamEvent, _BetaMessageStream_endRequest, _BetaMessageStream_accumulateMessage; Object.defineProperty(exports, "__esModule", { value: true }); exports.BetaMessageStream = void 0; const tslib_1 = require("../internal/tslib.js"); const parser_1 = require("../_vendor/partial-json-parser/parser.js"); const error_1 = require("../error.js"); const errors_1 = require("../internal/errors.js"); const streaming_1 = require("../streaming.js"); const beta_parser_1 = require("./beta-parser.js"); const JSON_BUF_PROPERTY = '__json_buf'; function tracksToolInput(content) { return content.type === 'tool_use' || content.type === 'server_tool_use' || content.type === 'mcp_tool_use'; } class BetaMessageStream { constructor(params, opts) { _BetaMessageStream_instances.add(this); this.messages = []; this.receivedMessages = []; _BetaMessageStream_currentMessageSnapshot.set(this, void 0); _BetaMessageStream_params.set(this, null); this.controller = new AbortController(); _BetaMessageStream_connectedPromise.set(this, void 0); _BetaMessageStream_resolveConnectedPromise.set(this, () => { }); _BetaMessageStream_rejectConnectedPromise.set(this, () => { }); _BetaMessageStream_endPromise.set(this, void 0); _BetaMessageStream_resolveEndPromise.set(this, () => { }); _BetaMessageStream_rejectEndPromise.set(this, () => { }); _BetaMessageStream_listeners.set(this, {}); _BetaMessageStream_ended.set(this, false); _BetaMessageStream_errored.set(this, false); _BetaMessageStream_aborted.set(this, false); _BetaMessageStream_catchingPromiseCreated.set(this, false); _BetaMessageStream_response.set(this, void 0); _BetaMessageStream_request_id.set(this, void 0); _BetaMessageStream_logger.set(this, void 0); _BetaMessageStream_handleError.set(this, (error) => { tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_errored, true, "f"); if ((0, errors_1.isAbortError)(error)) { error = new error_1.APIUserAbortError(); } if (error instanceof error_1.APIUserAbortError) { tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_aborted, true, "f"); return this._emit('abort', error); } if (error instanceof error_1.AnthropicError) { return this._emit('error', error); } if (error instanceof Error) { const anthropicError = new error_1.AnthropicError(error.message); // @ts-ignore anthropicError.cause = error; return this._emit('error', anthropicError); } return this._emit('error', new error_1.AnthropicError(String(error))); }); tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => { tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_resolveConnectedPromise, resolve, "f"); tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_rejectConnectedPromise, reject, "f"); }), "f"); tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => { tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_resolveEndPromise, resolve, "f"); tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_rejectEndPromise, reject, "f"); }), "f"); // Don't let these promises cause unhandled rejection errors. // we will manually cause an unhandled rejection error later // if the user hasn't registered any error listener or called // any promise-returning method. tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_connectedPromise, "f").catch(() => { }); tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_endPromise, "f").catch(() => { }); tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_params, params, "f"); tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_logger, opts?.logger ?? console, "f"); } get response() { return tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_response, "f"); } get request_id() { return tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_request_id, "f"); } /** * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request, * returned vie the `request-id` header which is useful for debugging requests and resporting * issues to Anthropic. * * This is the same as the `APIPromise.withResponse()` method. * * This method will raise an error if you created the stream using `MessageStream.fromReadableStream` * as no `Response` is available. */ async withResponse() { tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_catchingPromiseCreated, true, "f"); const response = await tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_connectedPromise, "f"); if (!response) { throw new Error('Could not resolve a `Response` object'); } return { data: this, response, request_id: response.headers.get('request-id'), }; } /** * Intended for use on the frontend, consuming a stream produced with * `.toReadableStream()` on the backend. * * Note that messages sent to the model do not appear in `.on('message')` * in this context. */ static fromReadableStream(stream) { const runner = new BetaMessageStream(null); runner._run(() => runner._fromReadableStream(stream)); return runner; } static createMessage(messages, params, options, { logger } = {}) { const runner = new BetaMessageStream(params, { logger }); for (const message of params.messages) { runner._addMessageParam(message); } tslib_1.__classPrivateFieldSet(runner, _BetaMessageStream_params, { ...params, stream: true }, "f"); runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'stream' } })); return runner; } _run(executor) { executor().then(() => { this._emitFinal(); this._emit('end'); }, tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_handleError, "f")); } _addMessageParam(message) { this.messages.push(message); } _addMessage(message, emit = true) { this.receivedMessages.push(message); if (emit) { this._emit('message', message); } } async _createMessage(messages, params, options) { const signal = options?.signal; let abortHandler; if (signal) { if (signal.aborted) this.controller.abort(); abortHandler = this.controller.abort.bind(this.controller); signal.addEventListener('abort', abortHandler); } try { tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_beginRequest).call(this); const { response, data: stream } = await messages .create({ ...params, stream: true }, { ...options, signal: this.controller.signal }) .withResponse(); this._connected(response); for await (const event of stream) { tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_addStreamEvent).call(this, event); } if (stream.controller.signal?.aborted) { throw new error_1.APIUserAbortError(); } tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_endRequest).call(this); } finally { if (signal && abortHandler) { signal.removeEventListener('abort', abortHandler); } } } _connected(response) { if (this.ended) return; tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_response, response, "f"); tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_request_id, response?.headers.get('request-id'), "f"); tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_resolveConnectedPromise, "f").call(this, response); this._emit('connect'); } get ended() { return tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_ended, "f"); } get errored() { return tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_errored, "f"); } get aborted() { return tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_aborted, "f"); } abort() { this.controller.abort(); } /** * Adds the listener function to the end of the listeners array for the event. * No checks are made to see if the listener has already been added. Multiple calls passing * the same combination of event and listener will result in the listener being added, and * called, multiple times. * @returns this MessageStream, so that calls can be chained */ on(event, listener) { const listeners = tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_listeners, "f")[event] || (tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_listeners, "f")[event] = []); listeners.push({ listener }); return this; } /** * Removes the specified listener from the listener array for the event. * off() will remove, at most, one instance of a listener from the listener array. If any single * listener has been added multiple times to the listener array for the specified event, then * off() must be called multiple times to remove each instance. * @returns this MessageStream, so that calls can be chained */ off(event, listener) { const listeners = tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_listeners, "f")[event]; if (!listeners) return this; const index = listeners.findIndex((l) => l.listener === listener); if (index >= 0) listeners.splice(index, 1); return this; } /** * Adds a one-time listener function for the event. The next time the event is triggered, * this listener is removed and then invoked. * @returns this MessageStream, so that calls can be chained */ once(event, listener) { const listeners = tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_listeners, "f")[event] || (tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_listeners, "f")[event] = []); listeners.push({ listener, once: true }); return this; } /** * This is similar to `.once()`, but returns a Promise that resolves the next time * the event is triggered, instead of calling a listener callback. * @returns a Promise that resolves the next time given event is triggered, * or rejects if an error is emitted. (If you request the 'error' event, * returns a promise that resolves with the error). * * Example: * * const message = await stream.emitted('message') // rejects if the stream errors */ emitted(event) { return new Promise((resolve, reject) => { tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_catchingPromiseCreated, true, "f"); if (event !== 'error') this.once('error', reject); this.once(event, resolve); }); } async done() { tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_catchingPromiseCreated, true, "f"); await tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_endPromise, "f"); } get currentMessage() { return tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_currentMessageSnapshot, "f"); } /** * @returns a promise that resolves with the the final assistant Message response, * or rejects if an error occurred or the stream ended prematurely without producing a Message. * If structured outputs were used, this will be a ParsedMessage with a `parsed` field. */ async finalMessage() { await this.done(); return tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_getFinalMessage).call(this); } /** * @returns a promise that resolves with the the final assistant Message's text response, concatenated * together if there are more than one text blocks. * Rejects if an error occurred or the stream ended prematurely without producing a Message. */ async finalText() { await this.done(); return tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_getFinalText).call(this); } _emit(event, ...args) { // make sure we don't emit any MessageStreamEvents after end if (tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_ended, "f")) return; if (event === 'end') { tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_ended, true, "f"); tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_resolveEndPromise, "f").call(this); } const listeners = tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_listeners, "f")[event]; if (listeners) { tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_listeners, "f")[event] = listeners.filter((l) => !l.once); listeners.forEach(({ listener }) => listener(...args)); } if (event === 'abort') { const error = args[0]; if (!tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_catchingPromiseCreated, "f") && !listeners?.length) { Promise.reject(error); } tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_rejectConnectedPromise, "f").call(this, error); tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_rejectEndPromise, "f").call(this, error); this._emit('end'); return; } if (event === 'error') { // NOTE: _emit('error', error) should only be called from #handleError(). const error = args[0]; if (!tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_catchingPromiseCreated, "f") && !listeners?.length) { // Trigger an unhandled rejection if the user hasn't registered any error handlers. // If you are seeing stack traces here, make sure to handle errors via either: // - runner.on('error', () => ...) // - await runner.done() // - await runner.final...() // - etc. Promise.reject(error); } tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_rejectConnectedPromise, "f").call(this, error); tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_rejectEndPromise, "f").call(this, error); this._emit('end'); } } _emitFinal() { const finalMessage = this.receivedMessages.at(-1); if (finalMessage) { this._emit('finalMessage', tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_getFinalMessage).call(this)); } } async _fromReadableStream(readableStream, options) { const signal = options?.signal; let abortHandler; if (signal) { if (signal.aborted) this.controller.abort(); abortHandler = this.controller.abort.bind(this.controller); signal.addEventListener('abort', abortHandler); } try { tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_beginRequest).call(this); this._connected(null); const stream = streaming_1.Stream.fromReadableStream(readableStream, this.controller); for await (const event of stream) { tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_addStreamEvent).call(this, event); } if (stream.controller.signal?.aborted) { throw new error_1.APIUserAbortError(); } tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_endRequest).call(this); } finally { if (signal && abortHandler) { signal.removeEventListener('abort', abortHandler); } } } [(_BetaMessageStream_currentMessageSnapshot = new WeakMap(), _BetaMessageStream_params = new WeakMap(), _BetaMessageStream_connectedPromise = new WeakMap(), _BetaMessageStream_resolveConnectedPromise = new WeakMap(), _BetaMessageStream_rejectConnectedPromise = new WeakMap(), _BetaMessageStream_endPromise = new WeakMap(), _BetaMessageStream_resolveEndPromise = new WeakMap(), _BetaMessageStream_rejectEndPromise = new WeakMap(), _BetaMessageStream_listeners = new WeakMap(), _BetaMessageStream_ended = new WeakMap(), _BetaMessageStream_errored = new WeakMap(), _BetaMessageStream_aborted = new WeakMap(), _BetaMessageStream_catchingPromiseCreated = new WeakMap(), _BetaMessageStream_response = new WeakMap(), _BetaMessageStream_request_id = new WeakMap(), _BetaMessageStream_logger = new WeakMap(), _BetaMessageStream_handleError = new WeakMap(), _BetaMessageStream_instances = new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage() { if (this.receivedMessages.length === 0) { throw new error_1.AnthropicError('stream ended without producing a Message with role=assistant'); } return this.receivedMessages.at(-1); }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText() { if (this.receivedMessages.length === 0) { throw new error_1.AnthropicError('stream ended without producing a Message with role=assistant'); } const textBlocks = this.receivedMessages .at(-1) .content.filter((block) => block.type === 'text') .map((block) => block.text); if (textBlocks.length === 0) { throw new error_1.AnthropicError('stream ended without producing a content block with type=text'); } return textBlocks.join(' '); }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest() { if (this.ended) return; tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_currentMessageSnapshot, undefined, "f"); }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent(event) { if (this.ended) return; const messageSnapshot = tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_instances, "m", _BetaMessageStream_accumulateMessage).call(this, event); this._emit('streamEvent', event, messageSnapshot); switch (event.type) { case 'content_block_delta': { const content = messageSnapshot.content.at(-1); switch (event.delta.type) { case 'text_delta': { if (content.type === 'text') { this._emit('text', event.delta.text, content.text || ''); } break; } case 'citations_delta': { if (content.type === 'text') { this._emit('citation', event.delta.citation, content.citations ?? []); } break; } case 'input_json_delta': { if (tracksToolInput(content) && content.input) { this._emit('inputJson', event.delta.partial_json, content.input); } break; } case 'thinking_delta': { if (content.type === 'thinking') { this._emit('thinking', event.delta.thinking, content.thinking); } break; } case 'signature_delta': { if (content.type === 'thinking') { this._emit('signature', content.signature); } break; } default: checkNever(event.delta); } break; } case 'message_stop': { this._addMessageParam(messageSnapshot); this._addMessage((0, beta_parser_1.maybeParseBetaMessage)(messageSnapshot, tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_params, "f"), { logger: tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_logger, "f") }), true); break; } case 'content_block_stop': { this._emit('contentBlock', messageSnapshot.content.at(-1)); break; } case 'message_start': { tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, "f"); break; } case 'content_block_start': case 'message_delta': break; } }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest() { if (this.ended) { throw new error_1.AnthropicError(`stream has ended, this shouldn't happen`); } const snapshot = tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_currentMessageSnapshot, "f"); if (!snapshot) { throw new error_1.AnthropicError(`request ended without sending any chunks`); } tslib_1.__classPrivateFieldSet(this, _BetaMessageStream_currentMessageSnapshot, undefined, "f"); return (0, beta_parser_1.maybeParseBetaMessage)(snapshot, tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_params, "f"), { logger: tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_logger, "f") }); }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage(event) { let snapshot = tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_currentMessageSnapshot, "f"); if (event.type === 'message_start') { if (snapshot) { throw new error_1.AnthropicError(`Unexpected event order, got ${event.type} before receiving "message_stop"`); } return event.message; } if (!snapshot) { throw new error_1.AnthropicError(`Unexpected event order, got ${event.type} before "message_start"`); } switch (event.type) { case 'message_stop': return snapshot; case 'message_delta': snapshot.container = event.delta.container; snapshot.stop_reason = event.delta.stop_reason; snapshot.stop_sequence = event.delta.stop_sequence; snapshot.usage.output_tokens = event.usage.output_tokens; snapshot.context_management = event.context_management; if (event.usage.input_tokens != null) { snapshot.usage.input_tokens = event.usage.input_tokens; } if (event.usage.cache_creation_input_tokens != null) { snapshot.usage.cache_creation_input_tokens = event.usage.cache_creation_input_tokens; } if (event.usage.cache_read_input_tokens != null) { snapshot.usage.cache_read_input_tokens = event.usage.cache_read_input_tokens; } if (event.usage.server_tool_use != null) { snapshot.usage.server_tool_use = event.usage.server_tool_use; } return snapshot; case 'content_block_start': snapshot.content.push(event.content_block); return snapshot; case 'content_block_delta': { const snapshotContent = snapshot.content.at(event.index); switch (event.delta.type) { case 'text_delta': { if (snapshotContent?.type === 'text') { snapshot.content[event.index] = { ...snapshotContent, text: (snapshotContent.text || '') + event.delta.text, }; } break; } case 'citations_delta': { if (snapshotContent?.type === 'text') { snapshot.content[event.index] = { ...snapshotContent, citations: [...(snapshotContent.citations ?? []), event.delta.citation], }; } break; } case 'input_json_delta': { if (snapshotContent && tracksToolInput(snapshotContent)) { // we need to keep track of the raw JSON string as well so that we can // re-parse it for each delta, for now we just store it as an untyped // non-enumerable property on the snapshot let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || ''; jsonBuf += event.delta.partial_json; const newContent = { ...snapshotContent }; Object.defineProperty(newContent, JSON_BUF_PROPERTY, { value: jsonBuf, enumerable: false, writable: true, }); if (jsonBuf) { try { newContent.input = (0, parser_1.partialParse)(jsonBuf); } catch (err) { const error = new error_1.AnthropicError(`Unable to parse tool parameter JSON from model. Please retry your request or adjust your prompt. Error: ${err}. JSON: ${jsonBuf}`); tslib_1.__classPrivateFieldGet(this, _BetaMessageStream_handleError, "f").call(this, error); } } snapshot.content[event.index] = newContent; } break; } case 'thinking_delta': { if (snapshotContent?.type === 'thinking') { snapshot.content[event.index] = { ...snapshotContent, thinking: snapshotContent.thinking + event.delta.thinking, }; } break; } case 'signature_delta': { if (snapshotContent?.type === 'thinking') { snapshot.content[event.index] = { ...snapshotContent, signature: event.delta.signature, }; } break; } default: checkNever(event.delta); } return snapshot; } case 'content_block_stop': return snapshot; } }, Symbol.asyncIterator)]() { const pushQueue = []; const readQueue = []; let done = false; this.on('streamEvent', (event) => { const reader = readQueue.shift(); if (reader) { reader.resolve(event); } else { pushQueue.push(event); } }); this.on('end', () => { done = true; for (const reader of readQueue) { reader.resolve(undefined); } readQueue.length = 0; }); this.on('abort', (err) => { done = true; for (const reader of readQueue) { reader.reject(err); } readQueue.length = 0; }); this.on('error', (err) => { done = true; for (const reader of readQueue) { reader.reject(err); } readQueue.length = 0; }); return { next: async () => { if (!pushQueue.length) { if (done) { return { value: undefined, done: true }; } return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk) => (chunk ? { value: chunk, done: false } : { value: undefined, done: true })); } const chunk = pushQueue.shift(); return { value: chunk, done: false }; }, return: async () => { this.abort(); return { value: undefined, done: true }; }, }; } toReadableStream() { const stream = new streaming_1.Stream(this[Symbol.asyncIterator].bind(this), this.controller); return stream.toReadableStream(); } } exports.BetaMessageStream = BetaMessageStream; // used to ensure exhaustive case matching without throwing a runtime error function checkNever(x) { } //# sourceMappingURL=BetaMessageStream.js.map