From d5fd04573ac8f71fe59bd0bb2a6e31d980fd5079 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Wed, 18 Feb 2026 09:03:26 +0000 Subject: [PATCH 1/4] Add e2e test infrastructure and implementations for AI Transport guides Introduce guides/ai-transport/ directory with full runnable code for all 8 AI Transport guides (4 providers x 2 streaming patterns), each with publisher, subscriber, and e2e tests hitting real LLM APIs and Ably. - OpenAI, Anthropic, Vercel AI SDK, and LangGraph providers - Message-per-token and message-per-response streaming patterns - 24 e2e tests total (3 per guide): lifecycle ordering, response reconstruction, and token concatenation verification - Yarn workspaces with shared Vitest config - Exclude guides/ from root Jest config --- guides/ai-transport/.env.example | 10 + guides/ai-transport/.gitignore | 2 + guides/ai-transport/README.md | 61 + .../package.json | 14 + .../src/publisher.ts | 53 + .../src/subscriber.ts | 61 + .../test/e2e.test.ts | 76 + .../tsconfig.json | 4 + .../anthropic-message-per-token/package.json | 14 + .../src/publisher.ts | 64 + .../src/subscriber.ts | 42 + .../test/e2e.test.ts | 73 + .../anthropic-message-per-token/tsconfig.json | 4 + .../package.json | 16 + .../src/publisher.ts | 56 + .../src/subscriber.ts | 61 + .../test/e2e.test.ts | 76 + .../tsconfig.json | 4 + .../lang-graph-message-per-token/package.json | 16 + .../src/publisher.ts | 68 + .../src/subscriber.ts | 42 + .../test/e2e.test.ts | 73 + .../tsconfig.json | 4 + .../openai-message-per-response/package.json | 14 + .../src/publisher.ts | 52 + .../src/subscriber.ts | 61 + .../test/e2e.test.ts | 76 + .../openai-message-per-response/tsconfig.json | 4 + .../openai-message-per-token/package.json | 14 + .../openai-message-per-token/src/publisher.ts | 87 + .../src/subscriber.ts | 53 + .../openai-message-per-token/test/e2e.test.ts | 105 ++ .../openai-message-per-token/tsconfig.json | 4 + guides/ai-transport/package.json | 32 + guides/ai-transport/tsconfig.base.json | 16 + .../vercel-message-per-response/package.json | 15 + .../src/publisher.ts | 44 + .../src/subscriber.ts | 61 + .../test/e2e.test.ts | 76 + .../vercel-message-per-response/tsconfig.json | 4 + .../vercel-message-per-token/package.json | 15 + .../vercel-message-per-token/src/publisher.ts | 60 + .../src/subscriber.ts | 42 + .../vercel-message-per-token/test/e2e.test.ts | 73 + .../vercel-message-per-token/tsconfig.json | 4 + guides/ai-transport/vitest.config.ts | 9 + guides/ai-transport/vitest.setup.ts | 2 + guides/ai-transport/yarn.lock | 1556 +++++++++++++++++ jest.config.js | 2 +- 49 files changed, 3374 insertions(+), 1 deletion(-) create mode 100644 guides/ai-transport/.env.example create mode 100644 guides/ai-transport/.gitignore create mode 100644 guides/ai-transport/README.md create mode 100644 guides/ai-transport/anthropic-message-per-response/package.json create mode 100644 guides/ai-transport/anthropic-message-per-response/src/publisher.ts create mode 100644 guides/ai-transport/anthropic-message-per-response/src/subscriber.ts create mode 100644 guides/ai-transport/anthropic-message-per-response/test/e2e.test.ts create mode 100644 guides/ai-transport/anthropic-message-per-response/tsconfig.json create mode 100644 guides/ai-transport/anthropic-message-per-token/package.json create mode 100644 guides/ai-transport/anthropic-message-per-token/src/publisher.ts create mode 100644 guides/ai-transport/anthropic-message-per-token/src/subscriber.ts create mode 100644 guides/ai-transport/anthropic-message-per-token/test/e2e.test.ts create mode 100644 guides/ai-transport/anthropic-message-per-token/tsconfig.json create mode 100644 guides/ai-transport/lang-graph-message-per-response/package.json create mode 100644 guides/ai-transport/lang-graph-message-per-response/src/publisher.ts create mode 100644 guides/ai-transport/lang-graph-message-per-response/src/subscriber.ts create mode 100644 guides/ai-transport/lang-graph-message-per-response/test/e2e.test.ts create mode 100644 guides/ai-transport/lang-graph-message-per-response/tsconfig.json create mode 100644 guides/ai-transport/lang-graph-message-per-token/package.json create mode 100644 guides/ai-transport/lang-graph-message-per-token/src/publisher.ts create mode 100644 guides/ai-transport/lang-graph-message-per-token/src/subscriber.ts create mode 100644 guides/ai-transport/lang-graph-message-per-token/test/e2e.test.ts create mode 100644 guides/ai-transport/lang-graph-message-per-token/tsconfig.json create mode 100644 guides/ai-transport/openai-message-per-response/package.json create mode 100644 guides/ai-transport/openai-message-per-response/src/publisher.ts create mode 100644 guides/ai-transport/openai-message-per-response/src/subscriber.ts create mode 100644 guides/ai-transport/openai-message-per-response/test/e2e.test.ts create mode 100644 guides/ai-transport/openai-message-per-response/tsconfig.json create mode 100644 guides/ai-transport/openai-message-per-token/package.json create mode 100644 guides/ai-transport/openai-message-per-token/src/publisher.ts create mode 100644 guides/ai-transport/openai-message-per-token/src/subscriber.ts create mode 100644 guides/ai-transport/openai-message-per-token/test/e2e.test.ts create mode 100644 guides/ai-transport/openai-message-per-token/tsconfig.json create mode 100644 guides/ai-transport/package.json create mode 100644 guides/ai-transport/tsconfig.base.json create mode 100644 guides/ai-transport/vercel-message-per-response/package.json create mode 100644 guides/ai-transport/vercel-message-per-response/src/publisher.ts create mode 100644 guides/ai-transport/vercel-message-per-response/src/subscriber.ts create mode 100644 guides/ai-transport/vercel-message-per-response/test/e2e.test.ts create mode 100644 guides/ai-transport/vercel-message-per-response/tsconfig.json create mode 100644 guides/ai-transport/vercel-message-per-token/package.json create mode 100644 guides/ai-transport/vercel-message-per-token/src/publisher.ts create mode 100644 guides/ai-transport/vercel-message-per-token/src/subscriber.ts create mode 100644 guides/ai-transport/vercel-message-per-token/test/e2e.test.ts create mode 100644 guides/ai-transport/vercel-message-per-token/tsconfig.json create mode 100644 guides/ai-transport/vitest.config.ts create mode 100644 guides/ai-transport/vitest.setup.ts create mode 100644 guides/ai-transport/yarn.lock diff --git a/guides/ai-transport/.env.example b/guides/ai-transport/.env.example new file mode 100644 index 0000000000..b81e5dbda9 --- /dev/null +++ b/guides/ai-transport/.env.example @@ -0,0 +1,10 @@ +# Ably API key (required for all guides) +ABLY_API_KEY= + +# OpenAI API key (required for openai-* guides) +OPENAI_API_KEY= + +# Anthropic API key (required for anthropic-* and lang-graph-* guides) +ANTHROPIC_API_KEY= + +# Vercel AI SDK uses the underlying provider's key (e.g. OPENAI_API_KEY) diff --git a/guides/ai-transport/.gitignore b/guides/ai-transport/.gitignore new file mode 100644 index 0000000000..713d5006da --- /dev/null +++ b/guides/ai-transport/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +.env diff --git a/guides/ai-transport/README.md b/guides/ai-transport/README.md new file mode 100644 index 0000000000..888f95f42c --- /dev/null +++ b/guides/ai-transport/README.md @@ -0,0 +1,61 @@ +# AI Transport Guides - E2E Code + +Full, runnable implementations for each AI Transport guide. Each directory contains the complete publisher (server) and subscriber (client) code that the corresponding guide walks through. + +## Guides + +| Guide | Provider | Pattern | +|-------|----------|---------| +| `openai-message-per-token` | OpenAI | Message per token | +| `openai-message-per-response` | OpenAI | Message per response | +| `anthropic-message-per-token` | Anthropic | Message per token | +| `anthropic-message-per-response` | Anthropic | Message per response | +| `vercel-message-per-token` | Vercel AI SDK | Message per token | +| `vercel-message-per-response` | Vercel AI SDK | Message per response | +| `lang-graph-message-per-token` | LangGraph | Message per token | +| `lang-graph-message-per-response` | LangGraph | Message per response | + +## Streaming patterns + +- **Message per token**: Publisher sends discrete `start`, `token`, and `stop` events. Subscriber reconstructs the full response by appending tokens correlated by `responseId`. +- **Message per response**: Publisher creates a single message and appends each token to it. Subscriber handles `message.create` and `message.append` actions, with the full response available in message history. + +## Prerequisites + +- Node.js 20+ +- API keys for the relevant providers (see `.env.example`) + +## Setup + +```bash +cd guides/ai-transport +cp .env.example .env +# Fill in your API keys in .env + +yarn install +``` + +## Running a guide + +Each guide has a publisher (streams from LLM to Ably) and a subscriber (reads from Ably): + +```bash +# Terminal 1 - start the subscriber +npx tsx /src/subscriber.ts + +# Terminal 2 - start the publisher +npx tsx /src/publisher.ts +``` + +## Running tests + +```bash +# All guides +yarn test + +# Watch mode +yarn test:watch + +# Single guide +yarn vitest run +``` diff --git a/guides/ai-transport/anthropic-message-per-response/package.json b/guides/ai-transport/anthropic-message-per-response/package.json new file mode 100644 index 0000000000..ca8aaea8a2 --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-response/package.json @@ -0,0 +1,14 @@ +{ + "name": "guide-anthropic-message-per-response", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:publisher": "tsx src/publisher.ts", + "start:subscriber": "tsx src/subscriber.ts", + "test": "vitest run" + }, + "dependencies": { + "@anthropic-ai/sdk": "^0.71" + } +} diff --git a/guides/ai-transport/anthropic-message-per-response/src/publisher.ts b/guides/ai-transport/anthropic-message-per-response/src/publisher.ts new file mode 100644 index 0000000000..143e2be744 --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-response/src/publisher.ts @@ -0,0 +1,53 @@ +import Anthropic from '@anthropic-ai/sdk'; +import Ably from 'ably'; + +export async function publish(channel: Ably.RealtimeChannel, prompt: string) { + const anthropic = new Anthropic(); + let msgSerial: string | null = null; + let textBlockIndex: number | null = null; + + const stream = await anthropic.messages.create({ + model: 'claude-sonnet-4-5-20250929', + max_tokens: 1024, + messages: [{ role: 'user', content: prompt }], + stream: true, + }); + + for await (const event of stream) { + switch (event.type) { + case 'message_start': { + const result = await channel.publish({ name: 'response', data: '' }); + msgSerial = result.serials[0]; + break; + } + + case 'content_block_start': + if (event.content_block.type === 'text') { + textBlockIndex = event.index; + } + break; + + case 'content_block_delta': + if (event.index === textBlockIndex && event.delta.type === 'text_delta' && msgSerial) { + channel.appendMessage({ serial: msgSerial, data: event.delta.text }); + } + break; + + case 'message_stop': + break; + } + } +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('ai:anthropic-mpr-guide'); + await publish(channel, 'Tell me a short joke'); + console.log('Done streaming. Closing connection...'); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/anthropic-message-per-response/src/subscriber.ts b/guides/ai-transport/anthropic-message-per-response/src/subscriber.ts new file mode 100644 index 0000000000..d57e24ab12 --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-response/src/subscriber.ts @@ -0,0 +1,61 @@ +import Ably from 'ably'; + +// Subscribe to a channel and reconstruct streamed responses using message actions. +// Returns a promise that resolves with the full response text when no new appends +// arrive for 2 seconds (indicating the stream is complete). +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + const responses = new Map(); + let lastSerial: string | null = null; + let doneTimer: ReturnType | null = null; + + const resetTimer = () => { + if (doneTimer) clearTimeout(doneTimer); + doneTimer = setTimeout(() => { + if (lastSerial) { + const finalText = responses.get(lastSerial) || ''; + resolve(finalText); + } + }, 3000); + }; + + channel.subscribe((message: Ably.Message) => { + switch (message.action) { + case 'message.create': + console.log('\n[Response started]', message.serial); + responses.set(message.serial, message.data as string); + lastSerial = message.serial; + resetTimer(); + break; + + case 'message.append': { + const current = responses.get(message.serial) || ''; + responses.set(message.serial, current + (message.data as string)); + process.stdout.write(message.data as string); + resetTimer(); + break; + } + + case 'message.update': + responses.set(message.serial, message.data as string); + console.log('\n[Response updated with full content]'); + resetTimer(); + break; + } + }); + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('ai:anthropic-mpr-guide'); + console.log('Subscriber ready, waiting for tokens...'); + const response = await subscribe(channel); + console.log('\nFull response:', response); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/anthropic-message-per-response/test/e2e.test.ts b/guides/ai-transport/anthropic-message-per-response/test/e2e.test.ts new file mode 100644 index 0000000000..a3162774ed --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-response/test/e2e.test.ts @@ -0,0 +1,76 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { publish } from '../src/publisher.js'; +import { subscribe } from '../src/subscriber.js'; + +describe('anthropic-message-per-response', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `ai:test-anthropic-mpr-${Date.now()}`; + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes initial message and appends tokens', async () => { + const channel = subscriberClient.channels.get(channelName + '-actions'); + const pubChannel = publisherClient.channels.get(channelName + '-actions'); + const actions: { action: string; data?: string; serial?: string }[] = []; + + await channel.subscribe((message: Ably.Message) => { + actions.push({ + action: message.action!, + data: message.data as string | undefined, + serial: message.serial, + }); + }); + + await publish(pubChannel, 'Reply with exactly: OK'); + await new Promise((resolve) => setTimeout(resolve, 3000)); + + expect(actions[0].action).toBe('message.create'); + const appendActions = actions.filter((a) => a.action === 'message.append'); + expect(appendActions.length).toBeGreaterThan(0); + // All actions should share the same serial + const serials = new Set(actions.map((a) => a.serial)); + expect(serials.size).toBe(1); + }); + + it('subscriber reconstructs the full response from append actions', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); + const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); + const responsePromise = subscribe(subChannel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Hello world'); + const fullResponse = await responsePromise; + expect(fullResponse.length).toBeGreaterThan(0); + expect(fullResponse.toLowerCase()).toContain('hello'); + }); + + it('appended tokens concatenate to match the full response', async () => { + const channel = subscriberClient.channels.get(channelName + '-concat'); + const pubChannel = publisherClient.channels.get(channelName + '-concat'); + const appendedTokens: string[] = []; + + await channel.subscribe((message: Ably.Message) => { + if (message.action === 'message.append') { + appendedTokens.push(message.data as string); + } + }); + + const responsePromise = subscribe(channel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Test'); + const fullResponse = await responsePromise; + const concatenated = appendedTokens.join(''); + expect(concatenated).toBe(fullResponse); + }); +}); diff --git a/guides/ai-transport/anthropic-message-per-response/tsconfig.json b/guides/ai-transport/anthropic-message-per-response/tsconfig.json new file mode 100644 index 0000000000..13b3dd7d6b --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-response/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/anthropic-message-per-token/package.json b/guides/ai-transport/anthropic-message-per-token/package.json new file mode 100644 index 0000000000..4170180553 --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-token/package.json @@ -0,0 +1,14 @@ +{ + "name": "guide-anthropic-message-per-token", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:publisher": "tsx src/publisher.ts", + "start:subscriber": "tsx src/subscriber.ts", + "test": "vitest run" + }, + "dependencies": { + "@anthropic-ai/sdk": "^0.71" + } +} diff --git a/guides/ai-transport/anthropic-message-per-token/src/publisher.ts b/guides/ai-transport/anthropic-message-per-token/src/publisher.ts new file mode 100644 index 0000000000..8d6a2d5407 --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-token/src/publisher.ts @@ -0,0 +1,64 @@ +import Anthropic from '@anthropic-ai/sdk'; +import Ably from 'ably'; + +async function processEvent( + event: Anthropic.MessageStreamEvent, + channel: Ably.RealtimeChannel, + state: { responseId: string | null }, +) { + switch (event.type) { + case 'message_start': + state.responseId = event.message.id; + channel.publish({ + name: 'start', + extras: { headers: { responseId: state.responseId } }, + }); + break; + + case 'content_block_delta': + if (event.delta.type === 'text_delta') { + channel.publish({ + name: 'token', + data: event.delta.text, + extras: { headers: { responseId: state.responseId } }, + }); + } + break; + + case 'message_stop': + await channel.publish({ + name: 'stop', + extras: { headers: { responseId: state.responseId } }, + }); + break; + } +} + +export async function publish(channel: Ably.RealtimeChannel, prompt: string) { + const anthropic = new Anthropic(); + const state = { responseId: null as string | null }; + + const stream = await anthropic.messages.create({ + model: 'claude-sonnet-4-5-20250929', + max_tokens: 1024, + messages: [{ role: 'user', content: prompt }], + stream: true, + }); + + for await (const event of stream) { + await processEvent(event, channel, state); + } +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('anthropic-mpt-guide'); + await publish(channel, 'Tell me a short joke'); + console.log('Done streaming. Closing connection...'); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/anthropic-message-per-token/src/subscriber.ts b/guides/ai-transport/anthropic-message-per-token/src/subscriber.ts new file mode 100644 index 0000000000..8358f4edfb --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-token/src/subscriber.ts @@ -0,0 +1,42 @@ +import Ably from 'ably'; + +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + const responses = new Map(); + + channel.subscribe('start', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + console.log('\n[Response started]', responseId); + responses.set(responseId, ''); + }); + + channel.subscribe('token', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + const token = message.data as string; + const currentText = responses.get(responseId) || ''; + responses.set(responseId, currentText + token); + process.stdout.write(token); + }); + + channel.subscribe('stop', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + const finalText = responses.get(responseId) || ''; + console.log('\n[Response completed]', responseId); + resolve(finalText); + }); + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('anthropic-mpt-guide'); + console.log('Subscriber ready, waiting for tokens...'); + const response = await subscribe(channel); + console.log('\nFull response:', response); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/anthropic-message-per-token/test/e2e.test.ts b/guides/ai-transport/anthropic-message-per-token/test/e2e.test.ts new file mode 100644 index 0000000000..2a1efbfefe --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-token/test/e2e.test.ts @@ -0,0 +1,73 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { publish } from '../src/publisher.js'; +import { subscribe } from '../src/subscriber.js'; + +describe('anthropic-message-per-token', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `test-anthropic-mpt-${Date.now()}`; + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes start, token, and stop events in order', async () => { + const channel = subscriberClient.channels.get(channelName + '-lifecycle'); + const pubChannel = publisherClient.channels.get(channelName + '-lifecycle'); + const events: { name: string; data?: string; responseId?: string }[] = []; + + await channel.subscribe((message: Ably.Message) => { + events.push({ + name: message.name!, + data: message.data as string | undefined, + responseId: message.extras?.headers?.responseId, + }); + }); + + await publish(pubChannel, 'Reply with exactly: OK'); + await new Promise((resolve) => setTimeout(resolve, 2000)); + + expect(events[0].name).toBe('start'); + expect(events[events.length - 1].name).toBe('stop'); + const tokenEvents = events.filter((e) => e.name === 'token'); + expect(tokenEvents.length).toBeGreaterThan(0); + const responseIds = new Set(events.map((e) => e.responseId)); + expect(responseIds.size).toBe(1); + expect(responseIds.values().next().value).toBeTruthy(); + }); + + it('subscriber reconstructs the full response from token events', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); + const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); + const responsePromise = subscribe(subChannel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Hello world'); + const fullResponse = await responsePromise; + expect(fullResponse.length).toBeGreaterThan(0); + expect(fullResponse.toLowerCase()).toContain('hello'); + }); + + it('token data concatenates to match the complete response', async () => { + const channel = subscriberClient.channels.get(channelName + '-concat'); + const pubChannel = publisherClient.channels.get(channelName + '-concat'); + const tokens: string[] = []; + await channel.subscribe('token', (message: Ably.Message) => { + tokens.push(message.data as string); + }); + const responsePromise = subscribe(channel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Test'); + const fullResponse = await responsePromise; + const concatenated = tokens.join(''); + expect(concatenated).toBe(fullResponse); + }); +}); diff --git a/guides/ai-transport/anthropic-message-per-token/tsconfig.json b/guides/ai-transport/anthropic-message-per-token/tsconfig.json new file mode 100644 index 0000000000..13b3dd7d6b --- /dev/null +++ b/guides/ai-transport/anthropic-message-per-token/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/lang-graph-message-per-response/package.json b/guides/ai-transport/lang-graph-message-per-response/package.json new file mode 100644 index 0000000000..4d751fd84f --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-response/package.json @@ -0,0 +1,16 @@ +{ + "name": "guide-lang-graph-message-per-response", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:publisher": "tsx src/publisher.ts", + "start:subscriber": "tsx src/subscriber.ts", + "test": "vitest run" + }, + "dependencies": { + "@langchain/langgraph": "^0.2", + "@langchain/anthropic": "^0.3", + "@langchain/core": "^0.3" + } +} diff --git a/guides/ai-transport/lang-graph-message-per-response/src/publisher.ts b/guides/ai-transport/lang-graph-message-per-response/src/publisher.ts new file mode 100644 index 0000000000..58ba92f0f6 --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-response/src/publisher.ts @@ -0,0 +1,56 @@ +import { ChatAnthropic } from '@langchain/anthropic'; +import { StateGraph, Annotation, START, END } from '@langchain/langgraph'; +import Ably from 'ably'; + +const model = new ChatAnthropic({ model: 'claude-sonnet-4-5-20250929' }); + +const StateAnnotation = Annotation.Root({ + messages: Annotation({ + reducer: (x, y) => x.concat(y), + default: () => [], + }), +}); + +const graph = new StateGraph(StateAnnotation) + .addNode('agent', async (state) => { + const response = await model.invoke(state.messages); + return { messages: [response] }; + }) + .addEdge(START, 'agent') + .addEdge('agent', END); + +const app = graph.compile(); + +export async function publish(channel: Ably.RealtimeChannel, prompt: string) { + let msgSerial: string | null = null; + + const stream = await app.stream( + { messages: [{ role: 'user', content: prompt }] }, + { streamMode: 'messages' }, + ); + + for await (const [messageChunk, _metadata] of stream) { + if (!msgSerial && messageChunk?.id) { + const result = await channel.publish({ name: 'response', data: '' }); + msgSerial = result.serials[0]; + } + + const content = messageChunk?.content; + if (content && msgSerial) { + channel.appendMessage({ serial: msgSerial, data: content }); + } + } +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('ai:langgraph-mpr-guide'); + await publish(channel, 'Tell me a short joke'); + console.log('Done streaming. Closing connection...'); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/lang-graph-message-per-response/src/subscriber.ts b/guides/ai-transport/lang-graph-message-per-response/src/subscriber.ts new file mode 100644 index 0000000000..c9ba750fd2 --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-response/src/subscriber.ts @@ -0,0 +1,61 @@ +import Ably from 'ably'; + +// Subscribe to a channel and reconstruct streamed responses using message actions. +// Returns a promise that resolves with the full response text when no new appends +// arrive for 2 seconds (indicating the stream is complete). +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + const responses = new Map(); + let lastSerial: string | null = null; + let doneTimer: ReturnType | null = null; + + const resetTimer = () => { + if (doneTimer) clearTimeout(doneTimer); + doneTimer = setTimeout(() => { + if (lastSerial) { + const finalText = responses.get(lastSerial) || ''; + resolve(finalText); + } + }, 3000); + }; + + channel.subscribe((message: Ably.Message) => { + switch (message.action) { + case 'message.create': + console.log('\n[Response started]', message.serial); + responses.set(message.serial, message.data as string); + lastSerial = message.serial; + resetTimer(); + break; + + case 'message.append': { + const current = responses.get(message.serial) || ''; + responses.set(message.serial, current + (message.data as string)); + process.stdout.write(message.data as string); + resetTimer(); + break; + } + + case 'message.update': + responses.set(message.serial, message.data as string); + console.log('\n[Response updated with full content]'); + resetTimer(); + break; + } + }); + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('ai:langgraph-mpr-guide'); + console.log('Subscriber ready, waiting for tokens...'); + const response = await subscribe(channel); + console.log('\nFull response:', response); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/lang-graph-message-per-response/test/e2e.test.ts b/guides/ai-transport/lang-graph-message-per-response/test/e2e.test.ts new file mode 100644 index 0000000000..10d7dc2163 --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-response/test/e2e.test.ts @@ -0,0 +1,76 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { publish } from '../src/publisher.js'; +import { subscribe } from '../src/subscriber.js'; + +describe('lang-graph-message-per-response', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `ai:test-lg-mpr-${Date.now()}`; + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes initial message and appends tokens', async () => { + const channel = subscriberClient.channels.get(channelName + '-actions'); + const pubChannel = publisherClient.channels.get(channelName + '-actions'); + const actions: { action: string; data?: string; serial?: string }[] = []; + + await channel.subscribe((message: Ably.Message) => { + actions.push({ + action: message.action!, + data: message.data as string | undefined, + serial: message.serial, + }); + }); + + await publish(pubChannel, 'Reply with exactly: OK'); + await new Promise((resolve) => setTimeout(resolve, 3000)); + + expect(actions[0].action).toBe('message.create'); + const appendActions = actions.filter((a) => a.action === 'message.append'); + expect(appendActions.length).toBeGreaterThan(0); + // All actions should share the same serial + const serials = new Set(actions.map((a) => a.serial)); + expect(serials.size).toBe(1); + }); + + it('subscriber reconstructs the full response from append actions', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); + const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); + const responsePromise = subscribe(subChannel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Hello world'); + const fullResponse = await responsePromise; + expect(fullResponse.length).toBeGreaterThan(0); + expect(fullResponse.toLowerCase()).toContain('hello'); + }); + + it('appended tokens concatenate to match the full response', async () => { + const channel = subscriberClient.channels.get(channelName + '-concat'); + const pubChannel = publisherClient.channels.get(channelName + '-concat'); + const appendedTokens: string[] = []; + + await channel.subscribe((message: Ably.Message) => { + if (message.action === 'message.append') { + appendedTokens.push(message.data as string); + } + }); + + const responsePromise = subscribe(channel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Test'); + const fullResponse = await responsePromise; + const concatenated = appendedTokens.join(''); + expect(concatenated).toBe(fullResponse); + }); +}); diff --git a/guides/ai-transport/lang-graph-message-per-response/tsconfig.json b/guides/ai-transport/lang-graph-message-per-response/tsconfig.json new file mode 100644 index 0000000000..13b3dd7d6b --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-response/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/lang-graph-message-per-token/package.json b/guides/ai-transport/lang-graph-message-per-token/package.json new file mode 100644 index 0000000000..125378263d --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-token/package.json @@ -0,0 +1,16 @@ +{ + "name": "guide-lang-graph-message-per-token", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:publisher": "tsx src/publisher.ts", + "start:subscriber": "tsx src/subscriber.ts", + "test": "vitest run" + }, + "dependencies": { + "@langchain/langgraph": "^0.2", + "@langchain/anthropic": "^0.3", + "@langchain/core": "^0.3" + } +} diff --git a/guides/ai-transport/lang-graph-message-per-token/src/publisher.ts b/guides/ai-transport/lang-graph-message-per-token/src/publisher.ts new file mode 100644 index 0000000000..51c5a62df8 --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-token/src/publisher.ts @@ -0,0 +1,68 @@ +import { ChatAnthropic } from '@langchain/anthropic'; +import { StateGraph, Annotation, START, END } from '@langchain/langgraph'; +import Ably from 'ably'; + +const model = new ChatAnthropic({ model: 'claude-sonnet-4-5-20250929' }); + +const StateAnnotation = Annotation.Root({ + messages: Annotation({ + reducer: (x, y) => x.concat(y), + default: () => [], + }), +}); + +const graph = new StateGraph(StateAnnotation) + .addNode('agent', async (state) => { + const response = await model.invoke(state.messages); + return { messages: [response] }; + }) + .addEdge(START, 'agent') + .addEdge('agent', END); + +const app = graph.compile(); + +export async function publish(channel: Ably.RealtimeChannel, prompt: string) { + let responseId: string | null = null; + + const stream = await app.stream( + { messages: [{ role: 'user', content: prompt }] }, + { streamMode: 'messages' }, + ); + + for await (const [messageChunk, _metadata] of stream) { + if (!responseId && messageChunk?.id) { + responseId = messageChunk.id; + channel.publish({ + name: 'start', + extras: { headers: { responseId } }, + }); + } + + const content = messageChunk?.content; + if (content) { + channel.publish({ + name: 'token', + data: content, + extras: { headers: { responseId } }, + }); + } + } + + await channel.publish({ + name: 'stop', + extras: { headers: { responseId } }, + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('langgraph-mpt-guide'); + await publish(channel, 'Tell me a short joke'); + console.log('Done streaming. Closing connection...'); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/lang-graph-message-per-token/src/subscriber.ts b/guides/ai-transport/lang-graph-message-per-token/src/subscriber.ts new file mode 100644 index 0000000000..6c423d77c2 --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-token/src/subscriber.ts @@ -0,0 +1,42 @@ +import Ably from 'ably'; + +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + const responses = new Map(); + + channel.subscribe('start', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + console.log('\n[Response started]', responseId); + responses.set(responseId, ''); + }); + + channel.subscribe('token', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + const token = message.data as string; + const currentText = responses.get(responseId) || ''; + responses.set(responseId, currentText + token); + process.stdout.write(token); + }); + + channel.subscribe('stop', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + const finalText = responses.get(responseId) || ''; + console.log('\n[Response completed]', responseId); + resolve(finalText); + }); + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('langgraph-mpt-guide'); + console.log('Subscriber ready, waiting for tokens...'); + const response = await subscribe(channel); + console.log('\nFull response:', response); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/lang-graph-message-per-token/test/e2e.test.ts b/guides/ai-transport/lang-graph-message-per-token/test/e2e.test.ts new file mode 100644 index 0000000000..518bcc1df0 --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-token/test/e2e.test.ts @@ -0,0 +1,73 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { publish } from '../src/publisher.js'; +import { subscribe } from '../src/subscriber.js'; + +describe('lang-graph-message-per-token', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `test-lg-mpt-${Date.now()}`; + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes start, token, and stop events in order', async () => { + const channel = subscriberClient.channels.get(channelName + '-lifecycle'); + const pubChannel = publisherClient.channels.get(channelName + '-lifecycle'); + const events: { name: string; data?: string; responseId?: string }[] = []; + + await channel.subscribe((message: Ably.Message) => { + events.push({ + name: message.name!, + data: message.data as string | undefined, + responseId: message.extras?.headers?.responseId, + }); + }); + + await publish(pubChannel, 'Reply with exactly: OK'); + await new Promise((resolve) => setTimeout(resolve, 2000)); + + expect(events[0].name).toBe('start'); + expect(events[events.length - 1].name).toBe('stop'); + const tokenEvents = events.filter((e) => e.name === 'token'); + expect(tokenEvents.length).toBeGreaterThan(0); + const responseIds = new Set(events.map((e) => e.responseId)); + expect(responseIds.size).toBe(1); + expect(responseIds.values().next().value).toBeTruthy(); + }); + + it('subscriber reconstructs the full response from token events', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); + const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); + const responsePromise = subscribe(subChannel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Hello world'); + const fullResponse = await responsePromise; + expect(fullResponse.length).toBeGreaterThan(0); + expect(fullResponse.toLowerCase()).toContain('hello'); + }); + + it('token data concatenates to match the complete response', async () => { + const channel = subscriberClient.channels.get(channelName + '-concat'); + const pubChannel = publisherClient.channels.get(channelName + '-concat'); + const tokens: string[] = []; + await channel.subscribe('token', (message: Ably.Message) => { + tokens.push(message.data as string); + }); + const responsePromise = subscribe(channel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Test'); + const fullResponse = await responsePromise; + const concatenated = tokens.join(''); + expect(concatenated).toBe(fullResponse); + }); +}); diff --git a/guides/ai-transport/lang-graph-message-per-token/tsconfig.json b/guides/ai-transport/lang-graph-message-per-token/tsconfig.json new file mode 100644 index 0000000000..13b3dd7d6b --- /dev/null +++ b/guides/ai-transport/lang-graph-message-per-token/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/openai-message-per-response/package.json b/guides/ai-transport/openai-message-per-response/package.json new file mode 100644 index 0000000000..2b741fd2ce --- /dev/null +++ b/guides/ai-transport/openai-message-per-response/package.json @@ -0,0 +1,14 @@ +{ + "name": "guide-openai-message-per-response", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:publisher": "tsx src/publisher.ts", + "start:subscriber": "tsx src/subscriber.ts", + "test": "vitest run" + }, + "dependencies": { + "openai": "^4" + } +} diff --git a/guides/ai-transport/openai-message-per-response/src/publisher.ts b/guides/ai-transport/openai-message-per-response/src/publisher.ts new file mode 100644 index 0000000000..9d9d91604d --- /dev/null +++ b/guides/ai-transport/openai-message-per-response/src/publisher.ts @@ -0,0 +1,52 @@ +import OpenAI from 'openai'; +import Ably from 'ably'; + +export async function publish(channel: Ably.RealtimeChannel, prompt: string) { + const openai = new OpenAI(); + let msgSerial: string | null = null; + let messageItemId: string | null = null; + + const stream = await openai.responses.create({ + model: 'gpt-4o-mini', + input: prompt, + stream: true, + }); + + for await (const event of stream) { + switch (event.type) { + case 'response.created': { + const result = await channel.publish({ name: 'response', data: '' }); + msgSerial = result.serials[0]; + break; + } + + case 'response.output_item.added': + if (event.item.type === 'message') { + messageItemId = event.item.id; + } + break; + + case 'response.output_text.delta': + if (event.item_id === messageItemId && msgSerial) { + channel.appendMessage({ serial: msgSerial, data: event.delta }); + } + break; + + case 'response.completed': + break; + } + } +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('ai:openai-mpr-guide'); + await publish(channel, 'Tell me a short joke'); + console.log('Done streaming. Closing connection...'); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/openai-message-per-response/src/subscriber.ts b/guides/ai-transport/openai-message-per-response/src/subscriber.ts new file mode 100644 index 0000000000..4e91c9d02f --- /dev/null +++ b/guides/ai-transport/openai-message-per-response/src/subscriber.ts @@ -0,0 +1,61 @@ +import Ably from 'ably'; + +// Subscribe to a channel and reconstruct streamed responses using message actions. +// Returns a promise that resolves with the full response text when no new appends +// arrive for 2 seconds (indicating the stream is complete). +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + const responses = new Map(); + let lastSerial: string | null = null; + let doneTimer: ReturnType | null = null; + + const resetTimer = () => { + if (doneTimer) clearTimeout(doneTimer); + doneTimer = setTimeout(() => { + if (lastSerial) { + const finalText = responses.get(lastSerial) || ''; + resolve(finalText); + } + }, 3000); + }; + + channel.subscribe((message: Ably.Message) => { + switch (message.action) { + case 'message.create': + console.log('\n[Response started]', message.serial); + responses.set(message.serial, message.data as string); + lastSerial = message.serial; + resetTimer(); + break; + + case 'message.append': { + const current = responses.get(message.serial) || ''; + responses.set(message.serial, current + (message.data as string)); + process.stdout.write(message.data as string); + resetTimer(); + break; + } + + case 'message.update': + responses.set(message.serial, message.data as string); + console.log('\n[Response updated with full content]'); + resetTimer(); + break; + } + }); + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('ai:openai-mpr-guide'); + console.log('Subscriber ready, waiting for tokens...'); + const response = await subscribe(channel); + console.log('\nFull response:', response); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/openai-message-per-response/test/e2e.test.ts b/guides/ai-transport/openai-message-per-response/test/e2e.test.ts new file mode 100644 index 0000000000..e63bc9a462 --- /dev/null +++ b/guides/ai-transport/openai-message-per-response/test/e2e.test.ts @@ -0,0 +1,76 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { publish } from '../src/publisher.js'; +import { subscribe } from '../src/subscriber.js'; + +describe('openai-message-per-response', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `ai:test-openai-mpr-${Date.now()}`; + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes initial message and appends tokens', async () => { + const channel = subscriberClient.channels.get(channelName + '-actions'); + const pubChannel = publisherClient.channels.get(channelName + '-actions'); + const actions: { action: string; data?: string; serial?: string }[] = []; + + await channel.subscribe((message: Ably.Message) => { + actions.push({ + action: message.action!, + data: message.data as string | undefined, + serial: message.serial, + }); + }); + + await publish(pubChannel, 'Reply with exactly: OK'); + await new Promise((resolve) => setTimeout(resolve, 3000)); + + expect(actions[0].action).toBe('message.create'); + const appendActions = actions.filter((a) => a.action === 'message.append'); + expect(appendActions.length).toBeGreaterThan(0); + // All actions should share the same serial + const serials = new Set(actions.map((a) => a.serial)); + expect(serials.size).toBe(1); + }); + + it('subscriber reconstructs the full response from append actions', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); + const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); + const responsePromise = subscribe(subChannel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Hello world'); + const fullResponse = await responsePromise; + expect(fullResponse.length).toBeGreaterThan(0); + expect(fullResponse.toLowerCase()).toContain('hello'); + }); + + it('appended tokens concatenate to match the full response', async () => { + const channel = subscriberClient.channels.get(channelName + '-concat'); + const pubChannel = publisherClient.channels.get(channelName + '-concat'); + const appendedTokens: string[] = []; + + await channel.subscribe((message: Ably.Message) => { + if (message.action === 'message.append') { + appendedTokens.push(message.data as string); + } + }); + + const responsePromise = subscribe(channel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Test'); + const fullResponse = await responsePromise; + const concatenated = appendedTokens.join(''); + expect(concatenated).toBe(fullResponse); + }); +}); diff --git a/guides/ai-transport/openai-message-per-response/tsconfig.json b/guides/ai-transport/openai-message-per-response/tsconfig.json new file mode 100644 index 0000000000..13b3dd7d6b --- /dev/null +++ b/guides/ai-transport/openai-message-per-response/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/openai-message-per-token/package.json b/guides/ai-transport/openai-message-per-token/package.json new file mode 100644 index 0000000000..37b29bff0e --- /dev/null +++ b/guides/ai-transport/openai-message-per-token/package.json @@ -0,0 +1,14 @@ +{ + "name": "guide-openai-message-per-token", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:publisher": "tsx src/publisher.ts", + "start:subscriber": "tsx src/subscriber.ts", + "test": "vitest run" + }, + "dependencies": { + "openai": "^4" + } +} diff --git a/guides/ai-transport/openai-message-per-token/src/publisher.ts b/guides/ai-transport/openai-message-per-token/src/publisher.ts new file mode 100644 index 0000000000..5f3d10fe75 --- /dev/null +++ b/guides/ai-transport/openai-message-per-token/src/publisher.ts @@ -0,0 +1,87 @@ +import OpenAI from 'openai'; +import Ably from 'ably'; +import 'dotenv/config'; + +// Process each streaming event and publish to Ably. +// Returns a promise for the 'stop' event so the caller can await it. +async function processEvent( + event: OpenAI.Responses.ResponseStreamEvent, + channel: Ably.RealtimeChannel, + state: { responseId: string | null; messageItemId: string | null }, +) { + switch (event.type) { + case 'response.created': + state.responseId = event.response.id; + channel.publish({ + name: 'start', + extras: { + headers: { responseId: state.responseId }, + }, + }); + break; + + case 'response.output_item.added': + if (event.item.type === 'message') { + state.messageItemId = event.item.id; + } + break; + + case 'response.output_text.delta': + if (event.item_id === state.messageItemId) { + channel.publish({ + name: 'token', + data: event.delta, + extras: { + headers: { responseId: state.responseId }, + }, + }); + } + break; + + case 'response.completed': + // Await the final publish so all messages are flushed before returning + await channel.publish({ + name: 'stop', + extras: { + headers: { responseId: state.responseId }, + }, + }); + break; + } +} + +// Stream a response from OpenAI and publish tokens to Ably +export async function publish(channel: Ably.RealtimeChannel, prompt: string) { + const openai = new OpenAI(); + const state = { responseId: null as string | null, messageItemId: null as string | null }; + + const stream = await openai.responses.create({ + model: 'gpt-4o-mini', + input: prompt, + stream: true, + }); + + for await (const event of stream) { + await processEvent(event, channel, state); + } +} + +// Run as a standalone script +async function main() { + const realtime = new Ably.Realtime({ + key: process.env.ABLY_API_KEY, + echoMessages: false, + }); + + const channel = realtime.channels.get('openai-mpt-guide'); + + await publish(channel, 'Tell me a short joke'); + + console.log('Done streaming. Closing connection...'); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/openai-message-per-token/src/subscriber.ts b/guides/ai-transport/openai-message-per-token/src/subscriber.ts new file mode 100644 index 0000000000..4d19ef17d9 --- /dev/null +++ b/guides/ai-transport/openai-message-per-token/src/subscriber.ts @@ -0,0 +1,53 @@ +import Ably from 'ably'; +import 'dotenv/config'; + +// Subscribe to a channel and reconstruct streamed responses. +// Returns a promise that resolves with the full response text when a stop event is received. +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + const responses = new Map(); + + channel.subscribe('start', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + console.log('\n[Response started]', responseId); + responses.set(responseId, ''); + }); + + channel.subscribe('token', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + const token = message.data as string; + + const currentText = responses.get(responseId) || ''; + responses.set(responseId, currentText + token); + + process.stdout.write(token); + }); + + channel.subscribe('stop', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + const finalText = responses.get(responseId) || ''; + console.log('\n[Response completed]', responseId); + resolve(finalText); + }); + }); +} + +// Run as a standalone script +async function main() { + const realtime = new Ably.Realtime({ + key: process.env.ABLY_API_KEY, + }); + + const channel = realtime.channels.get('openai-mpt-guide'); + + console.log('Subscriber ready, waiting for tokens...'); + const response = await subscribe(channel); + console.log('\nFull response:', response); + + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/openai-message-per-token/test/e2e.test.ts b/guides/ai-transport/openai-message-per-token/test/e2e.test.ts new file mode 100644 index 0000000000..286046426d --- /dev/null +++ b/guides/ai-transport/openai-message-per-token/test/e2e.test.ts @@ -0,0 +1,105 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { publish } from '../src/publisher.js'; +import { subscribe } from '../src/subscriber.js'; + +describe('openai-message-per-token', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `test-openai-mpt-${Date.now()}`; + + publisherClient = new Ably.Realtime({ + key: process.env.ABLY_API_KEY, + echoMessages: false, + }); + + subscriberClient = new Ably.Realtime({ + key: process.env.ABLY_API_KEY, + }); + }); + + afterAll(async () => { + // Allow pending publishes to flush before closing + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes start, token, and stop events in order', async () => { + const channel = subscriberClient.channels.get(channelName + '-lifecycle'); + const pubChannel = publisherClient.channels.get(channelName + '-lifecycle'); + + const events: { name: string; data?: string; responseId?: string }[] = []; + + await channel.subscribe((message: Ably.Message) => { + events.push({ + name: message.name!, + data: message.data as string | undefined, + responseId: message.extras?.headers?.responseId, + }); + }); + + await publish(pubChannel, 'Reply with exactly: OK'); + + // Wait for events to propagate + await new Promise((resolve) => setTimeout(resolve, 2000)); + + // First event must be 'start' + expect(events[0].name).toBe('start'); + + // Last event must be 'stop' + expect(events[events.length - 1].name).toBe('stop'); + + // Middle events must all be 'token' + const tokenEvents = events.filter((e) => e.name === 'token'); + expect(tokenEvents.length).toBeGreaterThan(0); + + // All events must share the same responseId + const responseIds = new Set(events.map((e) => e.responseId)); + expect(responseIds.size).toBe(1); + expect(responseIds.values().next().value).toBeTruthy(); + }); + + it('subscriber reconstructs the full response from token events', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); + const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); + + const responsePromise = subscribe(subChannel); + + // Ensure subscriber is attached before publishing + await new Promise((resolve) => setTimeout(resolve, 1000)); + + await publish(pubChannel, 'Reply with exactly: Hello world'); + + const fullResponse = await responsePromise; + + expect(fullResponse.length).toBeGreaterThan(0); + expect(fullResponse.toLowerCase()).toContain('hello'); + }); + + it('token data concatenates to match the complete response', async () => { + const channel = subscriberClient.channels.get(channelName + '-concat'); + const pubChannel = publisherClient.channels.get(channelName + '-concat'); + + const tokens: string[] = []; + + await channel.subscribe('token', (message: Ably.Message) => { + tokens.push(message.data as string); + }); + + const responsePromise = subscribe(channel); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + + await publish(pubChannel, 'Reply with exactly: Test'); + + const fullResponse = await responsePromise; + + // Concatenated tokens should equal the subscriber's reconstructed response + const concatenated = tokens.join(''); + expect(concatenated).toBe(fullResponse); + }); +}); diff --git a/guides/ai-transport/openai-message-per-token/tsconfig.json b/guides/ai-transport/openai-message-per-token/tsconfig.json new file mode 100644 index 0000000000..13b3dd7d6b --- /dev/null +++ b/guides/ai-transport/openai-message-per-token/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/package.json b/guides/ai-transport/package.json new file mode 100644 index 0000000000..8c7ebf44d2 --- /dev/null +++ b/guides/ai-transport/package.json @@ -0,0 +1,32 @@ +{ + "name": "ai-transport-guides", + "version": "0.1.0", + "private": true, + "type": "module", + "engines": { + "node": ">=20.0.0" + }, + "workspaces": [ + "openai-message-per-token", + "openai-message-per-response", + "anthropic-message-per-token", + "anthropic-message-per-response", + "vercel-message-per-token", + "vercel-message-per-response", + "lang-graph-message-per-token", + "lang-graph-message-per-response" + ], + "scripts": { + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "ably": "^2.17.0", + "dotenv": "^16.4.5" + }, + "devDependencies": { + "tsx": "^4.19.0", + "typescript": "^5", + "vitest": "^3.0.0" + } +} diff --git a/guides/ai-transport/tsconfig.base.json b/guides/ai-transport/tsconfig.base.json new file mode 100644 index 0000000000..10dc38349c --- /dev/null +++ b/guides/ai-transport/tsconfig.base.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "isolatedModules": true, + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + } +} diff --git a/guides/ai-transport/vercel-message-per-response/package.json b/guides/ai-transport/vercel-message-per-response/package.json new file mode 100644 index 0000000000..9f4184b334 --- /dev/null +++ b/guides/ai-transport/vercel-message-per-response/package.json @@ -0,0 +1,15 @@ +{ + "name": "guide-vercel-message-per-response", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:publisher": "tsx src/publisher.ts", + "start:subscriber": "tsx src/subscriber.ts", + "test": "vitest run" + }, + "dependencies": { + "ai": "^6", + "@ai-sdk/openai": "^2" + } +} diff --git a/guides/ai-transport/vercel-message-per-response/src/publisher.ts b/guides/ai-transport/vercel-message-per-response/src/publisher.ts new file mode 100644 index 0000000000..79dd60b720 --- /dev/null +++ b/guides/ai-transport/vercel-message-per-response/src/publisher.ts @@ -0,0 +1,44 @@ +import { streamText } from 'ai'; +import { openai } from '@ai-sdk/openai'; +import Ably from 'ably'; + +export async function publish(channel: Ably.RealtimeChannel, prompt: string) { + let msgSerial: string | null = null; + + const result = streamText({ + model: openai('gpt-4o-mini'), + prompt, + }); + + for await (const event of result.fullStream) { + switch (event.type) { + case 'text-start': { + const publishResult = await channel.publish({ name: 'response', data: '' }); + msgSerial = publishResult.serials[0]; + break; + } + + case 'text-delta': + if (msgSerial) { + channel.appendMessage({ serial: msgSerial, data: (event as any).text }); + } + break; + + case 'text-end': + break; + } + } +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('ai:vercel-mpr-guide'); + await publish(channel, 'Tell me a short joke'); + console.log('Done streaming. Closing connection...'); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/vercel-message-per-response/src/subscriber.ts b/guides/ai-transport/vercel-message-per-response/src/subscriber.ts new file mode 100644 index 0000000000..7fa402d9ae --- /dev/null +++ b/guides/ai-transport/vercel-message-per-response/src/subscriber.ts @@ -0,0 +1,61 @@ +import Ably from 'ably'; + +// Subscribe to a channel and reconstruct streamed responses using message actions. +// Returns a promise that resolves with the full response text when no new appends +// arrive for 2 seconds (indicating the stream is complete). +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + const responses = new Map(); + let lastSerial: string | null = null; + let doneTimer: ReturnType | null = null; + + const resetTimer = () => { + if (doneTimer) clearTimeout(doneTimer); + doneTimer = setTimeout(() => { + if (lastSerial) { + const finalText = responses.get(lastSerial) || ''; + resolve(finalText); + } + }, 3000); + }; + + channel.subscribe((message: Ably.Message) => { + switch (message.action) { + case 'message.create': + console.log('\n[Response started]', message.serial); + responses.set(message.serial, message.data as string); + lastSerial = message.serial; + resetTimer(); + break; + + case 'message.append': { + const current = responses.get(message.serial) || ''; + responses.set(message.serial, current + (message.data as string)); + process.stdout.write(message.data as string); + resetTimer(); + break; + } + + case 'message.update': + responses.set(message.serial, message.data as string); + console.log('\n[Response updated with full content]'); + resetTimer(); + break; + } + }); + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('ai:vercel-mpr-guide'); + console.log('Subscriber ready, waiting for tokens...'); + const response = await subscribe(channel); + console.log('\nFull response:', response); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/vercel-message-per-response/test/e2e.test.ts b/guides/ai-transport/vercel-message-per-response/test/e2e.test.ts new file mode 100644 index 0000000000..78fe8d1b32 --- /dev/null +++ b/guides/ai-transport/vercel-message-per-response/test/e2e.test.ts @@ -0,0 +1,76 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { publish } from '../src/publisher.js'; +import { subscribe } from '../src/subscriber.js'; + +describe('vercel-message-per-response', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `ai:test-vercel-mpr-${Date.now()}`; + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes initial message and appends tokens', async () => { + const channel = subscriberClient.channels.get(channelName + '-actions'); + const pubChannel = publisherClient.channels.get(channelName + '-actions'); + const actions: { action: string; data?: string; serial?: string }[] = []; + + await channel.subscribe((message: Ably.Message) => { + actions.push({ + action: message.action!, + data: message.data as string | undefined, + serial: message.serial, + }); + }); + + await publish(pubChannel, 'Reply with exactly: OK'); + await new Promise((resolve) => setTimeout(resolve, 3000)); + + expect(actions[0].action).toBe('message.create'); + const appendActions = actions.filter((a) => a.action === 'message.append'); + expect(appendActions.length).toBeGreaterThan(0); + // All actions should share the same serial + const serials = new Set(actions.map((a) => a.serial)); + expect(serials.size).toBe(1); + }); + + it('subscriber reconstructs the full response from append actions', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); + const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); + const responsePromise = subscribe(subChannel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Hello world'); + const fullResponse = await responsePromise; + expect(fullResponse.length).toBeGreaterThan(0); + expect(fullResponse.toLowerCase()).toContain('hello'); + }); + + it('appended tokens concatenate to match the full response', async () => { + const channel = subscriberClient.channels.get(channelName + '-concat'); + const pubChannel = publisherClient.channels.get(channelName + '-concat'); + const appendedTokens: string[] = []; + + await channel.subscribe((message: Ably.Message) => { + if (message.action === 'message.append') { + appendedTokens.push(message.data as string); + } + }); + + const responsePromise = subscribe(channel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Test'); + const fullResponse = await responsePromise; + const concatenated = appendedTokens.join(''); + expect(concatenated).toBe(fullResponse); + }); +}); diff --git a/guides/ai-transport/vercel-message-per-response/tsconfig.json b/guides/ai-transport/vercel-message-per-response/tsconfig.json new file mode 100644 index 0000000000..13b3dd7d6b --- /dev/null +++ b/guides/ai-transport/vercel-message-per-response/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/vercel-message-per-token/package.json b/guides/ai-transport/vercel-message-per-token/package.json new file mode 100644 index 0000000000..9bd0df936a --- /dev/null +++ b/guides/ai-transport/vercel-message-per-token/package.json @@ -0,0 +1,15 @@ +{ + "name": "guide-vercel-message-per-token", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:publisher": "tsx src/publisher.ts", + "start:subscriber": "tsx src/subscriber.ts", + "test": "vitest run" + }, + "dependencies": { + "ai": "^6", + "@ai-sdk/openai": "^2" + } +} diff --git a/guides/ai-transport/vercel-message-per-token/src/publisher.ts b/guides/ai-transport/vercel-message-per-token/src/publisher.ts new file mode 100644 index 0000000000..b96a0644c3 --- /dev/null +++ b/guides/ai-transport/vercel-message-per-token/src/publisher.ts @@ -0,0 +1,60 @@ +import { streamText } from 'ai'; +import { openai } from '@ai-sdk/openai'; +import Ably from 'ably'; + +async function processEvent( + event: { type: string; id?: string; text?: string }, + channel: Ably.RealtimeChannel, + state: { responseId: string | null }, +) { + switch (event.type) { + case 'text-start': + state.responseId = event.id || null; + channel.publish({ + name: 'start', + extras: { headers: { responseId: state.responseId } }, + }); + break; + + case 'text-delta': + channel.publish({ + name: 'token', + data: event.text, + extras: { headers: { responseId: state.responseId } }, + }); + break; + + case 'text-end': + await channel.publish({ + name: 'stop', + extras: { headers: { responseId: state.responseId } }, + }); + break; + } +} + +export async function publish(channel: Ably.RealtimeChannel, prompt: string) { + const state = { responseId: null as string | null }; + + const result = streamText({ + model: openai('gpt-4o-mini'), + prompt, + }); + + for await (const event of result.fullStream) { + await processEvent(event as { type: string; id?: string; text?: string }, channel, state); + } +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('vercel-mpt-guide'); + await publish(channel, 'Tell me a short joke'); + console.log('Done streaming. Closing connection...'); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/vercel-message-per-token/src/subscriber.ts b/guides/ai-transport/vercel-message-per-token/src/subscriber.ts new file mode 100644 index 0000000000..07e6981332 --- /dev/null +++ b/guides/ai-transport/vercel-message-per-token/src/subscriber.ts @@ -0,0 +1,42 @@ +import Ably from 'ably'; + +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + const responses = new Map(); + + channel.subscribe('start', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + console.log('\n[Response started]', responseId); + responses.set(responseId, ''); + }); + + channel.subscribe('token', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + const token = message.data as string; + const currentText = responses.get(responseId) || ''; + responses.set(responseId, currentText + token); + process.stdout.write(token); + }); + + channel.subscribe('stop', (message: Ably.Message) => { + const responseId = message.extras?.headers?.responseId; + const finalText = responses.get(responseId) || ''; + console.log('\n[Response completed]', responseId); + resolve(finalText); + }); + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('vercel-mpt-guide'); + console.log('Subscriber ready, waiting for tokens...'); + const response = await subscribe(channel); + console.log('\nFull response:', response); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/vercel-message-per-token/test/e2e.test.ts b/guides/ai-transport/vercel-message-per-token/test/e2e.test.ts new file mode 100644 index 0000000000..3c183ab76c --- /dev/null +++ b/guides/ai-transport/vercel-message-per-token/test/e2e.test.ts @@ -0,0 +1,73 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { publish } from '../src/publisher.js'; +import { subscribe } from '../src/subscriber.js'; + +describe('vercel-message-per-token', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `test-vercel-mpt-${Date.now()}`; + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes start, token, and stop events in order', async () => { + const channel = subscriberClient.channels.get(channelName + '-lifecycle'); + const pubChannel = publisherClient.channels.get(channelName + '-lifecycle'); + const events: { name: string; data?: string; responseId?: string }[] = []; + + await channel.subscribe((message: Ably.Message) => { + events.push({ + name: message.name!, + data: message.data as string | undefined, + responseId: message.extras?.headers?.responseId, + }); + }); + + await publish(pubChannel, 'Reply with exactly: OK'); + await new Promise((resolve) => setTimeout(resolve, 2000)); + + expect(events[0].name).toBe('start'); + expect(events[events.length - 1].name).toBe('stop'); + const tokenEvents = events.filter((e) => e.name === 'token'); + expect(tokenEvents.length).toBeGreaterThan(0); + const responseIds = new Set(events.map((e) => e.responseId)); + expect(responseIds.size).toBe(1); + expect(responseIds.values().next().value).toBeTruthy(); + }); + + it('subscriber reconstructs the full response from token events', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); + const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); + const responsePromise = subscribe(subChannel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Hello world'); + const fullResponse = await responsePromise; + expect(fullResponse.length).toBeGreaterThan(0); + expect(fullResponse.toLowerCase()).toContain('hello'); + }); + + it('token data concatenates to match the complete response', async () => { + const channel = subscriberClient.channels.get(channelName + '-concat'); + const pubChannel = publisherClient.channels.get(channelName + '-concat'); + const tokens: string[] = []; + await channel.subscribe('token', (message: Ably.Message) => { + tokens.push(message.data as string); + }); + const responsePromise = subscribe(channel); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await publish(pubChannel, 'Reply with exactly: Test'); + const fullResponse = await responsePromise; + const concatenated = tokens.join(''); + expect(concatenated).toBe(fullResponse); + }); +}); diff --git a/guides/ai-transport/vercel-message-per-token/tsconfig.json b/guides/ai-transport/vercel-message-per-token/tsconfig.json new file mode 100644 index 0000000000..13b3dd7d6b --- /dev/null +++ b/guides/ai-transport/vercel-message-per-token/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/vitest.config.ts b/guides/ai-transport/vitest.config.ts new file mode 100644 index 0000000000..993de2d259 --- /dev/null +++ b/guides/ai-transport/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + testTimeout: 30_000, + include: ['*/test/**/*.test.ts'], + setupFiles: ['./vitest.setup.ts'], + }, +}); diff --git a/guides/ai-transport/vitest.setup.ts b/guides/ai-transport/vitest.setup.ts new file mode 100644 index 0000000000..3c83d9f599 --- /dev/null +++ b/guides/ai-transport/vitest.setup.ts @@ -0,0 +1,2 @@ +import dotenv from 'dotenv'; +dotenv.config(); diff --git a/guides/ai-transport/yarn.lock b/guides/ai-transport/yarn.lock new file mode 100644 index 0000000000..0d5aeb63e9 --- /dev/null +++ b/guides/ai-transport/yarn.lock @@ -0,0 +1,1556 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ably/msgpack-js@^0.4.0": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@ably/msgpack-js/-/msgpack-js-0.4.1.tgz#81526bdea5362ca57c112356899a5e506a34b760" + integrity sha512-Sjxj6SOr17hExAVrsycN7u6oV4PhZcK7Z2S8dM71CH/butgO47cSo/TL6FJPCXUyDAzKkOWjMUpJGyZkEpyu4Q== + dependencies: + bops "^1.0.1" + +"@ai-sdk/gateway@3.0.46": + version "3.0.46" + resolved "https://registry.yarnpkg.com/@ai-sdk/gateway/-/gateway-3.0.46.tgz#e329bebbf66cfc16f2a5c616a40d45e9232a2d72" + integrity sha512-zH1UbNRjG5woOXXFOrVCZraqZuFTtmPvLardMGcgLkzpxKV0U3tAGoyWKSZ862H+eBJfI/Hf2yj/zzGJcCkycg== + dependencies: + "@ai-sdk/provider" "3.0.8" + "@ai-sdk/provider-utils" "4.0.15" + "@vercel/oidc" "3.1.0" + +"@ai-sdk/openai@^2": + version "2.0.91" + resolved "https://registry.yarnpkg.com/@ai-sdk/openai/-/openai-2.0.91.tgz#1c615ee29db62355be261c2da324b5a85169798f" + integrity sha512-lozfRHfSTHg5/UliQjTDcOtISYGbEpt4FS/6QM5PcLmhdT0HmROllaBmG7+JaK+uqFtDXZGgMIpz3bqB9nzqCQ== + dependencies: + "@ai-sdk/provider" "2.0.1" + "@ai-sdk/provider-utils" "3.0.21" + +"@ai-sdk/provider-utils@3.0.21": + version "3.0.21" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider-utils/-/provider-utils-3.0.21.tgz#b98175079d2787f0dda7027d74482f4ae1acfbc8" + integrity sha512-veuMwTLxsgh31Jjn0SnBABnM1f7ebHhRWcV2ZuY3hP3iJDCZ8VXBaYqcHXoOQDqUXTCas08sKQcHyWK+zl882Q== + dependencies: + "@ai-sdk/provider" "2.0.1" + "@standard-schema/spec" "^1.0.0" + eventsource-parser "^3.0.6" + +"@ai-sdk/provider-utils@4.0.15": + version "4.0.15" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider-utils/-/provider-utils-4.0.15.tgz#d585c7c89cfdf13697a40be5768ecd907a251585" + integrity sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w== + dependencies: + "@ai-sdk/provider" "3.0.8" + "@standard-schema/spec" "^1.1.0" + eventsource-parser "^3.0.6" + +"@ai-sdk/provider@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider/-/provider-2.0.1.tgz#4aba415f1815da33a7a81e5f41a0219af53278c0" + integrity sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng== + dependencies: + json-schema "^0.4.0" + +"@ai-sdk/provider@3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider/-/provider-3.0.8.tgz#fd7fac7533c03534ac1d3fb710a6b96e2aa00263" + integrity sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ== + dependencies: + json-schema "^0.4.0" + +"@anthropic-ai/sdk@^0.65.0": + version "0.65.0" + resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.65.0.tgz#3f464fe2029eacf8e7e7fb8197579d00c8ca7502" + integrity sha512-zIdPOcrCVEI8t3Di40nH4z9EoeyGZfXbYSvWdDLsB/KkaSYMnEgC7gmcgWu83g2NTn1ZTpbMvpdttWDGGIk6zw== + dependencies: + json-schema-to-ts "^3.1.1" + +"@anthropic-ai/sdk@^0.71": + version "0.71.2" + resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.71.2.tgz#1e3e08a7b2c3129828480a3d0ca4487472fdde3d" + integrity sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ== + dependencies: + json-schema-to-ts "^3.1.1" + +"@babel/runtime@^7.18.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b" + integrity sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA== + +"@cfworker/json-schema@^4.0.2": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@cfworker/json-schema/-/json-schema-4.1.1.tgz#4a2a3947ee9fa7b7c24be981422831b8674c3be6" + integrity sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og== + +"@esbuild/aix-ppc64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz#815b39267f9bffd3407ea6c376ac32946e24f8d2" + integrity sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg== + +"@esbuild/android-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz#19b882408829ad8e12b10aff2840711b2da361e8" + integrity sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg== + +"@esbuild/android-arm@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.3.tgz#90be58de27915efa27b767fcbdb37a4470627d7b" + integrity sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA== + +"@esbuild/android-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.3.tgz#d7dcc976f16e01a9aaa2f9b938fbec7389f895ac" + integrity sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ== + +"@esbuild/darwin-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz#9f6cac72b3a8532298a6a4493ed639a8988e8abd" + integrity sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg== + +"@esbuild/darwin-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz#ac61d645faa37fd650340f1866b0812e1fb14d6a" + integrity sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg== + +"@esbuild/freebsd-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz#b8625689d73cf1830fe58c39051acdc12474ea1b" + integrity sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w== + +"@esbuild/freebsd-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz#07be7dd3c9d42fe0eccd2ab9f9ded780bc53bead" + integrity sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA== + +"@esbuild/linux-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz#bf31918fe5c798586460d2b3d6c46ed2c01ca0b6" + integrity sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg== + +"@esbuild/linux-arm@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz#28493ee46abec1dc3f500223cd9f8d2df08f9d11" + integrity sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw== + +"@esbuild/linux-ia32@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz#750752a8b30b43647402561eea764d0a41d0ee29" + integrity sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg== + +"@esbuild/linux-loong64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz#a5a92813a04e71198c50f05adfaf18fc1e95b9ed" + integrity sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA== + +"@esbuild/linux-mips64el@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz#deb45d7fd2d2161eadf1fbc593637ed766d50bb1" + integrity sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw== + +"@esbuild/linux-ppc64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz#6f39ae0b8c4d3d2d61a65b26df79f6e12a1c3d78" + integrity sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA== + +"@esbuild/linux-riscv64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz#4c5c19c3916612ec8e3915187030b9df0b955c1d" + integrity sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ== + +"@esbuild/linux-s390x@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz#9ed17b3198fa08ad5ccaa9e74f6c0aff7ad0156d" + integrity sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw== + +"@esbuild/linux-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz#12383dcbf71b7cf6513e58b4b08d95a710bf52a5" + integrity sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA== + +"@esbuild/netbsd-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz#dd0cb2fa543205fcd931df44f4786bfcce6df7d7" + integrity sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA== + +"@esbuild/netbsd-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz#028ad1807a8e03e155153b2d025b506c3787354b" + integrity sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA== + +"@esbuild/openbsd-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz#e3c16ff3490c9b59b969fffca87f350ffc0e2af5" + integrity sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw== + +"@esbuild/openbsd-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz#c5a4693fcb03d1cbecbf8b422422468dfc0d2a8b" + integrity sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ== + +"@esbuild/openharmony-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz#082082444f12db564a0775a41e1991c0e125055e" + integrity sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g== + +"@esbuild/sunos-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz#5ab036c53f929e8405c4e96e865a424160a1b537" + integrity sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA== + +"@esbuild/win32-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz#38de700ef4b960a0045370c171794526e589862e" + integrity sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA== + +"@esbuild/win32-ia32@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz#451b93dc03ec5d4f38619e6cd64d9f9eff06f55c" + integrity sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q== + +"@esbuild/win32-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz#0eaf705c941a218a43dba8e09f1df1d6cd2f1f17" + integrity sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA== + +"@jridgewell/sourcemap-codec@^1.5.5": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@langchain/anthropic@^0.3": + version "0.3.34" + resolved "https://registry.yarnpkg.com/@langchain/anthropic/-/anthropic-0.3.34.tgz#ff131b9b612a76d7e97d960058efe3f0ccad8179" + integrity sha512-8bOW1A2VHRCjbzdYElrjxutKNs9NSIxYRGtR+OJWVzluMqoKKh2NmmFrpPizEyqCUEG2tTq5xt6XA1lwfqMJRA== + dependencies: + "@anthropic-ai/sdk" "^0.65.0" + fast-xml-parser "^4.4.1" + +"@langchain/core@^0.3": + version "0.3.80" + resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.80.tgz#c494a6944e53ab28bf32dc531e257b17cfc8f797" + integrity sha512-vcJDV2vk1AlCwSh3aBm/urQ1ZrlXFFBocv11bz/NBUfLWD5/UDNMzwPdaAd2dKvNmTWa9FM2lirLU3+JCf4cRA== + dependencies: + "@cfworker/json-schema" "^4.0.2" + ansi-styles "^5.0.0" + camelcase "6" + decamelize "1.2.0" + js-tiktoken "^1.0.12" + langsmith "^0.3.67" + mustache "^4.2.0" + p-queue "^6.6.2" + p-retry "4" + uuid "^10.0.0" + zod "^3.25.32" + zod-to-json-schema "^3.22.3" + +"@langchain/langgraph-checkpoint@~0.0.17": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.18.tgz#2f7a9cdeda948ccc8d312ba9463810709d71d0b8" + integrity sha512-IS7zJj36VgY+4pf8ZjsVuUWef7oTwt1y9ylvwu0aLuOn1d0fg05Om9DLm3v2GZ2Df6bhLV1kfWAM0IAl9O5rQQ== + dependencies: + uuid "^10.0.0" + +"@langchain/langgraph-sdk@~0.0.32": + version "0.0.112" + resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.112.tgz#3186919b60e3381aa8aa32ea9b9c39df1f02a9fd" + integrity sha512-/9W5HSWCqYgwma6EoOspL4BGYxGxeJP6lIquPSF4FA0JlKopaUv58ucZC3vAgdJyCgg6sorCIV/qg7SGpEcCLw== + dependencies: + "@types/json-schema" "^7.0.15" + p-queue "^6.6.2" + p-retry "4" + uuid "^9.0.0" + +"@langchain/langgraph@^0.2": + version "0.2.74" + resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.74.tgz#37367a1e8bafda3548037a91449a69a84f285def" + integrity sha512-oHpEi5sTZTPaeZX1UnzfM2OAJ21QGQrwReTV6+QnX7h8nDCBzhtipAw1cK616S+X8zpcVOjgOtJuaJhXa4mN8w== + dependencies: + "@langchain/langgraph-checkpoint" "~0.0.17" + "@langchain/langgraph-sdk" "~0.0.32" + uuid "^10.0.0" + zod "^3.23.8" + +"@opentelemetry/api@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" + integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== + +"@rollup/rollup-android-arm-eabi@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz#add5e608d4e7be55bc3ca3d962490b8b1890e088" + integrity sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg== + +"@rollup/rollup-android-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz#10bd0382b73592beee6e9800a69401a29da625c4" + integrity sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w== + +"@rollup/rollup-darwin-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz#1e99ab04c0b8c619dd7bbde725ba2b87b55bfd81" + integrity sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg== + +"@rollup/rollup-darwin-x64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz#69e741aeb2839d2e8f0da2ce7a33d8bd23632423" + integrity sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w== + +"@rollup/rollup-freebsd-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz#3736c232a999c7bef7131355d83ebdf9651a0839" + integrity sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug== + +"@rollup/rollup-freebsd-x64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz#227dcb8f466684070169942bd3998901c9bfc065" + integrity sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q== + +"@rollup/rollup-linux-arm-gnueabihf@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz#ba004b30df31b724f99ce66e7128248bea17cb0c" + integrity sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw== + +"@rollup/rollup-linux-arm-musleabihf@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz#6929f3e07be6b6da5991f63c6b68b3e473d0a65a" + integrity sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw== + +"@rollup/rollup-linux-arm64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz#06e89fd4a25d21fe5575d60b6f913c0e65297bfa" + integrity sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g== + +"@rollup/rollup-linux-arm64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz#fddabf395b90990d5194038e6cd8c00156ed8ac0" + integrity sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q== + +"@rollup/rollup-linux-loong64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz#04c10bb764bbf09a3c1bd90432e92f58d6603c36" + integrity sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA== + +"@rollup/rollup-linux-loong64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz#f2450361790de80581d8687ea19142d8a4de5c0f" + integrity sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw== + +"@rollup/rollup-linux-ppc64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz#0474f4667259e407eee1a6d38e29041b708f6a30" + integrity sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w== + +"@rollup/rollup-linux-ppc64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz#9f32074819eeb1ddbe51f50ea9dcd61a6745ec33" + integrity sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw== + +"@rollup/rollup-linux-riscv64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz#3fdb9d4b1e29fb6b6a6da9f15654d42eb77b99b2" + integrity sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A== + +"@rollup/rollup-linux-riscv64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz#1de780d64e6be0e3e8762035c22e0d8ea68df8ed" + integrity sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw== + +"@rollup/rollup-linux-s390x-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz#1da022ffd2d9e9f0fd8344ea49e113001fbcac64" + integrity sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg== + +"@rollup/rollup-linux-x64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz#78c16eef9520bd10e1ea7a112593bb58e2842622" + integrity sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg== + +"@rollup/rollup-linux-x64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz#a7598591b4d9af96cb3167b50a5bf1e02dfea06c" + integrity sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw== + +"@rollup/rollup-openbsd-x64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz#c51d48c07cd6c466560e5bed934aec688ce02614" + integrity sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw== + +"@rollup/rollup-openharmony-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz#f09921d0b2a0b60afbf3586d2a7a7f208ba6df17" + integrity sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ== + +"@rollup/rollup-win32-arm64-msvc@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz#08d491717135376e4a99529821c94ecd433d5b36" + integrity sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ== + +"@rollup/rollup-win32-ia32-msvc@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz#b0c12aac1104a8b8f26a5e0098e5facbb3e3964a" + integrity sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew== + +"@rollup/rollup-win32-x64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz#b9cccef26f5e6fdc013bf3c0911a3c77428509d0" + integrity sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ== + +"@rollup/rollup-win32-x64-msvc@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz#a03348e7b559c792b6277cc58874b89ef46e1e72" + integrity sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA== + +"@sindresorhus/is@^4.0.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + +"@standard-schema/spec@^1.0.0", "@standard-schema/spec@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" + integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== + +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + +"@types/cacheable-request@^6.0.1": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "^3.1.4" + "@types/node" "*" + "@types/responselike" "^1.0.0" + +"@types/chai@^5.2.2": + version "5.2.3" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.2.3.tgz#8e9cd9e1c3581fa6b341a5aed5588eb285be0b4a" + integrity sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA== + dependencies: + "@types/deep-eql" "*" + assertion-error "^2.0.1" + +"@types/deep-eql@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== + +"@types/estree@1.0.8", "@types/estree@^1.0.0": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/http-cache-semantics@*": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#f6a7788f438cbfde15f29acad46512b4c01913b3" + integrity sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== + dependencies: + "@types/node" "*" + +"@types/node-fetch@^2.6.4": + version "2.6.13" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.13.tgz#e0c9b7b5edbdb1b50ce32c127e85e880872d56ee" + integrity sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw== + dependencies: + "@types/node" "*" + form-data "^4.0.4" + +"@types/node@*": + version "25.2.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.2.3.tgz#9c18245be768bdb4ce631566c7da303a5c99a7f8" + integrity sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ== + dependencies: + undici-types "~7.16.0" + +"@types/node@^18.11.18": + version "18.19.130" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.130.tgz#da4c6324793a79defb7a62cba3947ec5add00d59" + integrity sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg== + dependencies: + undici-types "~5.26.4" + +"@types/responselike@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" + integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== + dependencies: + "@types/node" "*" + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/uuid@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-10.0.0.tgz#e9c07fe50da0f53dc24970cca94d619ff03f6f6d" + integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== + +"@vercel/oidc@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@vercel/oidc/-/oidc-3.1.0.tgz#066caee449b84079f33c7445fc862464fe10ec32" + integrity sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w== + +"@vitest/expect@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.2.4.tgz#8362124cd811a5ee11c5768207b9df53d34f2433" + integrity sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig== + dependencies: + "@types/chai" "^5.2.2" + "@vitest/spy" "3.2.4" + "@vitest/utils" "3.2.4" + chai "^5.2.0" + tinyrainbow "^2.0.0" + +"@vitest/mocker@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-3.2.4.tgz#4471c4efbd62db0d4fa203e65cc6b058a85cabd3" + integrity sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ== + dependencies: + "@vitest/spy" "3.2.4" + estree-walker "^3.0.3" + magic-string "^0.30.17" + +"@vitest/pretty-format@3.2.4", "@vitest/pretty-format@^3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-3.2.4.tgz#3c102f79e82b204a26c7a5921bf47d534919d3b4" + integrity sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA== + dependencies: + tinyrainbow "^2.0.0" + +"@vitest/runner@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-3.2.4.tgz#5ce0274f24a971f6500f6fc166d53d8382430766" + integrity sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ== + dependencies: + "@vitest/utils" "3.2.4" + pathe "^2.0.3" + strip-literal "^3.0.0" + +"@vitest/snapshot@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-3.2.4.tgz#40a8bc0346ac0aee923c0eefc2dc005d90bc987c" + integrity sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ== + dependencies: + "@vitest/pretty-format" "3.2.4" + magic-string "^0.30.17" + pathe "^2.0.3" + +"@vitest/spy@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-3.2.4.tgz#cc18f26f40f3f028da6620046881f4e4518c2599" + integrity sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw== + dependencies: + tinyspy "^4.0.3" + +"@vitest/utils@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-3.2.4.tgz#c0813bc42d99527fb8c5b138c7a88516bca46fea" + integrity sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA== + dependencies: + "@vitest/pretty-format" "3.2.4" + loupe "^3.1.4" + tinyrainbow "^2.0.0" + +ably@^2.17.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/ably/-/ably-2.17.1.tgz#7fe6877ba141ee70d8856523ec3a21d6716c1916" + integrity sha512-70yfXHoM7JtJD/8FCtPD1gkWW0f+AJqbJp0PsqDAqiyxFB8cPFY+FuKHgNTYb8eRHKXq8hT1xiDphUcY0+GHnA== + dependencies: + "@ably/msgpack-js" "^0.4.0" + dequal "^2.0.3" + fastestsmallesttextencoderdecoder "^1.0.22" + got "^11.8.5" + ulid "^2.3.0" + ws "^8.17.1" + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +agentkeepalive@^4.2.1: + version "4.6.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" + integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== + dependencies: + humanize-ms "^1.2.1" + +ai@^6: + version "6.0.86" + resolved "https://registry.yarnpkg.com/ai/-/ai-6.0.86.tgz#cee563e8a0d9b87f8fdda764f190e7dd3f81ba00" + integrity sha512-U2W2LBCHA/pr0Ui7vmmsjBiLEzBbZF3yVHNy7Rbzn7IX+SvoQPFM5rN74hhfVzZoE8zBuGD4nLLk+j0elGacvQ== + dependencies: + "@ai-sdk/gateway" "3.0.46" + "@ai-sdk/provider" "3.0.8" + "@ai-sdk/provider-utils" "4.0.15" + "@opentelemetry/api" "1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +base64-js@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.2.tgz#474211c95e6cf2a547db461e4f6778b51d08fa65" + integrity sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg== + +base64-js@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bops@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bops/-/bops-1.0.1.tgz#502aaf00ee119db1dbae088e3df4bea2e241dbcc" + integrity sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag== + dependencies: + base64-js "1.0.2" + to-utf8 "0.0.1" + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + +cacheable-request@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +camelcase@6: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +chai@^5.2.0: + version "5.3.3" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.3.3.tgz#dd3da955e270916a4bd3f625f4b919996ada7e06" + integrity sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" + +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-error@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.3.tgz#2427361117b70cca8dc89680ead32b157019caf5" + integrity sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA== + +clone-response@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== + dependencies: + mimic-response "^1.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +console-table-printer@^2.12.1: + version "2.15.0" + resolved "https://registry.yarnpkg.com/console-table-printer/-/console-table-printer-2.15.0.tgz#5c808204640b8f024d545bde8aabe5d344dfadc1" + integrity sha512-SrhBq4hYVjLCkBVOWaTzceJalvn5K1Zq5aQA6wXC/cYjI3frKWNPEMK3sZsJfNNQApvCQmgBcc13ZKmFj8qExw== + dependencies: + simple-wcswidth "^1.1.2" + +debug@^4.4.1: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +decamelize@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== + +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + +dotenv@^16.4.5: + version "16.6.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +end-of-stream@^1.1.0: + version "1.4.5" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== + dependencies: + once "^1.4.0" + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-module-lexer@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" + integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +esbuild@^0.27.0, esbuild@~0.27.0: + version "0.27.3" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.27.3.tgz#5859ca8e70a3af956b26895ce4954d7e73bd27a8" + integrity sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.27.3" + "@esbuild/android-arm" "0.27.3" + "@esbuild/android-arm64" "0.27.3" + "@esbuild/android-x64" "0.27.3" + "@esbuild/darwin-arm64" "0.27.3" + "@esbuild/darwin-x64" "0.27.3" + "@esbuild/freebsd-arm64" "0.27.3" + "@esbuild/freebsd-x64" "0.27.3" + "@esbuild/linux-arm" "0.27.3" + "@esbuild/linux-arm64" "0.27.3" + "@esbuild/linux-ia32" "0.27.3" + "@esbuild/linux-loong64" "0.27.3" + "@esbuild/linux-mips64el" "0.27.3" + "@esbuild/linux-ppc64" "0.27.3" + "@esbuild/linux-riscv64" "0.27.3" + "@esbuild/linux-s390x" "0.27.3" + "@esbuild/linux-x64" "0.27.3" + "@esbuild/netbsd-arm64" "0.27.3" + "@esbuild/netbsd-x64" "0.27.3" + "@esbuild/openbsd-arm64" "0.27.3" + "@esbuild/openbsd-x64" "0.27.3" + "@esbuild/openharmony-arm64" "0.27.3" + "@esbuild/sunos-x64" "0.27.3" + "@esbuild/win32-arm64" "0.27.3" + "@esbuild/win32-ia32" "0.27.3" + "@esbuild/win32-x64" "0.27.3" + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventemitter3@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +eventsource-parser@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.6.tgz#292e165e34cacbc936c3c92719ef326d4aeb4e90" + integrity sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg== + +expect-type@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.3.0.tgz#0d58ed361877a31bbc4dd6cf71bbfef7faf6bd68" + integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA== + +fast-xml-parser@^4.4.1: + version "4.5.3" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz#c54d6b35aa0f23dc1ea60b6c884340c006dc6efb" + integrity sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig== + dependencies: + strnum "^1.1.1" + +fastestsmallesttextencoderdecoder@^1.0.22: + version "1.0.22" + resolved "https://registry.yarnpkg.com/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz#59b47e7b965f45258629cc6c127bf783281c5e93" + integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== + +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +form-data-encoder@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" + integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== + +form-data@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + +formdata-node@^4.3.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" + integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== + dependencies: + node-domexception "1.0.0" + web-streams-polyfill "4.0.0-beta.3" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-tsconfig@^4.7.5: + version "4.13.6" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.13.6.tgz#2fbfda558a98a691a798f123afd95915badce876" + integrity sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw== + dependencies: + resolve-pkg-maps "^1.0.0" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +got@^11.8.5: + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +http-cache-semantics@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5" + integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ== + +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + +js-tiktoken@^1.0.12: + version "1.0.21" + resolved "https://registry.yarnpkg.com/js-tiktoken/-/js-tiktoken-1.0.21.tgz#368a9957591a30a62997dd0c4cf30866f00f8221" + integrity sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g== + dependencies: + base64-js "^1.5.1" + +js-tokens@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4" + integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-to-ts@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz#81f3acaf5a34736492f6f5f51870ef9ece1ca853" + integrity sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g== + dependencies: + "@babel/runtime" "^7.18.3" + ts-algebra "^2.0.0" + +json-schema@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +keyv@^4.0.0: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +langsmith@^0.3.67: + version "0.3.87" + resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.3.87.tgz#f1c991c93a5d4d226a31671be7e4443b4b8673b1" + integrity sha512-XXR1+9INH8YX96FKWc5tie0QixWz6tOqAsAKfcJyPkE0xPep+NDz0IQLR32q4bn10QK3LqD2HN6T3n6z1YLW7Q== + dependencies: + "@types/uuid" "^10.0.0" + chalk "^4.1.2" + console-table-printer "^2.12.1" + p-queue "^6.6.2" + semver "^7.6.3" + uuid "^10.0.0" + +loupe@^3.1.0, loupe@^3.1.4: + version "3.2.1" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" + integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +magic-string@^0.30.17: + version "0.30.21" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +ms@^2.0.0, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mustache@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" + integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +node-domexception@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +openai@^4: + version "4.104.0" + resolved "https://registry.yarnpkg.com/openai/-/openai-4.104.0.tgz#c489765dc051b95019845dab64b0e5207cae4d30" + integrity sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA== + dependencies: + "@types/node" "^18.11.18" + "@types/node-fetch" "^2.6.4" + abort-controller "^3.0.0" + agentkeepalive "^4.2.1" + form-data-encoder "1.7.2" + formdata-node "^4.3.2" + node-fetch "^2.6.7" + +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== + +p-queue@^6.6.2: + version "6.6.2" + resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" + integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== + dependencies: + eventemitter3 "^4.0.4" + p-timeout "^3.2.0" + +p-retry@4: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-timeout@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" + +pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +pathval@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" + integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^4.0.2, picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +postcss@^8.5.6: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +pump@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" + integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +resolve-alpn@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +responselike@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== + dependencies: + lowercase-keys "^2.0.0" + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +rollup@^4.43.0: + version "4.57.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.57.1.tgz#947f70baca32db2b9c594267fe9150aa316e5a88" + integrity sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.57.1" + "@rollup/rollup-android-arm64" "4.57.1" + "@rollup/rollup-darwin-arm64" "4.57.1" + "@rollup/rollup-darwin-x64" "4.57.1" + "@rollup/rollup-freebsd-arm64" "4.57.1" + "@rollup/rollup-freebsd-x64" "4.57.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.57.1" + "@rollup/rollup-linux-arm-musleabihf" "4.57.1" + "@rollup/rollup-linux-arm64-gnu" "4.57.1" + "@rollup/rollup-linux-arm64-musl" "4.57.1" + "@rollup/rollup-linux-loong64-gnu" "4.57.1" + "@rollup/rollup-linux-loong64-musl" "4.57.1" + "@rollup/rollup-linux-ppc64-gnu" "4.57.1" + "@rollup/rollup-linux-ppc64-musl" "4.57.1" + "@rollup/rollup-linux-riscv64-gnu" "4.57.1" + "@rollup/rollup-linux-riscv64-musl" "4.57.1" + "@rollup/rollup-linux-s390x-gnu" "4.57.1" + "@rollup/rollup-linux-x64-gnu" "4.57.1" + "@rollup/rollup-linux-x64-musl" "4.57.1" + "@rollup/rollup-openbsd-x64" "4.57.1" + "@rollup/rollup-openharmony-arm64" "4.57.1" + "@rollup/rollup-win32-arm64-msvc" "4.57.1" + "@rollup/rollup-win32-ia32-msvc" "4.57.1" + "@rollup/rollup-win32-x64-gnu" "4.57.1" + "@rollup/rollup-win32-x64-msvc" "4.57.1" + fsevents "~2.3.2" + +semver@^7.6.3: + version "7.7.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + +simple-wcswidth@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/simple-wcswidth/-/simple-wcswidth-1.1.2.tgz#66722f37629d5203f9b47c5477b1225b85d6525b" + integrity sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + +std-env@^3.9.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" + integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== + +strip-literal@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-3.1.0.tgz#222b243dd2d49c0bcd0de8906adbd84177196032" + integrity sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg== + dependencies: + js-tokens "^9.0.1" + +strnum@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.1.2.tgz#57bca4fbaa6f271081715dbc9ed7cee5493e28e4" + integrity sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +tinybench@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== + +tinyexec@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.14, tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + +tinypool@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591" + integrity sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg== + +tinyrainbow@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz#9509b2162436315e80e3eee0fcce4474d2444294" + integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw== + +tinyspy@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-4.0.4.tgz#d77a002fb53a88aa1429b419c1c92492e0c81f78" + integrity sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q== + +to-utf8@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + integrity sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-algebra@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ts-algebra/-/ts-algebra-2.0.0.tgz#4e3e0953878f26518fce7f6bb115064a65388b7a" + integrity sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw== + +tsx@^4.19.0: + version "4.21.0" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.21.0.tgz#32aa6cf17481e336f756195e6fe04dae3e6308b1" + integrity sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw== + dependencies: + esbuild "~0.27.0" + get-tsconfig "^4.7.5" + optionalDependencies: + fsevents "~2.3.3" + +typescript@^5: + version "5.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + +ulid@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.4.0.tgz#9d9ee22e63f4390ee1bcd9ad09fca39d8ae0afed" + integrity sha512-fIRiVTJNcSRmXKPZtGzFQv9WRrZ3M9eoptl/teFJvjOzmpU+/K/JH6HZ8deBfb5vMEpicJcLn7JmvdknlMq7Zg== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +undici-types@~7.16.0: + version "7.16.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" + integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== + +uuid@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +vite-node@3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.2.4.tgz#f3676d94c4af1e76898c162c92728bca65f7bb07" + integrity sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg== + dependencies: + cac "^6.7.14" + debug "^4.4.1" + es-module-lexer "^1.7.0" + pathe "^2.0.3" + vite "^5.0.0 || ^6.0.0 || ^7.0.0-0" + +"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0": + version "7.3.1" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.3.1.tgz#7f6cfe8fb9074138605e822a75d9d30b814d6507" + integrity sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA== + dependencies: + esbuild "^0.27.0" + fdir "^6.5.0" + picomatch "^4.0.3" + postcss "^8.5.6" + rollup "^4.43.0" + tinyglobby "^0.2.15" + optionalDependencies: + fsevents "~2.3.3" + +vitest@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.2.4.tgz#0637b903ad79d1539a25bc34c0ed54b5c67702ea" + integrity sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A== + dependencies: + "@types/chai" "^5.2.2" + "@vitest/expect" "3.2.4" + "@vitest/mocker" "3.2.4" + "@vitest/pretty-format" "^3.2.4" + "@vitest/runner" "3.2.4" + "@vitest/snapshot" "3.2.4" + "@vitest/spy" "3.2.4" + "@vitest/utils" "3.2.4" + chai "^5.2.0" + debug "^4.4.1" + expect-type "^1.2.1" + magic-string "^0.30.17" + pathe "^2.0.3" + picomatch "^4.0.2" + std-env "^3.9.0" + tinybench "^2.9.0" + tinyexec "^0.3.2" + tinyglobby "^0.2.14" + tinypool "^1.1.1" + tinyrainbow "^2.0.0" + vite "^5.0.0 || ^6.0.0 || ^7.0.0-0" + vite-node "3.2.4" + why-is-node-running "^2.3.0" + +web-streams-polyfill@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" + integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +why-is-node-running@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^8.17.1: + version "8.19.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.19.0.tgz#ddc2bdfa5b9ad860204f5a72a4863a8895fd8c8b" + integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== + +zod-to-json-schema@^3.22.3: + version "3.25.1" + resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz#7f24962101a439ddade2bf1aeab3c3bfec7d84ba" + integrity sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA== + +zod@^3.23.8, zod@^3.25.32: + version "3.25.76" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" + integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== diff --git a/jest.config.js b/jest.config.js index 09d4f81d9f..9e3892d5ab 100644 --- a/jest.config.js +++ b/jest.config.js @@ -12,7 +12,7 @@ module.exports = { }, coveragePathIgnorePatterns: ['src/styles/svg'], testPathIgnorePatterns: [`node_modules`, `\\.cache`, `.*/public`], - modulePathIgnorePatterns: ['/examples/'], + modulePathIgnorePatterns: ['/examples/', '/guides/'], // NOTE: This is a workaround for compilation issues with .d.ts files transformIgnorePatterns: [ `node_modules/(?!(gatsby|gatsby-script|use-keyboard-shortcut|react-medium-image-zoom|@react-hook/media-query|@mdx-js/react|@ably/ui/core|until-async)/)`, From 5c9ec660f8be4889cf186b01332b1431849ae90d Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Wed, 18 Feb 2026 09:31:28 +0000 Subject: [PATCH 2/4] Restructure guide directories to nest by language Move all guide contents into javascript/ subdirectories to prepare for future multi-language support (Java, Python, Swift). Update workspace paths, vitest config, and tsconfig extends accordingly. --- guides/ai-transport/README.md | 40 ++++++++++++------- .../{ => javascript}/package.json | 0 .../{ => javascript}/src/publisher.ts | 0 .../{ => javascript}/src/subscriber.ts | 0 .../{ => javascript}/test/e2e.test.ts | 0 .../{ => javascript}/tsconfig.json | 2 +- .../{ => javascript}/package.json | 0 .../{ => javascript}/src/publisher.ts | 0 .../{ => javascript}/src/subscriber.ts | 0 .../{ => javascript}/test/e2e.test.ts | 0 .../{ => javascript}/tsconfig.json | 2 +- .../{ => javascript}/package.json | 0 .../{ => javascript}/src/publisher.ts | 0 .../{ => javascript}/src/subscriber.ts | 0 .../{ => javascript}/test/e2e.test.ts | 0 .../{ => javascript}/tsconfig.json | 2 +- .../{ => javascript}/package.json | 0 .../{ => javascript}/src/publisher.ts | 0 .../{ => javascript}/src/subscriber.ts | 0 .../{ => javascript}/test/e2e.test.ts | 0 .../{ => javascript}/tsconfig.json | 2 +- .../{ => javascript}/package.json | 0 .../{ => javascript}/src/publisher.ts | 0 .../{ => javascript}/src/subscriber.ts | 0 .../{ => javascript}/test/e2e.test.ts | 0 .../javascript/tsconfig.json | 4 ++ .../openai-message-per-response/tsconfig.json | 4 -- .../{ => javascript}/package.json | 0 .../{ => javascript}/src/publisher.ts | 0 .../{ => javascript}/src/subscriber.ts | 0 .../{ => javascript}/test/e2e.test.ts | 0 .../javascript/tsconfig.json | 4 ++ .../openai-message-per-token/tsconfig.json | 4 -- guides/ai-transport/package.json | 16 ++++---- .../{ => javascript}/package.json | 0 .../{ => javascript}/src/publisher.ts | 0 .../{ => javascript}/src/subscriber.ts | 0 .../{ => javascript}/test/e2e.test.ts | 0 .../javascript/tsconfig.json | 4 ++ .../vercel-message-per-response/tsconfig.json | 4 -- .../{ => javascript}/package.json | 0 .../{ => javascript}/src/publisher.ts | 0 .../{ => javascript}/src/subscriber.ts | 0 .../{ => javascript}/test/e2e.test.ts | 0 .../javascript/tsconfig.json | 4 ++ .../vercel-message-per-token/tsconfig.json | 4 -- guides/ai-transport/vitest.config.ts | 2 +- 47 files changed, 55 insertions(+), 43 deletions(-) rename guides/ai-transport/anthropic-message-per-response/{ => javascript}/package.json (100%) rename guides/ai-transport/anthropic-message-per-response/{ => javascript}/src/publisher.ts (100%) rename guides/ai-transport/anthropic-message-per-response/{ => javascript}/src/subscriber.ts (100%) rename guides/ai-transport/anthropic-message-per-response/{ => javascript}/test/e2e.test.ts (100%) rename guides/ai-transport/anthropic-message-per-response/{ => javascript}/tsconfig.json (54%) rename guides/ai-transport/anthropic-message-per-token/{ => javascript}/package.json (100%) rename guides/ai-transport/anthropic-message-per-token/{ => javascript}/src/publisher.ts (100%) rename guides/ai-transport/anthropic-message-per-token/{ => javascript}/src/subscriber.ts (100%) rename guides/ai-transport/anthropic-message-per-token/{ => javascript}/test/e2e.test.ts (100%) rename guides/ai-transport/anthropic-message-per-token/{ => javascript}/tsconfig.json (54%) rename guides/ai-transport/lang-graph-message-per-response/{ => javascript}/package.json (100%) rename guides/ai-transport/lang-graph-message-per-response/{ => javascript}/src/publisher.ts (100%) rename guides/ai-transport/lang-graph-message-per-response/{ => javascript}/src/subscriber.ts (100%) rename guides/ai-transport/lang-graph-message-per-response/{ => javascript}/test/e2e.test.ts (100%) rename guides/ai-transport/lang-graph-message-per-response/{ => javascript}/tsconfig.json (54%) rename guides/ai-transport/lang-graph-message-per-token/{ => javascript}/package.json (100%) rename guides/ai-transport/lang-graph-message-per-token/{ => javascript}/src/publisher.ts (100%) rename guides/ai-transport/lang-graph-message-per-token/{ => javascript}/src/subscriber.ts (100%) rename guides/ai-transport/lang-graph-message-per-token/{ => javascript}/test/e2e.test.ts (100%) rename guides/ai-transport/lang-graph-message-per-token/{ => javascript}/tsconfig.json (54%) rename guides/ai-transport/openai-message-per-response/{ => javascript}/package.json (100%) rename guides/ai-transport/openai-message-per-response/{ => javascript}/src/publisher.ts (100%) rename guides/ai-transport/openai-message-per-response/{ => javascript}/src/subscriber.ts (100%) rename guides/ai-transport/openai-message-per-response/{ => javascript}/test/e2e.test.ts (100%) create mode 100644 guides/ai-transport/openai-message-per-response/javascript/tsconfig.json delete mode 100644 guides/ai-transport/openai-message-per-response/tsconfig.json rename guides/ai-transport/openai-message-per-token/{ => javascript}/package.json (100%) rename guides/ai-transport/openai-message-per-token/{ => javascript}/src/publisher.ts (100%) rename guides/ai-transport/openai-message-per-token/{ => javascript}/src/subscriber.ts (100%) rename guides/ai-transport/openai-message-per-token/{ => javascript}/test/e2e.test.ts (100%) create mode 100644 guides/ai-transport/openai-message-per-token/javascript/tsconfig.json delete mode 100644 guides/ai-transport/openai-message-per-token/tsconfig.json rename guides/ai-transport/vercel-message-per-response/{ => javascript}/package.json (100%) rename guides/ai-transport/vercel-message-per-response/{ => javascript}/src/publisher.ts (100%) rename guides/ai-transport/vercel-message-per-response/{ => javascript}/src/subscriber.ts (100%) rename guides/ai-transport/vercel-message-per-response/{ => javascript}/test/e2e.test.ts (100%) create mode 100644 guides/ai-transport/vercel-message-per-response/javascript/tsconfig.json delete mode 100644 guides/ai-transport/vercel-message-per-response/tsconfig.json rename guides/ai-transport/vercel-message-per-token/{ => javascript}/package.json (100%) rename guides/ai-transport/vercel-message-per-token/{ => javascript}/src/publisher.ts (100%) rename guides/ai-transport/vercel-message-per-token/{ => javascript}/src/subscriber.ts (100%) rename guides/ai-transport/vercel-message-per-token/{ => javascript}/test/e2e.test.ts (100%) create mode 100644 guides/ai-transport/vercel-message-per-token/javascript/tsconfig.json delete mode 100644 guides/ai-transport/vercel-message-per-token/tsconfig.json diff --git a/guides/ai-transport/README.md b/guides/ai-transport/README.md index 888f95f42c..49009fd285 100644 --- a/guides/ai-transport/README.md +++ b/guides/ai-transport/README.md @@ -1,19 +1,31 @@ # AI Transport Guides - E2E Code -Full, runnable implementations for each AI Transport guide. Each directory contains the complete publisher (server) and subscriber (client) code that the corresponding guide walks through. +Full, runnable implementations for each AI Transport guide. Each guide directory contains language-specific subdirectories with publisher (agent) and subscriber (client) code. + +## Structure + +``` +/ + javascript/ # JavaScript/TypeScript implementation + src/publisher.ts + src/subscriber.ts + test/e2e.test.ts + python/ # (future) + java/ # (future) +``` ## Guides -| Guide | Provider | Pattern | -|-------|----------|---------| -| `openai-message-per-token` | OpenAI | Message per token | -| `openai-message-per-response` | OpenAI | Message per response | -| `anthropic-message-per-token` | Anthropic | Message per token | -| `anthropic-message-per-response` | Anthropic | Message per response | -| `vercel-message-per-token` | Vercel AI SDK | Message per token | -| `vercel-message-per-response` | Vercel AI SDK | Message per response | -| `lang-graph-message-per-token` | LangGraph | Message per token | -| `lang-graph-message-per-response` | LangGraph | Message per response | +| Guide | Provider | Pattern | Languages | +|-------|----------|---------|-----------| +| `openai-message-per-token` | OpenAI | Message per token | JavaScript | +| `openai-message-per-response` | OpenAI | Message per response | JavaScript | +| `anthropic-message-per-token` | Anthropic | Message per token | JavaScript | +| `anthropic-message-per-response` | Anthropic | Message per response | JavaScript | +| `vercel-message-per-token` | Vercel AI SDK | Message per token | JavaScript | +| `vercel-message-per-response` | Vercel AI SDK | Message per response | JavaScript | +| `lang-graph-message-per-token` | LangGraph | Message per token | JavaScript | +| `lang-graph-message-per-response` | LangGraph | Message per response | JavaScript | ## Streaming patterns @@ -41,10 +53,10 @@ Each guide has a publisher (streams from LLM to Ably) and a subscriber (reads fr ```bash # Terminal 1 - start the subscriber -npx tsx /src/subscriber.ts +npx tsx /javascript/src/subscriber.ts # Terminal 2 - start the publisher -npx tsx /src/publisher.ts +npx tsx /javascript/src/publisher.ts ``` ## Running tests @@ -57,5 +69,5 @@ yarn test yarn test:watch # Single guide -yarn vitest run +npx vitest run ``` diff --git a/guides/ai-transport/anthropic-message-per-response/package.json b/guides/ai-transport/anthropic-message-per-response/javascript/package.json similarity index 100% rename from guides/ai-transport/anthropic-message-per-response/package.json rename to guides/ai-transport/anthropic-message-per-response/javascript/package.json diff --git a/guides/ai-transport/anthropic-message-per-response/src/publisher.ts b/guides/ai-transport/anthropic-message-per-response/javascript/src/publisher.ts similarity index 100% rename from guides/ai-transport/anthropic-message-per-response/src/publisher.ts rename to guides/ai-transport/anthropic-message-per-response/javascript/src/publisher.ts diff --git a/guides/ai-transport/anthropic-message-per-response/src/subscriber.ts b/guides/ai-transport/anthropic-message-per-response/javascript/src/subscriber.ts similarity index 100% rename from guides/ai-transport/anthropic-message-per-response/src/subscriber.ts rename to guides/ai-transport/anthropic-message-per-response/javascript/src/subscriber.ts diff --git a/guides/ai-transport/anthropic-message-per-response/test/e2e.test.ts b/guides/ai-transport/anthropic-message-per-response/javascript/test/e2e.test.ts similarity index 100% rename from guides/ai-transport/anthropic-message-per-response/test/e2e.test.ts rename to guides/ai-transport/anthropic-message-per-response/javascript/test/e2e.test.ts diff --git a/guides/ai-transport/anthropic-message-per-response/tsconfig.json b/guides/ai-transport/anthropic-message-per-response/javascript/tsconfig.json similarity index 54% rename from guides/ai-transport/anthropic-message-per-response/tsconfig.json rename to guides/ai-transport/anthropic-message-per-response/javascript/tsconfig.json index 13b3dd7d6b..6ece4d3313 100644 --- a/guides/ai-transport/anthropic-message-per-response/tsconfig.json +++ b/guides/ai-transport/anthropic-message-per-response/javascript/tsconfig.json @@ -1,4 +1,4 @@ { - "extends": "../tsconfig.base.json", + "extends": "../../tsconfig.base.json", "include": ["src/**/*.ts", "test/**/*.ts"] } diff --git a/guides/ai-transport/anthropic-message-per-token/package.json b/guides/ai-transport/anthropic-message-per-token/javascript/package.json similarity index 100% rename from guides/ai-transport/anthropic-message-per-token/package.json rename to guides/ai-transport/anthropic-message-per-token/javascript/package.json diff --git a/guides/ai-transport/anthropic-message-per-token/src/publisher.ts b/guides/ai-transport/anthropic-message-per-token/javascript/src/publisher.ts similarity index 100% rename from guides/ai-transport/anthropic-message-per-token/src/publisher.ts rename to guides/ai-transport/anthropic-message-per-token/javascript/src/publisher.ts diff --git a/guides/ai-transport/anthropic-message-per-token/src/subscriber.ts b/guides/ai-transport/anthropic-message-per-token/javascript/src/subscriber.ts similarity index 100% rename from guides/ai-transport/anthropic-message-per-token/src/subscriber.ts rename to guides/ai-transport/anthropic-message-per-token/javascript/src/subscriber.ts diff --git a/guides/ai-transport/anthropic-message-per-token/test/e2e.test.ts b/guides/ai-transport/anthropic-message-per-token/javascript/test/e2e.test.ts similarity index 100% rename from guides/ai-transport/anthropic-message-per-token/test/e2e.test.ts rename to guides/ai-transport/anthropic-message-per-token/javascript/test/e2e.test.ts diff --git a/guides/ai-transport/anthropic-message-per-token/tsconfig.json b/guides/ai-transport/anthropic-message-per-token/javascript/tsconfig.json similarity index 54% rename from guides/ai-transport/anthropic-message-per-token/tsconfig.json rename to guides/ai-transport/anthropic-message-per-token/javascript/tsconfig.json index 13b3dd7d6b..6ece4d3313 100644 --- a/guides/ai-transport/anthropic-message-per-token/tsconfig.json +++ b/guides/ai-transport/anthropic-message-per-token/javascript/tsconfig.json @@ -1,4 +1,4 @@ { - "extends": "../tsconfig.base.json", + "extends": "../../tsconfig.base.json", "include": ["src/**/*.ts", "test/**/*.ts"] } diff --git a/guides/ai-transport/lang-graph-message-per-response/package.json b/guides/ai-transport/lang-graph-message-per-response/javascript/package.json similarity index 100% rename from guides/ai-transport/lang-graph-message-per-response/package.json rename to guides/ai-transport/lang-graph-message-per-response/javascript/package.json diff --git a/guides/ai-transport/lang-graph-message-per-response/src/publisher.ts b/guides/ai-transport/lang-graph-message-per-response/javascript/src/publisher.ts similarity index 100% rename from guides/ai-transport/lang-graph-message-per-response/src/publisher.ts rename to guides/ai-transport/lang-graph-message-per-response/javascript/src/publisher.ts diff --git a/guides/ai-transport/lang-graph-message-per-response/src/subscriber.ts b/guides/ai-transport/lang-graph-message-per-response/javascript/src/subscriber.ts similarity index 100% rename from guides/ai-transport/lang-graph-message-per-response/src/subscriber.ts rename to guides/ai-transport/lang-graph-message-per-response/javascript/src/subscriber.ts diff --git a/guides/ai-transport/lang-graph-message-per-response/test/e2e.test.ts b/guides/ai-transport/lang-graph-message-per-response/javascript/test/e2e.test.ts similarity index 100% rename from guides/ai-transport/lang-graph-message-per-response/test/e2e.test.ts rename to guides/ai-transport/lang-graph-message-per-response/javascript/test/e2e.test.ts diff --git a/guides/ai-transport/lang-graph-message-per-response/tsconfig.json b/guides/ai-transport/lang-graph-message-per-response/javascript/tsconfig.json similarity index 54% rename from guides/ai-transport/lang-graph-message-per-response/tsconfig.json rename to guides/ai-transport/lang-graph-message-per-response/javascript/tsconfig.json index 13b3dd7d6b..6ece4d3313 100644 --- a/guides/ai-transport/lang-graph-message-per-response/tsconfig.json +++ b/guides/ai-transport/lang-graph-message-per-response/javascript/tsconfig.json @@ -1,4 +1,4 @@ { - "extends": "../tsconfig.base.json", + "extends": "../../tsconfig.base.json", "include": ["src/**/*.ts", "test/**/*.ts"] } diff --git a/guides/ai-transport/lang-graph-message-per-token/package.json b/guides/ai-transport/lang-graph-message-per-token/javascript/package.json similarity index 100% rename from guides/ai-transport/lang-graph-message-per-token/package.json rename to guides/ai-transport/lang-graph-message-per-token/javascript/package.json diff --git a/guides/ai-transport/lang-graph-message-per-token/src/publisher.ts b/guides/ai-transport/lang-graph-message-per-token/javascript/src/publisher.ts similarity index 100% rename from guides/ai-transport/lang-graph-message-per-token/src/publisher.ts rename to guides/ai-transport/lang-graph-message-per-token/javascript/src/publisher.ts diff --git a/guides/ai-transport/lang-graph-message-per-token/src/subscriber.ts b/guides/ai-transport/lang-graph-message-per-token/javascript/src/subscriber.ts similarity index 100% rename from guides/ai-transport/lang-graph-message-per-token/src/subscriber.ts rename to guides/ai-transport/lang-graph-message-per-token/javascript/src/subscriber.ts diff --git a/guides/ai-transport/lang-graph-message-per-token/test/e2e.test.ts b/guides/ai-transport/lang-graph-message-per-token/javascript/test/e2e.test.ts similarity index 100% rename from guides/ai-transport/lang-graph-message-per-token/test/e2e.test.ts rename to guides/ai-transport/lang-graph-message-per-token/javascript/test/e2e.test.ts diff --git a/guides/ai-transport/lang-graph-message-per-token/tsconfig.json b/guides/ai-transport/lang-graph-message-per-token/javascript/tsconfig.json similarity index 54% rename from guides/ai-transport/lang-graph-message-per-token/tsconfig.json rename to guides/ai-transport/lang-graph-message-per-token/javascript/tsconfig.json index 13b3dd7d6b..6ece4d3313 100644 --- a/guides/ai-transport/lang-graph-message-per-token/tsconfig.json +++ b/guides/ai-transport/lang-graph-message-per-token/javascript/tsconfig.json @@ -1,4 +1,4 @@ { - "extends": "../tsconfig.base.json", + "extends": "../../tsconfig.base.json", "include": ["src/**/*.ts", "test/**/*.ts"] } diff --git a/guides/ai-transport/openai-message-per-response/package.json b/guides/ai-transport/openai-message-per-response/javascript/package.json similarity index 100% rename from guides/ai-transport/openai-message-per-response/package.json rename to guides/ai-transport/openai-message-per-response/javascript/package.json diff --git a/guides/ai-transport/openai-message-per-response/src/publisher.ts b/guides/ai-transport/openai-message-per-response/javascript/src/publisher.ts similarity index 100% rename from guides/ai-transport/openai-message-per-response/src/publisher.ts rename to guides/ai-transport/openai-message-per-response/javascript/src/publisher.ts diff --git a/guides/ai-transport/openai-message-per-response/src/subscriber.ts b/guides/ai-transport/openai-message-per-response/javascript/src/subscriber.ts similarity index 100% rename from guides/ai-transport/openai-message-per-response/src/subscriber.ts rename to guides/ai-transport/openai-message-per-response/javascript/src/subscriber.ts diff --git a/guides/ai-transport/openai-message-per-response/test/e2e.test.ts b/guides/ai-transport/openai-message-per-response/javascript/test/e2e.test.ts similarity index 100% rename from guides/ai-transport/openai-message-per-response/test/e2e.test.ts rename to guides/ai-transport/openai-message-per-response/javascript/test/e2e.test.ts diff --git a/guides/ai-transport/openai-message-per-response/javascript/tsconfig.json b/guides/ai-transport/openai-message-per-response/javascript/tsconfig.json new file mode 100644 index 0000000000..6ece4d3313 --- /dev/null +++ b/guides/ai-transport/openai-message-per-response/javascript/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/openai-message-per-response/tsconfig.json b/guides/ai-transport/openai-message-per-response/tsconfig.json deleted file mode 100644 index 13b3dd7d6b..0000000000 --- a/guides/ai-transport/openai-message-per-response/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "include": ["src/**/*.ts", "test/**/*.ts"] -} diff --git a/guides/ai-transport/openai-message-per-token/package.json b/guides/ai-transport/openai-message-per-token/javascript/package.json similarity index 100% rename from guides/ai-transport/openai-message-per-token/package.json rename to guides/ai-transport/openai-message-per-token/javascript/package.json diff --git a/guides/ai-transport/openai-message-per-token/src/publisher.ts b/guides/ai-transport/openai-message-per-token/javascript/src/publisher.ts similarity index 100% rename from guides/ai-transport/openai-message-per-token/src/publisher.ts rename to guides/ai-transport/openai-message-per-token/javascript/src/publisher.ts diff --git a/guides/ai-transport/openai-message-per-token/src/subscriber.ts b/guides/ai-transport/openai-message-per-token/javascript/src/subscriber.ts similarity index 100% rename from guides/ai-transport/openai-message-per-token/src/subscriber.ts rename to guides/ai-transport/openai-message-per-token/javascript/src/subscriber.ts diff --git a/guides/ai-transport/openai-message-per-token/test/e2e.test.ts b/guides/ai-transport/openai-message-per-token/javascript/test/e2e.test.ts similarity index 100% rename from guides/ai-transport/openai-message-per-token/test/e2e.test.ts rename to guides/ai-transport/openai-message-per-token/javascript/test/e2e.test.ts diff --git a/guides/ai-transport/openai-message-per-token/javascript/tsconfig.json b/guides/ai-transport/openai-message-per-token/javascript/tsconfig.json new file mode 100644 index 0000000000..6ece4d3313 --- /dev/null +++ b/guides/ai-transport/openai-message-per-token/javascript/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/openai-message-per-token/tsconfig.json b/guides/ai-transport/openai-message-per-token/tsconfig.json deleted file mode 100644 index 13b3dd7d6b..0000000000 --- a/guides/ai-transport/openai-message-per-token/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "include": ["src/**/*.ts", "test/**/*.ts"] -} diff --git a/guides/ai-transport/package.json b/guides/ai-transport/package.json index 8c7ebf44d2..8f29318749 100644 --- a/guides/ai-transport/package.json +++ b/guides/ai-transport/package.json @@ -7,14 +7,14 @@ "node": ">=20.0.0" }, "workspaces": [ - "openai-message-per-token", - "openai-message-per-response", - "anthropic-message-per-token", - "anthropic-message-per-response", - "vercel-message-per-token", - "vercel-message-per-response", - "lang-graph-message-per-token", - "lang-graph-message-per-response" + "openai-message-per-token/javascript", + "openai-message-per-response/javascript", + "anthropic-message-per-token/javascript", + "anthropic-message-per-response/javascript", + "vercel-message-per-token/javascript", + "vercel-message-per-response/javascript", + "lang-graph-message-per-token/javascript", + "lang-graph-message-per-response/javascript" ], "scripts": { "test": "vitest run", diff --git a/guides/ai-transport/vercel-message-per-response/package.json b/guides/ai-transport/vercel-message-per-response/javascript/package.json similarity index 100% rename from guides/ai-transport/vercel-message-per-response/package.json rename to guides/ai-transport/vercel-message-per-response/javascript/package.json diff --git a/guides/ai-transport/vercel-message-per-response/src/publisher.ts b/guides/ai-transport/vercel-message-per-response/javascript/src/publisher.ts similarity index 100% rename from guides/ai-transport/vercel-message-per-response/src/publisher.ts rename to guides/ai-transport/vercel-message-per-response/javascript/src/publisher.ts diff --git a/guides/ai-transport/vercel-message-per-response/src/subscriber.ts b/guides/ai-transport/vercel-message-per-response/javascript/src/subscriber.ts similarity index 100% rename from guides/ai-transport/vercel-message-per-response/src/subscriber.ts rename to guides/ai-transport/vercel-message-per-response/javascript/src/subscriber.ts diff --git a/guides/ai-transport/vercel-message-per-response/test/e2e.test.ts b/guides/ai-transport/vercel-message-per-response/javascript/test/e2e.test.ts similarity index 100% rename from guides/ai-transport/vercel-message-per-response/test/e2e.test.ts rename to guides/ai-transport/vercel-message-per-response/javascript/test/e2e.test.ts diff --git a/guides/ai-transport/vercel-message-per-response/javascript/tsconfig.json b/guides/ai-transport/vercel-message-per-response/javascript/tsconfig.json new file mode 100644 index 0000000000..6ece4d3313 --- /dev/null +++ b/guides/ai-transport/vercel-message-per-response/javascript/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/vercel-message-per-response/tsconfig.json b/guides/ai-transport/vercel-message-per-response/tsconfig.json deleted file mode 100644 index 13b3dd7d6b..0000000000 --- a/guides/ai-transport/vercel-message-per-response/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "include": ["src/**/*.ts", "test/**/*.ts"] -} diff --git a/guides/ai-transport/vercel-message-per-token/package.json b/guides/ai-transport/vercel-message-per-token/javascript/package.json similarity index 100% rename from guides/ai-transport/vercel-message-per-token/package.json rename to guides/ai-transport/vercel-message-per-token/javascript/package.json diff --git a/guides/ai-transport/vercel-message-per-token/src/publisher.ts b/guides/ai-transport/vercel-message-per-token/javascript/src/publisher.ts similarity index 100% rename from guides/ai-transport/vercel-message-per-token/src/publisher.ts rename to guides/ai-transport/vercel-message-per-token/javascript/src/publisher.ts diff --git a/guides/ai-transport/vercel-message-per-token/src/subscriber.ts b/guides/ai-transport/vercel-message-per-token/javascript/src/subscriber.ts similarity index 100% rename from guides/ai-transport/vercel-message-per-token/src/subscriber.ts rename to guides/ai-transport/vercel-message-per-token/javascript/src/subscriber.ts diff --git a/guides/ai-transport/vercel-message-per-token/test/e2e.test.ts b/guides/ai-transport/vercel-message-per-token/javascript/test/e2e.test.ts similarity index 100% rename from guides/ai-transport/vercel-message-per-token/test/e2e.test.ts rename to guides/ai-transport/vercel-message-per-token/javascript/test/e2e.test.ts diff --git a/guides/ai-transport/vercel-message-per-token/javascript/tsconfig.json b/guides/ai-transport/vercel-message-per-token/javascript/tsconfig.json new file mode 100644 index 0000000000..6ece4d3313 --- /dev/null +++ b/guides/ai-transport/vercel-message-per-token/javascript/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/vercel-message-per-token/tsconfig.json b/guides/ai-transport/vercel-message-per-token/tsconfig.json deleted file mode 100644 index 13b3dd7d6b..0000000000 --- a/guides/ai-transport/vercel-message-per-token/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "include": ["src/**/*.ts", "test/**/*.ts"] -} diff --git a/guides/ai-transport/vitest.config.ts b/guides/ai-transport/vitest.config.ts index 993de2d259..e785262498 100644 --- a/guides/ai-transport/vitest.config.ts +++ b/guides/ai-transport/vitest.config.ts @@ -3,7 +3,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { testTimeout: 30_000, - include: ['*/test/**/*.test.ts'], + include: ['*/*/test/**/*.test.ts'], setupFiles: ['./vitest.setup.ts'], }, }); From 37cba3e182e49963eb83fc7dc10d265cf3ae572c Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 9 Mar 2026 10:55:52 +0000 Subject: [PATCH 3/4] fixup! Add e2e test infrastructure and implementations for AI Transport guides --- .../javascript/src/subscriber.ts | 21 +- .../javascript/test/e2e.test.ts | 8 +- .../javascript/test/e2e.test.ts | 8 +- .../javascript/src/subscriber.ts | 23 +- .../javascript/test/e2e.test.ts | 8 +- .../javascript/test/e2e.test.ts | 8 +- .../javascript/src/subscriber.ts | 21 +- .../javascript/test/e2e.test.ts | 8 +- .../javascript/test/e2e.test.ts | 44 +- guides/ai-transport/package-lock.json | 3346 +++++++++++++++++ guides/ai-transport/package.json | 4 +- guides/ai-transport/test-helpers.ts | 30 + guides/ai-transport/tsconfig.json | 8 + .../javascript/src/subscriber.ts | 21 +- .../javascript/test/e2e.test.ts | 8 +- .../javascript/test/e2e.test.ts | 8 +- guides/ai-transport/yarn.lock | 704 ++-- 17 files changed, 3740 insertions(+), 538 deletions(-) create mode 100644 guides/ai-transport/package-lock.json create mode 100644 guides/ai-transport/test-helpers.ts create mode 100644 guides/ai-transport/tsconfig.json diff --git a/guides/ai-transport/anthropic-message-per-response/javascript/src/subscriber.ts b/guides/ai-transport/anthropic-message-per-response/javascript/src/subscriber.ts index d57e24ab12..37812c7f1c 100644 --- a/guides/ai-transport/anthropic-message-per-response/javascript/src/subscriber.ts +++ b/guides/ai-transport/anthropic-message-per-response/javascript/src/subscriber.ts @@ -10,7 +10,9 @@ export function subscribe(channel: Ably.RealtimeChannel): Promise { let doneTimer: ReturnType | null = null; const resetTimer = () => { - if (doneTimer) clearTimeout(doneTimer); + if (doneTimer) { + clearTimeout(doneTimer); + } doneTimer = setTimeout(() => { if (lastSerial) { const finalText = responses.get(lastSerial) || ''; @@ -20,24 +22,29 @@ export function subscribe(channel: Ably.RealtimeChannel): Promise { }; channel.subscribe((message: Ably.Message) => { + const serial = message.serial; + if (!serial) { + return; + } + switch (message.action) { case 'message.create': - console.log('\n[Response started]', message.serial); - responses.set(message.serial, message.data as string); - lastSerial = message.serial; + console.log('\n[Response started]', serial); + responses.set(serial, message.data as string); + lastSerial = serial; resetTimer(); break; case 'message.append': { - const current = responses.get(message.serial) || ''; - responses.set(message.serial, current + (message.data as string)); + const current = responses.get(serial) || ''; + responses.set(serial, current + (message.data as string)); process.stdout.write(message.data as string); resetTimer(); break; } case 'message.update': - responses.set(message.serial, message.data as string); + responses.set(serial, message.data as string); console.log('\n[Response updated with full content]'); resetTimer(); break; diff --git a/guides/ai-transport/anthropic-message-per-response/javascript/test/e2e.test.ts b/guides/ai-transport/anthropic-message-per-response/javascript/test/e2e.test.ts index a3162774ed..c34d4f41c9 100644 --- a/guides/ai-transport/anthropic-message-per-response/javascript/test/e2e.test.ts +++ b/guides/ai-transport/anthropic-message-per-response/javascript/test/e2e.test.ts @@ -2,6 +2,7 @@ import Ably from 'ably'; import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { publish } from '../src/publisher.js'; import { subscribe } from '../src/subscriber.js'; +import { waitForMessage } from '../../../test-helpers.js'; describe('anthropic-message-per-response', () => { let publisherClient: Ably.Realtime; @@ -33,8 +34,9 @@ describe('anthropic-message-per-response', () => { }); }); + const appendReceived = waitForMessage(channel, (m) => m.action === 'message.append'); await publish(pubChannel, 'Reply with exactly: OK'); - await new Promise((resolve) => setTimeout(resolve, 3000)); + await appendReceived; expect(actions[0].action).toBe('message.create'); const appendActions = actions.filter((a) => a.action === 'message.append'); @@ -48,7 +50,7 @@ describe('anthropic-message-per-response', () => { const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); const responsePromise = subscribe(subChannel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await subChannel.attach(); await publish(pubChannel, 'Reply with exactly: Hello world'); const fullResponse = await responsePromise; expect(fullResponse.length).toBeGreaterThan(0); @@ -67,7 +69,7 @@ describe('anthropic-message-per-response', () => { }); const responsePromise = subscribe(channel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await channel.attach(); await publish(pubChannel, 'Reply with exactly: Test'); const fullResponse = await responsePromise; const concatenated = appendedTokens.join(''); diff --git a/guides/ai-transport/anthropic-message-per-token/javascript/test/e2e.test.ts b/guides/ai-transport/anthropic-message-per-token/javascript/test/e2e.test.ts index 2a1efbfefe..e88b91a98a 100644 --- a/guides/ai-transport/anthropic-message-per-token/javascript/test/e2e.test.ts +++ b/guides/ai-transport/anthropic-message-per-token/javascript/test/e2e.test.ts @@ -2,6 +2,7 @@ import Ably from 'ably'; import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { publish } from '../src/publisher.js'; import { subscribe } from '../src/subscriber.js'; +import { waitForMessage } from '../../../test-helpers.js'; describe('anthropic-message-per-token', () => { let publisherClient: Ably.Realtime; @@ -33,8 +34,9 @@ describe('anthropic-message-per-token', () => { }); }); + const stopReceived = waitForMessage(channel, (m) => m.name === 'stop'); await publish(pubChannel, 'Reply with exactly: OK'); - await new Promise((resolve) => setTimeout(resolve, 2000)); + await stopReceived; expect(events[0].name).toBe('start'); expect(events[events.length - 1].name).toBe('stop'); @@ -49,7 +51,7 @@ describe('anthropic-message-per-token', () => { const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); const responsePromise = subscribe(subChannel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await subChannel.attach(); await publish(pubChannel, 'Reply with exactly: Hello world'); const fullResponse = await responsePromise; expect(fullResponse.length).toBeGreaterThan(0); @@ -64,7 +66,7 @@ describe('anthropic-message-per-token', () => { tokens.push(message.data as string); }); const responsePromise = subscribe(channel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await channel.attach(); await publish(pubChannel, 'Reply with exactly: Test'); const fullResponse = await responsePromise; const concatenated = tokens.join(''); diff --git a/guides/ai-transport/lang-graph-message-per-response/javascript/src/subscriber.ts b/guides/ai-transport/lang-graph-message-per-response/javascript/src/subscriber.ts index c9ba750fd2..f56fdc7f7f 100644 --- a/guides/ai-transport/lang-graph-message-per-response/javascript/src/subscriber.ts +++ b/guides/ai-transport/lang-graph-message-per-response/javascript/src/subscriber.ts @@ -10,7 +10,9 @@ export function subscribe(channel: Ably.RealtimeChannel): Promise { let doneTimer: ReturnType | null = null; const resetTimer = () => { - if (doneTimer) clearTimeout(doneTimer); + if (doneTimer) { + clearTimeout(doneTimer); + } doneTimer = setTimeout(() => { if (lastSerial) { const finalText = responses.get(lastSerial) || ''; @@ -20,24 +22,29 @@ export function subscribe(channel: Ably.RealtimeChannel): Promise { }; channel.subscribe((message: Ably.Message) => { + const serial = message.serial; + if (!serial) { + return; + } + switch (message.action) { case 'message.create': - console.log('\n[Response started]', message.serial); - responses.set(message.serial, message.data as string); - lastSerial = message.serial; + console.log('\n[Response started]', serial); + responses.set(serial, message.data as string); + lastSerial = serial; resetTimer(); break; case 'message.append': { - const current = responses.get(message.serial) || ''; - responses.set(message.serial, current + (message.data as string)); + const current = responses.get(serial) || ''; + responses.set(serial, current + (message.data as string)); process.stdout.write(message.data as string); resetTimer(); break; } case 'message.update': - responses.set(message.serial, message.data as string); + responses.set(serial, message.data as string); console.log('\n[Response updated with full content]'); resetTimer(); break; @@ -48,7 +55,7 @@ export function subscribe(channel: Ably.RealtimeChannel): Promise { async function main() { const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); - const channel = realtime.channels.get('ai:langgraph-mpr-guide'); + const channel = realtime.channels.get('ai:lg-mpr-guide'); console.log('Subscriber ready, waiting for tokens...'); const response = await subscribe(channel); console.log('\nFull response:', response); diff --git a/guides/ai-transport/lang-graph-message-per-response/javascript/test/e2e.test.ts b/guides/ai-transport/lang-graph-message-per-response/javascript/test/e2e.test.ts index 10d7dc2163..ca5d5e9660 100644 --- a/guides/ai-transport/lang-graph-message-per-response/javascript/test/e2e.test.ts +++ b/guides/ai-transport/lang-graph-message-per-response/javascript/test/e2e.test.ts @@ -2,6 +2,7 @@ import Ably from 'ably'; import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { publish } from '../src/publisher.js'; import { subscribe } from '../src/subscriber.js'; +import { waitForMessage } from '../../../test-helpers.js'; describe('lang-graph-message-per-response', () => { let publisherClient: Ably.Realtime; @@ -33,8 +34,9 @@ describe('lang-graph-message-per-response', () => { }); }); + const appendReceived = waitForMessage(channel, (m) => m.action === 'message.append'); await publish(pubChannel, 'Reply with exactly: OK'); - await new Promise((resolve) => setTimeout(resolve, 3000)); + await appendReceived; expect(actions[0].action).toBe('message.create'); const appendActions = actions.filter((a) => a.action === 'message.append'); @@ -48,7 +50,7 @@ describe('lang-graph-message-per-response', () => { const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); const responsePromise = subscribe(subChannel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await subChannel.attach(); await publish(pubChannel, 'Reply with exactly: Hello world'); const fullResponse = await responsePromise; expect(fullResponse.length).toBeGreaterThan(0); @@ -67,7 +69,7 @@ describe('lang-graph-message-per-response', () => { }); const responsePromise = subscribe(channel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await channel.attach(); await publish(pubChannel, 'Reply with exactly: Test'); const fullResponse = await responsePromise; const concatenated = appendedTokens.join(''); diff --git a/guides/ai-transport/lang-graph-message-per-token/javascript/test/e2e.test.ts b/guides/ai-transport/lang-graph-message-per-token/javascript/test/e2e.test.ts index 518bcc1df0..e3b2b4154e 100644 --- a/guides/ai-transport/lang-graph-message-per-token/javascript/test/e2e.test.ts +++ b/guides/ai-transport/lang-graph-message-per-token/javascript/test/e2e.test.ts @@ -2,6 +2,7 @@ import Ably from 'ably'; import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { publish } from '../src/publisher.js'; import { subscribe } from '../src/subscriber.js'; +import { waitForMessage } from '../../../test-helpers.js'; describe('lang-graph-message-per-token', () => { let publisherClient: Ably.Realtime; @@ -33,8 +34,9 @@ describe('lang-graph-message-per-token', () => { }); }); + const stopReceived = waitForMessage(channel, (m) => m.name === 'stop'); await publish(pubChannel, 'Reply with exactly: OK'); - await new Promise((resolve) => setTimeout(resolve, 2000)); + await stopReceived; expect(events[0].name).toBe('start'); expect(events[events.length - 1].name).toBe('stop'); @@ -49,7 +51,7 @@ describe('lang-graph-message-per-token', () => { const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); const responsePromise = subscribe(subChannel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await subChannel.attach(); await publish(pubChannel, 'Reply with exactly: Hello world'); const fullResponse = await responsePromise; expect(fullResponse.length).toBeGreaterThan(0); @@ -64,7 +66,7 @@ describe('lang-graph-message-per-token', () => { tokens.push(message.data as string); }); const responsePromise = subscribe(channel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await channel.attach(); await publish(pubChannel, 'Reply with exactly: Test'); const fullResponse = await responsePromise; const concatenated = tokens.join(''); diff --git a/guides/ai-transport/openai-message-per-response/javascript/src/subscriber.ts b/guides/ai-transport/openai-message-per-response/javascript/src/subscriber.ts index 4e91c9d02f..44744a5812 100644 --- a/guides/ai-transport/openai-message-per-response/javascript/src/subscriber.ts +++ b/guides/ai-transport/openai-message-per-response/javascript/src/subscriber.ts @@ -10,7 +10,9 @@ export function subscribe(channel: Ably.RealtimeChannel): Promise { let doneTimer: ReturnType | null = null; const resetTimer = () => { - if (doneTimer) clearTimeout(doneTimer); + if (doneTimer) { + clearTimeout(doneTimer); + } doneTimer = setTimeout(() => { if (lastSerial) { const finalText = responses.get(lastSerial) || ''; @@ -20,24 +22,29 @@ export function subscribe(channel: Ably.RealtimeChannel): Promise { }; channel.subscribe((message: Ably.Message) => { + const serial = message.serial; + if (!serial) { + return; + } + switch (message.action) { case 'message.create': - console.log('\n[Response started]', message.serial); - responses.set(message.serial, message.data as string); - lastSerial = message.serial; + console.log('\n[Response started]', serial); + responses.set(serial, message.data as string); + lastSerial = serial; resetTimer(); break; case 'message.append': { - const current = responses.get(message.serial) || ''; - responses.set(message.serial, current + (message.data as string)); + const current = responses.get(serial) || ''; + responses.set(serial, current + (message.data as string)); process.stdout.write(message.data as string); resetTimer(); break; } case 'message.update': - responses.set(message.serial, message.data as string); + responses.set(serial, message.data as string); console.log('\n[Response updated with full content]'); resetTimer(); break; diff --git a/guides/ai-transport/openai-message-per-response/javascript/test/e2e.test.ts b/guides/ai-transport/openai-message-per-response/javascript/test/e2e.test.ts index e63bc9a462..3565e618ba 100644 --- a/guides/ai-transport/openai-message-per-response/javascript/test/e2e.test.ts +++ b/guides/ai-transport/openai-message-per-response/javascript/test/e2e.test.ts @@ -2,6 +2,7 @@ import Ably from 'ably'; import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { publish } from '../src/publisher.js'; import { subscribe } from '../src/subscriber.js'; +import { waitForMessage } from '../../../test-helpers.js'; describe('openai-message-per-response', () => { let publisherClient: Ably.Realtime; @@ -33,8 +34,9 @@ describe('openai-message-per-response', () => { }); }); + const appendReceived = waitForMessage(channel, (m) => m.action === 'message.append'); await publish(pubChannel, 'Reply with exactly: OK'); - await new Promise((resolve) => setTimeout(resolve, 3000)); + await appendReceived; expect(actions[0].action).toBe('message.create'); const appendActions = actions.filter((a) => a.action === 'message.append'); @@ -48,7 +50,7 @@ describe('openai-message-per-response', () => { const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); const responsePromise = subscribe(subChannel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await subChannel.attach(); await publish(pubChannel, 'Reply with exactly: Hello world'); const fullResponse = await responsePromise; expect(fullResponse.length).toBeGreaterThan(0); @@ -67,7 +69,7 @@ describe('openai-message-per-response', () => { }); const responsePromise = subscribe(channel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await channel.attach(); await publish(pubChannel, 'Reply with exactly: Test'); const fullResponse = await responsePromise; const concatenated = appendedTokens.join(''); diff --git a/guides/ai-transport/openai-message-per-token/javascript/test/e2e.test.ts b/guides/ai-transport/openai-message-per-token/javascript/test/e2e.test.ts index 286046426d..8fcbe5ede9 100644 --- a/guides/ai-transport/openai-message-per-token/javascript/test/e2e.test.ts +++ b/guides/ai-transport/openai-message-per-token/javascript/test/e2e.test.ts @@ -2,6 +2,7 @@ import Ably from 'ably'; import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { publish } from '../src/publisher.js'; import { subscribe } from '../src/subscriber.js'; +import { waitForMessage } from '../../../test-helpers.js'; describe('openai-message-per-token', () => { let publisherClient: Ably.Realtime; @@ -10,19 +11,11 @@ describe('openai-message-per-token', () => { beforeAll(() => { channelName = `test-openai-mpt-${Date.now()}`; - - publisherClient = new Ably.Realtime({ - key: process.env.ABLY_API_KEY, - echoMessages: false, - }); - - subscriberClient = new Ably.Realtime({ - key: process.env.ABLY_API_KEY, - }); + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); }); afterAll(async () => { - // Allow pending publishes to flush before closing await new Promise((resolve) => setTimeout(resolve, 500)); publisherClient?.close(); subscriberClient?.close(); @@ -31,7 +24,6 @@ describe('openai-message-per-token', () => { it('publishes start, token, and stop events in order', async () => { const channel = subscriberClient.channels.get(channelName + '-lifecycle'); const pubChannel = publisherClient.channels.get(channelName + '-lifecycle'); - const events: { name: string; data?: string; responseId?: string }[] = []; await channel.subscribe((message: Ably.Message) => { @@ -42,22 +34,14 @@ describe('openai-message-per-token', () => { }); }); + const stopReceived = waitForMessage(channel, (m) => m.name === 'stop'); await publish(pubChannel, 'Reply with exactly: OK'); + await stopReceived; - // Wait for events to propagate - await new Promise((resolve) => setTimeout(resolve, 2000)); - - // First event must be 'start' expect(events[0].name).toBe('start'); - - // Last event must be 'stop' expect(events[events.length - 1].name).toBe('stop'); - - // Middle events must all be 'token' const tokenEvents = events.filter((e) => e.name === 'token'); expect(tokenEvents.length).toBeGreaterThan(0); - - // All events must share the same responseId const responseIds = new Set(events.map((e) => e.responseId)); expect(responseIds.size).toBe(1); expect(responseIds.values().next().value).toBeTruthy(); @@ -66,16 +50,10 @@ describe('openai-message-per-token', () => { it('subscriber reconstructs the full response from token events', async () => { const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); - const responsePromise = subscribe(subChannel); - - // Ensure subscriber is attached before publishing - await new Promise((resolve) => setTimeout(resolve, 1000)); - + await subChannel.attach(); await publish(pubChannel, 'Reply with exactly: Hello world'); - const fullResponse = await responsePromise; - expect(fullResponse.length).toBeGreaterThan(0); expect(fullResponse.toLowerCase()).toContain('hello'); }); @@ -83,22 +61,14 @@ describe('openai-message-per-token', () => { it('token data concatenates to match the complete response', async () => { const channel = subscriberClient.channels.get(channelName + '-concat'); const pubChannel = publisherClient.channels.get(channelName + '-concat'); - const tokens: string[] = []; - await channel.subscribe('token', (message: Ably.Message) => { tokens.push(message.data as string); }); - const responsePromise = subscribe(channel); - - await new Promise((resolve) => setTimeout(resolve, 1000)); - + await channel.attach(); await publish(pubChannel, 'Reply with exactly: Test'); - const fullResponse = await responsePromise; - - // Concatenated tokens should equal the subscriber's reconstructed response const concatenated = tokens.join(''); expect(concatenated).toBe(fullResponse); }); diff --git a/guides/ai-transport/package-lock.json b/guides/ai-transport/package-lock.json new file mode 100644 index 0000000000..526e4440cb --- /dev/null +++ b/guides/ai-transport/package-lock.json @@ -0,0 +1,3346 @@ +{ + "name": "ai-transport-guides", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ai-transport-guides", + "version": "0.1.0", + "workspaces": [ + "openai-message-per-token/javascript", + "openai-message-per-response/javascript", + "anthropic-message-per-token/javascript", + "anthropic-message-per-response/javascript", + "vercel-message-per-token/javascript", + "vercel-message-per-response/javascript", + "lang-graph-message-per-token/javascript", + "lang-graph-message-per-response/javascript" + ], + "dependencies": { + "ably": "^2.17.0", + "dotenv": "^16.4.5" + }, + "devDependencies": { + "tsx": "^4.19.0", + "typescript": "^5", + "vitest": "^3.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "anthropic-message-per-response/javascript": { + "name": "guide-anthropic-message-per-response", + "version": "0.1.0", + "dependencies": { + "@anthropic-ai/sdk": "^0.71" + } + }, + "anthropic-message-per-token/javascript": { + "name": "guide-anthropic-message-per-token", + "version": "0.1.0", + "dependencies": { + "@anthropic-ai/sdk": "^0.71" + } + }, + "lang-graph-message-per-response/javascript": { + "name": "guide-lang-graph-message-per-response", + "version": "0.1.0", + "dependencies": { + "@langchain/anthropic": "^0.3", + "@langchain/core": "^0.3", + "@langchain/langgraph": "^0.2" + } + }, + "lang-graph-message-per-token/javascript": { + "name": "guide-lang-graph-message-per-token", + "version": "0.1.0", + "dependencies": { + "@langchain/anthropic": "^0.3", + "@langchain/core": "^0.3", + "@langchain/langgraph": "^0.2" + } + }, + "node_modules/@ably/msgpack-js": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@ably/msgpack-js/-/msgpack-js-0.4.1.tgz", + "integrity": "sha512-Sjxj6SOr17hExAVrsycN7u6oV4PhZcK7Z2S8dM71CH/butgO47cSo/TL6FJPCXUyDAzKkOWjMUpJGyZkEpyu4Q==", + "license": "Apache-2.0", + "dependencies": { + "bops": "^1.0.1" + } + }, + "node_modules/@ai-sdk/gateway": { + "version": "3.0.46", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.46.tgz", + "integrity": "sha512-zH1UbNRjG5woOXXFOrVCZraqZuFTtmPvLardMGcgLkzpxKV0U3tAGoyWKSZ862H+eBJfI/Hf2yj/zzGJcCkycg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.15", + "@vercel/oidc": "3.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/gateway/node_modules/@ai-sdk/provider": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz", + "integrity": "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/gateway/node_modules/@ai-sdk/provider-utils": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.15.tgz", + "integrity": "sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@standard-schema/spec": "^1.1.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/openai": { + "version": "2.0.91", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-2.0.91.tgz", + "integrity": "sha512-lozfRHfSTHg5/UliQjTDcOtISYGbEpt4FS/6QM5PcLmhdT0HmROllaBmG7+JaK+uqFtDXZGgMIpz3bqB9nzqCQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.1", + "@ai-sdk/provider-utils": "3.0.21" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.1.tgz", + "integrity": "sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.21.tgz", + "integrity": "sha512-veuMwTLxsgh31Jjn0SnBABnM1f7ebHhRWcV2ZuY3hP3iJDCZ8VXBaYqcHXoOQDqUXTCas08sKQcHyWK+zl882Q==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.1", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.71.2", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.2.tgz", + "integrity": "sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cfworker/json-schema": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.1.tgz", + "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@langchain/anthropic": { + "version": "0.3.34", + "resolved": "https://registry.npmjs.org/@langchain/anthropic/-/anthropic-0.3.34.tgz", + "integrity": "sha512-8bOW1A2VHRCjbzdYElrjxutKNs9NSIxYRGtR+OJWVzluMqoKKh2NmmFrpPizEyqCUEG2tTq5xt6XA1lwfqMJRA==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "^0.65.0", + "fast-xml-parser": "^4.4.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.3.58 <0.4.0" + } + }, + "node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.65.0.tgz", + "integrity": "sha512-zIdPOcrCVEI8t3Di40nH4z9EoeyGZfXbYSvWdDLsB/KkaSYMnEgC7gmcgWu83g2NTn1ZTpbMvpdttWDGGIk6zw==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@langchain/core": { + "version": "0.3.80", + "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.80.tgz", + "integrity": "sha512-vcJDV2vk1AlCwSh3aBm/urQ1ZrlXFFBocv11bz/NBUfLWD5/UDNMzwPdaAd2dKvNmTWa9FM2lirLU3+JCf4cRA==", + "license": "MIT", + "dependencies": { + "@cfworker/json-schema": "^4.0.2", + "ansi-styles": "^5.0.0", + "camelcase": "6", + "decamelize": "1.2.0", + "js-tiktoken": "^1.0.12", + "langsmith": "^0.3.67", + "mustache": "^4.2.0", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^10.0.0", + "zod": "^3.25.32", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@langchain/langgraph": { + "version": "0.2.74", + "resolved": "https://registry.npmjs.org/@langchain/langgraph/-/langgraph-0.2.74.tgz", + "integrity": "sha512-oHpEi5sTZTPaeZX1UnzfM2OAJ21QGQrwReTV6+QnX7h8nDCBzhtipAw1cK616S+X8zpcVOjgOtJuaJhXa4mN8w==", + "license": "MIT", + "dependencies": { + "@langchain/langgraph-checkpoint": "~0.0.17", + "@langchain/langgraph-sdk": "~0.0.32", + "uuid": "^10.0.0", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.36 <0.3.0 || >=0.3.40 < 0.4.0", + "zod-to-json-schema": "^3.x" + }, + "peerDependenciesMeta": { + "zod-to-json-schema": { + "optional": true + } + } + }, + "node_modules/@langchain/langgraph-checkpoint": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.18.tgz", + "integrity": "sha512-IS7zJj36VgY+4pf8ZjsVuUWef7oTwt1y9ylvwu0aLuOn1d0fg05Om9DLm3v2GZ2Df6bhLV1kfWAM0IAl9O5rQQ==", + "license": "MIT", + "dependencies": { + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.31 <0.4.0" + } + }, + "node_modules/@langchain/langgraph-sdk": { + "version": "0.0.112", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.112.tgz", + "integrity": "sha512-/9W5HSWCqYgwma6EoOspL4BGYxGxeJP6lIquPSF4FA0JlKopaUv58ucZC3vAgdJyCgg6sorCIV/qg7SGpEcCLw==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.15", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^9.0.0" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.31 <0.4.0", + "react": "^18 || ^19", + "react-dom": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@langchain/core": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@langchain/langgraph-sdk/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.4" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "license": "MIT" + }, + "node_modules/@vercel/oidc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz", + "integrity": "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/ably": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/ably/-/ably-2.17.1.tgz", + "integrity": "sha512-70yfXHoM7JtJD/8FCtPD1gkWW0f+AJqbJp0PsqDAqiyxFB8cPFY+FuKHgNTYb8eRHKXq8hT1xiDphUcY0+GHnA==", + "license": "Apache-2.0", + "dependencies": { + "@ably/msgpack-js": "^0.4.0", + "dequal": "^2.0.3", + "fastestsmallesttextencoderdecoder": "^1.0.22", + "got": "^11.8.5", + "ulid": "^2.3.0", + "ws": "^8.17.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ai": { + "version": "6.0.86", + "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.86.tgz", + "integrity": "sha512-U2W2LBCHA/pr0Ui7vmmsjBiLEzBbZF3yVHNy7Rbzn7IX+SvoQPFM5rN74hhfVzZoE8zBuGD4nLLk+j0elGacvQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/gateway": "3.0.46", + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.15", + "@opentelemetry/api": "1.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/ai/node_modules/@ai-sdk/provider": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz", + "integrity": "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ai/node_modules/@ai-sdk/provider-utils": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.15.tgz", + "integrity": "sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@standard-schema/spec": "^1.1.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.0.2.tgz", + "integrity": "sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bops": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bops/-/bops-1.0.1.tgz", + "integrity": "sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag==", + "license": "MIT", + "dependencies": { + "base64-js": "1.0.2", + "to-utf8": "0.0.1" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/console-table-printer": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.15.0.tgz", + "integrity": "sha512-SrhBq4hYVjLCkBVOWaTzceJalvn5K1Zq5aQA6wXC/cYjI3frKWNPEMK3sZsJfNNQApvCQmgBcc13ZKmFj8qExw==", + "license": "MIT", + "dependencies": { + "simple-wcswidth": "^1.1.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.1.1" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastestsmallesttextencoderdecoder": { + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", + "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==", + "license": "CC0-1.0" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/guide-anthropic-message-per-response": { + "resolved": "anthropic-message-per-response/javascript", + "link": true + }, + "node_modules/guide-anthropic-message-per-token": { + "resolved": "anthropic-message-per-token/javascript", + "link": true + }, + "node_modules/guide-lang-graph-message-per-response": { + "resolved": "lang-graph-message-per-response/javascript", + "link": true + }, + "node_modules/guide-lang-graph-message-per-token": { + "resolved": "lang-graph-message-per-token/javascript", + "link": true + }, + "node_modules/guide-openai-message-per-response": { + "resolved": "openai-message-per-response/javascript", + "link": true + }, + "node_modules/guide-openai-message-per-token": { + "resolved": "openai-message-per-token/javascript", + "link": true + }, + "node_modules/guide-vercel-message-per-response": { + "resolved": "vercel-message-per-response/javascript", + "link": true + }, + "node_modules/guide-vercel-message-per-token": { + "resolved": "vercel-message-per-token/javascript", + "link": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/js-tiktoken": { + "version": "1.0.21", + "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz", + "integrity": "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.5.1" + } + }, + "node_modules/js-tiktoken/node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/langsmith": { + "version": "0.3.87", + "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.3.87.tgz", + "integrity": "sha512-XXR1+9INH8YX96FKWc5tie0QixWz6tOqAsAKfcJyPkE0xPep+NDz0IQLR32q4bn10QK3LqD2HN6T3n6z1YLW7Q==", + "license": "MIT", + "dependencies": { + "@types/uuid": "^10.0.0", + "chalk": "^4.1.2", + "console-table-printer": "^2.12.1", + "p-queue": "^6.6.2", + "semver": "^7.6.3", + "uuid": "^10.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "*", + "@opentelemetry/exporter-trace-otlp-proto": "*", + "@opentelemetry/sdk-trace-base": "*", + "openai": "*" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@opentelemetry/exporter-trace-otlp-proto": { + "optional": true + }, + "@opentelemetry/sdk-trace-base": { + "optional": true + }, + "openai": { + "optional": true + } + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openai": { + "version": "4.104.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz", + "integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-wcswidth": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.1.2.tgz", + "integrity": "sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strnum": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-utf8": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/to-utf8/-/to-utf8-0.0.1.tgz", + "integrity": "sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ulid": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ulid/-/ulid-2.4.0.tgz", + "integrity": "sha512-fIRiVTJNcSRmXKPZtGzFQv9WRrZ3M9eoptl/teFJvjOzmpU+/K/JH6HZ8deBfb5vMEpicJcLn7JmvdknlMq7Zg==", + "license": "MIT", + "bin": { + "ulid": "bin/cli.js" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + }, + "openai-message-per-response/javascript": { + "name": "guide-openai-message-per-response", + "version": "0.1.0", + "dependencies": { + "openai": "^4" + } + }, + "openai-message-per-token/javascript": { + "name": "guide-openai-message-per-token", + "version": "0.1.0", + "dependencies": { + "openai": "^4" + } + }, + "vercel-message-per-response/javascript": { + "name": "guide-vercel-message-per-response", + "version": "0.1.0", + "dependencies": { + "@ai-sdk/openai": "^2", + "ai": "^6" + } + }, + "vercel-message-per-token/javascript": { + "name": "guide-vercel-message-per-token", + "version": "0.1.0", + "dependencies": { + "@ai-sdk/openai": "^2", + "ai": "^6" + } + } + } +} diff --git a/guides/ai-transport/package.json b/guides/ai-transport/package.json index 8f29318749..954619158c 100644 --- a/guides/ai-transport/package.json +++ b/guides/ai-transport/package.json @@ -18,7 +18,9 @@ ], "scripts": { "test": "vitest run", - "test:watch": "vitest" + "test:watch": "vitest", + "lint": "tsc --noEmit", + "lint:fix": "tsc --noEmit" }, "dependencies": { "ably": "^2.17.0", diff --git a/guides/ai-transport/test-helpers.ts b/guides/ai-transport/test-helpers.ts new file mode 100644 index 0000000000..e402cd5767 --- /dev/null +++ b/guides/ai-transport/test-helpers.ts @@ -0,0 +1,30 @@ +import Ably from 'ably'; + +type MessagePredicate = (message: Ably.Message) => boolean; + +/** + * Wait for a message matching the predicate on the given channel. + * Resolves with the first matching message, or rejects on timeout. + */ +export async function waitForMessage( + channel: Ably.RealtimeChannel, + predicate: MessagePredicate = () => true, + timeoutMs = 5000, +): Promise { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + channel.unsubscribe(listener); + reject(new Error(`waitForMessage timed out after ${timeoutMs}ms`)); + }, timeoutMs); + + const listener = (message: Ably.Message) => { + if (predicate(message)) { + clearTimeout(timer); + channel.unsubscribe(listener); + resolve(message); + } + }; + + channel.subscribe(listener); + }); +} diff --git a/guides/ai-transport/tsconfig.json b/guides/ai-transport/tsconfig.json new file mode 100644 index 0000000000..d637c70af6 --- /dev/null +++ b/guides/ai-transport/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.base.json", + "include": [ + "test-helpers.ts", + "*/javascript/src/**/*.ts", + "*/javascript/test/**/*.ts" + ] +} diff --git a/guides/ai-transport/vercel-message-per-response/javascript/src/subscriber.ts b/guides/ai-transport/vercel-message-per-response/javascript/src/subscriber.ts index 7fa402d9ae..f6b6dca1f7 100644 --- a/guides/ai-transport/vercel-message-per-response/javascript/src/subscriber.ts +++ b/guides/ai-transport/vercel-message-per-response/javascript/src/subscriber.ts @@ -10,7 +10,9 @@ export function subscribe(channel: Ably.RealtimeChannel): Promise { let doneTimer: ReturnType | null = null; const resetTimer = () => { - if (doneTimer) clearTimeout(doneTimer); + if (doneTimer) { + clearTimeout(doneTimer); + } doneTimer = setTimeout(() => { if (lastSerial) { const finalText = responses.get(lastSerial) || ''; @@ -20,24 +22,29 @@ export function subscribe(channel: Ably.RealtimeChannel): Promise { }; channel.subscribe((message: Ably.Message) => { + const serial = message.serial; + if (!serial) { + return; + } + switch (message.action) { case 'message.create': - console.log('\n[Response started]', message.serial); - responses.set(message.serial, message.data as string); - lastSerial = message.serial; + console.log('\n[Response started]', serial); + responses.set(serial, message.data as string); + lastSerial = serial; resetTimer(); break; case 'message.append': { - const current = responses.get(message.serial) || ''; - responses.set(message.serial, current + (message.data as string)); + const current = responses.get(serial) || ''; + responses.set(serial, current + (message.data as string)); process.stdout.write(message.data as string); resetTimer(); break; } case 'message.update': - responses.set(message.serial, message.data as string); + responses.set(serial, message.data as string); console.log('\n[Response updated with full content]'); resetTimer(); break; diff --git a/guides/ai-transport/vercel-message-per-response/javascript/test/e2e.test.ts b/guides/ai-transport/vercel-message-per-response/javascript/test/e2e.test.ts index 78fe8d1b32..9200e5e589 100644 --- a/guides/ai-transport/vercel-message-per-response/javascript/test/e2e.test.ts +++ b/guides/ai-transport/vercel-message-per-response/javascript/test/e2e.test.ts @@ -2,6 +2,7 @@ import Ably from 'ably'; import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { publish } from '../src/publisher.js'; import { subscribe } from '../src/subscriber.js'; +import { waitForMessage } from '../../../test-helpers.js'; describe('vercel-message-per-response', () => { let publisherClient: Ably.Realtime; @@ -33,8 +34,9 @@ describe('vercel-message-per-response', () => { }); }); + const appendReceived = waitForMessage(channel, (m) => m.action === 'message.append'); await publish(pubChannel, 'Reply with exactly: OK'); - await new Promise((resolve) => setTimeout(resolve, 3000)); + await appendReceived; expect(actions[0].action).toBe('message.create'); const appendActions = actions.filter((a) => a.action === 'message.append'); @@ -48,7 +50,7 @@ describe('vercel-message-per-response', () => { const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); const responsePromise = subscribe(subChannel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await subChannel.attach(); await publish(pubChannel, 'Reply with exactly: Hello world'); const fullResponse = await responsePromise; expect(fullResponse.length).toBeGreaterThan(0); @@ -67,7 +69,7 @@ describe('vercel-message-per-response', () => { }); const responsePromise = subscribe(channel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await channel.attach(); await publish(pubChannel, 'Reply with exactly: Test'); const fullResponse = await responsePromise; const concatenated = appendedTokens.join(''); diff --git a/guides/ai-transport/vercel-message-per-token/javascript/test/e2e.test.ts b/guides/ai-transport/vercel-message-per-token/javascript/test/e2e.test.ts index 3c183ab76c..4795fbd6e6 100644 --- a/guides/ai-transport/vercel-message-per-token/javascript/test/e2e.test.ts +++ b/guides/ai-transport/vercel-message-per-token/javascript/test/e2e.test.ts @@ -2,6 +2,7 @@ import Ably from 'ably'; import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { publish } from '../src/publisher.js'; import { subscribe } from '../src/subscriber.js'; +import { waitForMessage } from '../../../test-helpers.js'; describe('vercel-message-per-token', () => { let publisherClient: Ably.Realtime; @@ -33,8 +34,9 @@ describe('vercel-message-per-token', () => { }); }); + const stopReceived = waitForMessage(channel, (m) => m.name === 'stop'); await publish(pubChannel, 'Reply with exactly: OK'); - await new Promise((resolve) => setTimeout(resolve, 2000)); + await stopReceived; expect(events[0].name).toBe('start'); expect(events[events.length - 1].name).toBe('stop'); @@ -49,7 +51,7 @@ describe('vercel-message-per-token', () => { const subChannel = subscriberClient.channels.get(channelName + '-reconstruct'); const pubChannel = publisherClient.channels.get(channelName + '-reconstruct'); const responsePromise = subscribe(subChannel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await subChannel.attach(); await publish(pubChannel, 'Reply with exactly: Hello world'); const fullResponse = await responsePromise; expect(fullResponse.length).toBeGreaterThan(0); @@ -64,7 +66,7 @@ describe('vercel-message-per-token', () => { tokens.push(message.data as string); }); const responsePromise = subscribe(channel); - await new Promise((resolve) => setTimeout(resolve, 1000)); + await channel.attach(); await publish(pubChannel, 'Reply with exactly: Test'); const fullResponse = await responsePromise; const concatenated = tokens.join(''); diff --git a/guides/ai-transport/yarn.lock b/guides/ai-transport/yarn.lock index 0d5aeb63e9..5c1c338b4a 100644 --- a/guides/ai-transport/yarn.lock +++ b/guides/ai-transport/yarn.lock @@ -4,14 +4,14 @@ "@ably/msgpack-js@^0.4.0": version "0.4.1" - resolved "https://registry.yarnpkg.com/@ably/msgpack-js/-/msgpack-js-0.4.1.tgz#81526bdea5362ca57c112356899a5e506a34b760" + resolved "https://registry.npmjs.org/@ably/msgpack-js/-/msgpack-js-0.4.1.tgz" integrity sha512-Sjxj6SOr17hExAVrsycN7u6oV4PhZcK7Z2S8dM71CH/butgO47cSo/TL6FJPCXUyDAzKkOWjMUpJGyZkEpyu4Q== dependencies: bops "^1.0.1" "@ai-sdk/gateway@3.0.46": version "3.0.46" - resolved "https://registry.yarnpkg.com/@ai-sdk/gateway/-/gateway-3.0.46.tgz#e329bebbf66cfc16f2a5c616a40d45e9232a2d72" + resolved "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.46.tgz" integrity sha512-zH1UbNRjG5woOXXFOrVCZraqZuFTtmPvLardMGcgLkzpxKV0U3tAGoyWKSZ862H+eBJfI/Hf2yj/zzGJcCkycg== dependencies: "@ai-sdk/provider" "3.0.8" @@ -20,7 +20,7 @@ "@ai-sdk/openai@^2": version "2.0.91" - resolved "https://registry.yarnpkg.com/@ai-sdk/openai/-/openai-2.0.91.tgz#1c615ee29db62355be261c2da324b5a85169798f" + resolved "https://registry.npmjs.org/@ai-sdk/openai/-/openai-2.0.91.tgz" integrity sha512-lozfRHfSTHg5/UliQjTDcOtISYGbEpt4FS/6QM5PcLmhdT0HmROllaBmG7+JaK+uqFtDXZGgMIpz3bqB9nzqCQ== dependencies: "@ai-sdk/provider" "2.0.1" @@ -28,7 +28,7 @@ "@ai-sdk/provider-utils@3.0.21": version "3.0.21" - resolved "https://registry.yarnpkg.com/@ai-sdk/provider-utils/-/provider-utils-3.0.21.tgz#b98175079d2787f0dda7027d74482f4ae1acfbc8" + resolved "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.21.tgz" integrity sha512-veuMwTLxsgh31Jjn0SnBABnM1f7ebHhRWcV2ZuY3hP3iJDCZ8VXBaYqcHXoOQDqUXTCas08sKQcHyWK+zl882Q== dependencies: "@ai-sdk/provider" "2.0.1" @@ -37,7 +37,7 @@ "@ai-sdk/provider-utils@4.0.15": version "4.0.15" - resolved "https://registry.yarnpkg.com/@ai-sdk/provider-utils/-/provider-utils-4.0.15.tgz#d585c7c89cfdf13697a40be5768ecd907a251585" + resolved "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.15.tgz" integrity sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w== dependencies: "@ai-sdk/provider" "3.0.8" @@ -46,188 +46,63 @@ "@ai-sdk/provider@2.0.1": version "2.0.1" - resolved "https://registry.yarnpkg.com/@ai-sdk/provider/-/provider-2.0.1.tgz#4aba415f1815da33a7a81e5f41a0219af53278c0" + resolved "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.1.tgz" integrity sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng== dependencies: json-schema "^0.4.0" "@ai-sdk/provider@3.0.8": version "3.0.8" - resolved "https://registry.yarnpkg.com/@ai-sdk/provider/-/provider-3.0.8.tgz#fd7fac7533c03534ac1d3fb710a6b96e2aa00263" + resolved "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz" integrity sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ== dependencies: json-schema "^0.4.0" "@anthropic-ai/sdk@^0.65.0": version "0.65.0" - resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.65.0.tgz#3f464fe2029eacf8e7e7fb8197579d00c8ca7502" + resolved "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.65.0.tgz" integrity sha512-zIdPOcrCVEI8t3Di40nH4z9EoeyGZfXbYSvWdDLsB/KkaSYMnEgC7gmcgWu83g2NTn1ZTpbMvpdttWDGGIk6zw== dependencies: json-schema-to-ts "^3.1.1" "@anthropic-ai/sdk@^0.71": version "0.71.2" - resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.71.2.tgz#1e3e08a7b2c3129828480a3d0ca4487472fdde3d" + resolved "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.2.tgz" integrity sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ== dependencies: json-schema-to-ts "^3.1.1" "@babel/runtime@^7.18.3": version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz" integrity sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA== "@cfworker/json-schema@^4.0.2": version "4.1.1" - resolved "https://registry.yarnpkg.com/@cfworker/json-schema/-/json-schema-4.1.1.tgz#4a2a3947ee9fa7b7c24be981422831b8674c3be6" + resolved "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.1.tgz" integrity sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og== -"@esbuild/aix-ppc64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz#815b39267f9bffd3407ea6c376ac32946e24f8d2" - integrity sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg== - -"@esbuild/android-arm64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz#19b882408829ad8e12b10aff2840711b2da361e8" - integrity sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg== - -"@esbuild/android-arm@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.3.tgz#90be58de27915efa27b767fcbdb37a4470627d7b" - integrity sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA== - -"@esbuild/android-x64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.3.tgz#d7dcc976f16e01a9aaa2f9b938fbec7389f895ac" - integrity sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ== - "@esbuild/darwin-arm64@0.27.3": version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz#9f6cac72b3a8532298a6a4493ed639a8988e8abd" + resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz" integrity sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg== -"@esbuild/darwin-x64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz#ac61d645faa37fd650340f1866b0812e1fb14d6a" - integrity sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg== - -"@esbuild/freebsd-arm64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz#b8625689d73cf1830fe58c39051acdc12474ea1b" - integrity sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w== - -"@esbuild/freebsd-x64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz#07be7dd3c9d42fe0eccd2ab9f9ded780bc53bead" - integrity sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA== - -"@esbuild/linux-arm64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz#bf31918fe5c798586460d2b3d6c46ed2c01ca0b6" - integrity sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg== - -"@esbuild/linux-arm@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz#28493ee46abec1dc3f500223cd9f8d2df08f9d11" - integrity sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw== - -"@esbuild/linux-ia32@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz#750752a8b30b43647402561eea764d0a41d0ee29" - integrity sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg== - -"@esbuild/linux-loong64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz#a5a92813a04e71198c50f05adfaf18fc1e95b9ed" - integrity sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA== - -"@esbuild/linux-mips64el@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz#deb45d7fd2d2161eadf1fbc593637ed766d50bb1" - integrity sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw== - -"@esbuild/linux-ppc64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz#6f39ae0b8c4d3d2d61a65b26df79f6e12a1c3d78" - integrity sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA== - -"@esbuild/linux-riscv64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz#4c5c19c3916612ec8e3915187030b9df0b955c1d" - integrity sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ== - -"@esbuild/linux-s390x@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz#9ed17b3198fa08ad5ccaa9e74f6c0aff7ad0156d" - integrity sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw== - -"@esbuild/linux-x64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz#12383dcbf71b7cf6513e58b4b08d95a710bf52a5" - integrity sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA== - -"@esbuild/netbsd-arm64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz#dd0cb2fa543205fcd931df44f4786bfcce6df7d7" - integrity sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA== - -"@esbuild/netbsd-x64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz#028ad1807a8e03e155153b2d025b506c3787354b" - integrity sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA== - -"@esbuild/openbsd-arm64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz#e3c16ff3490c9b59b969fffca87f350ffc0e2af5" - integrity sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw== - -"@esbuild/openbsd-x64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz#c5a4693fcb03d1cbecbf8b422422468dfc0d2a8b" - integrity sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ== - -"@esbuild/openharmony-arm64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz#082082444f12db564a0775a41e1991c0e125055e" - integrity sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g== - -"@esbuild/sunos-x64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz#5ab036c53f929e8405c4e96e865a424160a1b537" - integrity sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA== - -"@esbuild/win32-arm64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz#38de700ef4b960a0045370c171794526e589862e" - integrity sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA== - -"@esbuild/win32-ia32@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz#451b93dc03ec5d4f38619e6cd64d9f9eff06f55c" - integrity sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q== - -"@esbuild/win32-x64@0.27.3": - version "0.27.3" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz#0eaf705c941a218a43dba8e09f1df1d6cd2f1f17" - integrity sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA== - "@jridgewell/sourcemap-codec@^1.5.5": version "1.5.5" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz" integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== "@langchain/anthropic@^0.3": version "0.3.34" - resolved "https://registry.yarnpkg.com/@langchain/anthropic/-/anthropic-0.3.34.tgz#ff131b9b612a76d7e97d960058efe3f0ccad8179" + resolved "https://registry.npmjs.org/@langchain/anthropic/-/anthropic-0.3.34.tgz" integrity sha512-8bOW1A2VHRCjbzdYElrjxutKNs9NSIxYRGtR+OJWVzluMqoKKh2NmmFrpPizEyqCUEG2tTq5xt6XA1lwfqMJRA== dependencies: "@anthropic-ai/sdk" "^0.65.0" fast-xml-parser "^4.4.1" -"@langchain/core@^0.3": +"@langchain/core@^0.3", "@langchain/core@>=0.2.31 <0.4.0", "@langchain/core@>=0.2.36 <0.3.0 || >=0.3.40 < 0.4.0", "@langchain/core@>=0.3.58 <0.4.0": version "0.3.80" - resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.80.tgz#c494a6944e53ab28bf32dc531e257b17cfc8f797" + resolved "https://registry.npmjs.org/@langchain/core/-/core-0.3.80.tgz" integrity sha512-vcJDV2vk1AlCwSh3aBm/urQ1ZrlXFFBocv11bz/NBUfLWD5/UDNMzwPdaAd2dKvNmTWa9FM2lirLU3+JCf4cRA== dependencies: "@cfworker/json-schema" "^4.0.2" @@ -245,14 +120,14 @@ "@langchain/langgraph-checkpoint@~0.0.17": version "0.0.18" - resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.18.tgz#2f7a9cdeda948ccc8d312ba9463810709d71d0b8" + resolved "https://registry.npmjs.org/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.18.tgz" integrity sha512-IS7zJj36VgY+4pf8ZjsVuUWef7oTwt1y9ylvwu0aLuOn1d0fg05Om9DLm3v2GZ2Df6bhLV1kfWAM0IAl9O5rQQ== dependencies: uuid "^10.0.0" "@langchain/langgraph-sdk@~0.0.32": version "0.0.112" - resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.112.tgz#3186919b60e3381aa8aa32ea9b9c39df1f02a9fd" + resolved "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.112.tgz" integrity sha512-/9W5HSWCqYgwma6EoOspL4BGYxGxeJP6lIquPSF4FA0JlKopaUv58ucZC3vAgdJyCgg6sorCIV/qg7SGpEcCLw== dependencies: "@types/json-schema" "^7.0.15" @@ -262,7 +137,7 @@ "@langchain/langgraph@^0.2": version "0.2.74" - resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.74.tgz#37367a1e8bafda3548037a91449a69a84f285def" + resolved "https://registry.npmjs.org/@langchain/langgraph/-/langgraph-0.2.74.tgz" integrity sha512-oHpEi5sTZTPaeZX1UnzfM2OAJ21QGQrwReTV6+QnX7h8nDCBzhtipAw1cK616S+X8zpcVOjgOtJuaJhXa4mN8w== dependencies: "@langchain/langgraph-checkpoint" "~0.0.17" @@ -270,156 +145,36 @@ uuid "^10.0.0" zod "^3.23.8" -"@opentelemetry/api@1.9.0": +"@opentelemetry/api@*", "@opentelemetry/api@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" + resolved "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== -"@rollup/rollup-android-arm-eabi@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz#add5e608d4e7be55bc3ca3d962490b8b1890e088" - integrity sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg== - -"@rollup/rollup-android-arm64@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz#10bd0382b73592beee6e9800a69401a29da625c4" - integrity sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w== - "@rollup/rollup-darwin-arm64@4.57.1": version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz#1e99ab04c0b8c619dd7bbde725ba2b87b55bfd81" + resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz" integrity sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg== -"@rollup/rollup-darwin-x64@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz#69e741aeb2839d2e8f0da2ce7a33d8bd23632423" - integrity sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w== - -"@rollup/rollup-freebsd-arm64@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz#3736c232a999c7bef7131355d83ebdf9651a0839" - integrity sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug== - -"@rollup/rollup-freebsd-x64@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz#227dcb8f466684070169942bd3998901c9bfc065" - integrity sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q== - -"@rollup/rollup-linux-arm-gnueabihf@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz#ba004b30df31b724f99ce66e7128248bea17cb0c" - integrity sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw== - -"@rollup/rollup-linux-arm-musleabihf@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz#6929f3e07be6b6da5991f63c6b68b3e473d0a65a" - integrity sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw== - -"@rollup/rollup-linux-arm64-gnu@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz#06e89fd4a25d21fe5575d60b6f913c0e65297bfa" - integrity sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g== - -"@rollup/rollup-linux-arm64-musl@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz#fddabf395b90990d5194038e6cd8c00156ed8ac0" - integrity sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q== - -"@rollup/rollup-linux-loong64-gnu@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz#04c10bb764bbf09a3c1bd90432e92f58d6603c36" - integrity sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA== - -"@rollup/rollup-linux-loong64-musl@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz#f2450361790de80581d8687ea19142d8a4de5c0f" - integrity sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw== - -"@rollup/rollup-linux-ppc64-gnu@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz#0474f4667259e407eee1a6d38e29041b708f6a30" - integrity sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w== - -"@rollup/rollup-linux-ppc64-musl@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz#9f32074819eeb1ddbe51f50ea9dcd61a6745ec33" - integrity sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw== - -"@rollup/rollup-linux-riscv64-gnu@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz#3fdb9d4b1e29fb6b6a6da9f15654d42eb77b99b2" - integrity sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A== - -"@rollup/rollup-linux-riscv64-musl@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz#1de780d64e6be0e3e8762035c22e0d8ea68df8ed" - integrity sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw== - -"@rollup/rollup-linux-s390x-gnu@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz#1da022ffd2d9e9f0fd8344ea49e113001fbcac64" - integrity sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg== - -"@rollup/rollup-linux-x64-gnu@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz#78c16eef9520bd10e1ea7a112593bb58e2842622" - integrity sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg== - -"@rollup/rollup-linux-x64-musl@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz#a7598591b4d9af96cb3167b50a5bf1e02dfea06c" - integrity sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw== - -"@rollup/rollup-openbsd-x64@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz#c51d48c07cd6c466560e5bed934aec688ce02614" - integrity sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw== - -"@rollup/rollup-openharmony-arm64@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz#f09921d0b2a0b60afbf3586d2a7a7f208ba6df17" - integrity sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ== - -"@rollup/rollup-win32-arm64-msvc@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz#08d491717135376e4a99529821c94ecd433d5b36" - integrity sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ== - -"@rollup/rollup-win32-ia32-msvc@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz#b0c12aac1104a8b8f26a5e0098e5facbb3e3964a" - integrity sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew== - -"@rollup/rollup-win32-x64-gnu@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz#b9cccef26f5e6fdc013bf3c0911a3c77428509d0" - integrity sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ== - -"@rollup/rollup-win32-x64-msvc@4.57.1": - version "4.57.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz#a03348e7b559c792b6277cc58874b89ef46e1e72" - integrity sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA== - "@sindresorhus/is@^4.0.0": version "4.6.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== "@standard-schema/spec@^1.0.0", "@standard-schema/spec@^1.1.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" + resolved "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz" integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== "@szmarczak/http-timer@^4.0.5": version "4.0.6" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz" integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== dependencies: defer-to-connect "^2.0.0" "@types/cacheable-request@^6.0.1": version "6.0.3" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + resolved "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz" integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== dependencies: "@types/http-cache-semantics" "*" @@ -429,7 +184,7 @@ "@types/chai@^5.2.2": version "5.2.3" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.2.3.tgz#8e9cd9e1c3581fa6b341a5aed5588eb285be0b4a" + resolved "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz" integrity sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA== dependencies: "@types/deep-eql" "*" @@ -437,78 +192,78 @@ "@types/deep-eql@*": version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + resolved "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz" integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== -"@types/estree@1.0.8", "@types/estree@^1.0.0": +"@types/estree@^1.0.0", "@types/estree@1.0.8": version "1.0.8" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== "@types/http-cache-semantics@*": version "4.2.0" - resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#f6a7788f438cbfde15f29acad46512b4c01913b3" + resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz" integrity sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q== "@types/json-schema@^7.0.15": version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/keyv@^3.1.4": version "3.1.4" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + resolved "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz" integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== dependencies: "@types/node" "*" "@types/node-fetch@^2.6.4": version "2.6.13" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.13.tgz#e0c9b7b5edbdb1b50ce32c127e85e880872d56ee" + resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz" integrity sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw== dependencies: "@types/node" "*" form-data "^4.0.4" -"@types/node@*": +"@types/node@*", "@types/node@^18.0.0 || ^20.0.0 || >=22.0.0", "@types/node@^20.19.0 || >=22.12.0": version "25.2.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-25.2.3.tgz#9c18245be768bdb4ce631566c7da303a5c99a7f8" + resolved "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz" integrity sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ== dependencies: undici-types "~7.16.0" "@types/node@^18.11.18": version "18.19.130" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.130.tgz#da4c6324793a79defb7a62cba3947ec5add00d59" + resolved "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz" integrity sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg== dependencies: undici-types "~5.26.4" "@types/responselike@^1.0.0": version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" + resolved "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz" integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== dependencies: "@types/node" "*" "@types/retry@0.12.0": version "0.12.0" - resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz" integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== "@types/uuid@^10.0.0": version "10.0.0" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-10.0.0.tgz#e9c07fe50da0f53dc24970cca94d619ff03f6f6d" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz" integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== "@vercel/oidc@3.1.0": version "3.1.0" - resolved "https://registry.yarnpkg.com/@vercel/oidc/-/oidc-3.1.0.tgz#066caee449b84079f33c7445fc862464fe10ec32" + resolved "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz" integrity sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w== "@vitest/expect@3.2.4": version "3.2.4" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.2.4.tgz#8362124cd811a5ee11c5768207b9df53d34f2433" + resolved "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz" integrity sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig== dependencies: "@types/chai" "^5.2.2" @@ -519,23 +274,23 @@ "@vitest/mocker@3.2.4": version "3.2.4" - resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-3.2.4.tgz#4471c4efbd62db0d4fa203e65cc6b058a85cabd3" + resolved "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz" integrity sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ== dependencies: "@vitest/spy" "3.2.4" estree-walker "^3.0.3" magic-string "^0.30.17" -"@vitest/pretty-format@3.2.4", "@vitest/pretty-format@^3.2.4": +"@vitest/pretty-format@^3.2.4", "@vitest/pretty-format@3.2.4": version "3.2.4" - resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-3.2.4.tgz#3c102f79e82b204a26c7a5921bf47d534919d3b4" + resolved "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz" integrity sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA== dependencies: tinyrainbow "^2.0.0" "@vitest/runner@3.2.4": version "3.2.4" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-3.2.4.tgz#5ce0274f24a971f6500f6fc166d53d8382430766" + resolved "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz" integrity sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ== dependencies: "@vitest/utils" "3.2.4" @@ -544,7 +299,7 @@ "@vitest/snapshot@3.2.4": version "3.2.4" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-3.2.4.tgz#40a8bc0346ac0aee923c0eefc2dc005d90bc987c" + resolved "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz" integrity sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ== dependencies: "@vitest/pretty-format" "3.2.4" @@ -553,14 +308,14 @@ "@vitest/spy@3.2.4": version "3.2.4" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-3.2.4.tgz#cc18f26f40f3f028da6620046881f4e4518c2599" + resolved "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz" integrity sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw== dependencies: tinyspy "^4.0.3" "@vitest/utils@3.2.4": version "3.2.4" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-3.2.4.tgz#c0813bc42d99527fb8c5b138c7a88516bca46fea" + resolved "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz" integrity sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA== dependencies: "@vitest/pretty-format" "3.2.4" @@ -569,7 +324,7 @@ ably@^2.17.0: version "2.17.1" - resolved "https://registry.yarnpkg.com/ably/-/ably-2.17.1.tgz#7fe6877ba141ee70d8856523ec3a21d6716c1916" + resolved "https://registry.npmjs.org/ably/-/ably-2.17.1.tgz" integrity sha512-70yfXHoM7JtJD/8FCtPD1gkWW0f+AJqbJp0PsqDAqiyxFB8cPFY+FuKHgNTYb8eRHKXq8hT1xiDphUcY0+GHnA== dependencies: "@ably/msgpack-js" "^0.4.0" @@ -581,21 +336,21 @@ ably@^2.17.0: abort-controller@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== dependencies: event-target-shim "^5.0.0" agentkeepalive@^4.2.1: version "4.6.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz" integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== dependencies: humanize-ms "^1.2.1" ai@^6: version "6.0.86" - resolved "https://registry.yarnpkg.com/ai/-/ai-6.0.86.tgz#cee563e8a0d9b87f8fdda764f190e7dd3f81ba00" + resolved "https://registry.npmjs.org/ai/-/ai-6.0.86.tgz" integrity sha512-U2W2LBCHA/pr0Ui7vmmsjBiLEzBbZF3yVHNy7Rbzn7IX+SvoQPFM5rN74hhfVzZoE8zBuGD4nLLk+j0elGacvQ== dependencies: "@ai-sdk/gateway" "3.0.46" @@ -605,39 +360,39 @@ ai@^6: ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" ansi-styles@^5.0.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== assertion-error@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz" integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -base64-js@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.2.tgz#474211c95e6cf2a547db461e4f6778b51d08fa65" - integrity sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg== - base64-js@^1.5.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +base64-js@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.0.2.tgz" + integrity sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg== + bops@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/bops/-/bops-1.0.1.tgz#502aaf00ee119db1dbae088e3df4bea2e241dbcc" + resolved "https://registry.npmjs.org/bops/-/bops-1.0.1.tgz" integrity sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag== dependencies: base64-js "1.0.2" @@ -645,17 +400,17 @@ bops@^1.0.1: cac@^6.7.14: version "6.7.14" - resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + resolved "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz" integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== cacheable-lookup@^5.0.3: version "5.0.4" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz" integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== cacheable-request@^7.0.2: version "7.0.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz" integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== dependencies: clone-response "^1.0.2" @@ -668,7 +423,7 @@ cacheable-request@^7.0.2: call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== dependencies: es-errors "^1.3.0" @@ -676,12 +431,12 @@ call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: camelcase@6: version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== chai@^5.2.0: version "5.3.3" - resolved "https://registry.yarnpkg.com/chai/-/chai-5.3.3.tgz#dd3da955e270916a4bd3f625f4b919996ada7e06" + resolved "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz" integrity sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw== dependencies: assertion-error "^2.0.1" @@ -692,7 +447,7 @@ chai@^5.2.0: chalk@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -700,89 +455,89 @@ chalk@^4.1.2: check-error@^2.1.1: version "2.1.3" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.3.tgz#2427361117b70cca8dc89680ead32b157019caf5" + resolved "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz" integrity sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA== clone-response@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz" integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== dependencies: mimic-response "^1.0.0" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" console-table-printer@^2.12.1: version "2.15.0" - resolved "https://registry.yarnpkg.com/console-table-printer/-/console-table-printer-2.15.0.tgz#5c808204640b8f024d545bde8aabe5d344dfadc1" + resolved "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.15.0.tgz" integrity sha512-SrhBq4hYVjLCkBVOWaTzceJalvn5K1Zq5aQA6wXC/cYjI3frKWNPEMK3sZsJfNNQApvCQmgBcc13ZKmFj8qExw== dependencies: simple-wcswidth "^1.1.2" debug@^4.4.1: version "4.4.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: ms "^2.1.3" decamelize@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== decompress-response@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz" integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== dependencies: mimic-response "^3.1.0" deep-eql@^5.0.1: version "5.0.2" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz" integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== defer-to-connect@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== dequal@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== dotenv@^16.4.5: version "16.6.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz" integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== dunder-proto@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== dependencies: call-bind-apply-helpers "^1.0.1" @@ -791,36 +546,36 @@ dunder-proto@^1.0.1: end-of-stream@^1.1.0: version "1.4.5" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz" integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== dependencies: once "^1.4.0" es-define-property@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== es-errors@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-module-lexer@^1.7.0: version "1.7.0" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" + resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz" integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== dependencies: es-errors "^1.3.0" es-set-tostringtag@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz" integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== dependencies: es-errors "^1.3.0" @@ -830,7 +585,7 @@ es-set-tostringtag@^2.1.0: esbuild@^0.27.0, esbuild@~0.27.0: version "0.27.3" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.27.3.tgz#5859ca8e70a3af956b26895ce4954d7e73bd27a8" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz" integrity sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg== optionalDependencies: "@esbuild/aix-ppc64" "0.27.3" @@ -862,56 +617,56 @@ esbuild@^0.27.0, esbuild@~0.27.0: estree-walker@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz" integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== dependencies: "@types/estree" "^1.0.0" event-target-shim@^5.0.0: version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== eventemitter3@^4.0.4: version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== eventsource-parser@^3.0.6: version "3.0.6" - resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.6.tgz#292e165e34cacbc936c3c92719ef326d4aeb4e90" + resolved "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz" integrity sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg== expect-type@^1.2.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.3.0.tgz#0d58ed361877a31bbc4dd6cf71bbfef7faf6bd68" + resolved "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz" integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA== fast-xml-parser@^4.4.1: version "4.5.3" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz#c54d6b35aa0f23dc1ea60b6c884340c006dc6efb" + resolved "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz" integrity sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig== dependencies: strnum "^1.1.1" fastestsmallesttextencoderdecoder@^1.0.22: version "1.0.22" - resolved "https://registry.yarnpkg.com/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz#59b47e7b965f45258629cc6c127bf783281c5e93" + resolved "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz" integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== fdir@^6.5.0: version "6.5.0" - resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz" integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== form-data-encoder@1.7.2: version "1.7.2" - resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" + resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz" integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== form-data@^4.0.4: version "4.0.5" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz" integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== dependencies: asynckit "^0.4.0" @@ -922,25 +677,20 @@ form-data@^4.0.4: formdata-node@^4.3.2: version "4.4.1" - resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" + resolved "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz" integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== dependencies: node-domexception "1.0.0" web-streams-polyfill "4.0.0-beta.3" -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== get-intrinsic@^1.2.6: version "1.3.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== dependencies: call-bind-apply-helpers "^1.0.2" @@ -956,7 +706,7 @@ get-intrinsic@^1.2.6: get-proto@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== dependencies: dunder-proto "^1.0.1" @@ -964,26 +714,26 @@ get-proto@^1.0.1: get-stream@^5.1.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz" integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== dependencies: pump "^3.0.0" get-tsconfig@^4.7.5: version "4.13.6" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.13.6.tgz#2fbfda558a98a691a798f123afd95915badce876" + resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz" integrity sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw== dependencies: resolve-pkg-maps "^1.0.0" gopd@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== got@^11.8.5: version "11.8.6" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + resolved "https://registry.npmjs.org/got/-/got-11.8.6.tgz" integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== dependencies: "@sindresorhus/is" "^4.0.0" @@ -998,38 +748,92 @@ got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" +"guide-anthropic-message-per-response@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/anthropic-message-per-response/javascript": + version "0.1.0" + resolved "file:anthropic-message-per-response/javascript" + dependencies: + "@anthropic-ai/sdk" "^0.71" + +"guide-anthropic-message-per-token@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/anthropic-message-per-token/javascript": + version "0.1.0" + resolved "file:anthropic-message-per-token/javascript" + dependencies: + "@anthropic-ai/sdk" "^0.71" + +"guide-lang-graph-message-per-response@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/lang-graph-message-per-response/javascript": + version "0.1.0" + resolved "file:lang-graph-message-per-response/javascript" + dependencies: + "@langchain/anthropic" "^0.3" + "@langchain/core" "^0.3" + "@langchain/langgraph" "^0.2" + +"guide-lang-graph-message-per-token@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/lang-graph-message-per-token/javascript": + version "0.1.0" + resolved "file:lang-graph-message-per-token/javascript" + dependencies: + "@langchain/anthropic" "^0.3" + "@langchain/core" "^0.3" + "@langchain/langgraph" "^0.2" + +"guide-openai-message-per-response@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/openai-message-per-response/javascript": + version "0.1.0" + resolved "file:openai-message-per-response/javascript" + dependencies: + openai "^4" + +"guide-openai-message-per-token@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/openai-message-per-token/javascript": + version "0.1.0" + resolved "file:openai-message-per-token/javascript" + dependencies: + openai "^4" + +"guide-vercel-message-per-response@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/vercel-message-per-response/javascript": + version "0.1.0" + resolved "file:vercel-message-per-response/javascript" + dependencies: + "@ai-sdk/openai" "^2" + ai "^6" + +"guide-vercel-message-per-token@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/vercel-message-per-token/javascript": + version "0.1.0" + resolved "file:vercel-message-per-token/javascript" + dependencies: + "@ai-sdk/openai" "^2" + ai "^6" + has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-symbols@^1.0.3, has-symbols@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== has-tostringtag@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: has-symbols "^1.0.3" hasown@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" http-cache-semantics@^4.0.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz" integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ== http2-wrapper@^1.0.0-beta.5.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz" integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== dependencies: quick-lru "^5.1.1" @@ -1037,31 +841,31 @@ http2-wrapper@^1.0.0-beta.5.2: humanize-ms@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== dependencies: ms "^2.0.0" js-tiktoken@^1.0.12: version "1.0.21" - resolved "https://registry.yarnpkg.com/js-tiktoken/-/js-tiktoken-1.0.21.tgz#368a9957591a30a62997dd0c4cf30866f00f8221" + resolved "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz" integrity sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g== dependencies: base64-js "^1.5.1" js-tokens@^9.0.1: version "9.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz" integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== json-buffer@3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== json-schema-to-ts@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz#81f3acaf5a34736492f6f5f51870ef9ece1ca853" + resolved "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz" integrity sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g== dependencies: "@babel/runtime" "^7.18.3" @@ -1069,19 +873,19 @@ json-schema-to-ts@^3.1.1: json-schema@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== keyv@^4.0.0: version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" langsmith@^0.3.67: version "0.3.87" - resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.3.87.tgz#f1c991c93a5d4d226a31671be7e4443b4b8673b1" + resolved "https://registry.npmjs.org/langsmith/-/langsmith-0.3.87.tgz" integrity sha512-XXR1+9INH8YX96FKWc5tie0QixWz6tOqAsAKfcJyPkE0xPep+NDz0IQLR32q4bn10QK3LqD2HN6T3n6z1YLW7Q== dependencies: "@types/uuid" "^10.0.0" @@ -1093,90 +897,90 @@ langsmith@^0.3.67: loupe@^3.1.0, loupe@^3.1.4: version "3.2.1" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" + resolved "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz" integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== lowercase-keys@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== magic-string@^0.30.17: version "0.30.21" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz" integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== dependencies: "@jridgewell/sourcemap-codec" "^1.5.5" math-intrinsics@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== mime-db@1.52.0: version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-types@^2.1.12: version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" mimic-response@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== mimic-response@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== ms@^2.0.0, ms@^2.1.3: version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== mustache@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" + resolved "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz" integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== nanoid@^3.3.11: version "3.3.11" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz" integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== node-domexception@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== node-fetch@^2.6.7: version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" normalize-url@^6.0.1: version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -openai@^4: +openai@*, openai@^4: version "4.104.0" - resolved "https://registry.yarnpkg.com/openai/-/openai-4.104.0.tgz#c489765dc051b95019845dab64b0e5207cae4d30" + resolved "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz" integrity sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA== dependencies: "@types/node" "^18.11.18" @@ -1189,17 +993,17 @@ openai@^4: p-cancelable@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz" integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== p-finally@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== p-queue@^6.6.2: version "6.6.2" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" + resolved "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz" integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== dependencies: eventemitter3 "^4.0.4" @@ -1207,7 +1011,7 @@ p-queue@^6.6.2: p-retry@4: version "4.6.2" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + resolved "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz" integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== dependencies: "@types/retry" "0.12.0" @@ -1215,34 +1019,34 @@ p-retry@4: p-timeout@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz" integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== dependencies: p-finally "^1.0.0" pathe@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + resolved "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz" integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== pathval@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" + resolved "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz" integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== picocolors@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^4.0.2, picomatch@^4.0.3: +"picomatch@^3 || ^4", picomatch@^4.0.2, picomatch@^4.0.3: version "4.0.3" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz" integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== postcss@^8.5.6: version "8.5.6" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz" integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== dependencies: nanoid "^3.3.11" @@ -1251,7 +1055,7 @@ postcss@^8.5.6: pump@^3.0.0: version "3.0.3" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz" integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA== dependencies: end-of-stream "^1.1.0" @@ -1259,34 +1063,34 @@ pump@^3.0.0: quick-lru@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== resolve-alpn@^1.0.0: version "1.2.1" - resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz" integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== resolve-pkg-maps@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== responselike@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + resolved "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz" integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== dependencies: lowercase-keys "^2.0.0" retry@^0.13.1: version "0.13.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + resolved "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz" integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== rollup@^4.43.0: version "4.57.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.57.1.tgz#947f70baca32db2b9c594267fe9150aa316e5a88" + resolved "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz" integrity sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A== dependencies: "@types/estree" "1.0.8" @@ -1320,66 +1124,66 @@ rollup@^4.43.0: semver@^7.6.3: version "7.7.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz" integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== siginfo@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + resolved "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz" integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== simple-wcswidth@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/simple-wcswidth/-/simple-wcswidth-1.1.2.tgz#66722f37629d5203f9b47c5477b1225b85d6525b" + resolved "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.1.2.tgz" integrity sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw== source-map-js@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== stackback@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + resolved "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz" integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== std-env@^3.9.0: version "3.10.0" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" + resolved "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz" integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== strip-literal@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-3.1.0.tgz#222b243dd2d49c0bcd0de8906adbd84177196032" + resolved "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz" integrity sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg== dependencies: js-tokens "^9.0.1" strnum@^1.1.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.1.2.tgz#57bca4fbaa6f271081715dbc9ed7cee5493e28e4" + resolved "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz" integrity sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA== supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" tinybench@^2.9.0: version "2.9.0" - resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + resolved "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz" integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== tinyexec@^0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + resolved "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz" integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== tinyglobby@^0.2.14, tinyglobby@^0.2.15: version "0.2.15" - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz" integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== dependencies: fdir "^6.5.0" @@ -1387,37 +1191,37 @@ tinyglobby@^0.2.14, tinyglobby@^0.2.15: tinypool@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591" + resolved "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz" integrity sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg== tinyrainbow@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz#9509b2162436315e80e3eee0fcce4474d2444294" + resolved "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz" integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw== tinyspy@^4.0.3: version "4.0.4" - resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-4.0.4.tgz#d77a002fb53a88aa1429b419c1c92492e0c81f78" + resolved "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz" integrity sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q== to-utf8@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + resolved "https://registry.npmjs.org/to-utf8/-/to-utf8-0.0.1.tgz" integrity sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ== tr46@~0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== ts-algebra@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ts-algebra/-/ts-algebra-2.0.0.tgz#4e3e0953878f26518fce7f6bb115064a65388b7a" + resolved "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz" integrity sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw== -tsx@^4.19.0: +tsx@^4.19.0, tsx@^4.8.1: version "4.21.0" - resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.21.0.tgz#32aa6cf17481e336f756195e6fe04dae3e6308b1" + resolved "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz" integrity sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw== dependencies: esbuild "~0.27.0" @@ -1427,37 +1231,37 @@ tsx@^4.19.0: typescript@^5: version "5.9.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz" integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== ulid@^2.3.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.4.0.tgz#9d9ee22e63f4390ee1bcd9ad09fca39d8ae0afed" + resolved "https://registry.npmjs.org/ulid/-/ulid-2.4.0.tgz" integrity sha512-fIRiVTJNcSRmXKPZtGzFQv9WRrZ3M9eoptl/teFJvjOzmpU+/K/JH6HZ8deBfb5vMEpicJcLn7JmvdknlMq7Zg== undici-types@~5.26.4: version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== undici-types@~7.16.0: version "7.16.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz" integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== uuid@^10.0.0: version "10.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + resolved "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz" integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== uuid@^9.0.0: version "9.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== vite-node@3.2.4: version "3.2.4" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.2.4.tgz#f3676d94c4af1e76898c162c92728bca65f7bb07" + resolved "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz" integrity sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg== dependencies: cac "^6.7.14" @@ -1468,7 +1272,7 @@ vite-node@3.2.4: "vite@^5.0.0 || ^6.0.0 || ^7.0.0-0": version "7.3.1" - resolved "https://registry.yarnpkg.com/vite/-/vite-7.3.1.tgz#7f6cfe8fb9074138605e822a75d9d30b814d6507" + resolved "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz" integrity sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA== dependencies: esbuild "^0.27.0" @@ -1482,7 +1286,7 @@ vite-node@3.2.4: vitest@^3.0.0: version "3.2.4" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.2.4.tgz#0637b903ad79d1539a25bc34c0ed54b5c67702ea" + resolved "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz" integrity sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A== dependencies: "@types/chai" "^5.2.2" @@ -1511,17 +1315,17 @@ vitest@^3.0.0: web-streams-polyfill@4.0.0-beta.3: version "4.0.0-beta.3" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" + resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz" integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== webidl-conversions@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== whatwg-url@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" @@ -1529,7 +1333,7 @@ whatwg-url@^5.0.0: why-is-node-running@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + resolved "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz" integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== dependencies: siginfo "^2.0.0" @@ -1537,20 +1341,20 @@ why-is-node-running@^2.3.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^8.17.1: +ws@^8.17.1, ws@^8.18.0: version "8.19.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.19.0.tgz#ddc2bdfa5b9ad860204f5a72a4863a8895fd8c8b" + resolved "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz" integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== -zod-to-json-schema@^3.22.3: +zod-to-json-schema@^3.22.3, zod-to-json-schema@^3.x: version "3.25.1" - resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz#7f24962101a439ddade2bf1aeab3c3bfec7d84ba" + resolved "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz" integrity sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA== -zod@^3.23.8, zod@^3.25.32: +zod@^3.23.8, "zod@^3.25 || ^4", "zod@^3.25.0 || ^4.0.0", zod@^3.25.32, "zod@^3.25.76 || ^4.1.8": version "3.25.76" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" + resolved "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz" integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== From 71326b2651d4dc5ff28283360cbd7591eecb645e Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 10 Mar 2026 12:10:21 +0000 Subject: [PATCH 4/4] Add e2e tests for citations and human-in-the-loop guides --- .../javascript/package.json | 14 + .../javascript/src/agent.ts | 140 ++++++++ .../javascript/src/client.ts | 64 ++++ .../javascript/test/e2e.test.ts | 58 +++ .../javascript/tsconfig.json | 4 + .../javascript/package.json | 14 + .../javascript/src/agent.ts | 98 +++++ .../javascript/src/approver.ts | 81 +++++ .../javascript/test/e2e.test.ts | 74 ++++ .../javascript/tsconfig.json | 4 + .../openai-citations/javascript/package.json | 14 + .../openai-citations/javascript/src/agent.ts | 76 ++++ .../openai-citations/javascript/src/client.ts | 58 +++ .../javascript/test/e2e.test.ts | 61 ++++ .../openai-citations/javascript/tsconfig.json | 4 + .../javascript/package.json | 14 + .../javascript/src/agent.ts | 88 +++++ .../javascript/src/approver.ts | 80 +++++ .../javascript/test/e2e.test.ts | 71 ++++ .../javascript/tsconfig.json | 4 + guides/ai-transport/package.json | 4 + guides/ai-transport/yarn.lock | 336 ++++++++++++++---- 22 files changed, 1291 insertions(+), 70 deletions(-) create mode 100644 guides/ai-transport/anthropic-citations/javascript/package.json create mode 100644 guides/ai-transport/anthropic-citations/javascript/src/agent.ts create mode 100644 guides/ai-transport/anthropic-citations/javascript/src/client.ts create mode 100644 guides/ai-transport/anthropic-citations/javascript/test/e2e.test.ts create mode 100644 guides/ai-transport/anthropic-citations/javascript/tsconfig.json create mode 100644 guides/ai-transport/anthropic-human-in-the-loop/javascript/package.json create mode 100644 guides/ai-transport/anthropic-human-in-the-loop/javascript/src/agent.ts create mode 100644 guides/ai-transport/anthropic-human-in-the-loop/javascript/src/approver.ts create mode 100644 guides/ai-transport/anthropic-human-in-the-loop/javascript/test/e2e.test.ts create mode 100644 guides/ai-transport/anthropic-human-in-the-loop/javascript/tsconfig.json create mode 100644 guides/ai-transport/openai-citations/javascript/package.json create mode 100644 guides/ai-transport/openai-citations/javascript/src/agent.ts create mode 100644 guides/ai-transport/openai-citations/javascript/src/client.ts create mode 100644 guides/ai-transport/openai-citations/javascript/test/e2e.test.ts create mode 100644 guides/ai-transport/openai-citations/javascript/tsconfig.json create mode 100644 guides/ai-transport/openai-human-in-the-loop/javascript/package.json create mode 100644 guides/ai-transport/openai-human-in-the-loop/javascript/src/agent.ts create mode 100644 guides/ai-transport/openai-human-in-the-loop/javascript/src/approver.ts create mode 100644 guides/ai-transport/openai-human-in-the-loop/javascript/test/e2e.test.ts create mode 100644 guides/ai-transport/openai-human-in-the-loop/javascript/tsconfig.json diff --git a/guides/ai-transport/anthropic-citations/javascript/package.json b/guides/ai-transport/anthropic-citations/javascript/package.json new file mode 100644 index 0000000000..d051b2467f --- /dev/null +++ b/guides/ai-transport/anthropic-citations/javascript/package.json @@ -0,0 +1,14 @@ +{ + "name": "guide-anthropic-citations", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:agent": "tsx src/agent.ts", + "start:client": "tsx src/client.ts", + "test": "vitest run" + }, + "dependencies": { + "@anthropic-ai/sdk": "^0.71" + } +} diff --git a/guides/ai-transport/anthropic-citations/javascript/src/agent.ts b/guides/ai-transport/anthropic-citations/javascript/src/agent.ts new file mode 100644 index 0000000000..908933de8d --- /dev/null +++ b/guides/ai-transport/anthropic-citations/javascript/src/agent.ts @@ -0,0 +1,140 @@ +import Anthropic from '@anthropic-ai/sdk'; +import Ably from 'ably'; + +interface Citation { + type: string; + cited_text: string; + document_index: number; + document_title: string; + start_char_index?: number; + end_char_index?: number; + start_page_number?: number; + end_page_number?: number; + source?: string; + responseStartOffset: number; + responseEndOffset: number; +} + +export async function publish( + channel: Ably.RealtimeChannel, + question: string, + documentContent: string, +): Promise<{ msgSerial: string; citations: Citation[] }> { + const anthropic = new Anthropic(); + + const response = await anthropic.messages.create({ + model: 'claude-sonnet-4-5', + max_tokens: 1024, + messages: [ + { + role: 'user', + content: [ + { + type: 'document', + source: { + type: 'text', + media_type: 'text/plain', + data: documentContent, + }, + title: 'Source Document', + citations: { enabled: true }, + }, + { + type: 'text', + text: question, + }, + ], + }, + ], + }); + + let fullText = ''; + const citations: Citation[] = []; + let currentOffset = 0; + + // Extract text and citations from response + for (const block of response.content) { + if (block.type === 'text') { + const text = block.text; + + if ('citations' in block && Array.isArray(block.citations)) { + for (const citation of block.citations as unknown as Record[]) { + citations.push({ + type: citation.type as string, + cited_text: citation.cited_text as string, + document_index: citation.document_index as number, + document_title: citation.document_title as string, + start_char_index: citation.start_char_index as number | undefined, + end_char_index: citation.end_char_index as number | undefined, + start_page_number: citation.start_page_number as number | undefined, + end_page_number: citation.end_page_number as number | undefined, + source: citation.source as string | undefined, + // Track position in the full response text + responseStartOffset: currentOffset, + responseEndOffset: currentOffset + text.length, + }); + } + } + + fullText += text; + currentOffset += text.length; + } + } + + const result = await channel.publish('response', fullText); + const msgSerial = result.serials[0]!; + + // Publish each citation as an annotation + for (const citation of citations) { + let sourceDomain; + try { + sourceDomain = citation.source ? new URL(citation.source).hostname : citation.document_title; + } catch { + sourceDomain = citation.document_title || 'document'; + } + + await channel.annotations.publish(msgSerial, { + type: 'citations:multiple.v1', + name: sourceDomain, + data: { + title: citation.document_title, + citedText: citation.cited_text, + citationType: citation.type, + startOffset: citation.responseStartOffset, + endOffset: citation.responseEndOffset, + documentIndex: citation.document_index, + ...(citation.start_char_index !== undefined && { + startCharIndex: citation.start_char_index, + endCharIndex: citation.end_char_index, + }), + ...(citation.start_page_number !== undefined && { + startPageNumber: citation.start_page_number, + endPageNumber: citation.end_page_number, + }), + }, + }); + } + + return { msgSerial, citations }; +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('ai:anthropic-citations-guide'); + + const document = `The James Webb Space Telescope (JWST) is a space telescope designed to conduct infrared astronomy. Its high-resolution and high-sensitivity instruments allow it to view objects too old and distant for the Hubble Space Telescope. This enables investigations across many fields of astronomy and cosmology, such as observation of the first stars and the formation of the first galaxies.`; + + const { msgSerial, citations } = await publish( + channel, + 'What is the JWST designed for? Cite your sources.', + document, + ); + console.log('Message serial:', msgSerial); + console.log('Citations:', citations.length); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/anthropic-citations/javascript/src/client.ts b/guides/ai-transport/anthropic-citations/javascript/src/client.ts new file mode 100644 index 0000000000..37e93796c9 --- /dev/null +++ b/guides/ai-transport/anthropic-citations/javascript/src/client.ts @@ -0,0 +1,64 @@ +import Ably from 'ably'; + +interface CitationSummaryResult { + content: string; + citationSummary: Record; +} + +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + let content = ''; + let citationSummary: Record = {}; + let doneTimer: ReturnType | null = null; + + const resetTimer = () => { + if (doneTimer) { + clearTimeout(doneTimer); + } + doneTimer = setTimeout(() => { + resolve({ content, citationSummary }); + }, 3000); + }; + + channel.subscribe((message: Ably.Message) => { + const serial = message.serial; + if (!serial) { + return; + } + + switch (message.action) { + case 'message.create': + console.log('\n[Response received]', serial); + content = message.data as string; + resetTimer(); + break; + + case 'message.summary': + if (message.annotations?.summary?.['citations:multiple.v1']) { + citationSummary = message.annotations.summary['citations:multiple.v1'] as Record< + string, + { total: number } + >; + console.log('\n[Citation summary received]', citationSummary); + } + resetTimer(); + break; + } + }); + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('ai:anthropic-citations-guide'); + console.log('Client ready, waiting for response and citations...'); + const { content, citationSummary } = await subscribe(channel); + console.log('\nFull response:', content); + console.log('Citation summary:', citationSummary); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/anthropic-citations/javascript/test/e2e.test.ts b/guides/ai-transport/anthropic-citations/javascript/test/e2e.test.ts new file mode 100644 index 0000000000..4e54a02db7 --- /dev/null +++ b/guides/ai-transport/anthropic-citations/javascript/test/e2e.test.ts @@ -0,0 +1,58 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { publish } from '../src/agent.js'; +import { subscribe } from '../src/client.js'; +import { waitForMessage } from '../../../test-helpers.js'; + +const document = + 'Ably provides realtime messaging infrastructure. It supports pub/sub, presence, and history features.'; + +describe('anthropic-citations', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `ai:test-anthropic-citations-${Date.now()}`; + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes response and citation annotations', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-annotations'); + const pubChannel = publisherClient.channels.get(channelName + '-annotations'); + + const responsePromise = subscribe(subChannel); + await subChannel.attach(); + + const summaryReceived = waitForMessage(subChannel, (m) => m.action === 'message.summary'); + + await publish(pubChannel, 'What features does Ably provide? Cite your sources.', document); + await summaryReceived; + + const { content, citationSummary } = await responsePromise; + + expect(content.length).toBeGreaterThan(0); + expect(Object.keys(citationSummary).length).toBeGreaterThan(0); + }); + + it('citations reference the source document', async () => { + const pubChannel = publisherClient.channels.get(channelName + '-doc-ref'); + + const { msgSerial, citations } = await publish( + pubChannel, + 'What features does Ably provide? Cite your sources.', + document, + ); + + expect(msgSerial).toBeDefined(); + expect(citations.length).toBeGreaterThan(0); + expect(citations[0].document_title).toBe('Source Document'); + }); +}); diff --git a/guides/ai-transport/anthropic-citations/javascript/tsconfig.json b/guides/ai-transport/anthropic-citations/javascript/tsconfig.json new file mode 100644 index 0000000000..6ece4d3313 --- /dev/null +++ b/guides/ai-transport/anthropic-citations/javascript/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/anthropic-human-in-the-loop/javascript/package.json b/guides/ai-transport/anthropic-human-in-the-loop/javascript/package.json new file mode 100644 index 0000000000..c35f2f450f --- /dev/null +++ b/guides/ai-transport/anthropic-human-in-the-loop/javascript/package.json @@ -0,0 +1,14 @@ +{ + "name": "guide-anthropic-human-in-the-loop", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:agent": "tsx src/agent.ts", + "start:approver": "tsx src/approver.ts", + "test": "vitest run" + }, + "dependencies": { + "@anthropic-ai/sdk": "^0.71" + } +} diff --git a/guides/ai-transport/anthropic-human-in-the-loop/javascript/src/agent.ts b/guides/ai-transport/anthropic-human-in-the-loop/javascript/src/agent.ts new file mode 100644 index 0000000000..c561bbf677 --- /dev/null +++ b/guides/ai-transport/anthropic-human-in-the-loop/javascript/src/agent.ts @@ -0,0 +1,98 @@ +import Anthropic from '@anthropic-ai/sdk'; +import Ably from 'ably'; + +export async function runAgent(channel: Ably.RealtimeChannel, prompt: string) { + const anthropic = new Anthropic(); + + const response = await anthropic.messages.create({ + model: 'claude-sonnet-4-5', + max_tokens: 1024, + tools: [ + { + name: 'publish_blog_post', + description: 'Publish a blog post to the website. Requires human approval.', + input_schema: { + type: 'object' as const, + properties: { + title: { + type: 'string', + description: 'Title of the blog post to publish', + }, + }, + required: ['title'], + }, + }, + ], + messages: [{ role: 'user', content: prompt }], + }); + + for (const block of response.content) { + if (block.type === 'tool_use') { + const toolUse = block; + + // Set up listener for approval response before publishing request + const approvalPromise = new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + channel.unsubscribe('approval-response', listener); + reject(new Error('Approval response timed out')); + }, 30000); + + const listener = (message: Ably.Message) => { + if (message.extras?.headers?.toolCallId === toolUse.id) { + clearTimeout(timeout); + channel.unsubscribe('approval-response', listener); + resolve(message); + } + }; + + channel.subscribe('approval-response', listener); + }); + + // Publish approval request to channel + await channel.publish({ + name: 'approval-request', + data: { + tool: toolUse.name, + arguments: toolUse.input, + }, + extras: { + headers: { + toolCallId: toolUse.id, + }, + }, + }); + + const approvalResponse = await approvalPromise; + + const decision = (approvalResponse.data as { decision: string }).decision; + + if (decision === 'approved') { + // Simulate tool execution + const input = toolUse.input as { title: string }; + return { published: true, title: input.title }; + } else { + throw new Error(`Tool call rejected: ${toolUse.name}`); + } + } + } + + // No tool use in response - return the text content + const textBlock = response.content.find((b) => b.type === 'text'); + return { published: false, text: textBlock?.type === 'text' ? textBlock.text : '' }; +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('ai:anthropic-hitl-guide'); + try { + const result = await runAgent(channel, 'Publish a blog post called "Hello World"'); + console.log('Result:', result); + } finally { + realtime.close(); + } +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/anthropic-human-in-the-loop/javascript/src/approver.ts b/guides/ai-transport/anthropic-human-in-the-loop/javascript/src/approver.ts new file mode 100644 index 0000000000..bd578706a1 --- /dev/null +++ b/guides/ai-transport/anthropic-human-in-the-loop/javascript/src/approver.ts @@ -0,0 +1,81 @@ +import Ably from 'ably'; + +export function autoApprove(channel: Ably.RealtimeChannel): () => void { + const listener = (message: Ably.Message) => { + const toolCallId = message.extras?.headers?.toolCallId; + channel.publish({ + name: 'approval-response', + data: { decision: 'approved' }, + extras: { + headers: { + toolCallId, + }, + }, + }); + }; + + channel.subscribe('approval-request', listener); + + return () => { + channel.unsubscribe('approval-request', listener); + }; +} + +export function autoReject(channel: Ably.RealtimeChannel): () => void { + const listener = (message: Ably.Message) => { + const toolCallId = message.extras?.headers?.toolCallId; + channel.publish({ + name: 'approval-response', + data: { decision: 'rejected' }, + extras: { + headers: { + toolCallId, + }, + }, + }); + }; + + channel.subscribe('approval-request', listener); + + return () => { + channel.unsubscribe('approval-request', listener); + }; +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('ai:anthropic-hitl-guide'); + + const { createInterface } = await import('readline'); + const rl = createInterface({ input: process.stdin, output: process.stdout }); + + console.log('Approver ready, waiting for approval requests...'); + + channel.subscribe('approval-request', (message: Ably.Message) => { + const data = message.data as { tool: string; arguments: Record }; + const toolCallId = message.extras?.headers?.toolCallId; + + console.log(`\nApproval request received:`); + console.log(` Tool: ${data.tool}`); + console.log(` Arguments: ${JSON.stringify(data.arguments)}`); + + rl.question('Approve? (y/n): ', (answer) => { + const decision = answer.toLowerCase() === 'y' ? 'approved' : 'rejected'; + channel.publish({ + name: 'approval-response', + data: { decision }, + extras: { + headers: { + toolCallId, + }, + }, + }); + console.log(`Decision sent: ${decision}`); + }); + }); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/anthropic-human-in-the-loop/javascript/test/e2e.test.ts b/guides/ai-transport/anthropic-human-in-the-loop/javascript/test/e2e.test.ts new file mode 100644 index 0000000000..dbf1535a3d --- /dev/null +++ b/guides/ai-transport/anthropic-human-in-the-loop/javascript/test/e2e.test.ts @@ -0,0 +1,74 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { runAgent } from '../src/agent.js'; +import { autoApprove, autoReject } from '../src/approver.js'; +import { waitForMessage } from '../../../test-helpers.js'; + +describe('anthropic-human-in-the-loop', () => { + let agentClient: Ably.Realtime; + let approverClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `ai:test-anthropic-hitl-${Date.now()}`; + agentClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + approverClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + agentClient?.close(); + approverClient?.close(); + }); + + it('agent publishes approval request when tool use is triggered', async () => { + const agentChannel = agentClient.channels.get(channelName + '-request'); + const approverChannel = approverClient.channels.get(channelName + '-request'); + + const requestReceived = waitForMessage( + approverChannel, + (m) => m.name === 'approval-request', + 30000, + ); + + // Set up auto-approve so the agent can complete (otherwise it hangs waiting) + const cleanup = autoApprove(approverChannel); + + await runAgent(agentChannel, "Publish the blog post called 'Test Post'"); + + const message = await requestReceived; + cleanup(); + + expect(message.name).toBe('approval-request'); + const data = message.data as { tool: string; arguments: { title: string } }; + expect(data.tool).toBe('publish_blog_post'); + }); + + it('agent completes tool execution after approval', async () => { + const agentChannel = agentClient.channels.get(channelName + '-approve'); + const approverChannel = approverClient.channels.get(channelName + '-approve'); + + const cleanup = autoApprove(approverChannel); + await approverChannel.attach(); + + const result = await runAgent(agentChannel, "Publish the blog post called 'Approved Post'"); + cleanup(); + + expect(result).toHaveProperty('published', true); + expect(result).toHaveProperty('title'); + }); + + it('agent rejects when approval is denied', async () => { + const agentChannel = agentClient.channels.get(channelName + '-reject'); + const approverChannel = approverClient.channels.get(channelName + '-reject'); + + const cleanup = autoReject(approverChannel); + await approverChannel.attach(); + + await expect( + runAgent(agentChannel, "Publish the blog post called 'Rejected Post'"), + ).rejects.toThrow('Tool call rejected'); + + cleanup(); + }); +}); diff --git a/guides/ai-transport/anthropic-human-in-the-loop/javascript/tsconfig.json b/guides/ai-transport/anthropic-human-in-the-loop/javascript/tsconfig.json new file mode 100644 index 0000000000..6ece4d3313 --- /dev/null +++ b/guides/ai-transport/anthropic-human-in-the-loop/javascript/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/openai-citations/javascript/package.json b/guides/ai-transport/openai-citations/javascript/package.json new file mode 100644 index 0000000000..4c3bfd7681 --- /dev/null +++ b/guides/ai-transport/openai-citations/javascript/package.json @@ -0,0 +1,14 @@ +{ + "name": "guide-openai-citations", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:agent": "tsx src/agent.ts", + "start:client": "tsx src/client.ts", + "test": "vitest run" + }, + "dependencies": { + "openai": "^4" + } +} diff --git a/guides/ai-transport/openai-citations/javascript/src/agent.ts b/guides/ai-transport/openai-citations/javascript/src/agent.ts new file mode 100644 index 0000000000..90726a42c9 --- /dev/null +++ b/guides/ai-transport/openai-citations/javascript/src/agent.ts @@ -0,0 +1,76 @@ +import OpenAI from 'openai'; +import Ably from 'ably'; + +interface Citation { + url: string; + title: string; + startIndex: number; + endIndex: number; +} + +export async function ask(channel: Ably.RealtimeChannel, question: string) { + const openai = new OpenAI(); + + const response = await openai.responses.create({ + model: 'gpt-5', + input: question, + tools: [{ type: 'web_search_preview' }], + }); + + let fullText = ''; + const citations: Citation[] = []; + + for (const item of response.output) { + if (item.type === 'message') { + for (const content of item.content) { + if (content.type === 'output_text') { + fullText = content.text; + if (content.annotations) { + for (const annotation of content.annotations) { + if (annotation.type === 'url_citation') { + citations.push({ + url: annotation.url, + title: annotation.title, + startIndex: annotation.start_index, + endIndex: annotation.end_index, + }); + } + } + } + } + } + } + } + + const result = await channel.publish('response', fullText); + const msgSerial = result.serials[0]!; + + for (const citation of citations) { + const sourceDomain = new URL(citation.url).hostname; + await channel.annotations.publish(msgSerial, { + type: 'citations:multiple.v1', + name: sourceDomain, + data: { + url: citation.url, + title: citation.title, + startIndex: citation.startIndex, + endIndex: citation.endIndex, + }, + }); + } + + return { msgSerial, citations }; +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('ai:openai-citations-guide'); + const { citations } = await ask(channel, 'What is the latest version of Node.js as of 2025?'); + console.log(`Published response with ${citations.length} citation(s).`); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/openai-citations/javascript/src/client.ts b/guides/ai-transport/openai-citations/javascript/src/client.ts new file mode 100644 index 0000000000..e859011229 --- /dev/null +++ b/guides/ai-transport/openai-citations/javascript/src/client.ts @@ -0,0 +1,58 @@ +import Ably from 'ably'; + +interface ClientResult { + content: string; + citationSummary: Record; +} + +export function subscribe(channel: Ably.RealtimeChannel): Promise { + return new Promise((resolve) => { + let content = ''; + let citationSummary: Record = {}; + let doneTimer: ReturnType | null = null; + + const resetTimer = () => { + if (doneTimer) { + clearTimeout(doneTimer); + } + doneTimer = setTimeout(() => { + resolve({ content, citationSummary }); + }, 3000); + }; + + channel.subscribe((message: Ably.Message) => { + switch (message.action) { + case 'message.create': + console.log('\n[Response received]', message.serial); + content = message.data as string; + resetTimer(); + break; + + case 'message.summary': { + const summary = message.annotations?.summary?.['citations:multiple.v1']; + if (summary) { + citationSummary = summary as Record; + console.log('\n[Citation summary received]', Object.keys(citationSummary).length, 'source(s)'); + } + resetTimer(); + break; + } + } + }); + }); +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('ai:openai-citations-guide'); + console.log('Client ready, waiting for response...'); + const { content, citationSummary } = await subscribe(channel); + console.log('\nFull response:', content); + console.log('\nCitation sources:', citationSummary); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/openai-citations/javascript/test/e2e.test.ts b/guides/ai-transport/openai-citations/javascript/test/e2e.test.ts new file mode 100644 index 0000000000..cee8ab550d --- /dev/null +++ b/guides/ai-transport/openai-citations/javascript/test/e2e.test.ts @@ -0,0 +1,61 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { ask } from '../src/agent.js'; +import { subscribe } from '../src/client.js'; +import { waitForMessage } from '../../../test-helpers.js'; + +describe('openai-citations', () => { + let publisherClient: Ably.Realtime; + let subscriberClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `ai:test-openai-citations-${Date.now()}`; + publisherClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + subscriberClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + publisherClient?.close(); + subscriberClient?.close(); + }); + + it('publishes response and citation annotations', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-annotations'); + const pubChannel = publisherClient.channels.get(channelName + '-annotations'); + + const resultPromise = subscribe(subChannel); + await subChannel.attach(); + + const summaryReceived = waitForMessage(subChannel, (m) => m.action === 'message.summary', 120000); + await ask(pubChannel, 'What is the latest version of Node.js as of 2025?'); + await summaryReceived; + + const { content, citationSummary } = await resultPromise; + expect(content.length).toBeGreaterThan(0); + expect(Object.keys(citationSummary).length).toBeGreaterThan(0); + }, 150000); + + it('citation summaries group by source domain', async () => { + const subChannel = subscriberClient.channels.get(channelName + '-domains'); + const pubChannel = publisherClient.channels.get(channelName + '-domains'); + + const resultPromise = subscribe(subChannel); + await subChannel.attach(); + + const summaryReceived = waitForMessage(subChannel, (m) => m.action === 'message.summary', 120000); + await ask(pubChannel, 'What is the latest version of Node.js as of 2025?'); + await summaryReceived; + + const { citationSummary } = await resultPromise; + const domains = Object.keys(citationSummary); + expect(domains.length).toBeGreaterThan(0); + + for (const domain of domains) { + // Verify each key is a valid domain name (contains at least one dot) + expect(domain).toMatch(/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/); + expect(citationSummary[domain].total).toBeGreaterThan(0); + } + }, 150000); +}); diff --git a/guides/ai-transport/openai-citations/javascript/tsconfig.json b/guides/ai-transport/openai-citations/javascript/tsconfig.json new file mode 100644 index 0000000000..6ece4d3313 --- /dev/null +++ b/guides/ai-transport/openai-citations/javascript/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/openai-human-in-the-loop/javascript/package.json b/guides/ai-transport/openai-human-in-the-loop/javascript/package.json new file mode 100644 index 0000000000..82bdfd1d85 --- /dev/null +++ b/guides/ai-transport/openai-human-in-the-loop/javascript/package.json @@ -0,0 +1,14 @@ +{ + "name": "guide-openai-human-in-the-loop", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "start:agent": "tsx src/agent.ts", + "start:approver": "tsx src/approver.ts", + "test": "vitest run" + }, + "dependencies": { + "openai": "^4" + } +} diff --git a/guides/ai-transport/openai-human-in-the-loop/javascript/src/agent.ts b/guides/ai-transport/openai-human-in-the-loop/javascript/src/agent.ts new file mode 100644 index 0000000000..bd683d9327 --- /dev/null +++ b/guides/ai-transport/openai-human-in-the-loop/javascript/src/agent.ts @@ -0,0 +1,88 @@ +import OpenAI from 'openai'; +import Ably from 'ably'; + +export async function runAgent(channel: Ably.RealtimeChannel, prompt: string) { + const openai = new OpenAI(); + + const response = await openai.responses.create({ + model: 'gpt-4o', + input: prompt, + tools: [ + { + type: 'function', + name: 'publish_blog_post', + description: 'Publish a blog post to the website. Requires human approval.', + parameters: { + type: 'object', + properties: { + title: { + type: 'string', + description: 'Title of the blog post to publish', + }, + }, + required: ['title'], + }, + } as unknown as OpenAI.Responses.FunctionTool, + ], + }); + + const toolCalls = response.output.filter((item) => item.type === 'function_call'); + + for (const toolCall of toolCalls) { + // Set up listener for approval response before publishing request + const decisionPromise = new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + channel.unsubscribe('approval-response', listener); + reject(new Error('Timed out waiting for approval response')); + }, 30000); + + const listener = (message: Ably.Message) => { + const messageToolCallId = message.extras?.headers?.toolCallId; + if (messageToolCallId === toolCall.call_id) { + clearTimeout(timeout); + channel.unsubscribe('approval-response', listener); + resolve((message.data as { decision: string }).decision); + } + }; + + channel.subscribe('approval-response', listener); + }); + + await channel.publish({ + name: 'approval-request', + data: { + tool: toolCall.name, + arguments: toolCall.arguments, + }, + extras: { + headers: { + toolCallId: toolCall.call_id, + }, + }, + }); + + const decision = await decisionPromise; + + if (decision !== 'approved') { + throw new Error(`Tool call rejected: ${toolCall.name}`); + } + + const { title } = JSON.parse(toolCall.arguments); + return { published: true, title }; + } + + return { message: 'No tool calls were made by the model.' }; +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + const channel = realtime.channels.get('ai:openai-hitl-guide'); + const result = await runAgent(channel, 'Publish a blog post called "Hello World"'); + console.log('Result:', result); + realtime.close(); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/openai-human-in-the-loop/javascript/src/approver.ts b/guides/ai-transport/openai-human-in-the-loop/javascript/src/approver.ts new file mode 100644 index 0000000000..8c608dbc3b --- /dev/null +++ b/guides/ai-transport/openai-human-in-the-loop/javascript/src/approver.ts @@ -0,0 +1,80 @@ +import Ably from 'ably'; + +export function autoApprove(channel: Ably.RealtimeChannel): () => void { + const listener = (message: Ably.Message) => { + const toolCallId = message.extras?.headers?.toolCallId; + channel.publish({ + name: 'approval-response', + data: { decision: 'approved' }, + extras: { + headers: { + toolCallId, + }, + }, + }); + }; + + channel.subscribe('approval-request', listener); + + return () => { + channel.unsubscribe('approval-request', listener); + }; +} + +export function autoReject(channel: Ably.RealtimeChannel): () => void { + const listener = (message: Ably.Message) => { + const toolCallId = message.extras?.headers?.toolCallId; + channel.publish({ + name: 'approval-response', + data: { decision: 'rejected' }, + extras: { + headers: { + toolCallId, + }, + }, + }); + }; + + channel.subscribe('approval-request', listener); + + return () => { + channel.unsubscribe('approval-request', listener); + }; +} + +async function main() { + const realtime = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + const channel = realtime.channels.get('ai:openai-hitl-guide'); + + const { createInterface } = await import('readline'); + const rl = createInterface({ input: process.stdin, output: process.stdout }); + + console.log('Approver ready, waiting for approval requests...'); + + channel.subscribe('approval-request', (message: Ably.Message) => { + const data = message.data as { tool: string; arguments: string }; + const toolCallId = message.extras?.headers?.toolCallId; + + console.log(`\nApproval requested for tool: ${data.tool}`); + console.log(`Arguments: ${data.arguments}`); + + rl.question('Approve? (y/n): ', (answer) => { + const decision = answer.toLowerCase() === 'y' ? 'approved' : 'rejected'; + channel.publish({ + name: 'approval-response', + data: { decision }, + extras: { + headers: { + toolCallId, + }, + }, + }); + console.log(`Decision sent: ${decision}`); + }); + }); +} + +import { fileURLToPath } from 'url'; +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main().catch(console.error); +} diff --git a/guides/ai-transport/openai-human-in-the-loop/javascript/test/e2e.test.ts b/guides/ai-transport/openai-human-in-the-loop/javascript/test/e2e.test.ts new file mode 100644 index 0000000000..00662f0c57 --- /dev/null +++ b/guides/ai-transport/openai-human-in-the-loop/javascript/test/e2e.test.ts @@ -0,0 +1,71 @@ +import Ably from 'ably'; +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { runAgent } from '../src/agent.js'; +import { autoApprove, autoReject } from '../src/approver.js'; +import { waitForMessage } from '../../../test-helpers.js'; + +describe('openai-human-in-the-loop', () => { + let agentClient: Ably.Realtime; + let approverClient: Ably.Realtime; + let channelName: string; + + beforeAll(() => { + channelName = `ai:test-openai-hitl-${Date.now()}`; + agentClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY, echoMessages: false }); + approverClient = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); + }); + + afterAll(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + agentClient?.close(); + approverClient?.close(); + }); + + it('agent publishes approval request when tool use is triggered', async () => { + const agentChannel = agentClient.channels.get(channelName + '-request'); + const approverChannel = approverClient.channels.get(channelName + '-request'); + + const requestReceived = waitForMessage(approverChannel, (m) => m.name === 'approval-request', 30000); + + // Set up auto-approve so the agent doesn't hang waiting for a response + const cleanup = autoApprove(approverChannel); + + await runAgent(agentChannel, "Publish the blog post called 'Test Post'"); + const message = await requestReceived; + + cleanup(); + + const data = message.data as { tool: string; arguments: string }; + expect(data.tool).toBe('publish_blog_post'); + expect(data.arguments).toBeDefined(); + }); + + it('agent completes tool execution after approval', async () => { + const agentChannel = agentClient.channels.get(channelName + '-approve'); + const approverChannel = approverClient.channels.get(channelName + '-approve'); + + const cleanup = autoApprove(approverChannel); + await approverChannel.attach(); + + const result = await runAgent(agentChannel, "Publish the blog post called 'Approved Post'"); + + cleanup(); + + expect(result).toHaveProperty('published', true); + expect(result).toHaveProperty('title'); + }); + + it('agent rejects when approval is denied', async () => { + const agentChannel = agentClient.channels.get(channelName + '-reject'); + const approverChannel = approverClient.channels.get(channelName + '-reject'); + + const cleanup = autoReject(approverChannel); + await approverChannel.attach(); + + await expect(runAgent(agentChannel, "Publish the blog post called 'Rejected Post'")).rejects.toThrow( + 'Tool call rejected', + ); + + cleanup(); + }); +}); diff --git a/guides/ai-transport/openai-human-in-the-loop/javascript/tsconfig.json b/guides/ai-transport/openai-human-in-the-loop/javascript/tsconfig.json new file mode 100644 index 0000000000..6ece4d3313 --- /dev/null +++ b/guides/ai-transport/openai-human-in-the-loop/javascript/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/guides/ai-transport/package.json b/guides/ai-transport/package.json index 954619158c..1ed7256d8f 100644 --- a/guides/ai-transport/package.json +++ b/guides/ai-transport/package.json @@ -9,8 +9,12 @@ "workspaces": [ "openai-message-per-token/javascript", "openai-message-per-response/javascript", + "openai-citations/javascript", + "openai-human-in-the-loop/javascript", "anthropic-message-per-token/javascript", "anthropic-message-per-response/javascript", + "anthropic-citations/javascript", + "anthropic-human-in-the-loop/javascript", "vercel-message-per-token/javascript", "vercel-message-per-response/javascript", "lang-graph-message-per-token/javascript", diff --git a/guides/ai-transport/yarn.lock b/guides/ai-transport/yarn.lock index 5c1c338b4a..16a95a0e86 100644 --- a/guides/ai-transport/yarn.lock +++ b/guides/ai-transport/yarn.lock @@ -82,11 +82,136 @@ resolved "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.1.tgz" integrity sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og== +"@esbuild/aix-ppc64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz#815b39267f9bffd3407ea6c376ac32946e24f8d2" + integrity sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg== + +"@esbuild/android-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz#19b882408829ad8e12b10aff2840711b2da361e8" + integrity sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg== + +"@esbuild/android-arm@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.3.tgz#90be58de27915efa27b767fcbdb37a4470627d7b" + integrity sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA== + +"@esbuild/android-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.3.tgz#d7dcc976f16e01a9aaa2f9b938fbec7389f895ac" + integrity sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ== + "@esbuild/darwin-arm64@0.27.3": version "0.27.3" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz" integrity sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg== +"@esbuild/darwin-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz#ac61d645faa37fd650340f1866b0812e1fb14d6a" + integrity sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg== + +"@esbuild/freebsd-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz#b8625689d73cf1830fe58c39051acdc12474ea1b" + integrity sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w== + +"@esbuild/freebsd-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz#07be7dd3c9d42fe0eccd2ab9f9ded780bc53bead" + integrity sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA== + +"@esbuild/linux-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz#bf31918fe5c798586460d2b3d6c46ed2c01ca0b6" + integrity sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg== + +"@esbuild/linux-arm@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz#28493ee46abec1dc3f500223cd9f8d2df08f9d11" + integrity sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw== + +"@esbuild/linux-ia32@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz#750752a8b30b43647402561eea764d0a41d0ee29" + integrity sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg== + +"@esbuild/linux-loong64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz#a5a92813a04e71198c50f05adfaf18fc1e95b9ed" + integrity sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA== + +"@esbuild/linux-mips64el@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz#deb45d7fd2d2161eadf1fbc593637ed766d50bb1" + integrity sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw== + +"@esbuild/linux-ppc64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz#6f39ae0b8c4d3d2d61a65b26df79f6e12a1c3d78" + integrity sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA== + +"@esbuild/linux-riscv64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz#4c5c19c3916612ec8e3915187030b9df0b955c1d" + integrity sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ== + +"@esbuild/linux-s390x@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz#9ed17b3198fa08ad5ccaa9e74f6c0aff7ad0156d" + integrity sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw== + +"@esbuild/linux-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz#12383dcbf71b7cf6513e58b4b08d95a710bf52a5" + integrity sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA== + +"@esbuild/netbsd-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz#dd0cb2fa543205fcd931df44f4786bfcce6df7d7" + integrity sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA== + +"@esbuild/netbsd-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz#028ad1807a8e03e155153b2d025b506c3787354b" + integrity sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA== + +"@esbuild/openbsd-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz#e3c16ff3490c9b59b969fffca87f350ffc0e2af5" + integrity sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw== + +"@esbuild/openbsd-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz#c5a4693fcb03d1cbecbf8b422422468dfc0d2a8b" + integrity sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ== + +"@esbuild/openharmony-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz#082082444f12db564a0775a41e1991c0e125055e" + integrity sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g== + +"@esbuild/sunos-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz#5ab036c53f929e8405c4e96e865a424160a1b537" + integrity sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA== + +"@esbuild/win32-arm64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz#38de700ef4b960a0045370c171794526e589862e" + integrity sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA== + +"@esbuild/win32-ia32@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz#451b93dc03ec5d4f38619e6cd64d9f9eff06f55c" + integrity sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q== + +"@esbuild/win32-x64@0.27.3": + version "0.27.3" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz#0eaf705c941a218a43dba8e09f1df1d6cd2f1f17" + integrity sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA== + "@jridgewell/sourcemap-codec@^1.5.5": version "1.5.5" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz" @@ -100,7 +225,7 @@ "@anthropic-ai/sdk" "^0.65.0" fast-xml-parser "^4.4.1" -"@langchain/core@^0.3", "@langchain/core@>=0.2.31 <0.4.0", "@langchain/core@>=0.2.36 <0.3.0 || >=0.3.40 < 0.4.0", "@langchain/core@>=0.3.58 <0.4.0": +"@langchain/core@^0.3": version "0.3.80" resolved "https://registry.npmjs.org/@langchain/core/-/core-0.3.80.tgz" integrity sha512-vcJDV2vk1AlCwSh3aBm/urQ1ZrlXFFBocv11bz/NBUfLWD5/UDNMzwPdaAd2dKvNmTWa9FM2lirLU3+JCf4cRA== @@ -145,16 +270,136 @@ uuid "^10.0.0" zod "^3.23.8" -"@opentelemetry/api@*", "@opentelemetry/api@1.9.0": +"@opentelemetry/api@1.9.0": version "1.9.0" resolved "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== +"@rollup/rollup-android-arm-eabi@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz#add5e608d4e7be55bc3ca3d962490b8b1890e088" + integrity sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg== + +"@rollup/rollup-android-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz#10bd0382b73592beee6e9800a69401a29da625c4" + integrity sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w== + "@rollup/rollup-darwin-arm64@4.57.1": version "4.57.1" resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz" integrity sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg== +"@rollup/rollup-darwin-x64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz#69e741aeb2839d2e8f0da2ce7a33d8bd23632423" + integrity sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w== + +"@rollup/rollup-freebsd-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz#3736c232a999c7bef7131355d83ebdf9651a0839" + integrity sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug== + +"@rollup/rollup-freebsd-x64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz#227dcb8f466684070169942bd3998901c9bfc065" + integrity sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q== + +"@rollup/rollup-linux-arm-gnueabihf@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz#ba004b30df31b724f99ce66e7128248bea17cb0c" + integrity sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw== + +"@rollup/rollup-linux-arm-musleabihf@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz#6929f3e07be6b6da5991f63c6b68b3e473d0a65a" + integrity sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw== + +"@rollup/rollup-linux-arm64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz#06e89fd4a25d21fe5575d60b6f913c0e65297bfa" + integrity sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g== + +"@rollup/rollup-linux-arm64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz#fddabf395b90990d5194038e6cd8c00156ed8ac0" + integrity sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q== + +"@rollup/rollup-linux-loong64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz#04c10bb764bbf09a3c1bd90432e92f58d6603c36" + integrity sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA== + +"@rollup/rollup-linux-loong64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz#f2450361790de80581d8687ea19142d8a4de5c0f" + integrity sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw== + +"@rollup/rollup-linux-ppc64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz#0474f4667259e407eee1a6d38e29041b708f6a30" + integrity sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w== + +"@rollup/rollup-linux-ppc64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz#9f32074819eeb1ddbe51f50ea9dcd61a6745ec33" + integrity sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw== + +"@rollup/rollup-linux-riscv64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz#3fdb9d4b1e29fb6b6a6da9f15654d42eb77b99b2" + integrity sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A== + +"@rollup/rollup-linux-riscv64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz#1de780d64e6be0e3e8762035c22e0d8ea68df8ed" + integrity sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw== + +"@rollup/rollup-linux-s390x-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz#1da022ffd2d9e9f0fd8344ea49e113001fbcac64" + integrity sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg== + +"@rollup/rollup-linux-x64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz#78c16eef9520bd10e1ea7a112593bb58e2842622" + integrity sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg== + +"@rollup/rollup-linux-x64-musl@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz#a7598591b4d9af96cb3167b50a5bf1e02dfea06c" + integrity sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw== + +"@rollup/rollup-openbsd-x64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz#c51d48c07cd6c466560e5bed934aec688ce02614" + integrity sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw== + +"@rollup/rollup-openharmony-arm64@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz#f09921d0b2a0b60afbf3586d2a7a7f208ba6df17" + integrity sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ== + +"@rollup/rollup-win32-arm64-msvc@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz#08d491717135376e4a99529821c94ecd433d5b36" + integrity sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ== + +"@rollup/rollup-win32-ia32-msvc@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz#b0c12aac1104a8b8f26a5e0098e5facbb3e3964a" + integrity sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew== + +"@rollup/rollup-win32-x64-gnu@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz#b9cccef26f5e6fdc013bf3c0911a3c77428509d0" + integrity sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ== + +"@rollup/rollup-win32-x64-msvc@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz#a03348e7b559c792b6277cc58874b89ef46e1e72" + integrity sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA== + "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" @@ -195,7 +440,7 @@ resolved "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz" integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== -"@types/estree@^1.0.0", "@types/estree@1.0.8": +"@types/estree@1.0.8", "@types/estree@^1.0.0": version "1.0.8" resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== @@ -225,7 +470,7 @@ "@types/node" "*" form-data "^4.0.4" -"@types/node@*", "@types/node@^18.0.0 || ^20.0.0 || >=22.0.0", "@types/node@^20.19.0 || >=22.12.0": +"@types/node@*": version "25.2.3" resolved "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz" integrity sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ== @@ -281,7 +526,7 @@ estree-walker "^3.0.3" magic-string "^0.30.17" -"@vitest/pretty-format@^3.2.4", "@vitest/pretty-format@3.2.4": +"@vitest/pretty-format@3.2.4", "@vitest/pretty-format@^3.2.4": version "3.2.4" resolved "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz" integrity sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA== @@ -380,16 +625,16 @@ asynckit@^0.4.0: resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -base64-js@^1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - base64-js@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.0.2.tgz" integrity sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg== +base64-js@^1.5.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + bops@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/bops/-/bops-1.0.1.tgz" @@ -683,6 +928,11 @@ formdata-node@^4.3.2: node-domexception "1.0.0" web-streams-polyfill "4.0.0-beta.3" +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -748,60 +998,6 @@ got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" -"guide-anthropic-message-per-response@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/anthropic-message-per-response/javascript": - version "0.1.0" - resolved "file:anthropic-message-per-response/javascript" - dependencies: - "@anthropic-ai/sdk" "^0.71" - -"guide-anthropic-message-per-token@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/anthropic-message-per-token/javascript": - version "0.1.0" - resolved "file:anthropic-message-per-token/javascript" - dependencies: - "@anthropic-ai/sdk" "^0.71" - -"guide-lang-graph-message-per-response@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/lang-graph-message-per-response/javascript": - version "0.1.0" - resolved "file:lang-graph-message-per-response/javascript" - dependencies: - "@langchain/anthropic" "^0.3" - "@langchain/core" "^0.3" - "@langchain/langgraph" "^0.2" - -"guide-lang-graph-message-per-token@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/lang-graph-message-per-token/javascript": - version "0.1.0" - resolved "file:lang-graph-message-per-token/javascript" - dependencies: - "@langchain/anthropic" "^0.3" - "@langchain/core" "^0.3" - "@langchain/langgraph" "^0.2" - -"guide-openai-message-per-response@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/openai-message-per-response/javascript": - version "0.1.0" - resolved "file:openai-message-per-response/javascript" - dependencies: - openai "^4" - -"guide-openai-message-per-token@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/openai-message-per-token/javascript": - version "0.1.0" - resolved "file:openai-message-per-token/javascript" - dependencies: - openai "^4" - -"guide-vercel-message-per-response@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/vercel-message-per-response/javascript": - version "0.1.0" - resolved "file:vercel-message-per-response/javascript" - dependencies: - "@ai-sdk/openai" "^2" - ai "^6" - -"guide-vercel-message-per-token@file:/Users/greg/Projects/Cursor-test/claude/docs-backup/guides/ai-transport/vercel-message-per-token/javascript": - version "0.1.0" - resolved "file:vercel-message-per-token/javascript" - dependencies: - "@ai-sdk/openai" "^2" - ai "^6" - has-flag@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" @@ -978,7 +1174,7 @@ once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -openai@*, openai@^4: +openai@^4: version "4.104.0" resolved "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz" integrity sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA== @@ -1039,7 +1235,7 @@ picocolors@^1.1.1: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -"picomatch@^3 || ^4", picomatch@^4.0.2, picomatch@^4.0.3: +picomatch@^4.0.2, picomatch@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz" integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== @@ -1219,7 +1415,7 @@ ts-algebra@^2.0.0: resolved "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz" integrity sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw== -tsx@^4.19.0, tsx@^4.8.1: +tsx@^4.19.0: version "4.21.0" resolved "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz" integrity sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw== @@ -1344,17 +1540,17 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^8.17.1, ws@^8.18.0: +ws@^8.17.1: version "8.19.0" resolved "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz" integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== -zod-to-json-schema@^3.22.3, zod-to-json-schema@^3.x: +zod-to-json-schema@^3.22.3: version "3.25.1" resolved "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz" integrity sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA== -zod@^3.23.8, "zod@^3.25 || ^4", "zod@^3.25.0 || ^4.0.0", zod@^3.25.32, "zod@^3.25.76 || ^4.1.8": +zod@^3.23.8, zod@^3.25.32: version "3.25.76" resolved "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz" integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==