diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index b9110ed5..28303487 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -42,4 +42,3 @@ jobs: bash ./bin/publish-npm env: NPM_TOKEN: ${{ secrets.ANTHROPIC_NPM_TOKEN || secrets.NPM_TOKEN }} - diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 78458f5c..c80d8dba 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -21,4 +21,3 @@ jobs: env: STAINLESS_API_KEY: ${{ secrets.STAINLESS_API_KEY }} NPM_TOKEN: ${{ secrets.ANTHROPIC_NPM_TOKEN || secrets.NPM_TOKEN }} - diff --git a/bin/cli b/bin/cli index 121c38be..00d7c372 100755 --- a/bin/cli +++ b/bin/cli @@ -4,19 +4,26 @@ const { spawnSync } = require('child_process'); const commands = { migrate: { - description: 'Run migrations to update your code using @anthropic-ai/sdk@0.41 to be compatible with @anthropic-ai/sdk@0.50', + description: + 'Run migrations to update your code using @anthropic-ai/sdk@0.41 to be compatible with @anthropic-ai/sdk@0.50', fn: () => { const result = spawnSync( 'npx', - ['-y', 'https://github.com/stainless-api/migrate-ts/releases/download/0.0.2/stainless-api-migrate-0.0.2-6.tgz', '--migrationConfig', require.resolve('./migration-config.json'), ...process.argv.slice(3)], + [ + '-y', + 'https://github.com/stainless-api/migrate-ts/releases/download/0.0.2/stainless-api-migrate-0.0.2-6.tgz', + '--migrationConfig', + require.resolve('./migration-config.json'), + ...process.argv.slice(3), + ], { stdio: 'inherit' }, ); if (result.status !== 0) { process.exit(result.status); } - } - } -} + }, + }, +}; function exitWithHelp() { console.log(`Usage: anthropic-ai-sdk `); diff --git a/examples/structured-output.ts b/examples/structured-output.ts new file mode 100755 index 00000000..90956de9 --- /dev/null +++ b/examples/structured-output.ts @@ -0,0 +1,124 @@ +#!/usr/bin/env -S npm run tsn -T + +import Anthropic from '@anthropic-ai/sdk'; + +const client = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY + +async function main() { + console.log('Structured Output Examples'); + console.log('=========================='); + console.log(); + + // Non-streaming example + console.log('Non-streaming structured output:'); + console.log('--------------------------------'); + + const message = await client.messages.create({ + model: 'claude-sonnet-4-5-20250929', + max_tokens: 1024, + messages: [ + { + role: 'user', + content: 'What are the ingredients for a vegetarian lasagna recipe for 4 people?', + }, + ], + tools: [ + { + name: 'json', + description: 'Respond with a JSON object', + input_schema: { + type: 'object', + properties: { + ingredients: { + type: 'array', + items: { type: 'string' }, + }, + }, + required: ['ingredients'], + additionalProperties: false, + }, + }, + ], + // Force the model to use the json tool - this is the key to structured output + tool_choice: { type: 'tool', name: 'json' }, + }); + + // Extract the structured output from the tool_use block + const toolUseBlock = message.content.find( + (block): block is Anthropic.ToolUseBlock => block.type === 'tool_use', + ); + + if (toolUseBlock && toolUseBlock.name === 'json') { + console.log('\nStructured output:'); + console.dir(toolUseBlock.input, { depth: 4 }); + } + + console.log(); + console.log(); + + // Streaming example + console.log('Streaming structured output:'); + console.log('---------------------------'); + + const stream = client.messages + .stream({ + model: 'claude-sonnet-4-5-20250929', + max_tokens: 1024, + messages: [ + { + role: 'user', + content: 'List 5 famous landmarks in Paris with their construction years.', + }, + ], + tools: [ + { + name: 'json', + description: 'Respond with a JSON object', + input_schema: { + type: 'object', + properties: { + landmarks: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + year: { type: 'number' }, + }, + required: ['name', 'year'], + }, + }, + }, + required: ['landmarks'], + additionalProperties: false, + }, + }, + ], + // Force the model to use the json tool + tool_choice: { type: 'tool', name: 'json' }, + }) + // When a JSON content block delta is encountered this + // event will be fired with the delta and the currently accumulated object + .on('inputJson', (delta, snapshot) => { + console.log('Delta:', delta); + console.log('Current snapshot:', snapshot); + console.log(); + }); + + await stream.done(); + + const finalMessage = await stream.finalMessage(); + const streamingToolBlock = finalMessage.content.find( + (block): block is Anthropic.ToolUseBlock => block.type === 'tool_use', + ); + + if (streamingToolBlock && streamingToolBlock.name === 'json') { + console.log('\nFinal structured output:'); + console.dir(streamingToolBlock.input, { depth: 4 }); + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +});