From 22c404766574198fb636dd8537867835d7ef8b3c Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Fri, 2 Feb 2024 20:06:56 +0000 Subject: [PATCH] feat(api): add new usage response fields (#281) --- api.md | 2 + src/resources/beta/beta.ts | 2 + src/resources/beta/index.ts | 2 + src/resources/beta/messages.ts | 67 ++++- src/resources/completions.ts | 21 +- .../api-resources/beta/MessageStream.test.ts | 283 +++++++++--------- 6 files changed, 221 insertions(+), 156 deletions(-) diff --git a/api.md b/api.md index 85491d74..b3685e6e 100644 --- a/api.md +++ b/api.md @@ -22,12 +22,14 @@ Types: - ContentBlockStopEvent - Message - MessageDeltaEvent +- MessageDeltaUsage - MessageParam - MessageStartEvent - MessageStopEvent - MessageStreamEvent - TextBlock - TextDelta +- Usage Methods: diff --git a/src/resources/beta/beta.ts b/src/resources/beta/beta.ts index 0f37525e..8dafcaf3 100644 --- a/src/resources/beta/beta.ts +++ b/src/resources/beta/beta.ts @@ -15,12 +15,14 @@ export namespace Beta { export import ContentBlockStopEvent = MessagesAPI.ContentBlockStopEvent; export import Message = MessagesAPI.Message; export import MessageDeltaEvent = MessagesAPI.MessageDeltaEvent; + export import MessageDeltaUsage = MessagesAPI.MessageDeltaUsage; export import MessageParam = MessagesAPI.MessageParam; export import MessageStartEvent = MessagesAPI.MessageStartEvent; export import MessageStopEvent = MessagesAPI.MessageStopEvent; export import MessageStreamEvent = MessagesAPI.MessageStreamEvent; export import TextBlock = MessagesAPI.TextBlock; export import TextDelta = MessagesAPI.TextDelta; + export import Usage = MessagesAPI.Usage; export import MessageCreateParams = MessagesAPI.MessageCreateParams; export import MessageCreateParamsNonStreaming = MessagesAPI.MessageCreateParamsNonStreaming; export import MessageCreateParamsStreaming = MessagesAPI.MessageCreateParamsStreaming; diff --git a/src/resources/beta/index.ts b/src/resources/beta/index.ts index 1019e682..54305259 100644 --- a/src/resources/beta/index.ts +++ b/src/resources/beta/index.ts @@ -8,12 +8,14 @@ export { ContentBlockStopEvent, Message, MessageDeltaEvent, + MessageDeltaUsage, MessageParam, MessageStartEvent, MessageStopEvent, MessageStreamEvent, TextBlock, TextDelta, + Usage, MessageCreateParams, MessageCreateParamsNonStreaming, MessageCreateParamsStreaming, diff --git a/src/resources/beta/messages.ts b/src/resources/beta/messages.ts index 6401acc1..c759b716 100644 --- a/src/resources/beta/messages.ts +++ b/src/resources/beta/messages.ts @@ -12,7 +12,15 @@ export class Messages extends APIResource { /** * Create a Message. * - * The Messages API is currently in beta. + * Send a structured list of input messages, and the model will generate the next + * message in the conversation. + * + * Messages can be used for either single queries to the model or for multi-turn + * conversations. + * + * The Messages API is currently in beta. During beta, you must send the + * `anthropic-beta: messages-2023-12-15` header in your requests. If you are using + * our client SDKs, this is handled for you automatically. */ create(body: MessageCreateParamsNonStreaming, options?: Core.RequestOptions): APIPromise; create( @@ -156,12 +164,22 @@ export interface Message { stop_sequence: string | null; type: 'message'; + + /** + * Container for the number of tokens used. + */ + usage: Usage; } export interface MessageDeltaEvent { delta: MessageDeltaEvent.Delta; type: 'message_delta'; + + /** + * Container for the number of tokens used. + */ + usage: MessageDeltaUsage; } export namespace MessageDeltaEvent { @@ -172,6 +190,13 @@ export namespace MessageDeltaEvent { } } +export interface MessageDeltaUsage { + /** + * The cumulative number of output tokens which were used. + */ + output_tokens: number; +} + export interface MessageParam { content: string | Array; @@ -208,6 +233,18 @@ export interface TextDelta { type: 'text_delta'; } +export interface Usage { + /** + * The number of input tokens which were used. + */ + input_tokens: number; + + /** + * The number of output tokens which were used. + */ + output_tokens: number; +} + export type MessageCreateParams = MessageCreateParamsNonStreaming | MessageCreateParamsStreaming; export interface MessageCreateParamsBase { @@ -283,6 +320,11 @@ export interface MessageCreateParamsBase { * See our * [guide to prompt design](https://docs.anthropic.com/claude/docs/introduction-to-prompt-design) * for more details on how to best construct prompts. + * + * Note that if you want to include a + * [system prompt](https://docs.anthropic.com/claude/docs/how-to-use-system-prompts), + * you can use the top-level `system` parameter — there is no `"system"` role for + * input messages in the Messages API. */ messages: Array; @@ -321,8 +363,8 @@ export interface MessageCreateParamsBase { /** * Whether to incrementally stream the response using server-sent events. * - * See [streaming](https://docs.anthropic.com/claude/reference/streaming) for - * details. + * See [streaming](https://docs.anthropic.com/claude/reference/messages-streaming) + * for details. */ stream?: boolean; @@ -374,7 +416,7 @@ export namespace MessageCreateParams { * this id to help detect abuse. Do not include any identifying information such as * name, email address, or phone number. */ - user_id?: string; + user_id?: string | null; } export type MessageCreateParamsNonStreaming = MessagesAPI.MessageCreateParamsNonStreaming; @@ -385,8 +427,8 @@ export interface MessageCreateParamsNonStreaming extends MessageCreateParamsBase /** * Whether to incrementally stream the response using server-sent events. * - * See [streaming](https://docs.anthropic.com/claude/reference/streaming) for - * details. + * See [streaming](https://docs.anthropic.com/claude/reference/messages-streaming) + * for details. */ stream?: false; } @@ -395,8 +437,8 @@ export interface MessageCreateParamsStreaming extends MessageCreateParamsBase { /** * Whether to incrementally stream the response using server-sent events. * - * See [streaming](https://docs.anthropic.com/claude/reference/streaming) for - * details. + * See [streaming](https://docs.anthropic.com/claude/reference/messages-streaming) + * for details. */ stream: true; } @@ -474,6 +516,11 @@ export interface MessageStreamParams { * See our * [guide to prompt design](https://docs.anthropic.com/claude/docs/introduction-to-prompt-design) * for more details on how to best construct prompts. + * + * Note that if you want to include a + * [system prompt](https://docs.anthropic.com/claude/docs/how-to-use-system-prompts), + * you can use the top-level `system` parameter — there is no `"system"` role for + * input messages in the Messages API. */ messages: Array; @@ -557,7 +604,7 @@ export namespace MessageStreamParams { * this id to help detect abuse. Do not include any identifying information such as * name, email address, or phone number. */ - user_id?: string; + user_id?: string | null; } } @@ -568,12 +615,14 @@ export namespace Messages { export import ContentBlockStopEvent = MessagesAPI.ContentBlockStopEvent; export import Message = MessagesAPI.Message; export import MessageDeltaEvent = MessagesAPI.MessageDeltaEvent; + export import MessageDeltaUsage = MessagesAPI.MessageDeltaUsage; export import MessageParam = MessagesAPI.MessageParam; export import MessageStartEvent = MessagesAPI.MessageStartEvent; export import MessageStopEvent = MessagesAPI.MessageStopEvent; export import MessageStreamEvent = MessagesAPI.MessageStreamEvent; export import TextBlock = MessagesAPI.TextBlock; export import TextDelta = MessagesAPI.TextDelta; + export import Usage = MessagesAPI.Usage; export import MessageCreateParams = MessagesAPI.MessageCreateParams; export import MessageCreateParamsNonStreaming = MessagesAPI.MessageCreateParamsNonStreaming; export import MessageCreateParamsStreaming = MessagesAPI.MessageCreateParamsStreaming; diff --git a/src/resources/completions.ts b/src/resources/completions.ts index 6a9b5d60..b4d26290 100644 --- a/src/resources/completions.ts +++ b/src/resources/completions.ts @@ -8,7 +8,7 @@ import { Stream } from '@anthropic-ai/sdk/streaming'; export class Completions extends APIResource { /** - * Create a Completion + * Create a Text Completion */ create(body: CompletionCreateParamsNonStreaming, options?: Core.RequestOptions): APIPromise; create( @@ -59,7 +59,7 @@ export interface Completion { * `stop_sequences` parameter, or a stop sequence built into the model * - `"max_tokens"`: we exceeded `max_tokens_to_sample` or the model's maximum */ - stop_reason: string; + stop_reason: string | null; type: 'completion'; } @@ -124,8 +124,9 @@ export interface CompletionCreateParamsBase { /** * Whether to incrementally stream the response using server-sent events. * - * See [streaming](https://docs.anthropic.com/claude/reference/streaming) for - * details. + * See + * [streaming](https://docs.anthropic.com/claude/reference/text-completions-streaming) + * for details. */ stream?: boolean; @@ -168,7 +169,7 @@ export namespace CompletionCreateParams { * this id to help detect abuse. Do not include any identifying information such as * name, email address, or phone number. */ - user_id?: string; + user_id?: string | null; } export type CompletionCreateParamsNonStreaming = CompletionsAPI.CompletionCreateParamsNonStreaming; @@ -179,8 +180,9 @@ export interface CompletionCreateParamsNonStreaming extends CompletionCreatePara /** * Whether to incrementally stream the response using server-sent events. * - * See [streaming](https://docs.anthropic.com/claude/reference/streaming) for - * details. + * See + * [streaming](https://docs.anthropic.com/claude/reference/text-completions-streaming) + * for details. */ stream?: false; } @@ -189,8 +191,9 @@ export interface CompletionCreateParamsStreaming extends CompletionCreateParamsB /** * Whether to incrementally stream the response using server-sent events. * - * See [streaming](https://docs.anthropic.com/claude/reference/streaming) for - * details. + * See + * [streaming](https://docs.anthropic.com/claude/reference/text-completions-streaming) + * for details. */ stream: true; } diff --git a/tests/api-resources/beta/MessageStream.test.ts b/tests/api-resources/beta/MessageStream.test.ts index 1324e803..132242de 100644 --- a/tests/api-resources/beta/MessageStream.test.ts +++ b/tests/api-resources/beta/MessageStream.test.ts @@ -37,6 +37,7 @@ async function* messageIterable(message: Message): AsyncGenerator { model: 'claude-2.1', stop_reason: 'end_turn', stop_sequence: null, + usage: { output_tokens: 6, input_tokens: 10 }, }), ); @@ -152,151 +154,155 @@ describe('MessageStream class', () => { await stream.done(); expect(events.map((event) => event.type)).toMatchInlineSnapshot(` - [ - "connect", - "streamEvent", - "streamEvent", - "streamEvent", - "text", - "streamEvent", - "text", - "streamEvent", - "text", - "streamEvent", - "contentBlock", - "streamEvent", - "streamEvent", - "message", - "finalMessage", - "end", - ] - `); + [ + "connect", + "streamEvent", + "streamEvent", + "streamEvent", + "text", + "streamEvent", + "text", + "streamEvent", + "text", + "streamEvent", + "contentBlock", + "streamEvent", + "streamEvent", + "message", + "finalMessage", + "end", + ] + `); expect(events).toMatchInlineSnapshot(` - [ - { - "args": [], - "type": "connect", - }, - { - "args": [ - "{"type":"message_start","message":{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[],"model":"claude-2.1","stop_reason":null,"stop_sequence":null}}", - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[],"model":"claude-2.1","stop_reason":null,"stop_sequence":null}", - ], - "type": "streamEvent", - }, - { - "args": [ - "{"type":"content_block_start","content_block":{"type":"text","text":""},"index":0}", - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":""}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null}", - ], - "type": "streamEvent", - }, - { - "args": [ - "{"type":"content_block_delta","delta":{"type":"text_delta","text":"Hello"},"index":0}", - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello"}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null}", - ], - "type": "streamEvent", - }, - { - "args": [ - ""Hello"", - ""Hello"", - ], - "type": "text", - }, - { - "args": [ - "{"type":"content_block_delta","delta":{"type":"text_delta","text":" ther"},"index":0}", - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello ther"}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null}", - ], - "type": "streamEvent", - }, - { - "args": [ - "" ther"", - ""Hello ther"", - ], - "type": "text", - }, - { - "args": [ - "{"type":"content_block_delta","delta":{"type":"text_delta","text":"e!"},"index":0}", - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null}", - ], - "type": "streamEvent", - }, - { - "args": [ - ""e!"", - ""Hello there!"", - ], - "type": "text", - }, - { - "args": [ - "{"type":"content_block_stop","index":0}", - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null}", - ], - "type": "streamEvent", - }, - { - "args": [ - "{"type":"text","text":"Hello there!"}", - ], - "type": "contentBlock", - }, - { - "args": [ - "{"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null}}", - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":"end_turn","stop_sequence":null}", - ], - "type": "streamEvent", - }, - { - "args": [ - "{"type":"message_stop"}", - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":"end_turn","stop_sequence":null}", - ], - "type": "streamEvent", - }, - { - "args": [ - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":"end_turn","stop_sequence":null}", - ], - "type": "message", - }, - { - "args": [ - "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":"end_turn","stop_sequence":null}", - ], - "type": "finalMessage", - }, - { - "args": [], - "type": "end", - }, - ] + [ + { + "args": [], + "type": "connect", + }, + { + "args": [ + "{"type":"message_start","message":{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[],"model":"claude-2.1","stop_reason":null,"stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}}", + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[],"model":"claude-2.1","stop_reason":null,"stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "streamEvent", + }, + { + "args": [ + "{"type":"content_block_start","content_block":{"type":"text","text":""},"index":0}", + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":""}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "streamEvent", + }, + { + "args": [ + "{"type":"content_block_delta","delta":{"type":"text_delta","text":"Hello"},"index":0}", + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello"}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "streamEvent", + }, + { + "args": [ + ""Hello"", + ""Hello"", + ], + "type": "text", + }, + { + "args": [ + "{"type":"content_block_delta","delta":{"type":"text_delta","text":" ther"},"index":0}", + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello ther"}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "streamEvent", + }, + { + "args": [ + "" ther"", + ""Hello ther"", + ], + "type": "text", + }, + { + "args": [ + "{"type":"content_block_delta","delta":{"type":"text_delta","text":"e!"},"index":0}", + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "streamEvent", + }, + { + "args": [ + ""e!"", + ""Hello there!"", + ], + "type": "text", + }, + { + "args": [ + "{"type":"content_block_stop","index":0}", + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":null,"stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "streamEvent", + }, + { + "args": [ + "{"type":"text","text":"Hello there!"}", + ], + "type": "contentBlock", + }, + { + "args": [ + "{"type":"message_delta","usage":{"output_tokens":6},"delta":{"stop_reason":"end_turn","stop_sequence":null}}", + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":"end_turn","stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "streamEvent", + }, + { + "args": [ + "{"type":"message_stop"}", + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":"end_turn","stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "streamEvent", + }, + { + "args": [ + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":"end_turn","stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "message", + }, + { + "args": [ + "{"type":"message","id":"msg_01hhptzfxdaeehfxfv070yb6b8","role":"assistant","content":[{"type":"text","text":"Hello there!"}],"model":"claude-2.1","stop_reason":"end_turn","stop_sequence":null,"usage":{"output_tokens":6,"input_tokens":10}}", + ], + "type": "finalMessage", + }, + { + "args": [], + "type": "end", + }, + ] `); expect(await stream.finalText()).toMatchInlineSnapshot(`"Hello there!"`); expect(await stream.finalMessage()).toMatchInlineSnapshot(` - { - "content": [ - { - "text": "Hello there!", - "type": "text", - }, - ], - "id": "msg_01hhptzfxdaeehfxfv070yb6b8", - "model": "claude-2.1", - "role": "assistant", - "stop_reason": "end_turn", - "stop_sequence": null, - "type": "message", - } + { + "content": [ + { + "text": "Hello there!", + "type": "text", + }, + ], + "id": "msg_01hhptzfxdaeehfxfv070yb6b8", + "model": "claude-2.1", + "role": "assistant", + "stop_reason": "end_turn", + "stop_sequence": null, + "type": "message", + "usage": { + "input_tokens": 10, + "output_tokens": 6, + }, + } `); }); @@ -320,6 +326,7 @@ describe('MessageStream class', () => { model: 'claude-2.1', stop_reason: 'end_turn', stop_sequence: null, + usage: { output_tokens: 6, input_tokens: 10 }, }), );