diff --git a/js/package.json b/js/package.json index dc4df56dc7..129c5ee9d9 100644 --- a/js/package.json +++ b/js/package.json @@ -31,7 +31,10 @@ }, "pnpm": { "overrides": { - "cross-spawn": "^7.0.5" + "cross-spawn": "^7.0.5", + "@genkit-ai/vertexai>@anthropic-ai/sdk": "^0.24.3", + "@anthropic-ai/vertex-sdk>@anthropic-ai/sdk": "^0.24.3", + "@genkit-ai/anthropic>@anthropic-ai/sdk": "^0.71.2" } }, "packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402" diff --git a/js/plugins/anthropic/package.json b/js/plugins/anthropic/package.json index 5b3e19be1f..7bafa4b182 100644 --- a/js/plugins/anthropic/package.json +++ b/js/plugins/anthropic/package.json @@ -29,7 +29,7 @@ "genkit": "workspace:^" }, "dependencies": { - "@anthropic-ai/sdk": "^0.68.0" + "@anthropic-ai/sdk": "^0.71.2" }, "devDependencies": { "@types/node": "^20.11.16", @@ -64,6 +64,7 @@ "build": "npm-run-all build:clean check compile", "build:watch": "tsup-node --watch", "test": "tsx --test tests/*_test.ts", + "test:live": "tsx --test tests/live_test.ts", "test:file": "tsx --test", "test:live": "tsx --test tests/live_test.ts", "test:coverage": "check-node-version --node '>=22' && tsx --test --experimental-test-coverage --test-coverage-include='src/**/*.ts' ./tests/**/*_test.ts" diff --git a/js/plugins/anthropic/src/models.ts b/js/plugins/anthropic/src/models.ts index 98767af40c..3b7f872179 100644 --- a/js/plugins/anthropic/src/models.ts +++ b/js/plugins/anthropic/src/models.ts @@ -91,19 +91,59 @@ export const KNOWN_CLAUDE_MODELS: Record< 'claude-opus-4': commonRef('claude-opus-4', AnthropicThinkingConfigSchema), 'claude-sonnet-4-5': commonRef( 'claude-sonnet-4-5', - AnthropicThinkingConfigSchema + AnthropicThinkingConfigSchema, + { + supports: { + multiturn: true, + tools: true, + media: true, + systemRole: true, + output: ['text', 'json'], + constrained: 'all', + }, + } ), 'claude-haiku-4-5': commonRef( 'claude-haiku-4-5', - AnthropicThinkingConfigSchema + AnthropicThinkingConfigSchema, + { + supports: { + multiturn: true, + tools: true, + media: true, + systemRole: true, + output: ['text', 'json'], + constrained: 'all', + }, + } ), 'claude-opus-4-5': commonRef( 'claude-opus-4-5', - AnthropicThinkingConfigSchema + AnthropicThinkingConfigSchema, + { + supports: { + multiturn: true, + tools: true, + media: true, + systemRole: true, + output: ['text', 'json'], + constrained: 'all', + }, + } ), 'claude-opus-4-1': commonRef( 'claude-opus-4-1', - AnthropicThinkingConfigSchema + AnthropicThinkingConfigSchema, + { + supports: { + multiturn: true, + tools: true, + media: true, + systemRole: true, + output: ['text', 'json'], + constrained: 'all', + }, + } ), }; @@ -232,9 +272,11 @@ export function claudeModel( defaultApiVersion: apiVersion, } = params; // Use supported model ref if available, otherwise create generic model ref - const modelRef = KNOWN_CLAUDE_MODELS[name]; - const modelInfo = modelRef ? modelRef.info : GENERIC_CLAUDE_MODEL_INFO; - const configSchema = modelRef?.configSchema ?? AnthropicConfigSchema; + const knownModelRef = KNOWN_CLAUDE_MODELS[name]; + let modelInfo = knownModelRef + ? knownModelRef.info + : GENERIC_CLAUDE_MODEL_INFO; + const configSchema = knownModelRef?.configSchema ?? AnthropicConfigSchema; return model< AnthropicBaseConfigSchemaType | AnthropicThinkingConfigSchemaType diff --git a/js/plugins/anthropic/src/runner/beta.ts b/js/plugins/anthropic/src/runner/beta.ts index 6a71fa71d5..bb4f86b125 100644 --- a/js/plugins/anthropic/src/runner/beta.ts +++ b/js/plugins/anthropic/src/runner/beta.ts @@ -66,6 +66,57 @@ const BETA_UNSUPPORTED_SERVER_TOOL_BLOCK_TYPES = new Set([ 'container_upload', ]); +const BETA_APIS = [ + // 'message-batches-2024-09-24', + // 'prompt-caching-2024-07-31', + // 'computer-use-2025-01-24', + // 'pdfs-2024-09-25', + // 'token-counting-2024-11-01', + // 'token-efficient-tools-2025-02-19', + // 'output-128k-2025-02-19', + // 'files-api-2025-04-14', + // 'mcp-client-2025-04-04', + // 'dev-full-thinking-2025-05-14', + // 'interleaved-thinking-2025-05-14', + // 'code-execution-2025-05-22', + // 'extended-cache-ttl-2025-04-11', + // 'context-1m-2025-08-07', + // 'context-management-2025-06-27', + // 'model-context-window-exceeded-2025-08-26', + // 'skills-2025-10-02', + // 'effort-param-2025-11-24', + // 'advanced-tool-use-2025-11-20', + 'structured-outputs-2025-11-13', +]; + +/** + * Transforms a JSON schema to be compatible with Anthropic's structured output requirements. + * Anthropic requires `additionalProperties: false` on all object types. + * @see https://docs.anthropic.com/en/docs/build-with-claude/structured-outputs#json-schema-limitations + */ +function toAnthropicSchema( + schema: Record +): Record { + const out = structuredClone(schema); + + // Remove $schema if present + delete out.$schema; + + // Add additionalProperties: false to objects + if (out.type === 'object') { + out.additionalProperties = false; + } + + // Recursively process nested objects + for (const key in out) { + if (typeof out[key] === 'object' && out[key] !== null) { + out[key] = toAnthropicSchema(out[key] as Record); + } + } + + return out; +} + const unsupportedServerToolError = (blockType: string): string => `Anthropic beta runner does not yet support server-managed tool block '${blockType}'. Please retry against the stable API or wait for dedicated support.`; @@ -254,6 +305,7 @@ export class BetaRunner extends BaseRunner { max_tokens: request.config?.maxOutputTokens ?? this.DEFAULT_MAX_OUTPUT_TOKENS, messages, + betas: BETA_APIS, }; if (betaSystem !== undefined) body.system = betaSystem; @@ -281,10 +333,12 @@ export class BetaRunner extends BaseRunner { body.thinking = thinkingConfig as BetaMessageCreateParams['thinking']; } - if (request.output?.format && request.output.format !== 'text') { - throw new Error( - `Only text output format is supported for Claude models currently` - ); + // Apply structured output when model supports it and constrained output is requested + if (this.isStructuredOutputEnabled(request)) { + body.output_format = { + type: 'json_schema', + schema: toAnthropicSchema(request.output!.schema!), + }; } return body; @@ -322,6 +376,7 @@ export class BetaRunner extends BaseRunner { request.config?.maxOutputTokens ?? this.DEFAULT_MAX_OUTPUT_TOKENS, messages, stream: true, + betas: BETA_APIS, }; if (betaSystem !== undefined) body.system = betaSystem; @@ -349,12 +404,13 @@ export class BetaRunner extends BaseRunner { body.thinking = thinkingConfig as BetaMessageCreateParams['thinking']; } - if (request.output?.format && request.output.format !== 'text') { - throw new Error( - `Only text output format is supported for Claude models currently` - ); + // Apply structured output when model supports it and constrained output is requested + if (this.isStructuredOutputEnabled(request)) { + body.output_format = { + type: 'json_schema', + schema: toAnthropicSchema(request.output!.schema!), + }; } - return body; } @@ -491,4 +547,14 @@ export class BetaRunner extends BaseRunner { return 'other'; } } + + private isStructuredOutputEnabled( + request: GenerateRequest + ): boolean { + return !!( + request.output?.schema && + request.output.constrained && + request.output.format === 'json' + ); + } } diff --git a/js/plugins/anthropic/tests/live_test.ts b/js/plugins/anthropic/tests/live_test.ts index f008157afe..0c370196dd 100644 --- a/js/plugins/anthropic/tests/live_test.ts +++ b/js/plugins/anthropic/tests/live_test.ts @@ -22,7 +22,7 @@ */ import * as assert from 'assert'; -import { genkit } from 'genkit'; +import { genkit, z } from 'genkit'; import { describe, it } from 'node:test'; import { anthropic } from '../src/index.js'; @@ -80,4 +80,50 @@ describe('Live Anthropic API Tests', { skip: !API_KEY }, () => { assert.ok(result.text.toLowerCase().includes('hello')); }); + + it('should return structured output matching the schema', async () => { + const ai = genkit({ + plugins: [anthropic({ apiKey: API_KEY, apiVersion: 'beta' })], + }); + + const schema = z.object({ + name: z.string(), + age: z.number(), + city: z.string(), + isStudent: z.boolean(), + isEmployee: z.boolean(), + isRetired: z.boolean(), + isUnemployed: z.boolean(), + isDisabled: z.boolean(), + }); + + const result = await ai.generate({ + model: 'anthropic/claude-sonnet-4-5', + prompt: + 'Generate a fictional person with name "Alice", age 30, and city "New York". Return only the JSON.', + output: { schema, format: 'json', constrained: true }, + }); + + const parsed = result.output; + assert.ok(parsed, 'Should have parsed output'); + assert.deepStrictEqual( + { name: parsed.name, age: parsed.age, city: parsed.city }, + { name: 'Alice', age: 30, city: 'New York' } + ); + + // Check that boolean fields are present and are actually booleans + for (const key of [ + 'isStudent', + 'isEmployee', + 'isRetired', + 'isUnemployed', + 'isDisabled', + ]) { + assert.strictEqual( + typeof parsed[key], + 'boolean', + `Field ${key} should be a boolean but got: ${typeof parsed[key]}` + ); + } + }); }); diff --git a/js/plugins/anthropic/tests/mocks/anthropic-client.ts b/js/plugins/anthropic/tests/mocks/anthropic-client.ts index 321df8f24f..35742c76c2 100644 --- a/js/plugins/anthropic/tests/mocks/anthropic-client.ts +++ b/js/plugins/anthropic/tests/mocks/anthropic-client.ts @@ -379,7 +379,7 @@ function toBetaMessage(message: Message): BetaMessage { server_tool_use: message.usage.server_tool_use as any, service_tier: message.usage.service_tier, }, - }; + } as BetaMessage; } function toBetaStreamEvent( diff --git a/js/plugins/anthropic/tests/structured_output_test.ts b/js/plugins/anthropic/tests/structured_output_test.ts new file mode 100644 index 0000000000..9a1e31fcd5 --- /dev/null +++ b/js/plugins/anthropic/tests/structured_output_test.ts @@ -0,0 +1,358 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type Anthropic from '@anthropic-ai/sdk'; +import * as assert from 'assert'; +import { genkit, z } from 'genkit'; +import { describe, test } from 'node:test'; +import { anthropic } from '../src/index.js'; +import { __testClient } from '../src/types.js'; +import { + createMockAnthropicClient, + createMockAnthropicMessage, +} from './mocks/anthropic-client.js'; + +/** + * Test constants for consistent test setup + */ +const TEST_API_KEY = 'test-key'; +const SUPPORTING_MODEL = 'anthropic/claude-sonnet-4-5'; +const NON_SUPPORTING_MODEL = 'anthropic/claude-sonnet-4'; + +/** + * Options for creating a plugin with a mock client + */ +interface CreatePluginOptions { + apiVersion?: 'beta' | 'stable'; + mockClient: Anthropic; +} + +/** + * Creates an Anthropic plugin configured with a mock client for testing + */ +function createPlugin(options: CreatePluginOptions) { + return anthropic({ + apiKey: TEST_API_KEY, + apiVersion: options.apiVersion, + // @ts-ignore + [__testClient]: options.mockClient, + }); +} + +/** + * Creates a Genkit instance with the given plugin + */ +function createGenkitInstance(plugin: ReturnType) { + return genkit({ + plugins: [plugin], + }); +} + +/** + * Helper to get the proper create stub from the mock client for a given API version. + */ +function getCreateStub(mockClient: Anthropic, apiVersion: 'beta' | 'stable') { + return apiVersion === 'beta' + ? (mockClient.beta.messages.create as any) + : (mockClient.messages.create as any); +} + +/** + * Extracts the API request object from the mock for verification + * @param apiVersion - 'beta' or 'stable' to determine which API endpoint to check + */ +function getApiRequest( + mockClient: Anthropic, + apiVersion: 'beta' | 'stable', + callIndex: number = 0 +) { + const stub = getCreateStub(mockClient, apiVersion); + return stub.mock.calls[callIndex]?.arguments[0]; +} + +/** + * Verifies that the API was called the expected number of times + * @param apiVersion - 'beta' or 'stable' to determine which API endpoint to verify + */ +function verifyApiCalled( + mockClient: Anthropic, + apiVersion: 'beta' | 'stable', + expectedCalls: number = 1 +) { + const stub = getCreateStub(mockClient, apiVersion); + assert.strictEqual( + stub.mock.calls.length, + expectedCalls, + `${apiVersion === 'beta' ? 'Beta' : 'Stable'} API should be called ${expectedCalls} time(s)` + ); +} + +/** + * Tests for structured output (constrained generation) functionality. + * These tests verify that output_format is correctly passed to the Anthropic API + * when using the beta API with constrained output, and that it's NOT passed + * in various edge cases (stable API, non-json format, missing schema, etc.) + */ +describe('Structured Output Tests', () => { + test('should pass output_format to API when using beta API with constrained output', async () => { + const mockClient = createMockAnthropicClient({ + messageResponse: createMockAnthropicMessage({ + text: '{"name":"Alice","age":30,"city":"New York","isStudent":false,"isEmployee":true,"isRetired":false,"isUnemployed":false,"isDisabled":false}', + }), + }); + + // Set up plugin with beta API enabled + const plugin = createPlugin({ + apiVersion: 'beta', + mockClient, + }); + + const ai = createGenkitInstance(plugin); + + // Call generate with sonnet 4.5 (supports native constrained output) + await ai.generate({ + model: SUPPORTING_MODEL, + prompt: + 'Generate a fictional person with name "Alice", age 30, and city "New York". Return only the JSON.', + output: { + schema: z.object({ + name: z.string(), + age: z.number(), + city: z.string(), + isStudent: z.boolean(), + isEmployee: z.boolean(), + isRetired: z.boolean(), + isUnemployed: z.boolean(), + isDisabled: z.boolean(), + }), + format: 'json', + constrained: true, + }, + }); + + // Verify the beta API was called + verifyApiCalled(mockClient, 'beta'); + + // Verify output_format was included in the API request + const apiRequest = getApiRequest(mockClient, 'beta'); + assert.ok(apiRequest.output_format, 'Request should have output_format'); + assert.strictEqual( + apiRequest.output_format.type, + 'json_schema', + 'output_format type should be json_schema' + ); + assert.ok( + apiRequest.output_format.schema, + 'output_format should have schema' + ); + // Verify schema transformation: additionalProperties should be false for constrained output + assert.strictEqual( + apiRequest.output_format.schema.additionalProperties, + false, + 'Schema should have additionalProperties: false' + ); + }); + + test('should NOT pass output_format to API when constrained is false and using beta API', async () => { + const mockClient = createMockAnthropicClient({ + messageResponse: createMockAnthropicMessage({ + text: '{"name":"Alice"}', + }), + }); + + // Set up plugin with beta API enabled + const plugin = createPlugin({ + apiVersion: 'beta', + mockClient, + }); + + const ai = createGenkitInstance(plugin); + + // Call generate with constrained: false + await ai.generate({ + model: SUPPORTING_MODEL, + prompt: 'Generate JSON', + output: { + format: 'json', + constrained: false, + schema: z.object({ + name: z.string(), + }), + }, + }); + + // Verify the beta API was called + verifyApiCalled(mockClient, 'beta'); + + // Verify output_format was NOT included when constrained is false + const apiRequest = getApiRequest(mockClient, 'beta'); + assert.strictEqual( + apiRequest.output_format, + undefined, + 'Request should NOT have output_format when constrained is false' + ); + }); + + test('should NOT pass output_format to API when format is not json and using beta API', async () => { + const mockClient = createMockAnthropicClient({ + messageResponse: createMockAnthropicMessage({ + text: 'Some text response', + }), + }); + + // Set up plugin with beta API enabled + const plugin = createPlugin({ + apiVersion: 'beta', + mockClient, + }); + + const ai = createGenkitInstance(plugin); + + // Call generate with format: 'text' (not 'json') + await ai.generate({ + model: SUPPORTING_MODEL, + prompt: 'Generate text', + output: { + format: 'text', + constrained: true, + }, + }); + + // Verify the beta API was called + verifyApiCalled(mockClient, 'beta'); + + // Verify output_format was NOT included when format is not json + const apiRequest = getApiRequest(mockClient, 'beta'); + assert.strictEqual( + apiRequest.output_format, + undefined, + 'Request should NOT have output_format when format is text' + ); + }); + + test('should NOT pass output_format to API when schema is not provided and using beta API', async () => { + const mockClient = createMockAnthropicClient({ + messageResponse: createMockAnthropicMessage({ + text: '{"anything": "goes"}', + }), + }); + + // Set up plugin with beta API enabled + const plugin = createPlugin({ + apiVersion: 'beta', + mockClient, + }); + + const ai = createGenkitInstance(plugin); + + // Call generate with constrained: true but no schema + await ai.generate({ + model: SUPPORTING_MODEL, + prompt: 'Generate JSON', + output: { + format: 'json', + constrained: true, + // No schema provided + }, + }); + + // Verify the beta API was called + verifyApiCalled(mockClient, 'beta'); + + // Verify output_format was NOT included when schema is missing + const apiRequest = getApiRequest(mockClient, 'beta'); + assert.strictEqual( + apiRequest.output_format, + undefined, + 'Request should NOT have output_format when schema is not provided' + ); + }); + + test('should NOT pass output_format to API when model does not support structured output and using beta API', async () => { + const mockClient = createMockAnthropicClient({ + messageResponse: createMockAnthropicMessage({ + text: '{"name":"Alice"}', + }), + }); + + // Set up plugin with beta API enabled + const plugin = createPlugin({ + apiVersion: 'beta', + mockClient, + }); + + const ai = createGenkitInstance(plugin); + + // Call generate with model that does not support structured output + await ai.generate({ + model: NON_SUPPORTING_MODEL, + prompt: 'Generate JSON', + output: { + format: 'json', + constrained: true, + }, + }); + + // Verify the beta API was called + verifyApiCalled(mockClient, 'beta'); + + // Verify output_format was NOT included when model does not support structured output + const apiRequest = getApiRequest(mockClient, 'beta'); + assert.strictEqual( + apiRequest.output_format, + undefined, + 'Request should NOT have output_format when model does not support structured output' + ); + }); + + test('should throw an error when using stable API with non-text output format', async () => { + const mockClient = createMockAnthropicClient({ + messageResponse: createMockAnthropicMessage({ + text: '{"name":"Alice","age":30,"city":"New York"}', + }), + }); + + // Set up plugin with stable API (not beta) + const plugin = createPlugin({ + apiVersion: 'stable', + mockClient, + }); + + const ai = createGenkitInstance(plugin); + + // Call generate with constrained output (would work with beta API) + // Expect an error to be thrown since only text output is supported for stable API + await assert.rejects( + async () => { + await ai.generate({ + model: SUPPORTING_MODEL, + prompt: 'Generate JSON', + output: { + format: 'json', + constrained: true, + schema: z.object({ + name: z.string(), + age: z.number(), + city: z.string(), + }), + }, + }); + }, + /Only text output format is supported for Claude models currently/, + 'Should throw an error for non-text output on stable API' + ); + }); +}); diff --git a/js/pnpm-lock.yaml b/js/pnpm-lock.yaml index 454817f405..ef7cd9a5bc 100644 --- a/js/pnpm-lock.yaml +++ b/js/pnpm-lock.yaml @@ -6,6 +6,9 @@ settings: overrides: cross-spawn: ^7.0.5 + '@genkit-ai/vertexai>@anthropic-ai/sdk': ^0.24.3 + '@anthropic-ai/vertex-sdk>@anthropic-ai/sdk': ^0.24.3 + '@genkit-ai/anthropic>@anthropic-ai/sdk': ^0.71.2 importers: @@ -181,7 +184,7 @@ importers: optionalDependencies: '@genkit-ai/firebase': specifier: ^1.16.1 - version: 1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + version: 1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) doc-snippets: dependencies: @@ -260,8 +263,8 @@ importers: plugins/anthropic: dependencies: '@anthropic-ai/sdk': - specifier: ^0.68.0 - version: 0.68.0(zod@3.25.76) + specifier: ^0.71.2 + version: 0.71.2(zod@3.25.76) devDependencies: '@types/node': specifier: ^20.11.16 @@ -1088,7 +1091,7 @@ importers: version: link:../../plugins/compat-oai '@genkit-ai/express': specifier: ^1.1.0 - version: 1.12.0(@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit) + version: 1.12.0(@genkit-ai/core@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit) genkit: specifier: workspace:* version: link:../../genkit @@ -1705,7 +1708,7 @@ importers: version: link:../../plugins/ollama genkitx-openai: specifier: ^0.10.1 - version: 0.10.1(@genkit-ai/ai@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3) + version: 0.10.1(@genkit-ai/ai@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3) devDependencies: rimraf: specifier: ^6.0.1 @@ -2145,8 +2148,8 @@ packages: '@anthropic-ai/sdk@0.24.3': resolution: {integrity: sha512-916wJXO6T6k8R6BAAcLhLPv/pnLGy7YSEBZXZ1XTFbLcTZE8oTy3oDW9WJf9KKZwMvVcePIfoTSvzXHRcGxkQQ==} - '@anthropic-ai/sdk@0.68.0': - resolution: {integrity: sha512-SMYAmbbiprG8k1EjEPMTwaTqssDT7Ae+jxcR5kWXiqTlbwMR2AthXtscEVWOHkRfyAV5+y3PFYTJRNa3OJWIEw==} + '@anthropic-ai/sdk@0.71.2': + resolution: {integrity: sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==} hasBin: true peerDependencies: zod: ^3.25.0 || ^4.0.0 @@ -2767,11 +2770,11 @@ packages: '@firebase/webchannel-wrapper@1.0.3': resolution: {integrity: sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==} - '@genkit-ai/ai@1.26.0-rc.0': - resolution: {integrity: sha512-TrNRK/fSuhM8XHOGAV6lDH9daGYfWCPyW55ZDtH3IeDAVNtfcvOhgmM+uvgtsvjKYeJiDHdwVQeabL1e9tzdYg==} + '@genkit-ai/ai@1.26.0': + resolution: {integrity: sha512-L6sX2pocyGQTJU77w/Y6DP/VfWEgD/WyFZL/P2RSxz/xr25/twbdPE45xzjP7KTaFHFhAAp+lOMYhvh9kEBS3g==} - '@genkit-ai/core@1.26.0-rc.0': - resolution: {integrity: sha512-ZnzyWLeb364csirXJusPKKV5i6ZqzsKHUc9ZKRGBSoPXkrz/w0hLGoPCFjCSbfm3DmRvC45/HOn3uEVtwkN2MA==} + '@genkit-ai/core@1.26.0': + resolution: {integrity: sha512-wLcfyWjRyDMeyIcx2De0Sl8P4MxuTVPdCyr7wSR4YZmLIOA02LrdhQXGPcx8Rh7N0z5IxUAxPZ5rVdsUitxIzA==} '@genkit-ai/express@1.12.0': resolution: {integrity: sha512-QAxSS07dX5ovSfsUB4s90KaDnv4zg1wnoxCZCa+jBsYUyv9NvCCTsOk25xAQgGxc7xi3+MD+3AsPier5oZILIg==} @@ -5948,8 +5951,8 @@ packages: resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} engines: {node: '>=18'} - genkit@1.26.0-rc.0: - resolution: {integrity: sha512-Yx4qtT0ImwE2Nu8ts1lrq4eL/qCa+vFmgNOWnCJLc205Vcco0yZEQ0Wr0OL3sBhIAyLuAfx6CCUPJE735ypTsg==} + genkit@1.26.0: + resolution: {integrity: sha512-+bfQWefF56mZU8RTH0zHwlXyreA1rMkEXBBb5mNqP1OVuv92F8eJWP80/8M+wvL8OeaxBiejtbGIjcepOJRgpA==} genkitx-openai@0.10.1: resolution: {integrity: sha512-E9/DzyQcBUSTy81xT2pvEmdnn9Q/cKoojEt6lD/EdOeinhqE9oa59d/kuXTokCMekTrj3Rk7LtNBQIDjnyjNOA==} @@ -7449,6 +7452,7 @@ packages: next@15.4.10: resolution: {integrity: sha512-itVlc79QjpKMFMRhP+kbGKaSG/gZM6RCvwhEbwmCNF06CdDiNaoHcbeg0PqkEa2GOcn8KJ0nnc7+yL7EjoYLHQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -9202,7 +9206,7 @@ snapshots: '@anthropic-ai/sdk@0.24.3(encoding@0.1.13)': dependencies: '@types/node': 18.19.112 - '@types/node-fetch': 2.6.11 + '@types/node-fetch': 2.6.12 abort-controller: 3.0.0 agentkeepalive: 4.5.0 form-data-encoder: 1.7.2 @@ -9212,7 +9216,7 @@ snapshots: transitivePeerDependencies: - encoding - '@anthropic-ai/sdk@0.68.0(zod@3.25.76)': + '@anthropic-ai/sdk@0.71.2(zod@3.25.76)': dependencies: json-schema-to-ts: 3.1.1 optionalDependencies: @@ -9943,9 +9947,9 @@ snapshots: '@firebase/webchannel-wrapper@1.0.3': {} - '@genkit-ai/ai@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/ai@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/core': 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) '@opentelemetry/api': 1.9.0 '@types/node': 20.19.26 colorette: 2.0.20 @@ -9964,9 +9968,9 @@ snapshots: - supports-color optional: true - '@genkit-ai/ai@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': + '@genkit-ai/ai@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': dependencies: - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/core': 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) '@opentelemetry/api': 1.9.0 '@types/node': 20.19.26 colorette: 2.0.20 @@ -9984,7 +9988,7 @@ snapshots: - genkit - supports-color - '@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/core@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0) @@ -10006,7 +10010,7 @@ snapshots: zod: 3.25.76 zod-to-json-schema: 3.25.0(zod@3.25.76) optionalDependencies: - '@genkit-ai/firebase': 1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/firebase': 1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) transitivePeerDependencies: - '@google-cloud/firestore' - encoding @@ -10016,7 +10020,7 @@ snapshots: - supports-color optional: true - '@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': + '@genkit-ai/core@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0) @@ -10047,9 +10051,9 @@ snapshots: - genkit - supports-color - '@genkit-ai/express@1.12.0(@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit)': + '@genkit-ai/express@1.12.0(@genkit-ai/core@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit)': dependencies: - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/core': 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) body-parser: 1.20.3 cors: 2.8.5 express: 5.1.0 @@ -10057,12 +10061,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@genkit-ai/firebase@1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/firebase@1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: - '@genkit-ai/google-cloud': 1.16.1(encoding@0.1.13)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/google-cloud': 1.16.1(encoding@0.1.13)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) '@google-cloud/firestore': 7.11.6(encoding@0.1.13) firebase-admin: 13.5.0(encoding@0.1.13) - genkit: 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) optionalDependencies: firebase: 11.9.1 transitivePeerDependencies: @@ -10070,12 +10074,12 @@ snapshots: - supports-color optional: true - '@genkit-ai/firebase@1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/firebase@1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: - '@genkit-ai/google-cloud': 1.25.0(encoding@0.1.13)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/google-cloud': 1.25.0(encoding@0.1.13)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) '@google-cloud/firestore': 7.11.6(encoding@0.1.13) firebase-admin: 13.5.0(encoding@0.1.13) - genkit: 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) optionalDependencies: firebase: 11.9.1 transitivePeerDependencies: @@ -10096,7 +10100,7 @@ snapshots: - supports-color optional: true - '@genkit-ai/google-cloud@1.16.1(encoding@0.1.13)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/google-cloud@1.16.1(encoding@0.1.13)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: '@google-cloud/logging-winston': 6.0.1(encoding@0.1.13)(winston@3.17.0) '@google-cloud/opentelemetry-cloud-monitoring-exporter': 0.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@1.25.1(@opentelemetry/api@1.9.0))(encoding@0.1.13) @@ -10112,7 +10116,7 @@ snapshots: '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) - genkit: 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) google-auth-library: 9.15.1(encoding@0.1.13) node-fetch: 3.3.2 winston: 3.17.0 @@ -10121,7 +10125,7 @@ snapshots: - supports-color optional: true - '@genkit-ai/google-cloud@1.25.0(encoding@0.1.13)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/google-cloud@1.25.0(encoding@0.1.13)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: '@google-cloud/logging-winston': 6.0.1(encoding@0.1.13)(winston@3.19.0) '@google-cloud/opentelemetry-cloud-monitoring-exporter': 0.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@1.25.1(@opentelemetry/api@1.9.0))(encoding@0.1.13) @@ -10137,7 +10141,7 @@ snapshots: '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) - genkit: 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) google-auth-library: 9.15.1(encoding@0.1.13) node-fetch: 3.3.2 winston: 3.19.0 @@ -13986,10 +13990,10 @@ snapshots: transitivePeerDependencies: - supports-color - genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1): + genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1): dependencies: - '@genkit-ai/ai': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/ai': 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/core': 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) uuid: 10.0.0 transitivePeerDependencies: - '@google-cloud/firestore' @@ -13999,10 +14003,10 @@ snapshots: - supports-color optional: true - genkitx-openai@0.10.1(@genkit-ai/ai@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3): + genkitx-openai@0.10.1(@genkit-ai/ai@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3): dependencies: - '@genkit-ai/ai': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/ai': 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/core': 1.26.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) openai: 4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.67) zod: 3.25.67 transitivePeerDependencies: diff --git a/js/testapps/anthropic/src/beta/basic.ts b/js/testapps/anthropic/src/beta/basic.ts index d1309b3400..f9841f4c6d 100644 --- a/js/testapps/anthropic/src/beta/basic.ts +++ b/js/testapps/anthropic/src/beta/basic.ts @@ -15,12 +15,16 @@ */ import { anthropic } from '@genkit-ai/anthropic'; -import { genkit } from 'genkit'; +import { genkit, z } from 'genkit'; const ai = genkit({ plugins: [ // Default all flows in this sample to the beta surface - anthropic({ apiVersion: 'beta', cacheSystemPrompt: true }), + anthropic({ + apiVersion: 'beta', + cacheSystemPrompt: true, + apiKey: process.env.ANTHROPIC_API_KEY, + }), ], }); @@ -28,15 +32,21 @@ const betaHaiku = anthropic.model('claude-3-5-haiku', { apiVersion: 'beta' }); const betaSonnet = anthropic.model('claude-sonnet-4-5', { apiVersion: 'beta' }); const betaOpus41 = anthropic.model('claude-opus-4-1', { apiVersion: 'beta' }); +const GreetingSchema = z.object({ + greeting: z.string(), + apiVersion: z.string(), +}); + ai.defineFlow('anthropic-beta-hello', async () => { - const { text } = await ai.generate({ + const { output } = await ai.generate({ model: betaHaiku, prompt: 'You are Claude on the beta API. Provide a concise greeting that mentions that you are using the beta API.', config: { temperature: 0.6 }, + output: { schema: GreetingSchema, format: 'json', constrained: true }, }); - return text; + return output; }); ai.defineFlow('anthropic-beta-stream', async (_, { sendChunk }) => {