diff --git a/.changeset/angry-hats-cry.md b/.changeset/angry-hats-cry.md new file mode 100644 index 000000000000..e46ec6d49ac0 --- /dev/null +++ b/.changeset/angry-hats-cry.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/gateway': patch +--- + +feat(provider/gateway): Add new xAI models diff --git a/.changeset/beige-bikes-repeat.md b/.changeset/beige-bikes-repeat.md new file mode 100644 index 000000000000..d602c7b4af27 --- /dev/null +++ b/.changeset/beige-bikes-repeat.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/openai': patch +--- + +fix the "incomplete_details" key from nullable to nullish for openai compatibility diff --git a/.changeset/blue-books-hang.md b/.changeset/blue-books-hang.md new file mode 100644 index 000000000000..c00c57bd32fe --- /dev/null +++ b/.changeset/blue-books-hang.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/gateway': patch +--- + +feat(provider/gateway): Add gpt-5-codex to Gateway model string autocomplete diff --git a/.changeset/curly-glasses-count.md b/.changeset/curly-glasses-count.md new file mode 100644 index 000000000000..ce538e65bf5c --- /dev/null +++ b/.changeset/curly-glasses-count.md @@ -0,0 +1,45 @@ +--- +'ai': minor +'@ai-sdk/amazon-bedrock': minor +'@ai-sdk/angular': minor +'@ai-sdk/anthropic': minor +'@ai-sdk/assemblyai': minor +'@ai-sdk/azure': minor +'@ai-sdk/cerebras': minor +'@ai-sdk/codemod': minor +'@ai-sdk/cohere': minor +'@ai-sdk/deepgram': minor +'@ai-sdk/deepinfra': minor +'@ai-sdk/deepseek': minor +'@ai-sdk/elevenlabs': minor +'@ai-sdk/fal': minor +'@ai-sdk/fireworks': minor +'@ai-sdk/gateway': minor +'@ai-sdk/gladia': minor +'@ai-sdk/google': minor +'@ai-sdk/google-vertex': minor +'@ai-sdk/groq': minor +'@ai-sdk/hume': minor +'@ai-sdk/langchain': minor +'@ai-sdk/llamaindex': minor +'@ai-sdk/lmnt': minor +'@ai-sdk/luma': minor +'@ai-sdk/mistral': minor +'@ai-sdk/openai': minor +'@ai-sdk/openai-compatible': minor +'@ai-sdk/perplexity': minor +'@ai-sdk/provider': minor +'@ai-sdk/provider-utils': minor +'@ai-sdk/react': minor +'@ai-sdk/replicate': minor +'@ai-sdk/revai': minor +'@ai-sdk/rsc': minor +'@ai-sdk/svelte': minor +'@ai-sdk/togetherai': minor +'@ai-sdk/valibot': minor +'@ai-sdk/vercel': minor +'@ai-sdk/vue': minor +'@ai-sdk/xai': minor +--- + +release: start 5.1 beta diff --git a/.changeset/cyan-mirrors-clap.md b/.changeset/cyan-mirrors-clap.md new file mode 100644 index 000000000000..676515acec5d --- /dev/null +++ b/.changeset/cyan-mirrors-clap.md @@ -0,0 +1,20 @@ +--- +'@ai-sdk/openai': patch +--- + +feat(provider/openai): `OpenAIChatLanguageModelOptions` type + +```ts +import { openai, type OpenAIChatLanguageModelOptions } from '@ai-sdk/openai'; +import { generateText } from 'ai'; + +await generateText({ + model: openai.chat('gpt-4o'), + prompt: 'Invent a new holiday and describe its traditions.', + providerOptions: { + openai: { + user: 'user-123', + } satisfies OpenAIChatLanguageModelOptions, + }, +}); +``` diff --git a/.changeset/eighty-ghosts-collect.md b/.changeset/eighty-ghosts-collect.md new file mode 100644 index 000000000000..cd9eb78fdb4b --- /dev/null +++ b/.changeset/eighty-ghosts-collect.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/gateway': patch +--- + +feat(provider/gateway): Add new Qwen models to Gateway model string autocomplete diff --git a/.changeset/four-candles-buy.md b/.changeset/four-candles-buy.md new file mode 100644 index 000000000000..4579aa270a50 --- /dev/null +++ b/.changeset/four-candles-buy.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/test-server': major +--- + +feat(packages/test-server): Add `test-server` as a package diff --git a/.changeset/funny-olives-reply.md b/.changeset/funny-olives-reply.md new file mode 100644 index 000000000000..1dfaf63b225f --- /dev/null +++ b/.changeset/funny-olives-reply.md @@ -0,0 +1,20 @@ +--- +'@ai-sdk/openai-compatible': patch +'@ai-sdk/amazon-bedrock': patch +'@ai-sdk/google-vertex': patch +'@ai-sdk/togetherai': patch +'@ai-sdk/deepinfra': patch +'@ai-sdk/fireworks': patch +'@ai-sdk/provider': patch +'@example/ai-core': patch +'@ai-sdk/baseten': patch +'@ai-sdk/gateway': patch +'@ai-sdk/mistral': patch +'@ai-sdk/cohere': patch +'@ai-sdk/google': patch +'@ai-sdk/openai': patch +'@ai-sdk/azure': patch +'ai': patch +--- + +feat: `EmbeddingModelV3` diff --git a/.changeset/gentle-students-begin.md b/.changeset/gentle-students-begin.md new file mode 100644 index 000000000000..520bcd47bd84 --- /dev/null +++ b/.changeset/gentle-students-begin.md @@ -0,0 +1,5 @@ +--- +'ai': patch +--- + +Export `parseJsonEventStream` and `uiMessageChunkSchema` from "ai" package diff --git a/.changeset/great-eels-mate.md b/.changeset/great-eels-mate.md new file mode 100644 index 000000000000..48fb0a3fb4de --- /dev/null +++ b/.changeset/great-eels-mate.md @@ -0,0 +1,5 @@ +--- +'ai': patch +--- + +fix(ai): update `uiMessageChunkSchema` to satisfy the `UIMessageChunk` type diff --git a/.changeset/grumpy-actors-sleep.md b/.changeset/grumpy-actors-sleep.md new file mode 100644 index 000000000000..a605c5e22878 --- /dev/null +++ b/.changeset/grumpy-actors-sleep.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/cerebras': patch +--- + +feat (provider/cerebras): enable structured outputs diff --git a/.changeset/itchy-monkeys-nail.md b/.changeset/itchy-monkeys-nail.md new file mode 100644 index 000000000000..f23122a14716 --- /dev/null +++ b/.changeset/itchy-monkeys-nail.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/gateway': patch +--- + +feat(provider/gateway): Add LongCat Thinking model to Gateway autocomplete diff --git a/.changeset/itchy-peaches-clean.md b/.changeset/itchy-peaches-clean.md new file mode 100644 index 000000000000..b6bf09bc47f0 --- /dev/null +++ b/.changeset/itchy-peaches-clean.md @@ -0,0 +1,36 @@ +--- +'@ai-sdk/openai-compatible': patch +'@ai-sdk/amazon-bedrock': patch +'@ai-sdk/google-vertex': patch +'@ai-sdk/assemblyai': patch +'@ai-sdk/elevenlabs': patch +'@ai-sdk/perplexity': patch +'@ai-sdk/togetherai': patch +'@ai-sdk/anthropic': patch +'@ai-sdk/deepinfra': patch +'@ai-sdk/fireworks': patch +'@ai-sdk/replicate': patch +'@ai-sdk/cerebras': patch +'@ai-sdk/deepgram': patch +'@ai-sdk/deepseek': patch +'@ai-sdk/provider': patch +'@ai-sdk/baseten': patch +'@ai-sdk/gateway': patch +'@ai-sdk/mistral': patch +'@ai-sdk/cohere': patch +'@ai-sdk/gladia': patch +'@ai-sdk/google': patch +'@ai-sdk/openai': patch +'@ai-sdk/vercel': patch +'@ai-sdk/azure': patch +'@ai-sdk/revai': patch +'@ai-sdk/groq': patch +'@ai-sdk/hume': patch +'@ai-sdk/lmnt': patch +'@ai-sdk/luma': patch +'@ai-sdk/fal': patch +'@ai-sdk/xai': patch +'ai': patch +--- + +feat: `Provider-V3` diff --git a/.changeset/lemon-guests-drop.md b/.changeset/lemon-guests-drop.md new file mode 100644 index 000000000000..884824144478 --- /dev/null +++ b/.changeset/lemon-guests-drop.md @@ -0,0 +1,33 @@ +--- +'@ai-sdk/gateway': patch +'@ai-sdk/openai': patch +'@ai-sdk/anthropic': patch +'@ai-sdk/google': patch +'@ai-sdk/google-vertex': patch +'@ai-sdk/azure': patch +'@ai-sdk/amazon-bedrock': patch +'@ai-sdk/cohere': patch +'@ai-sdk/mistral': patch +'@ai-sdk/groq': patch +'@ai-sdk/cerebras': patch +'@ai-sdk/deepinfra': patch +'@ai-sdk/deepseek': patch +'@ai-sdk/fireworks': patch +'@ai-sdk/perplexity': patch +'@ai-sdk/replicate': patch +'@ai-sdk/togetherai': patch +'@ai-sdk/xai': patch +'@ai-sdk/vercel': patch +'@ai-sdk/elevenlabs': patch +'@ai-sdk/assemblyai': patch +'@ai-sdk/deepgram': patch +'@ai-sdk/gladia': patch +'@ai-sdk/revai': patch +'@ai-sdk/luma': patch +'@ai-sdk/fal': patch +'@ai-sdk/hume': patch +'@ai-sdk/lmnt': patch +'@ai-sdk/baseten': patch +--- + +feat: add provider version to user-agent header diff --git a/.changeset/long-dodos-lay.md b/.changeset/long-dodos-lay.md new file mode 100644 index 000000000000..9d5661f0605f --- /dev/null +++ b/.changeset/long-dodos-lay.md @@ -0,0 +1,5 @@ +--- +'ai': patch +--- + +Extend addToolResult to support error results diff --git a/.changeset/many-lamps-report.md b/.changeset/many-lamps-report.md new file mode 100644 index 000000000000..1f9ea817b927 --- /dev/null +++ b/.changeset/many-lamps-report.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/mistral': patch +--- + +Add option for disabling parallel tool call in mistral diff --git a/.changeset/neat-news-visit.md b/.changeset/neat-news-visit.md new file mode 100644 index 000000000000..e0a83307895a --- /dev/null +++ b/.changeset/neat-news-visit.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/gateway': patch +--- + +add getCredits() gateway method diff --git a/.changeset/old-kiwis-hide.md b/.changeset/old-kiwis-hide.md new file mode 100644 index 000000000000..1a087e136ae1 --- /dev/null +++ b/.changeset/old-kiwis-hide.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/provider-utils': patch +--- + +Update for provider-util changeset after change in PR #8588 diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000000..c0193b8cfee1 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,103 @@ +{ + "mode": "pre", + "tag": "beta", + "initialVersions": { + "@example/ai-core": "0.0.0", + "@example/angular": "0.0.0", + "@example/express": "0.0.0", + "@example/fastify": "0.0.0", + "@example/hono": "0.0.0", + "@example/mcp": "0.0.0", + "@example/nest": "0.0.0", + "@example/next": "0.0.0", + "@example/next-agent": "0.0.0", + "@example/next-fastapi": "0.0.0", + "@example/next-google-vertex": "0.0.0", + "@example/next-langchain": "0.0.0", + "@example/next-openai": "0.0.0", + "@example/next-openai-kasada-bot-protection": "0.0.0", + "@example/next-openai-pages": "0.0.0", + "@example/next-openai-telemetry": "0.0.0", + "@example/next-openai-telemetry-sentry": "0.0.0", + "@example/next-openai-rate-limits": "0.0.0", + "@example/node-http-server": "0.0.0", + "@example/nuxt-openai": "0.0.0", + "@example/sveltekit-openai": "0.0.0", + "ai": "5.0.45", + "@ai-sdk/amazon-bedrock": "3.0.22", + "@ai-sdk/angular": "1.0.45", + "@ai-sdk/anthropic": "2.0.17", + "@ai-sdk/assemblyai": "1.0.9", + "@ai-sdk/azure": "2.0.32", + "@ai-sdk/cerebras": "1.0.18", + "@ai-sdk/codemod": "2.0.10", + "@ai-sdk/cohere": "2.0.10", + "@ai-sdk/deepgram": "1.0.9", + "@ai-sdk/deepinfra": "1.0.18", + "@ai-sdk/deepseek": "1.0.18", + "@ai-sdk/elevenlabs": "1.0.10", + "@ai-sdk/fal": "1.0.13", + "@ai-sdk/fireworks": "1.0.18", + "@ai-sdk/gateway": "1.0.23", + "@ai-sdk/gladia": "1.0.9", + "@ai-sdk/google": "2.0.14", + "@ai-sdk/google-vertex": "3.0.27", + "@ai-sdk/groq": "2.0.19", + "@ai-sdk/hume": "1.0.9", + "@ai-sdk/langchain": "1.0.45", + "@ai-sdk/llamaindex": "1.0.45", + "@ai-sdk/lmnt": "1.0.9", + "@ai-sdk/luma": "1.0.9", + "@ai-sdk/mistral": "2.0.14", + "@ai-sdk/openai": "2.0.32", + "@ai-sdk/openai-compatible": "1.0.18", + "@ai-sdk/perplexity": "2.0.9", + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.9", + "@ai-sdk/react": "2.0.45", + "@ai-sdk/replicate": "1.0.9", + "@ai-sdk/revai": "1.0.9", + "@ai-sdk/rsc": "1.0.45", + "ai-core-e2e-next-server": "0.0.0", + "@ai-sdk/svelte": "3.0.45", + "@ai-sdk/togetherai": "1.0.18", + "@ai-sdk/valibot": "1.0.9", + "@ai-sdk/vercel": "1.0.18", + "@ai-sdk/vue": "2.0.45", + "@ai-sdk/xai": "2.0.20", + "analyze-downloads": "0.0.0", + "eslint-config-vercel-ai": "0.0.0", + "generate-llms-txt": "0.0.0", + "@vercel/ai-tsconfig": "0.0.0", + "@ai-sdk/baseten": "0.0.0", + "@ai-sdk/test-server": "0.0.0" + }, + "changesets": [ + "angry-hats-cry", + "beige-bikes-repeat", + "blue-books-hang", + "curly-glasses-count", + "cyan-mirrors-clap", + "eighty-ghosts-collect", + "four-candles-buy", + "funny-olives-reply", + "gentle-students-begin", + "great-eels-mate", + "grumpy-actors-sleep", + "itchy-monkeys-nail", + "itchy-peaches-clean", + "lemon-guests-drop", + "many-lamps-report", + "neat-news-visit", + "old-kiwis-hide", + "quiet-pens-suffer", + "red-roses-glow", + "selfish-beers-mate", + "shaggy-emus-try", + "soft-glasses-happen", + "tall-terms-smash", + "thin-shoes-fold", + "two-birds-agree", + "wise-jobs-knock" + ] +} diff --git a/.changeset/quiet-pens-suffer.md b/.changeset/quiet-pens-suffer.md new file mode 100644 index 000000000000..6cb27771fc32 --- /dev/null +++ b/.changeset/quiet-pens-suffer.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/baseten': major +--- + +Added Baseten as a Provider for AI SDK diff --git a/.changeset/red-roses-glow.md b/.changeset/red-roses-glow.md new file mode 100644 index 000000000000..16ea869d6382 --- /dev/null +++ b/.changeset/red-roses-glow.md @@ -0,0 +1,5 @@ +--- +'ai': patch +--- + +Add safeValidateUIMessages utility to validate UI messages without throwing, returning a success/failure result object like Zod’s safeParse diff --git a/.changeset/selfish-beers-mate.md b/.changeset/selfish-beers-mate.md new file mode 100644 index 000000000000..2db2a3385a2f --- /dev/null +++ b/.changeset/selfish-beers-mate.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/gateway': patch +--- + +getCredits style improvements diff --git a/.changeset/shaggy-emus-try.md b/.changeset/shaggy-emus-try.md new file mode 100644 index 000000000000..7e4619114ccd --- /dev/null +++ b/.changeset/shaggy-emus-try.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/google': patch +--- + +add promptFeedback outputs diff --git a/.changeset/soft-glasses-happen.md b/.changeset/soft-glasses-happen.md new file mode 100644 index 000000000000..1bd825e7ed6b --- /dev/null +++ b/.changeset/soft-glasses-happen.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/gateway': patch +--- + +feat(provider/gateway): Add DeepSeek V3.1 Terminus to Gateway autocomplete diff --git a/.changeset/tall-terms-smash.md b/.changeset/tall-terms-smash.md new file mode 100644 index 000000000000..84db62dc0d36 --- /dev/null +++ b/.changeset/tall-terms-smash.md @@ -0,0 +1,5 @@ +--- +'ai': patch +--- + +fix(ai): download files when intermediate file cannot be downloaded diff --git a/.changeset/thin-shoes-fold.md b/.changeset/thin-shoes-fold.md new file mode 100644 index 000000000000..da420db0f70b --- /dev/null +++ b/.changeset/thin-shoes-fold.md @@ -0,0 +1,19 @@ +--- +'@ai-sdk/openai-compatible': patch +'@ai-sdk/amazon-bedrock': patch +'@ai-sdk/google-vertex': patch +'@ai-sdk/togetherai': patch +'@ai-sdk/deepinfra': patch +'@ai-sdk/fireworks': patch +'@ai-sdk/replicate': patch +'@ai-sdk/provider': patch +'@ai-sdk/google': patch +'@ai-sdk/openai': patch +'@ai-sdk/azure': patch +'@ai-sdk/luma': patch +'@ai-sdk/fal': patch +'@ai-sdk/xai': patch +'ai': patch +--- + +feat: `ImageModelV3` diff --git a/.changeset/two-birds-agree.md b/.changeset/two-birds-agree.md new file mode 100644 index 000000000000..34a72ae5f937 --- /dev/null +++ b/.changeset/two-birds-agree.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/xai': patch +--- + +feat(xai) add grok-4-fast model ids diff --git a/.changeset/violet-cameras-yell.md b/.changeset/violet-cameras-yell.md deleted file mode 100644 index 679379ce091f..000000000000 --- a/.changeset/violet-cameras-yell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@ai-sdk/openai': patch ---- - -fix (provider/openai): fix code interpreter tool in doGenerate diff --git a/.changeset/wise-jobs-knock.md b/.changeset/wise-jobs-knock.md new file mode 100644 index 000000000000..9d5a69106f25 --- /dev/null +++ b/.changeset/wise-jobs-knock.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/groq': patch +--- + +fix(provider/groq): track cached tokens usage diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8dfa57b22180..6498a4f55b8c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -22,11 +22,10 @@ Please explain how you *manually* verified that the change works end-to-end as e Remove the section if it's not needed (e.g. for docs). --> -## Tasks +## Checklist diff --git a/.github/workflows/assign-team-pull-request.yml b/.github/workflows/assign-team-pull-request.yml index 5de0ad5d32fe..411073e99892 100644 --- a/.github/workflows/assign-team-pull-request.yml +++ b/.github/workflows/assign-team-pull-request.yml @@ -14,7 +14,7 @@ jobs: # And only assign if pull request was created by a user, ignore bots if: github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.user.type == 'User' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Assign pull request to author run: gh pr edit $PULL_REQUEST_URL --add-assignee $AUTHOR_LOGIN env: diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 000000000000..68c6e61afd93 --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,107 @@ +name: Backport + +on: + pull_request_target: + types: [closed, labeled] + +concurrency: ${{ github.workflow }}-${{ github.event.pull_request.number }} + +jobs: + backport: + name: Backport to release-v5.0 + runs-on: ubuntu-latest + timeout-minutes: 10 + # Only run on merged PRs with backport label in the main repository + if: | + github.repository_owner == 'vercel' && + github.event.pull_request.merged == true && + contains(github.event.pull_request.labels.*.name, 'backport') && + github.event.pull_request.base.ref == 'main' + + steps: + - name: Create access token for GitHub App + uses: actions/create-github-app-token@v2 + id: app-token + with: + app-id: ${{ vars.VERCEL_AI_SDK_GITHUB_APP_CLIENT_ID }} + private-key: ${{ secrets.VERCEL_AI_SDK_GITHUB_APP_PRIVATE_KEY_PKCS8 }} + + - name: Get GitHub App User ID + id: app-user-id + run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + + - name: Configure git user for GitHub App + run: | + git config --global user.name '${{ steps.app-token.outputs.app-slug }}[bot]' + git config --global user.email '${{ steps.app-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com' + + - name: Checkout Repository + uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ steps.app-token.outputs.token }} + ref: release-v5.0 + + - name: Create backport branch + run: | + # Create a new branch from release-v5.0 for the backport + git checkout -b backport-pr-${{ github.event.pull_request.number }}-to-release-v5.0 origin/release-v5.0 + + - name: Cherry-pick commits + run: | + # Get the merge commit hash + MERGE_COMMIT="${{ github.event.pull_request.merge_commit_sha }}" + + # Cherry-pick the merge commit + if ! git cherry-pick -m 1 "$MERGE_COMMIT"; then + echo "Cherry-pick failed. This backport requires manual intervention." + echo "::error::Failed to cherry-pick merge commit $MERGE_COMMIT to release-v5.0 branch" + exit 1 + fi + + - name: Push backport branch + run: | + git push origin backport-pr-${{ github.event.pull_request.number }}-to-release-v5.0 + + - name: Create backport pull request + id: create-pr + run: | + # Create the backport PR + + PR_URL=$(gh pr create \ + --title "$PR_TITLE" \ + --body "$PR_BODY" \ + --base release-v5.0 \ + --head backport-pr-${{ github.event.pull_request.number }}-to-release-v5.0) + + echo "backport-pr-url=$PR_URL" >> "$GITHUB_OUTPUT" + echo "Created backport PR $PR_URL" + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + PR_TITLE: "Backport: ${{ github.event.pull_request.title }}" + PR_BODY: "This is an automated backport of #${{ github.event.pull_request.number }} to the release-v5.0 branch." + + - name: Remove backport label from original PR + if: steps.create-pr.outputs.backport-pr-url + run: | + # Remove the backport label from the original PR + gh pr edit ${{ github.event.pull_request.number }} --remove-label backport + echo "Removed backport label from original PR #${{ github.event.pull_request.number }}" + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + + - name: Success Comment on original PR + if: steps.create-pr.outputs.backport-pr-url + run: | + gh pr comment ${{ github.event.pull_request.number }} --body "✅ Backport PR created: ${{ steps.create-pr.outputs.backport-pr-url }}" + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + + - name: Failure Comment on original PR + if: failure() + run: | + gh pr comment ${{ github.event.pull_request.number }} --body "❌ Backport to release-v5.0 failed. This backport requires manual intervention. [View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89c274e80b81..807bd88a5127 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [main, v5] + branches: [main] pull_request: - branches: [main, v5] + branches: [main] jobs: build-examples: @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -20,7 +20,7 @@ jobs: version: 10.11.0 - name: Use Node.js 22 - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 cache: 'pnpm' @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -44,7 +44,7 @@ jobs: version: 10.11.0 - name: Use Node.js 22 - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 cache: 'pnpm' @@ -60,7 +60,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -68,7 +68,7 @@ jobs: version: 10.11.0 - name: Use Node.js 22 - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 cache: 'pnpm' @@ -84,7 +84,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -92,7 +92,7 @@ jobs: version: 10.11.0 - name: Use Node.js 22 - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 cache: 'pnpm' @@ -114,7 +114,7 @@ jobs: node-version: [20, 22] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -122,7 +122,7 @@ jobs: version: 10.11.0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/release-snapshot.yml b/.github/workflows/release-snapshot.yml index 97e198e40651..685cc25a1804 100644 --- a/.github/workflows/release-snapshot.yml +++ b/.github/workflows/release-snapshot.yml @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 @@ -48,7 +48,7 @@ jobs: version: 10.11.0 - name: Setup Node.js 22 - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0ecedf873e48..c1423f641063 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - v5 paths: - '.changeset/**' - '.github/workflows/release.yml' @@ -17,6 +16,8 @@ jobs: name: Release runs-on: ubuntu-latest timeout-minutes: 10 + # do not attempt running in forks + if: github.repository_owner == 'vercel' steps: - name: Create access token for GitHub App uses: actions/create-github-app-token@v2 @@ -37,7 +38,7 @@ jobs: git config --global user.email '${{ steps.app-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com' - name: Checkout Repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 token: ${{ steps.app-token.outputs.token }} @@ -49,7 +50,7 @@ jobs: version: 10.11.0 - name: Setup Node.js 22 - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 diff --git a/.github/workflows/slack-team-review-notification.yml b/.github/workflows/slack-team-review-notification.yml new file mode 100644 index 000000000000..a6bf4787b542 --- /dev/null +++ b/.github/workflows/slack-team-review-notification.yml @@ -0,0 +1,38 @@ +name: Slack Team Review Notification + +on: + pull_request: + types: [review_requested] + +jobs: + notify-slack: + runs-on: ubuntu-latest + + steps: + - name: debug + run: cat $GITHUB_EVENT_PATH + - name: Check if ai-sdk team was requested + id: check_team + run: | + echo "Checking requested teams..." + teams='${{ toJson(github.event.pull_request.requested_teams) }}' + + # Check if ai-sdk team is in the requested teams + if echo "$teams" | jq -e '.[] | select(.slug == "ai-sdk")' > /dev/null; then + echo "ai_sdk_requested=true" >> $GITHUB_OUTPUT + echo "✅ ai-sdk team was requested for review" + else + echo "ai_sdk_requested=false" >> $GITHUB_OUTPUT + echo "❌ ai-sdk team was not requested for review" + fi + + - name: Send Slack notification + if: steps.check_team.outputs.ai_sdk_requested == 'true' + run: | + curl ${{ env.SLACK_SEND_MESSAGE_URL }} -X POST -H "Content-Type: application/json" -d '{"channel_id": "${{ env.CHANNEL_ID }}", "number": "${{ env.NUMBER }}", "title": ${{ toJson(env.TITLE) }}, "url": "${{ env.URL }}"}' + env: + SLACK_SEND_MESSAGE_URL: ${{ secrets.SLACK_SEND_MESSAGE_URL }} + CHANNEL_ID: "C050WU03V3N" + NUMBER: ${{ github.event.pull_request.number }} + TITLE: ${{ github.event.pull_request.title }} + URL: ${{ github.event.pull_request.html_url }} \ No newline at end of file diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index bab6f8393283..79136f71e5ab 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -21,7 +21,7 @@ jobs: private-key: ${{ secrets.VERCEL_AI_SDK_GITHUB_APP_PRIVATE_KEY_PKCS8 }} - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Fetch existing provider labels id: fetch-labels @@ -92,7 +92,7 @@ jobs: GH_TOKEN: ${{ steps.app-token.outputs.token }} - name: Add comment if no provider detected - if: fromJSON(steps.classify-issue.outputs.json).confidence <= 0.6 + if: fromJSON(steps.classify-issue.outputs.json).confidence <= 0.6 && github.event.issue.author_association != 'MEMBER' run: | gh api /repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments \ --method POST \ diff --git a/.github/workflows/verify-changesets.yml b/.github/workflows/verify-changesets.yml index 4feca6aef7bb..cf10acc36dd2 100644 --- a/.github/workflows/verify-changesets.yml +++ b/.github/workflows/verify-changesets.yml @@ -16,12 +16,14 @@ jobs: verify-changesets: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 'lts/*' + cache: 'npm' + cache-dependency-path: .github/workflows/actions/verify-changesets/package.json - name: get all changed files from .changeset/*.md id: changeset-files run: | diff --git a/content/cookbook/00-guides/20-google-gemini-image-generation.mdx b/content/cookbook/00-guides/20-google-gemini-image-generation.mdx new file mode 100644 index 000000000000..69aa80e4ac9b --- /dev/null +++ b/content/cookbook/00-guides/20-google-gemini-image-generation.mdx @@ -0,0 +1,107 @@ +--- +title: Google Gemini Image Generation +description: Generate and edit images with Google Gemini 2.5 Flash Image using the AI SDK. +tags: ['image-generation', 'google', 'gemini'] +--- + +# Generate and Edit Images with Google Gemini 2.5 Flash + +This guide will show you how to generate and edit images with the AI SDK and Google's latest multimodal language model Gemini 2.5 Flash Image. + +## Generating Images + +As Gemini 2.5 Flash Image is a language model with multimodal capabilities, you can use the `generateText` or `streamText` functions (not `generateImage`) to create images. The model determines which modality to respond in based on your prompt and configuration. Here's how to create your first image: + +```ts +import { google } from '@ai-sdk/google'; +import { generateText } from 'ai'; +import fs from 'node:fs'; +import 'dotenv/config'; + +async function generateImage() { + const result = await generateText({ + model: google('gemini-2.5-flash-image-preview'), + prompt: + 'Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme', + }); + + // Save generated images + for (const file of result.files) { + if (file.mediaType.startsWith('image/')) { + const timestamp = Date.now(); + const fileName = `generated-${timestamp}.png`; + + fs.mkdirSync('output', { recursive: true }); + await fs.promises.writeFile(`output/${fileName}`, file.uint8Array); + + console.log(`Generated and saved image: output/${fileName}`); + } + } +} + +generateImage().catch(console.error); +``` + +Here are some key points to remember: + +- Generated images are returned in the `result.files` array +- Images are returned as `Uint8Array` data +- The model leverages Gemini's world knowledge, so detailed prompts yield better results + +## Editing Images + +Gemini 2.5 Flash Image excels at editing existing images with natural language instructions. You can add elements, modify styles, or transform images while maintaining their core characteristics: + +```ts +import { google } from '@ai-sdk/google'; +import { generateText } from 'ai'; +import fs from 'node:fs'; +import 'dotenv/config'; + +async function editImage() { + const editResult = await generateText({ + model: google('gemini-2.5-flash-image-preview'), + prompt: [ + { + role: 'user', + content: [ + { + type: 'text', + text: 'Add a small wizard hat to this cat. Keep everything else the same.', + }, + { + type: 'image', + // image: DataContent (string | Uint8Array | ArrayBuffer | Buffer) or URL + image: new URL( + 'https://raw.githubusercontent.com/vercel/ai/refs/heads/main/examples/ai-core/data/comic-cat.png', + ), + mediaType: 'image/jpeg', + }, + ], + }, + ], + }); + + // Save the edited image + const timestamp = Date.now(); + fs.mkdirSync('output', { recursive: true }); + + for (const file of editResult.files) { + if (file.mediaType.startsWith('image/')) { + await fs.promises.writeFile( + `output/edited-${timestamp}.png`, + file.uint8Array, + ); + console.log(`Saved edited image: output/edited-${timestamp}.png`); + } + } +} + +editImage().catch(console.error); +``` + +## What's Next? + +You've learned how to generate new images from text prompts and edit existing images using natural language instructions with Google's Gemini 2.5 Flash Image model. + +For more advanced techniques, integration patterns, and practical examples, check out our [Cookbook](/cookbook) where you'll find comprehensive guides for building sophisticated AI-powered applications. diff --git a/content/cookbook/00-guides/21-llama-3_1.mdx b/content/cookbook/00-guides/21-llama-3_1.mdx index 92883fa1d10d..7e9a5bb58109 100644 --- a/content/cookbook/00-guides/21-llama-3_1.mdx +++ b/content/cookbook/00-guides/21-llama-3_1.mdx @@ -57,7 +57,7 @@ const { text } = await generateText({ Llama 3.1 is available to use with many AI SDK providers including [DeepInfra](/providers/ai-sdk-providers/deepinfra), [Amazon Bedrock](/providers/ai-sdk-providers/amazon-bedrock), - [Baseten](/providers/openai-compatible-providers/baseten) + [Baseten](/providers/ai-sdk-providers/baseten) [Fireworks](/providers/ai-sdk-providers/fireworks), and more. diff --git a/content/cookbook/01-next/12-generate-image-with-chat-prompt.mdx b/content/cookbook/01-next/12-generate-image-with-chat-prompt.mdx index a37e0e57b7ad..22cf56547c21 100644 --- a/content/cookbook/01-next/12-generate-image-with-chat-prompt.mdx +++ b/content/cookbook/01-next/12-generate-image-with-chat-prompt.mdx @@ -12,7 +12,7 @@ When building a chatbot, you may want to allow the user to generate an image. Th Let's create an endpoint at `/api/chat` that generates the assistant's response based on the conversation history. You will also define a tool called `generateImage` that will generate an image based on the assistant's response. -```typescript filename='tools/get-weather.ts' +```typescript filename='tools/generate-image.ts' import { openai } from '@ai-sdk/openai'; import { experimental_generateImage, tool } from 'ai'; import z from 'zod'; @@ -43,7 +43,7 @@ import { type UIMessage, } from 'ai'; -import { generateImage } from '@/tools/get-weather'; +import { generateImage } from '@/tools/generate-image'; const tools = { generateImage, diff --git a/content/docs/02-foundations/02-providers-and-models.mdx b/content/docs/02-foundations/02-providers-and-models.mdx index 4977524cbc2c..62aa51860136 100644 --- a/content/docs/02-foundations/02-providers-and-models.mdx +++ b/content/docs/02-foundations/02-providers-and-models.mdx @@ -48,11 +48,11 @@ The AI SDK comes with a wide range of providers that you can use to interact wit - [Gladia Provider](/providers/ai-sdk-providers/gladia) (`@ai-sdk/gladia`) - [LMNT Provider](/providers/ai-sdk-providers/lmnt) (`@ai-sdk/lmnt`) - [AssemblyAI Provider](/providers/ai-sdk-providers/assemblyai) (`@ai-sdk/assemblyai`) +- [Baseten Provider](/providers/ai-sdk-providers/baseten) (`@ai-sdk/baseten`) You can also use the [OpenAI Compatible provider](/providers/openai-compatible-providers) with OpenAI-compatible APIs: - [LM Studio](/providers/openai-compatible-providers/lmstudio) -- [Baseten](/providers/openai-compatible-providers/baseten) - [Heroku](/providers/openai-compatible-providers/heroku) Our [language model specification](https://github.com/vercel/ai/tree/main/packages/provider/src/language-model/v2) is published as an open-source package, which you can use to create [custom providers](/providers/community-providers/custom-providers). @@ -88,7 +88,7 @@ You can access self-hosted models with the following providers: - [Ollama Provider](/providers/community-providers/ollama) - [LM Studio](/providers/openai-compatible-providers/lmstudio) -- [Baseten](/providers/openai-compatible-providers/baseten) +- [Baseten](/providers/ai-sdk-providers/baseten) - [Built-in AI](/providers/community-providers/built-in-ai) Additionally, any self-hosted provider that supports the OpenAI specification can be used with the [OpenAI Compatible Provider](/providers/openai-compatible-providers). diff --git a/content/docs/02-foundations/06-agents.mdx b/content/docs/02-foundations/06-agents.mdx deleted file mode 100644 index 95dc2b470935..000000000000 --- a/content/docs/02-foundations/06-agents.mdx +++ /dev/null @@ -1,535 +0,0 @@ ---- -title: Agents -description: Learn how to build agents with AI SDK Core. ---- - -# Agents - -When building AI applications, you often need **systems that can understand context and take meaningful actions**. When building these systems, the key consideration is finding the right balance between flexibility and control. Let's explore different approaches and patterns for building these systems, with a focus on helping you match capabilities to your needs. - -## Building Blocks - -When building AI systems, you can combine these fundamental components: - -### Single-Step LLM Generation - -The basic building block - one call to an LLM to get a response. Useful for straightforward tasks like classification or text generation. - -### Tool Usage - -Enhanced capabilities through tools (like calculators, APIs, or databases) that the LLM can use to accomplish tasks. Tools provide a controlled way to extend what the LLM can do. - -When solving complex problems, **an LLM can make multiple tool calls across multiple steps without you explicitly specifying the order** - for example, looking up information in a database, using that to make calculations, and then storing results. The AI SDK makes this [multi-step tool usage](#multi-step-tool-usage) straightforward through the `stopWhen` parameter. - -### Multi-Agent Systems - -Multiple LLMs working together, each specialized for different aspects of a complex task. This enables sophisticated behaviors while keeping individual components focused. - -## Patterns - -These building blocks can be combined with workflow patterns that help manage complexity: - -- [Sequential Processing](#sequential-processing-chains) - Steps executed in order -- [Parallel Processing](#parallel-processing) - Independent tasks run simultaneously -- [Evaluation/Feedback Loops](#evaluator-optimizer) - Results checked and improved iteratively -- [Orchestration](#orchestrator-worker) - Coordinating multiple components -- [Routing](#routing) - Directing work based on context - -## Choosing Your Approach - -The key factors to consider: - -- **Flexibility vs Control** - How much freedom does the LLM need vs how tightly must you constrain its actions? -- **Error Tolerance** - What are the consequences of mistakes in your use case? -- **Cost Considerations** - More complex systems typically mean more LLM calls and higher costs -- **Maintenance** - Simpler architectures are easier to debug and modify - -**Start with the simplest approach that meets your needs**. Add complexity only when required by: - -1. Breaking down tasks into clear steps -2. Adding tools for specific capabilities -3. Implementing feedback loops for quality control -4. Introducing multiple agents for complex workflows - -Let's look at examples of these patterns in action. - -## Patterns with Examples - -The following patterns, adapted from [Anthropic's guide on building effective agents](https://www.anthropic.com/research/building-effective-agents), serve as building blocks that can be combined to create comprehensive workflows. Each pattern addresses specific aspects of task execution, and by combining them thoughtfully, you can build reliable solutions for complex problems. - -### Sequential Processing (Chains) - -The simplest workflow pattern executes steps in a predefined order. Each step's output becomes input for the next step, creating a clear chain of operations. This pattern is ideal for tasks with well-defined sequences, like content generation pipelines or data transformation processes. - -```ts -import { openai } from '@ai-sdk/openai'; -import { generateText, generateObject } from 'ai'; -import { z } from 'zod'; - -async function generateMarketingCopy(input: string) { - const model = openai('gpt-4o'); - - // First step: Generate marketing copy - const { text: copy } = await generateText({ - model, - prompt: `Write persuasive marketing copy for: ${input}. Focus on benefits and emotional appeal.`, - }); - - // Perform quality check on copy - const { object: qualityMetrics } = await generateObject({ - model, - schema: z.object({ - hasCallToAction: z.boolean(), - emotionalAppeal: z.number().min(1).max(10), - clarity: z.number().min(1).max(10), - }), - prompt: `Evaluate this marketing copy for: - 1. Presence of call to action (true/false) - 2. Emotional appeal (1-10) - 3. Clarity (1-10) - - Copy to evaluate: ${copy}`, - }); - - // If quality check fails, regenerate with more specific instructions - if ( - !qualityMetrics.hasCallToAction || - qualityMetrics.emotionalAppeal < 7 || - qualityMetrics.clarity < 7 - ) { - const { text: improvedCopy } = await generateText({ - model, - prompt: `Rewrite this marketing copy with: - ${!qualityMetrics.hasCallToAction ? '- A clear call to action' : ''} - ${qualityMetrics.emotionalAppeal < 7 ? '- Stronger emotional appeal' : ''} - ${qualityMetrics.clarity < 7 ? '- Improved clarity and directness' : ''} - - Original copy: ${copy}`, - }); - return { copy: improvedCopy, qualityMetrics }; - } - - return { copy, qualityMetrics }; -} -``` - -### Routing - -This pattern allows the model to make decisions about which path to take through a workflow based on context and intermediate results. The model acts as an intelligent router, directing the flow of execution between different branches of your workflow. This is particularly useful when handling varied inputs that require different processing approaches. In the example below, the results of the first LLM call change the properties of the second LLM call like model size and system prompt. - -```ts -import { openai } from '@ai-sdk/openai'; -import { generateObject, generateText } from 'ai'; -import { z } from 'zod'; - -async function handleCustomerQuery(query: string) { - const model = openai('gpt-4o'); - - // First step: Classify the query type - const { object: classification } = await generateObject({ - model, - schema: z.object({ - reasoning: z.string(), - type: z.enum(['general', 'refund', 'technical']), - complexity: z.enum(['simple', 'complex']), - }), - prompt: `Classify this customer query: - ${query} - - Determine: - 1. Query type (general, refund, or technical) - 2. Complexity (simple or complex) - 3. Brief reasoning for classification`, - }); - - // Route based on classification - // Set model and system prompt based on query type and complexity - const { text: response } = await generateText({ - model: - classification.complexity === 'simple' - ? openai('gpt-4o-mini') - : openai('o3-mini'), - system: { - general: - 'You are an expert customer service agent handling general inquiries.', - refund: - 'You are a customer service agent specializing in refund requests. Follow company policy and collect necessary information.', - technical: - 'You are a technical support specialist with deep product knowledge. Focus on clear step-by-step troubleshooting.', - }[classification.type], - prompt: query, - }); - - return { response, classification }; -} -``` - -### Parallel Processing - -Some tasks can be broken down into independent subtasks that can be executed simultaneously. This pattern takes advantage of parallel execution to improve efficiency while maintaining the benefits of structured workflows. For example, analyzing multiple documents or processing different aspects of a single input concurrently (like code review). - -```ts -import { openai } from '@ai-sdk/openai'; -import { generateText, generateObject } from 'ai'; -import { z } from 'zod'; - -// Example: Parallel code review with multiple specialized reviewers -async function parallelCodeReview(code: string) { - const model = openai('gpt-4o'); - - // Run parallel reviews - const [securityReview, performanceReview, maintainabilityReview] = - await Promise.all([ - generateObject({ - model, - system: - 'You are an expert in code security. Focus on identifying security vulnerabilities, injection risks, and authentication issues.', - schema: z.object({ - vulnerabilities: z.array(z.string()), - riskLevel: z.enum(['low', 'medium', 'high']), - suggestions: z.array(z.string()), - }), - prompt: `Review this code: - ${code}`, - }), - - generateObject({ - model, - system: - 'You are an expert in code performance. Focus on identifying performance bottlenecks, memory leaks, and optimization opportunities.', - schema: z.object({ - issues: z.array(z.string()), - impact: z.enum(['low', 'medium', 'high']), - optimizations: z.array(z.string()), - }), - prompt: `Review this code: - ${code}`, - }), - - generateObject({ - model, - system: - 'You are an expert in code quality. Focus on code structure, readability, and adherence to best practices.', - schema: z.object({ - concerns: z.array(z.string()), - qualityScore: z.number().min(1).max(10), - recommendations: z.array(z.string()), - }), - prompt: `Review this code: - ${code}`, - }), - ]); - - const reviews = [ - { ...securityReview.object, type: 'security' }, - { ...performanceReview.object, type: 'performance' }, - { ...maintainabilityReview.object, type: 'maintainability' }, - ]; - - // Aggregate results using another model instance - const { text: summary } = await generateText({ - model, - system: 'You are a technical lead summarizing multiple code reviews.', - prompt: `Synthesize these code review results into a concise summary with key actions: - ${JSON.stringify(reviews, null, 2)}`, - }); - - return { reviews, summary }; -} -``` - -### Orchestrator-Worker - -In this pattern, a primary model (orchestrator) coordinates the execution of specialized workers. Each worker is optimized for a specific subtask, while the orchestrator maintains overall context and ensures coherent results. This pattern excels at complex tasks requiring different types of expertise or processing. - -```ts -import { openai } from '@ai-sdk/openai'; -import { generateObject } from 'ai'; -import { z } from 'zod'; - -async function implementFeature(featureRequest: string) { - // Orchestrator: Plan the implementation - const { object: implementationPlan } = await generateObject({ - model: openai('o3-mini'), - schema: z.object({ - files: z.array( - z.object({ - purpose: z.string(), - filePath: z.string(), - changeType: z.enum(['create', 'modify', 'delete']), - }), - ), - estimatedComplexity: z.enum(['low', 'medium', 'high']), - }), - system: - 'You are a senior software architect planning feature implementations.', - prompt: `Analyze this feature request and create an implementation plan: - ${featureRequest}`, - }); - - // Workers: Execute the planned changes - const fileChanges = await Promise.all( - implementationPlan.files.map(async file => { - // Each worker is specialized for the type of change - const workerSystemPrompt = { - create: - 'You are an expert at implementing new files following best practices and project patterns.', - modify: - 'You are an expert at modifying existing code while maintaining consistency and avoiding regressions.', - delete: - 'You are an expert at safely removing code while ensuring no breaking changes.', - }[file.changeType]; - - const { object: change } = await generateObject({ - model: openai('gpt-4o'), - schema: z.object({ - explanation: z.string(), - code: z.string(), - }), - system: workerSystemPrompt, - prompt: `Implement the changes for ${file.filePath} to support: - ${file.purpose} - - Consider the overall feature context: - ${featureRequest}`, - }); - - return { - file, - implementation: change, - }; - }), - ); - - return { - plan: implementationPlan, - changes: fileChanges, - }; -} -``` - -### Evaluator-Optimizer - -This pattern introduces quality control into workflows by having dedicated evaluation steps that assess intermediate results. Based on the evaluation, the workflow can either proceed, retry with adjusted parameters, or take corrective action. This creates more robust workflows capable of self-improvement and error recovery. - -```ts -import { openai } from '@ai-sdk/openai'; -import { generateText, generateObject } from 'ai'; -import { z } from 'zod'; - -async function translateWithFeedback(text: string, targetLanguage: string) { - let currentTranslation = ''; - let iterations = 0; - const MAX_ITERATIONS = 3; - - // Initial translation - const { text: translation } = await generateText({ - model: openai('gpt-4o-mini'), // use small model for first attempt - system: 'You are an expert literary translator.', - prompt: `Translate this text to ${targetLanguage}, preserving tone and cultural nuances: - ${text}`, - }); - - currentTranslation = translation; - - // Evaluation-optimization loop - while (iterations < MAX_ITERATIONS) { - // Evaluate current translation - const { object: evaluation } = await generateObject({ - model: openai('gpt-4o'), // use a larger model to evaluate - schema: z.object({ - qualityScore: z.number().min(1).max(10), - preservesTone: z.boolean(), - preservesNuance: z.boolean(), - culturallyAccurate: z.boolean(), - specificIssues: z.array(z.string()), - improvementSuggestions: z.array(z.string()), - }), - system: 'You are an expert in evaluating literary translations.', - prompt: `Evaluate this translation: - - Original: ${text} - Translation: ${currentTranslation} - - Consider: - 1. Overall quality - 2. Preservation of tone - 3. Preservation of nuance - 4. Cultural accuracy`, - }); - - // Check if quality meets threshold - if ( - evaluation.qualityScore >= 8 && - evaluation.preservesTone && - evaluation.preservesNuance && - evaluation.culturallyAccurate - ) { - break; - } - - // Generate improved translation based on feedback - const { text: improvedTranslation } = await generateText({ - model: openai('gpt-4o'), // use a larger model - system: 'You are an expert literary translator.', - prompt: `Improve this translation based on the following feedback: - ${evaluation.specificIssues.join('\n')} - ${evaluation.improvementSuggestions.join('\n')} - - Original: ${text} - Current Translation: ${currentTranslation}`, - }); - - currentTranslation = improvedTranslation; - iterations++; - } - - return { - finalTranslation: currentTranslation, - iterationsRequired: iterations, - }; -} -``` - -## Multi-Step Tool Usage - -If your use case involves solving problems where the solution path is poorly defined or too complex to map out as a workflow in advance, you may want to provide the LLM with a set of lower-level tools and allow it to break down the task into small pieces that it can solve on its own iteratively, without discrete instructions. To implement this kind of agentic pattern, you need to call an LLM in a loop until a task is complete. The AI SDK makes this simple with the `stopWhen` parameter. - -The AI SDK gives you control over the stopping conditions, enabling you to keep the LLM running until one of the conditions are met. The SDK automatically triggers an additional request to the model after every tool result (each request is considered a "step"), continuing until the model does not generate a tool call or other stopping conditions (e.g. `stepCountIs`) you define are satisfied. - -`stopWhen` can be used with both `generateText` and `streamText` - -### Using `stopWhen` - -This example demonstrates how to create an agent that solves math problems. -It has a calculator tool (using [math.js](https://mathjs.org/)) that it can call to evaluate mathematical expressions. - -```ts file='main.ts' -import { openai } from '@ai-sdk/openai'; -import { generateText, tool, stepCountIs } from 'ai'; -import * as mathjs from 'mathjs'; -import { z } from 'zod'; - -const { text: answer } = await generateText({ - model: openai('gpt-4o-2024-08-06'), - tools: { - calculate: tool({ - description: - 'A tool for evaluating mathematical expressions. ' + - 'Example expressions: ' + - "'1.2 * (2 + 4.5)', '12.7 cm to inch', 'sin(45 deg) ^ 2'.", - inputSchema: z.object({ expression: z.string() }), - execute: async ({ expression }) => mathjs.evaluate(expression), - }), - }, - stopWhen: stepCountIs(10), - system: - 'You are solving math problems. ' + - 'Reason step by step. ' + - 'Use the calculator when necessary. ' + - 'When you give the final answer, ' + - 'provide an explanation for how you arrived at it.', - prompt: - 'A taxi driver earns $9461 per 1-hour of work. ' + - 'If he works 12 hours a day and in 1 hour ' + - 'he uses 12 liters of petrol with a price of $134 for 1 liter. ' + - 'How much money does he earn in one day?', -}); - -console.log(`ANSWER: ${answer}`); -``` - -### Structured Answers - -When building an agent for tasks like mathematical analysis or report generation, it's often useful to have the agent's final output structured in a consistent format that your application can process. You can use an **answer tool** and the `toolChoice: 'required'` setting to force the LLM to answer with a structured output that matches the schema of the answer tool. The answer tool has no `execute` function, so invoking it will terminate the agent. - -```ts highlight="6,16-29,31,45" -import { openai } from '@ai-sdk/openai'; -import { generateText, tool, stepCountIs } from 'ai'; -import 'dotenv/config'; -import { z } from 'zod'; - -const { toolCalls } = await generateText({ - model: openai('gpt-4o-2024-08-06'), - tools: { - calculate: tool({ - description: - 'A tool for evaluating mathematical expressions. Example expressions: ' + - "'1.2 * (2 + 4.5)', '12.7 cm to inch', 'sin(45 deg) ^ 2'.", - inputSchema: z.object({ expression: z.string() }), - execute: async ({ expression }) => mathjs.evaluate(expression), - }), - // answer tool: the LLM will provide a structured answer - answer: tool({ - description: 'A tool for providing the final answer.', - inputSchema: z.object({ - steps: z.array( - z.object({ - calculation: z.string(), - reasoning: z.string(), - }), - ), - answer: z.string(), - }), - // no execute function - invoking it will terminate the agent - }), - }, - toolChoice: 'required', - stopWhen: stepCountIs(10), - system: - 'You are solving math problems. ' + - 'Reason step by step. ' + - 'Use the calculator when necessary. ' + - 'The calculator can only do simple additions, subtractions, multiplications, and divisions. ' + - 'When you give the final answer, provide an explanation for how you got it.', - prompt: - 'A taxi driver earns $9461 per 1-hour work. ' + - 'If he works 12 hours a day and in 1 hour he uses 14-liters petrol with price $134 for 1-liter. ' + - 'How much money does he earn in one day?', -}); - -console.log(`FINAL TOOL CALLS: ${JSON.stringify(toolCalls, null, 2)}`); -``` - - - You can also use the - [`experimental_output`](/docs/ai-sdk-core/generating-structured-data#structured-output-with-generatetext) - setting for `generateText` to generate structured outputs. - - -### Accessing all steps - -Calling `generateText` with `stopWhen` can result in several calls to the LLM (steps). -You can access information from all steps by using the `steps` property of the response. - -```ts highlight="3,9-10" -import { generateText, stepCountIs } from 'ai'; - -const { steps } = await generateText({ - model: openai('gpt-4o'), - stopWhen: stepCountIs(10), - // ... -}); - -// extract all tool calls from the steps: -const allToolCalls = steps.flatMap(step => step.toolCalls); -``` - -### Getting notified on each completed step - -You can use the `onStepFinish` callback to get notified on each completed step. -It is triggered when a step is finished, -i.e. all text deltas, tool calls, and tool results for the step are available. - -```tsx highlight="6-8" -import { generateText, stepCountIs } from 'ai'; - -const result = await generateText({ - model: 'openai/gpt-4.1', - stopWhen: stepCountIs(10), - onStepFinish({ text, toolCalls, toolResults, finishReason, usage }) { - // your own logic, e.g. for saving the chat history or recording usage - }, - // ... -}); -``` diff --git a/content/docs/03-agents/01-overview.mdx b/content/docs/03-agents/01-overview.mdx new file mode 100644 index 000000000000..4e65df2f64d4 --- /dev/null +++ b/content/docs/03-agents/01-overview.mdx @@ -0,0 +1,216 @@ +--- +title: Overview +description: Learn how to build agents with the AI SDK. +--- + +# Agents + +Agents are **large language models (LLMs)** using **tools** in a **loop** to accomplish tasks. + +Each component plays a distinct role: + +- **LLMs** process input (text) and decide what action to take next +- **Tools** extend what the model can do beyond text generation (e.g. reading files, calling APIs, writing to databases) +- **Loop** orchestrates execution through: + - **Context management** - Maintaining conversation history and deciding what the model sees (input) at each step + - **Stopping conditions** - Determining when the loop (task) is complete + +## Building Blocks + +You combine these fundamental components to create increasingly sophisticated systems: + +### Single-Step Generation + +One call to an LLM to get a response. Use this for straightforward tasks like classification or text generation. + +```ts +import { generateText } from 'ai'; + +const result = await generateText({ + model: 'openai/gpt-4o', + prompt: 'Classify this sentiment: "I love this product!"', +}); +``` + +### Tool Usage + +Enhance LLM capabilities through tools that provide access to external systems. Tools can read data to augment context (like fetching files or querying databases) or write data to take actions (like sending emails or updating records). + +```ts +import { generateText, tool } from 'ai'; +import { z } from 'zod'; + +const result = await generateText({ + model: 'openai/gpt-4o', + prompt: 'What is the weather in San Francisco?', + tools: { + weather: tool({ + description: 'Get the weather in a location', + parameters: z.object({ + location: z.string().describe('The location to get the weather for'), + }), + execute: async ({ location }) => ({ + location, + temperature: 72 + Math.floor(Math.random() * 21) - 10, + }), + }), + }, +}); + +console.log(result.toolResults); +``` + +### Multi-Step Tool Usage (Agents) + +For complex problems, an LLM can make multiple tool calls across multiple steps. The model decides the order and number of tool calls based on the task. + +```ts +import { generateText, stepCountIs, tool } from 'ai'; +import { z } from 'zod'; + +const result = await generateText({ + model: 'openai/gpt-4o', + prompt: 'What is the weather in San Francisco in celsius?', + tools: { + weather: tool({ + description: 'Get the weather in a location (in Fahrenheit)', + parameters: z.object({ + location: z.string().describe('The location to get the weather for'), + }), + execute: async ({ location }) => ({ + location, + temperature: 72 + Math.floor(Math.random() * 21) - 10, + }), + }), + convertFahrenheitToCelsius: tool({ + description: 'Convert temperature from Fahrenheit to Celsius', + parameters: z.object({ + temperature: z.number().describe('Temperature in Fahrenheit'), + }), + execute: async ({ temperature }) => { + const celsius = Math.round((temperature - 32) * (5 / 9)); + return { celsius }; + }, + }), + }, + stopWhen: stepCountIs(10), // Stop after maximum 10 steps +}); + +console.log(result.text); // Output: The weather in San Francisco is currently _°C. +``` + +The LLM might: + +1. Call the `weather` tool to get the temperature in Fahrenheit +2. Call the `convertFahrenheitToCelsius` tool to convert it +3. Generate a text response with the converted temperature + +This behavior is flexible - the LLM determines the approach based on its understanding of the task. + +## Implementation Approaches + +The AI SDK provides two approaches to build agents: + +### Agent Class + +Object-oriented abstraction that handles the loop for you. Best when you want to: + +- Reuse agent configurations +- Minimize boilerplate code +- Build consistent agent behaviors + +```ts +import { Experimental_Agent as Agent } from 'ai'; + +const myAgent = new Agent({ + model: 'openai/gpt-4o', + tools: { + // your tools here + }, + stopWhen: stepCountIs(10), // Continue for up to 10 steps +}); + +const result = await myAgent.generate({ + prompt: 'Analyze the latest sales data and create a summary report', +}); + +console.log(result.text); +``` + +[Learn more about the Agent class](/docs/agents/agent-class). + +### Core Functions + +Use `generateText` or `streamText` with tools. Choose between: + +**Built-in Loop** - Let the SDK manage the execution cycle: + +```ts +import { generateText, stepCountIs } from 'ai'; + +const result = await generateText({ + model: 'openai/gpt-4o', + prompt: 'Research machine learning trends and provide key insights', + tools: { + // your tools here + }, + stopWhen: stepCountIs(10), + prepareStep: ({ stepNumber }) => { + // Modify settings between steps + }, + onStepFinish: step => { + // Monitor or save progress + }, +}); +``` + +[Learn more about loop control](/docs/agents/loop-control). + +**Manual Loop** - Full control over execution: + +```ts +import { generateText, ModelMessage } from 'ai'; + +const messages: ModelMessage[] = [{ role: 'user', content: '...' }]; + +let step = 0; +const maxSteps = 10; + +while (step < maxSteps) { + const result = await generateText({ + model: 'openai/gpt-4o', + messages, + tools: { + // your tools here + }, + }); + + messages.push(...result.response.messages); + + if (result.text) { + break; // Stop when model generates text + } + + step++; +} +``` + +## When You Need More Control + +Agents are powerful but non-deterministic. When you need reliable, repeatable outcomes, combine tool calling with standard programming patterns: + +- Conditional statements for explicit branching +- Functions for reusable logic +- Error handling for robustness +- Explicit control flow for predictability + +This approach gives you the benefits of AI while maintaining control over critical paths. + +[Explore workflow patterns](/docs/agents/workflows). + +## Next Steps + +- **[Agent Class](/docs/agents/agent-class)** - Build reusable agents with the object-oriented API +- **[Loop Control](/docs/agents/loop-control)** - Control agent execution with stopWhen and prepareStep +- **[Workflow Patterns](/docs/agents/workflows)** - Build reliable multi-agent systems +- **[Manual Loop Example](/cookbook/node/manual-agent-loop)** - See a complete example of custom loop management diff --git a/content/docs/03-agents/02-workflows.mdx b/content/docs/03-agents/02-workflows.mdx new file mode 100644 index 000000000000..9d8134b54818 --- /dev/null +++ b/content/docs/03-agents/02-workflows.mdx @@ -0,0 +1,365 @@ +--- +title: Workflow Patterns +description: Learn workflow patterns for building reliable agents with the AI SDK. +--- + +# Workflow Patterns + +Combine the building blocks from the [overview](/docs/agents/overview) with these patterns to add structure and reliability to your agents: + +- [Sequential Processing](#sequential-processing-chains) - Steps executed in order +- [Parallel Processing](#parallel-processing) - Independent tasks run simultaneously +- [Evaluation/Feedback Loops](#evaluator-optimizer) - Results checked and improved iteratively +- [Orchestration](#orchestrator-worker) - Coordinating multiple components +- [Routing](#routing) - Directing work based on context + +## Choose Your Approach + +Consider these key factors: + +- **Flexibility vs Control** - How much freedom does the LLM need vs how tightly you must constrain its actions? +- **Error Tolerance** - What are the consequences of mistakes in your use case? +- **Cost Considerations** - More complex systems typically mean more LLM calls and higher costs +- **Maintenance** - Simpler architectures are easier to debug and modify + +**Start with the simplest approach that meets your needs**. Add complexity only when required by: + +1. Breaking down tasks into clear steps +2. Adding tools for specific capabilities +3. Implementing feedback loops for quality control +4. Introducing multiple agents for complex workflows + +Let's look at examples of these patterns in action. + +## Patterns with Examples + +These patterns, adapted from [Anthropic's guide on building effective agents](https://www.anthropic.com/research/building-effective-agents), serve as building blocks you can combine to create comprehensive workflows. Each pattern addresses specific aspects of task execution. Combine them thoughtfully to build reliable solutions for complex problems. + +## Sequential Processing (Chains) + +The simplest workflow pattern executes steps in a predefined order. Each step's output becomes input for the next step, creating a clear chain of operations. Use this pattern for tasks with well-defined sequences, like content generation pipelines or data transformation processes. + +```ts +import { generateText, generateObject } from 'ai'; +import { z } from 'zod'; + +async function generateMarketingCopy(input: string) { + const model = 'openai/gpt-4o'; + + // First step: Generate marketing copy + const { text: copy } = await generateText({ + model, + prompt: `Write persuasive marketing copy for: ${input}. Focus on benefits and emotional appeal.`, + }); + + // Perform quality check on copy + const { object: qualityMetrics } = await generateObject({ + model, + schema: z.object({ + hasCallToAction: z.boolean(), + emotionalAppeal: z.number().min(1).max(10), + clarity: z.number().min(1).max(10), + }), + prompt: `Evaluate this marketing copy for: + 1. Presence of call to action (true/false) + 2. Emotional appeal (1-10) + 3. Clarity (1-10) + + Copy to evaluate: ${copy}`, + }); + + // If quality check fails, regenerate with more specific instructions + if ( + !qualityMetrics.hasCallToAction || + qualityMetrics.emotionalAppeal < 7 || + qualityMetrics.clarity < 7 + ) { + const { text: improvedCopy } = await generateText({ + model, + prompt: `Rewrite this marketing copy with: + ${!qualityMetrics.hasCallToAction ? '- A clear call to action' : ''} + ${qualityMetrics.emotionalAppeal < 7 ? '- Stronger emotional appeal' : ''} + ${qualityMetrics.clarity < 7 ? '- Improved clarity and directness' : ''} + + Original copy: ${copy}`, + }); + return { copy: improvedCopy, qualityMetrics }; + } + + return { copy, qualityMetrics }; +} +``` + +## Routing + +This pattern lets the model decide which path to take through a workflow based on context and intermediate results. The model acts as an intelligent router, directing the flow of execution between different branches of your workflow. Use this when handling varied inputs that require different processing approaches. In the example below, the first LLM call's results determine the second call's model size and system prompt. + +```ts +import { generateObject, generateText } from 'ai'; +import { z } from 'zod'; + +async function handleCustomerQuery(query: string) { + const model = 'openai/gpt-4o'; + + // First step: Classify the query type + const { object: classification } = await generateObject({ + model, + schema: z.object({ + reasoning: z.string(), + type: z.enum(['general', 'refund', 'technical']), + complexity: z.enum(['simple', 'complex']), + }), + prompt: `Classify this customer query: + ${query} + + Determine: + 1. Query type (general, refund, or technical) + 2. Complexity (simple or complex) + 3. Brief reasoning for classification`, + }); + + // Route based on classification + // Set model and system prompt based on query type and complexity + const { text: response } = await generateText({ + model: + classification.complexity === 'simple' + ? 'openai/gpt-4o-mini' + : 'openai/o4-mini', + system: { + general: + 'You are an expert customer service agent handling general inquiries.', + refund: + 'You are a customer service agent specializing in refund requests. Follow company policy and collect necessary information.', + technical: + 'You are a technical support specialist with deep product knowledge. Focus on clear step-by-step troubleshooting.', + }[classification.type], + prompt: query, + }); + + return { response, classification }; +} +``` + +## Parallel Processing + +Break down tasks into independent subtasks that execute simultaneously. This pattern uses parallel execution to improve efficiency while maintaining the benefits of structured workflows. For example, analyze multiple documents or process different aspects of a single input concurrently (like code review). + +```ts +import { generateText, generateObject } from 'ai'; +import { z } from 'zod'; + +// Example: Parallel code review with multiple specialized reviewers +async function parallelCodeReview(code: string) { + const model = 'openai/gpt-4o'; + + // Run parallel reviews + const [securityReview, performanceReview, maintainabilityReview] = + await Promise.all([ + generateObject({ + model, + system: + 'You are an expert in code security. Focus on identifying security vulnerabilities, injection risks, and authentication issues.', + schema: z.object({ + vulnerabilities: z.array(z.string()), + riskLevel: z.enum(['low', 'medium', 'high']), + suggestions: z.array(z.string()), + }), + prompt: `Review this code: + ${code}`, + }), + + generateObject({ + model, + system: + 'You are an expert in code performance. Focus on identifying performance bottlenecks, memory leaks, and optimization opportunities.', + schema: z.object({ + issues: z.array(z.string()), + impact: z.enum(['low', 'medium', 'high']), + optimizations: z.array(z.string()), + }), + prompt: `Review this code: + ${code}`, + }), + + generateObject({ + model, + system: + 'You are an expert in code quality. Focus on code structure, readability, and adherence to best practices.', + schema: z.object({ + concerns: z.array(z.string()), + qualityScore: z.number().min(1).max(10), + recommendations: z.array(z.string()), + }), + prompt: `Review this code: + ${code}`, + }), + ]); + + const reviews = [ + { ...securityReview.object, type: 'security' }, + { ...performanceReview.object, type: 'performance' }, + { ...maintainabilityReview.object, type: 'maintainability' }, + ]; + + // Aggregate results using another model instance + const { text: summary } = await generateText({ + model, + system: 'You are a technical lead summarizing multiple code reviews.', + prompt: `Synthesize these code review results into a concise summary with key actions: + ${JSON.stringify(reviews, null, 2)}`, + }); + + return { reviews, summary }; +} +``` + +## Orchestrator-Worker + +A primary model (orchestrator) coordinates the execution of specialized workers. Each worker optimizes for a specific subtask, while the orchestrator maintains overall context and ensures coherent results. This pattern excels at complex tasks requiring different types of expertise or processing. + +```ts +import { generateObject } from 'ai'; +import { z } from 'zod'; + +async function implementFeature(featureRequest: string) { + // Orchestrator: Plan the implementation + const { object: implementationPlan } = await generateObject({ + model: 'openai/o4-mini', + schema: z.object({ + files: z.array( + z.object({ + purpose: z.string(), + filePath: z.string(), + changeType: z.enum(['create', 'modify', 'delete']), + }), + ), + estimatedComplexity: z.enum(['low', 'medium', 'high']), + }), + system: + 'You are a senior software architect planning feature implementations.', + prompt: `Analyze this feature request and create an implementation plan: + ${featureRequest}`, + }); + + // Workers: Execute the planned changes + const fileChanges = await Promise.all( + implementationPlan.files.map(async file => { + // Each worker is specialized for the type of change + const workerSystemPrompt = { + create: + 'You are an expert at implementing new files following best practices and project patterns.', + modify: + 'You are an expert at modifying existing code while maintaining consistency and avoiding regressions.', + delete: + 'You are an expert at safely removing code while ensuring no breaking changes.', + }[file.changeType]; + + const { object: change } = await generateObject({ + model: 'openai/gpt-4o', + schema: z.object({ + explanation: z.string(), + code: z.string(), + }), + system: workerSystemPrompt, + prompt: `Implement the changes for ${file.filePath} to support: + ${file.purpose} + + Consider the overall feature context: + ${featureRequest}`, + }); + + return { + file, + implementation: change, + }; + }), + ); + + return { + plan: implementationPlan, + changes: fileChanges, + }; +} +``` + +## Evaluator-Optimizer + +Add quality control to workflows with dedicated evaluation steps that assess intermediate results. Based on the evaluation, the workflow proceeds, retries with adjusted parameters, or takes corrective action. This creates robust workflows capable of self-improvement and error recovery. + +```ts +import { generateText, generateObject } from 'ai'; +import { z } from 'zod'; + +async function translateWithFeedback(text: string, targetLanguage: string) { + let currentTranslation = ''; + let iterations = 0; + const MAX_ITERATIONS = 3; + + // Initial translation + const { text: translation } = await generateText({ + model: 'openai/gpt-4o-mini', // use small model for first attempt + system: 'You are an expert literary translator.', + prompt: `Translate this text to ${targetLanguage}, preserving tone and cultural nuances: + ${text}`, + }); + + currentTranslation = translation; + + // Evaluation-optimization loop + while (iterations < MAX_ITERATIONS) { + // Evaluate current translation + const { object: evaluation } = await generateObject({ + model: 'openai/gpt-4o', // use a larger model to evaluate + schema: z.object({ + qualityScore: z.number().min(1).max(10), + preservesTone: z.boolean(), + preservesNuance: z.boolean(), + culturallyAccurate: z.boolean(), + specificIssues: z.array(z.string()), + improvementSuggestions: z.array(z.string()), + }), + system: 'You are an expert in evaluating literary translations.', + prompt: `Evaluate this translation: + + Original: ${text} + Translation: ${currentTranslation} + + Consider: + 1. Overall quality + 2. Preservation of tone + 3. Preservation of nuance + 4. Cultural accuracy`, + }); + + // Check if quality meets threshold + if ( + evaluation.qualityScore >= 8 && + evaluation.preservesTone && + evaluation.preservesNuance && + evaluation.culturallyAccurate + ) { + break; + } + + // Generate improved translation based on feedback + const { text: improvedTranslation } = await generateText({ + model: 'openai/gpt-4o', // use a larger model + system: 'You are an expert literary translator.', + prompt: `Improve this translation based on the following feedback: + ${evaluation.specificIssues.join('\n')} + ${evaluation.improvementSuggestions.join('\n')} + + Original: ${text} + Current Translation: ${currentTranslation}`, + }); + + currentTranslation = improvedTranslation; + iterations++; + } + + return { + finalTranslation: currentTranslation, + iterationsRequired: iterations, + }; +} +``` diff --git a/content/docs/03-agents/03-agent-class.mdx b/content/docs/03-agents/03-agent-class.mdx new file mode 100644 index 000000000000..cbe67bd66a3a --- /dev/null +++ b/content/docs/03-agents/03-agent-class.mdx @@ -0,0 +1,359 @@ +--- +title: Agent Class +description: Learn how to build agents with the Agent class. +--- + +# Agent Class + +The Agent class provides a structured way to encapsulate LLM configuration, tools, and behavior into reusable components. It handles the agent loop for you, allowing the LLM to call tools multiple times in sequence to accomplish complex tasks. Define agents once and use them across your application. + +## Why Use the Agent Class? + +When building AI applications, you often need to: + +- **Reuse configurations** - Same model settings, tools, and prompts across different parts of your application +- **Maintain consistency** - Ensure the same behavior and capabilities throughout your codebase +- **Simplify API routes** - Reduce boilerplate in your endpoints +- **Type safety** - Get full TypeScript support for your agent's tools and outputs + +The Agent class provides a single place to define your agent's behavior. + +## Creating an Agent + +Define an agent by instantiating the Agent class with your desired configuration: + +```ts +import { Experimental_Agent as Agent } from 'ai'; + +const myAgent = new Agent({ + model: 'openai/gpt-4o', + system: 'You are a helpful assistant.', + tools: { + // Your tools here + }, +}); +``` + +## Configuration Options + +The Agent class accepts all the same settings as `generateText` and `streamText`. Configure: + +### Model and System Prompt + +```ts +import { Experimental_Agent as Agent } from 'ai'; + +const agent = new Agent({ + model: 'openai/gpt-4o', + system: 'You are an expert software engineer.', +}); +``` + +### Tools + +Provide tools that the agent can use to accomplish tasks: + +```ts +import { Experimental_Agent as Agent, tool } from 'ai'; +import { z } from 'zod'; + +const codeAgent = new Agent({ + model: 'openai/gpt-4o', + tools: { + runCode: tool({ + description: 'Execute Python code', + inputSchema: z.object({ + code: z.string(), + }), + execute: async ({ code }) => { + // Execute code and return result + return { output: 'Code executed successfully' }; + }, + }), + }, +}); +``` + +### Loop Control + +By default, agents run for only one step. In each step, the model either generates text or calls a tool. If it generates text, the agent completes. If it calls a tool, the AI SDK executes that tool. + +To let agents call multiple tools in sequence, configure `stopWhen` to allow more steps. After each tool execution, the agent triggers a new generation where the model can call another tool or generate text: + +```ts +import { Experimental_Agent as Agent, stepCountIs } from 'ai'; + +const agent = new Agent({ + model: 'openai/gpt-4o', + stopWhen: stepCountIs(10), // Allow up to 10 steps +}); +``` + +Each step represents one generation (which results in either text or a tool call). The loop continues until: + +- The model generates text instead of calling a tool, or +- A stop condition is met + +You can combine multiple conditions: + +```ts +import { Experimental_Agent as Agent, stepCountIs } from 'ai'; + +const agent = new Agent({ + model: 'openai/gpt-4o', + stopWhen: [ + stepCountIs(10), // Maximum 10 steps + yourCustomCondition(), // Custom logic for when to stop + ], +}); +``` + +Learn more about [loop control and stop conditions](/docs/agents/loop-control). + +### Tool Choice + +Control how the agent uses tools: + +```ts +import { Experimental_Agent as Agent } from 'ai'; + +const agent = new Agent({ + model: 'openai/gpt-4o', + tools: { + // your tools here + }, + toolChoice: 'required', // Force tool use + // or toolChoice: 'none' to disable tools + // or toolChoice: 'auto' (default) to let the model decide +}); +``` + +You can also force the use of a specific tool: + +```ts +import { Experimental_Agent as Agent } from 'ai'; + +const agent = new Agent({ + model: 'openai/gpt-4o', + tools: { + weather: weatherTool, + cityAttractions: attractionsTool, + }, + toolChoice: { + type: 'tool', + toolName: 'weather', // Force the weather tool to be used + }, +}); +``` + +### Structured Output + +Define structured output schemas: + +```ts +import { Experimental_Agent as Agent, Output, stepCountIs } from 'ai'; +import { z } from 'zod'; + +const analysisAgent = new Agent({ + model: 'openai/gpt-4o', + experimental_output: Output.object({ + schema: z.object({ + sentiment: z.enum(['positive', 'neutral', 'negative']), + summary: z.string(), + keyPoints: z.array(z.string()), + }), + }), + stopWhen: stepCountIs(10), +}); + +const { experimental_output: output } = await analysisAgent.generate({ + prompt: 'Analyze customer feedback from the last quarter', +}); +``` + +## Define Agent Behavior with System Prompts + +System prompts define your agent's behavior, personality, and constraints. They set the context for all interactions and guide how the agent responds to user queries and uses tools. + +### Basic System Prompts + +Set the agent's role and expertise: + +```ts +const agent = new Agent({ + model: 'openai/gpt-4o', + system: + 'You are an expert data analyst. You provide clear insights from complex data.', +}); +``` + +### Detailed Behavioral Instructions + +Provide specific guidelines for agent behavior: + +```ts +const codeReviewAgent = new Agent({ + model: 'openai/gpt-4o', + system: `You are a senior software engineer conducting code reviews. + + Your approach: + - Focus on security vulnerabilities first + - Identify performance bottlenecks + - Suggest improvements for readability and maintainability + - Be constructive and educational in your feedback + - Always explain why something is an issue and how to fix it`, +}); +``` + +### Constrain Agent Behavior + +Set boundaries and ensure consistent behavior: + +```ts +const customerSupportAgent = new Agent({ + model: 'openai/gpt-4o', + system: `You are a customer support specialist for an e-commerce platform. + + Rules: + - Never make promises about refunds without checking the policy + - Always be empathetic and professional + - If you don't know something, say so and offer to escalate + - Keep responses concise and actionable + - Never share internal company information`, + tools: { + checkOrderStatus, + lookupPolicy, + createTicket, + }, +}); +``` + +### Tool Usage Instructions + +Guide how the agent should use available tools: + +```ts +const researchAgent = new Agent({ + model: 'openai/gpt-4o', + system: `You are a research assistant with access to search and document tools. + + When researching: + 1. Always start with a broad search to understand the topic + 2. Use document analysis for detailed information + 3. Cross-reference multiple sources before drawing conclusions + 4. Cite your sources when presenting information + 5. If information conflicts, present both viewpoints`, + tools: { + webSearch, + analyzeDocument, + extractQuotes, + }, +}); +``` + +### Format and Style Instructions + +Control the output format and communication style: + +```ts +const technicalWriterAgent = new Agent({ + model: 'openai/gpt-4o', + system: `You are a technical documentation writer. + + Writing style: + - Use clear, simple language + - Avoid jargon unless necessary + - Structure information with headers and bullet points + - Include code examples where relevant + - Write in second person ("you" instead of "the user") + + Always format responses in Markdown.`, +}); +``` + +## Using an Agent + +Once defined, you can use your agent in three ways: + +### Generate Text + +Use `generate()` for one-time text generation: + +```ts +const result = await myAgent.generate({ + prompt: 'What is the weather like?', +}); + +console.log(result.text); +``` + +### Stream Text + +Use `stream()` for streaming responses: + +```ts +const stream = myAgent.stream({ + prompt: 'Tell me a story', +}); + +for await (const chunk of stream.textStream) { + console.log(chunk); +} +``` + +### Respond to UI Messages + +Use `respond()` to create API responses for client applications: + +```ts +// In your API route (e.g., app/api/chat/route.ts) +import { validateUIMessages } from 'ai'; + +export async function POST(request: Request) { + const { messages } = await request.json(); + + return myAgent.respond({ + messages: await validateUIMessages({ messages }), + }); +} +``` + +## End-to-end Type Safety + +You can infer types for your Agent's `UIMessage`s: + +```ts +import { + Experimental_Agent as Agent, + Experimental_InferAgentUIMessage as InferAgentUIMessage, +} from 'ai'; + +const myAgent = new Agent({ + // ... configuration +}); + +// Infer the UIMessage type for UI components or persistence +export type MyAgentUIMessage = InferAgentUIMessage; +``` + +Use this type in your client components with `useChat`: + +```tsx filename="components/chat.tsx" +'use client'; + +import { useChat } from '@ai-sdk/react'; +import type { MyAgentUIMessage } from '@/agent/my-agent'; + +export function Chat() { + const { messages } = useChat(); + // Full type safety for your messages and tools +} +``` + +## Next Steps + +Now that you understand the Agent class, you can: + +- Explore [tool patterns](/docs/agents/tools) to add capabilities to your agents +- Learn about [workflow patterns](/docs/agents/workflows) for complex multi-agent systems +- Understand [building agentic systems](/docs/agents/building-agentic-systems) for architectural guidance diff --git a/content/docs/03-agents/04-loop-control.mdx b/content/docs/03-agents/04-loop-control.mdx new file mode 100644 index 000000000000..b1fc99eb74e5 --- /dev/null +++ b/content/docs/03-agents/04-loop-control.mdx @@ -0,0 +1,271 @@ +--- +title: Loop Control +description: Control agent execution with built-in loop management using stopWhen and prepareStep +--- + +# Loop Control + +When building agents with the AI SDK, you can control both the execution flow and the settings at each step of the agent loop. The AI SDK provides built-in loop control through two parameters: `stopWhen` for defining stopping conditions and `prepareStep` for modifying settings (model, tools, messages, and more) between steps. + +Both parameters work with: + +- `generateText` and `streamText` functions from AI SDK Core +- The `Agent` class for object-oriented agent implementations + +## Stop Conditions + +The `stopWhen` parameter controls when to stop the generation when there are tool results in the last step. By default, the stopping condition is `stepCountIs(1)`, which allows only a single step. + +When you provide `stopWhen`, the AI SDK continues generating responses after tool calls until a stopping condition is met. When the condition is an array, the generation stops when any of the conditions are met. + +### Use Built-in Conditions + +The AI SDK provides several built-in stopping conditions: + +```ts +import { generateText, stepCountIs } from 'ai'; + +const result = await generateText({ + model: 'openai/gpt-4o', + tools: { + // your tools + }, + stopWhen: stepCountIs(10), // Stop after 10 steps maximum + prompt: 'Analyze this dataset and create a summary report', +}); +``` + +### Combine Multiple Conditions + +Combine multiple stopping conditions. The loop stops when it meets any condition: + +```ts +import { generateText, stepCountIs, hasToolCall } from 'ai'; + +const result = await generateText({ + model: 'openai/gpt-4o', + tools: { + // your tools + }, + stopWhen: [ + stepCountIs(10), // Maximum 10 steps + hasToolCall('someTool'), // Stop after calling 'someTool' + ], + prompt: 'Research and analyze the topic', +}); +``` + +### Create Custom Conditions + +Build custom stopping conditions for specific requirements: + +```ts +import { generateText, StopCondition, ToolSet } from 'ai'; + +const tools = { + // your tools +} satisfies ToolSet; + +const hasAnswer: StopCondition = ({ steps }) => { + // Stop when the model generates text containing "ANSWER:" + return steps.some(step => step.text?.includes('ANSWER:')) ?? false; +}; + +const result = await generateText({ + model: 'openai/gpt-4o', + tools, + stopWhen: hasAnswer, + prompt: 'Find the answer and respond with "ANSWER: [your answer]"', +}); +``` + +Custom conditions receive step information across all steps: + +```ts +const budgetExceeded: StopCondition = ({ steps }) => { + const totalUsage = steps.reduce( + (acc, step) => ({ + inputTokens: acc.inputTokens + (step.usage?.inputTokens ?? 0), + outputTokens: acc.outputTokens + (step.usage?.outputTokens ?? 0), + }), + { inputTokens: 0, outputTokens: 0 }, + ); + + const costEstimate = + (totalUsage.inputTokens * 0.01 + totalUsage.outputTokens * 0.03) / 1000; + return costEstimate > 0.5; // Stop if cost exceeds $0.50 +}; +``` + +## Prepare Step + +The `prepareStep` callback runs before each step in the loop and defaults to the initial settings if you don't return any changes. Use it to modify settings, manage context, or implement dynamic behavior based on execution history. + +### Dynamic Model Selection + +Switch models based on step requirements: + +```ts +import { generateText } from 'ai'; + +const result = await generateText({ + model: 'openai/gpt-4o-mini', // Default model + tools: { + // your tools + }, + prepareStep: async ({ stepNumber, messages }) => { + // Use a stronger model for complex reasoning after initial steps + if (stepNumber > 2 && messages.length > 10) { + return { + model: 'openai/gpt-4o', + }; + } + // Continue with default settings + return {}; + }, +}); +``` + +### Context Management + +Manage growing conversation history in long-running loops: + +```ts +const result = await generateText({ + model: 'openai/gpt-4o', + tools: { + // your tools + }, + prepareStep: async ({ messages }) => { + // Keep only recent messages to stay within context limits + if (messages.length > 20) { + return { + messages: [ + messages[0], // Keep system message + ...messages.slice(-10), // Keep last 10 messages + ], + }; + } + return {}; + }, +}); +``` + +### Tool Selection + +Control which tools are available at each step: + +```ts +const result = await generateText({ + model: 'openai/gpt-4o', + tools: { + search: searchTool, + analyze: analyzeTool, + summarize: summarizeTool, + }, + prepareStep: async ({ stepNumber, steps }) => { + // Search phase (steps 0-2) + if (stepNumber <= 2) { + return { + activeTools: ['search'], + toolChoice: 'required', + }; + } + + // Analysis phase (steps 3-5) + if (stepNumber <= 5) { + return { + activeTools: ['analyze'], + }; + } + + // Summary phase (step 6+) + return { + activeTools: ['summarize'], + toolChoice: 'required', + }; + }, +}); +``` + +You can also force a specific tool to be used: + +```ts +prepareStep: async ({ stepNumber }) => { + if (stepNumber === 0) { + // Force the search tool to be used first + return { + toolChoice: { type: 'tool', toolName: 'search' }, + }; + } + + if (stepNumber === 5) { + // Force the summarize tool after analysis + return { + toolChoice: { type: 'tool', toolName: 'summarize' }, + }; + } + + return {}; +}; +``` + +### Message Modification + +Transform messages before sending them to the model: + +```ts +const result = await generateText({ + model: 'openai/gpt-4o', + messages, + tools: { + // your tools + }, + prepareStep: async ({ messages, stepNumber }) => { + // Summarize tool results to reduce token usage + const processedMessages = messages.map(msg => { + if (msg.role === 'tool' && msg.content.length > 1000) { + return { + ...msg, + content: summarizeToolResult(msg.content), + }; + } + return msg; + }); + + return { messages: processedMessages }; + }, +}); +``` + +## Access Step Information + +Both `stopWhen` and `prepareStep` receive detailed information about the current execution: + +```ts +prepareStep: async ({ + model, // Current model configuration + stepNumber, // Current step number (0-indexed) + steps, // All previous steps with their results + messages, // Messages to be sent to the model +}) => { + // Access previous tool calls and results + const previousToolCalls = steps.flatMap(step => step.toolCalls); + const previousResults = steps.flatMap(step => step.toolResults); + + // Make decisions based on execution history + if (previousToolCalls.some(call => call.toolName === 'dataAnalysis')) { + return { + toolChoice: { type: 'tool', toolName: 'reportGenerator' }, + }; + } + + return {}; +}, +``` + +## Manual Loop Control + +For scenarios requiring complete control over the agent loop, implement your own loop management instead of using `stopWhen` and `prepareStep`. This approach provides maximum flexibility for complex workflows. + +[Learn more about manual agent loops in the cookbook](/cookbook/node/manual-agent-loop). diff --git a/content/docs/03-agents/index.mdx b/content/docs/03-agents/index.mdx new file mode 100644 index 000000000000..9f33625efc2b --- /dev/null +++ b/content/docs/03-agents/index.mdx @@ -0,0 +1,34 @@ +--- +title: Agents +description: An overview of building agents with the AI SDK. +--- + +# Agents + +The following section show you how to build agents with the AI SDK - systems where large language models (LLMs) use tools in a loop to accomplish tasks. + + diff --git a/content/docs/03-ai-sdk-core/10-generating-structured-data.mdx b/content/docs/03-ai-sdk-core/10-generating-structured-data.mdx index f83761ef7025..1a3a22fa428b 100644 --- a/content/docs/03-ai-sdk-core/10-generating-structured-data.mdx +++ b/content/docs/03-ai-sdk-core/10-generating-structured-data.mdx @@ -214,7 +214,7 @@ You can access the reasoning used by the language model to generate the object v ```ts import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; import { generateObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const result = await generateObject({ model: openai('gpt-5'), diff --git a/content/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx b/content/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx index 872f6403f8b1..0c7374576fd0 100644 --- a/content/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +++ b/content/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx @@ -827,187 +827,24 @@ export const weatherTool = tool({ ## MCP Tools - - The MCP tools feature is experimental and may change in the future. - - -The AI SDK supports connecting to [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers to access their tools. -This enables your AI applications to discover and use tools across various services through a standardized interface. - -### Initializing an MCP Client - -Create an MCP client using either: - -- `SSE` (Server-Sent Events): Uses HTTP-based real-time communication, better suited for remote servers that need to send data over the network -- `stdio`: Uses standard input and output streams for communication, ideal for local tool servers running on the same machine (like CLI tools or local services) -- Custom transport: Bring your own transport by implementing the `MCPTransport` interface, ideal when implementing transports from MCP's official Typescript SDK (e.g. `StreamableHTTPClientTransport`) - -#### SSE Transport - -The SSE can be configured using a simple object with a `type` and `url` property: - -```typescript -import { experimental_createMCPClient as createMCPClient } from 'ai'; - -const mcpClient = await createMCPClient({ - transport: { - type: 'sse', - url: 'https://my-server.com/sse', - - // optional: configure HTTP headers, e.g. for authentication - headers: { - Authorization: 'Bearer my-api-key', - }, - }, -}); -``` - -#### Stdio Transport - -The Stdio transport requires importing the `StdioMCPTransport` class from the `ai/mcp-stdio` package: - -```typescript -import { experimental_createMCPClient as createMCPClient } from 'ai'; -import { Experimental_StdioMCPTransport as StdioMCPTransport } from 'ai/mcp-stdio'; - -const mcpClient = await createMCPClient({ - transport: new StdioMCPTransport({ - command: 'node', - args: ['src/stdio/dist/server.js'], - }), -}); -``` - -#### Custom Transport - -You can also bring your own transport, as long as it implements the `MCPTransport` interface. Below is an example of using the new `StreamableHTTPClientTransport` from MCP's official Typescript SDK: - -```typescript -import { - MCPTransport, - experimental_createMCPClient as createMCPClient, -} from 'ai'; -import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp'; - -const url = new URL('http://localhost:3000/mcp'); -const mcpClient = await createMCPClient({ - transport: new StreamableHTTPClientTransport(url, { - sessionId: 'session_123', - }), -}); -``` - - - The client returned by the `experimental_createMCPClient` function is a - lightweight client intended for use in tool conversion. It currently does not - support all features of the full MCP client, such as: authorization, session - management, resumable streams, and receiving notifications. - - -#### Closing the MCP Client - -After initialization, you should close the MCP client based on your usage pattern: - -- For short-lived usage (e.g., single requests), close the client when the response is finished -- For long-running clients (e.g., command line apps), keep the client open but ensure it's closed when the application terminates - -When streaming responses, you can close the client when the LLM response has finished. For example, when using `streamText`, you should use the `onFinish` callback: - -```typescript -const mcpClient = await experimental_createMCPClient({ - // ... -}); - -const tools = await mcpClient.tools(); - -const result = await streamText({ - model: openai('gpt-4.1'), - tools, - prompt: 'What is the weather in Brooklyn, New York?', - onFinish: async () => { - await mcpClient.close(); - }, -}); -``` - -When generating responses without streaming, you can use try/finally or cleanup functions in your framework: - -```typescript -let mcpClient: MCPClient | undefined; - -try { - mcpClient = await experimental_createMCPClient({ - // ... - }); -} finally { - await mcpClient?.close(); -} -``` - -### Using MCP Tools - -The client's `tools` method acts as an adapter between MCP tools and AI SDK tools. It supports two approaches for working with tool schemas: - -#### Schema Discovery - -The simplest approach where all tools offered by the server are listed, and input parameter types are inferred based the schemas provided by the server: - -```typescript -const tools = await mcpClient.tools(); -``` - -**Pros:** - -- Simpler to implement -- Automatically stays in sync with server changes - -**Cons:** - -- No TypeScript type safety during development -- No IDE autocompletion for tool parameters -- Errors only surface at runtime -- Loads all tools from the server - -#### Schema Definition - -You can also define the tools and their input schemas explicitly in your client code: - -```typescript -import { z } from 'zod'; - -const tools = await mcpClient.tools({ - schemas: { - 'get-data': { - inputSchema: z.object({ - query: z.string().describe('The data query'), - format: z.enum(['json', 'text']).optional(), - }), - }, - // For tools with zero inputs, you should use an empty object: - 'tool-with-no-args': { - inputSchema: z.object({}), - }, - }, -}); -``` - -**Pros:** - -- Control over which tools are loaded -- Full TypeScript type safety -- Better IDE support with autocompletion -- Catch parameter mismatches during development +The AI SDK supports connecting to Model Context Protocol (MCP) servers to access their tools. +MCP enables your AI applications to discover and use tools across various services through a standardized interface. -**Cons:** +For detailed information about MCP tools, including initialization, transport options, and usage patterns, see the [MCP Tools documentation](/docs/ai-sdk-core/mcp-tools). -- Need to manually keep schemas in sync with server -- More code to maintain +### AI SDK Tools vs MCP Tools -When you define `schemas`, the client will only pull the explicitly defined tools, even if the server offers additional tools. This can be beneficial for: +In most cases, you should define your own AI SDK tools for production applications. They provide full control, type safety, and optimal performance. MCP tools are best suited for rapid development iteration and scenarios where users bring their own tools. -- Keeping your application focused on the tools it needs -- Reducing unnecessary tool loading -- Making your tool dependencies explicit +| Aspect | AI SDK Tools | MCP Tools | +| ---------------------- | --------------------------------------------------------- | ----------------------------------------------------- | +| **Type Safety** | Full static typing end-to-end | Dynamic discovery at runtime | +| **Execution** | Same process as your request (low latency) | Separate server (network overhead) | +| **Prompt Control** | Full control over descriptions and schemas | Controlled by MCP server owner | +| **Schema Control** | You define and optimize for your model | Controlled by MCP server owner | +| **Version Management** | Full visibility over updates | Can update independently (version skew risk) | +| **Authentication** | Same process, no additional auth required | Separate server introduces additional auth complexity | +| **Best For** | Production applications requiring control and performance | Development iteration, user-provided tools | ## Examples diff --git a/content/docs/03-ai-sdk-core/16-mcp-tools.mdx b/content/docs/03-ai-sdk-core/16-mcp-tools.mdx new file mode 100644 index 000000000000..05d40b9a7910 --- /dev/null +++ b/content/docs/03-ai-sdk-core/16-mcp-tools.mdx @@ -0,0 +1,184 @@ +--- +title: Model Context Protocol (MCP) Tools +description: Learn how to connect to Model Context Protocol (MCP) servers and use their tools with AI SDK Core. +--- + +# Model Context Protocol (MCP) Tools + + + The MCP tools feature is experimental and may change in the future. + + +The AI SDK supports connecting to [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers to access their tools. +This enables your AI applications to discover and use tools across various services through a standardized interface. + +## Initializing an MCP Client + +We recommend using HTTP transport (like `StreamableHTTPClientTransport`) for production deployments. The stdio transport should only be used for connecting to local servers as it cannot be deployed to production environments. + +Create an MCP client using one of the following transport options: + +- **HTTP transport (Recommended)**: Use transports from MCP's official TypeScript SDK like `StreamableHTTPClientTransport` for production deployments +- SSE (Server-Sent Events): An alternative HTTP-based transport +- `stdio`: For local development only. Uses standard input/output streams for local MCP servers + +### HTTP Transport (Recommended) + +For production deployments, we recommend using HTTP transports like `StreamableHTTPClientTransport` from MCP's official TypeScript SDK: + +```typescript +import { experimental_createMCPClient as createMCPClient } from 'ai'; +import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; + +const url = new URL('https://your-server.com/mcp'); +const mcpClient = await createMCPClient({ + transport: new StreamableHTTPClientTransport(url, { + sessionId: 'session_123', + }), +}); +``` + +### SSE Transport + +SSE provides an alternative HTTP-based transport option. Configure it with a `type` and `url` property: + +```typescript +import { experimental_createMCPClient as createMCPClient } from 'ai'; + +const mcpClient = await createMCPClient({ + transport: { + type: 'sse', + url: 'https://my-server.com/sse', + + // optional: configure HTTP headers, e.g. for authentication + headers: { + Authorization: 'Bearer my-api-key', + }, + }, +}); +``` + +### Stdio Transport (Local Servers) + + + The stdio transport should only be used for local servers. + + +The Stdio transport can be imported from either the MCP SDK or the AI SDK: + +```typescript +import { experimental_createMCPClient as createMCPClient } from 'ai'; +import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; +// Or use the AI SDK's stdio transport: +// import { Experimental_StdioMCPTransport as StdioClientTransport } from 'ai/mcp-stdio'; + +const mcpClient = await createMCPClient({ + transport: new StdioClientTransport({ + command: 'node', + args: ['src/stdio/dist/server.js'], + }), +}); +``` + +### Custom Transport + +You can also bring your own transport by implementing the `MCPTransport` interface for specific requirements not covered by the standard transports. + + + The client returned by the `experimental_createMCPClient` function is a + lightweight client intended for use in tool conversion. It currently does not + support all features of the full MCP client, such as: authorization, session + management, resumable streams, and receiving notifications. + + +### Closing the MCP Client + +After initialization, you should close the MCP client based on your usage pattern: + +- For short-lived usage (e.g., single requests), close the client when the response is finished +- For long-running clients (e.g., command line apps), keep the client open but ensure it's closed when the application terminates + +When streaming responses, you can close the client when the LLM response has finished. For example, when using `streamText`, you should use the `onFinish` callback: + +```typescript +const mcpClient = await experimental_createMCPClient({ + // ... +}); + +const tools = await mcpClient.tools(); + +const result = await streamText({ + model: 'openai/gpt-4.1', + tools, + prompt: 'What is the weather in Brooklyn, New York?', + onFinish: async () => { + await mcpClient.close(); + }, +}); +``` + +When generating responses without streaming, you can use try/finally or cleanup functions in your framework: + +```typescript +let mcpClient: MCPClient | undefined; + +try { + mcpClient = await experimental_createMCPClient({ + // ... + }); +} finally { + await mcpClient?.close(); +} +``` + +## Using MCP Tools + +The client's `tools` method acts as an adapter between MCP tools and AI SDK tools. It supports two approaches for working with tool schemas: + +### Schema Discovery + +With schema discovery, all tools offered by the server are automatically listed, and input parameter types are inferred based on the schemas provided by the server: + +```typescript +const tools = await mcpClient.tools(); +``` + +This approach is simpler to implement and automatically stays in sync with server changes. However, you won't have TypeScript type safety during development, and all tools from the server will be loaded + +### Schema Definition + +For better type safety and control, you can define the tools and their input schemas explicitly in your client code: + +```typescript +import { z } from 'zod'; + +const tools = await mcpClient.tools({ + schemas: { + 'get-data': { + inputSchema: z.object({ + query: z.string().describe('The data query'), + format: z.enum(['json', 'text']).optional(), + }), + }, + // For tools with zero inputs, you should use an empty object: + 'tool-with-no-args': { + inputSchema: z.object({}), + }, + }, +}); +``` + +This approach provides full TypeScript type safety and IDE autocompletion, letting you catch parameter mismatches during development. When you define `schemas`, the client only pulls the explicitly defined tools, keeping your application focused on the tools it needs + +## Examples + +You can see MCP tools in action in the following example: + + diff --git a/content/docs/03-ai-sdk-core/35-image-generation.mdx b/content/docs/03-ai-sdk-core/35-image-generation.mdx index aa2afdff494b..0d39b409913a 100644 --- a/content/docs/03-ai-sdk-core/35-image-generation.mdx +++ b/content/docs/03-ai-sdk-core/35-image-generation.mdx @@ -231,7 +231,7 @@ try { ## Generating Images with Language Models -Some language models such as Google `gemini-2.0-flash-exp` support multi-modal outputs including images. +Some language models such as Google `gemini-2.5-flash-image-preview` support multi-modal outputs including images. With such models, you can access the generated images using the `files` property of the response. ```ts @@ -239,10 +239,7 @@ import { google } from '@ai-sdk/google'; import { generateText } from 'ai'; const result = await generateText({ - model: google('gemini-2.0-flash-exp'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, + model: google('gemini-2.5-flash-image-preview'), prompt: 'Generate an image of a comic cat', }); diff --git a/content/docs/03-ai-sdk-core/55-testing.mdx b/content/docs/03-ai-sdk-core/55-testing.mdx index 2be962fa7be5..2c8a7e349bd7 100644 --- a/content/docs/03-ai-sdk-core/55-testing.mdx +++ b/content/docs/03-ai-sdk-core/55-testing.mdx @@ -11,7 +11,7 @@ and calling them is slow and expensive. To enable you to unit test your code that uses the AI SDK, the AI SDK Core includes mock providers and test helpers. You can import the following helpers from `ai/test`: -- `MockEmbeddingModelV2`: A mock embedding model using the [embedding model v2 specification](https://github.com/vercel/ai/blob/v5/packages/provider/src/embedding-model/v2/embedding-model-v2.ts). +- `MockEmbeddingModelV3`: A mock embedding model using the [embedding model v3 specification](https://github.com/vercel/ai/blob/v5/packages/provider/src/embedding-model/v3/embedding-model-v3.ts). - `MockLanguageModelV2`: A mock language model using the [language model v2 specification](https://github.com/vercel/ai/blob/v5/packages/provider/src/language-model/v2/language-model-v2.ts). - `mockId`: Provides an incrementing integer ID. - `mockValues`: Iterates over an array of values with each call. Returns the last value when the array is exhausted. diff --git a/content/docs/04-ai-sdk-ui/02-chatbot.mdx b/content/docs/04-ai-sdk-ui/02-chatbot.mdx index c83bb61302fe..86e3e8dc228d 100644 --- a/content/docs/04-ai-sdk-ui/02-chatbot.mdx +++ b/content/docs/04-ai-sdk-ui/02-chatbot.mdx @@ -960,7 +960,7 @@ messages.map(message => ( ## Image Generation -Some models such as Google `gemini-2.0-flash-exp` support image generation. +Some models such as Google `gemini-2.5-flash-image-preview` support image generation. When images are generated, they are exposed as files to the client. On the client side, you can access file parts of the message object and render them as images. diff --git a/content/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx b/content/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx index aa6f5a85cf5f..d6f0d766a109 100644 --- a/content/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx +++ b/content/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx @@ -296,6 +296,59 @@ export default function Chat() { } ``` +### Error handling + +Sometimes an error may occur during client-side tool execution. Use the `addToolResult` method with a `state` of `output-error` and `errorText` value instead of `output` record the error. + +```tsx filename='app/page.tsx' highlight="19,36-41" +'use client'; + +import { useChat } from '@ai-sdk/react'; +import { + DefaultChatTransport, + lastAssistantMessageIsCompleteWithToolCalls, +} from 'ai'; +import { useState } from 'react'; + +export default function Chat() { + const { messages, sendMessage, addToolResult } = useChat({ + transport: new DefaultChatTransport({ + api: '/api/chat', + }), + + sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls, + + // run client-side tools that are automatically executed: + async onToolCall({ toolCall }) { + // Check if it's a dynamic tool first for proper type narrowing + if (toolCall.dynamic) { + return; + } + + if (toolCall.toolName === 'getWeatherInformation') { + try { + const weather = await getWeatherInformation(toolCall.input); + + // No await - avoids potential deadlocks + addToolResult({ + tool: 'getWeatherInformation', + toolCallId: toolCall.toolCallId, + output: weather, + }); + } catch (err) { + addToolResult({ + tool: 'getWeatherInformation', + toolCallId: toolCall.toolCallId, + state: 'output-error', + errorText: 'Unable to get the weather information', + }); + } + } + }, + }); +} +``` + ## Dynamic Tools When using dynamic tools (tools with unknown types at compile time), the UI parts use a generic `dynamic-tool` type instead of specific tool types: diff --git a/content/docs/04-ai-sdk-ui/08-object-generation.mdx b/content/docs/04-ai-sdk-ui/08-object-generation.mdx index b5258db889c9..1413906c16ae 100644 --- a/content/docs/04-ai-sdk-ui/08-object-generation.mdx +++ b/content/docs/04-ai-sdk-ui/08-object-generation.mdx @@ -5,7 +5,10 @@ description: Learn how to use the useObject hook. # Object Generation -`useObject` is an experimental feature and only available in React. + + `useObject` is an experimental feature and only available in React, Svelte, + and Vue. + The [`useObject`](/docs/reference/ai-sdk-ui/use-object) hook allows you to create interfaces that represent a structured JSON object that is being streamed. diff --git a/content/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx b/content/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx index 9b925b4f07a3..a0b204ff6880 100644 --- a/content/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +++ b/content/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx @@ -847,12 +847,12 @@ To see `generateText` in action, check out [these examples](#examples). }, { name: 'reasoning', - type: 'Array', + type: 'Array', description: 'The full reasoning that the model has generated in the last step.', properties: [ { - type: 'ReasoningPart', + type: 'ReasoningOutput', parameters: [ { name: 'type', @@ -864,6 +864,12 @@ To see `generateText` in action, check out [these examples](#examples). type: 'string', description: 'The reasoning text.', }, + { + name: 'providerMetadata', + type: 'SharedV2ProviderMetadata', + isOptional: true, + description: 'Additional provider metadata for the source.', + }, ], }, ], diff --git a/content/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx b/content/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx index 66974257d55b..0ebbd5af89d5 100644 --- a/content/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +++ b/content/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx @@ -1540,23 +1540,29 @@ To see `streamText` in action, check out [these examples](#examples). }, { name: 'reasoning', - type: 'Promise>', + type: 'Promise>', description: 'The full reasoning that the model has generated in the last step. Automatically consumes the stream.', properties: [ { - type: 'ReasoningPart', + type: 'ReasoningOutput', parameters: [ { name: 'type', type: "'reasoning'", - description: 'The type of the reasoning part.', + description: 'The type of the message part.', }, { name: 'text', type: 'string', description: 'The reasoning text.', }, + { + name: 'providerMetadata', + type: 'SharedV2ProviderMetadata', + isOptional: true, + description: 'Additional provider metadata for the source.', + }, ], }, ], diff --git a/content/docs/07-reference/01-ai-sdk-core/05-agent.mdx b/content/docs/07-reference/01-ai-sdk-core/05-agent.mdx new file mode 100644 index 000000000000..d85ac0c14be0 --- /dev/null +++ b/content/docs/07-reference/01-ai-sdk-core/05-agent.mdx @@ -0,0 +1,429 @@ +--- +title: Agent +description: API Reference for the Agent class. +--- + +# `Agent` + +Creates a reusable AI agent that can generate text, stream responses, and use tools across multiple steps. + +It is ideal for building autonomous AI systems that need to perform complex, multi-step tasks with tool calling capabilities. Unlike single-step functions like `generateText`, agents can iteratively call tools and make decisions based on intermediate results. + +```ts +import { Experimental_Agent as Agent } from 'ai'; + +const agent = new Agent({ + model: 'openai/gpt-4o', + system: 'You are a helpful assistant.', + tools: { + weather: weatherTool, + calculator: calculatorTool, + }, +}); + +const { text } = await agent.generate({ + prompt: 'What is the weather in NYC?', +}); + +console.log(text); +``` + +To see `Agent` in action, check out [these examples](#examples). + +## Import + + + +## Constructor + +### Parameters + +', + description: + 'The tools that the model can call. The model needs to support calling tools.', + }, + { + name: 'toolChoice', + type: 'ToolChoice', + description: + "The tool choice strategy. Options: 'auto' | 'none' | 'required' | { type: 'tool', toolName: string }. Default: 'auto'", + }, + { + name: 'stopWhen', + type: 'StopCondition | StopCondition[]', + description: + 'Condition for stopping the generation when there are tool results in the last step. Default: stepCountIs(1)', + }, + { + name: 'activeTools', + type: 'Array', + description: + 'Limits the tools that are available for the model to call without changing the tool call and result types.', + }, + { + name: 'experimental_output', + type: 'Output', + description: + 'Optional specification for parsing structured outputs from the LLM response.', + }, + { + name: 'prepareStep', + type: 'PrepareStepFunction', + description: + 'Optional function that you can use to provide different settings for a step.', + }, + { + name: 'experimental_repairToolCall', + type: 'ToolCallRepairFunction', + description: + 'A function that attempts to repair a tool call that failed to parse.', + }, + { + name: 'onStepFinish', + type: 'GenerateTextOnStepFinishCallback', + description: + 'Callback that is called when each step (LLM call) is finished, including intermediate steps.', + }, + { + name: 'experimental_context', + type: 'unknown', + description: + 'Context that is passed into tool calls. Experimental (can break in patch releases).', + }, + { + name: 'experimental_telemetry', + type: 'TelemetrySettings', + description: 'Optional telemetry configuration (experimental).', + }, + { + name: 'maxOutputTokens', + type: 'number', + description: 'Maximum number of tokens to generate.', + }, + { + name: 'temperature', + type: 'number', + description: + 'Temperature setting. The value is passed through to the provider. The range depends on the provider and model.', + }, + { + name: 'topP', + type: 'number', + description: + 'Top-p sampling setting. The value is passed through to the provider. The range depends on the provider and model.', + }, + { + name: 'topK', + type: 'number', + description: + 'Top-k sampling setting. The value is passed through to the provider. The range depends on the provider and model.', + }, + { + name: 'presencePenalty', + type: 'number', + description: + 'Presence penalty setting. The value is passed through to the provider. The range depends on the provider and model.', + }, + { + name: 'frequencyPenalty', + type: 'number', + description: + 'Frequency penalty setting. The value is passed through to the provider. The range depends on the provider and model.', + }, + { + name: 'stopSequences', + type: 'string[]', + description: + 'Stop sequences to use. The value is passed through to the provider.', + }, + { + name: 'seed', + type: 'number', + description: + 'Seed for random number generation. The value is passed through to the provider.', + }, + { + name: 'maxRetries', + type: 'number', + description: 'Maximum number of retries. Default: 2.', + }, + { + name: 'abortSignal', + type: 'AbortSignal', + description: + 'An optional abort signal that can be used to cancel the call.', + }, + ]} +/> + +## Methods + +### `generate()` + +Generates text and calls tools for a given prompt. Returns a promise that resolves to a `GenerateTextResult`. + +```ts +const result = await agent.generate({ + prompt: 'What is the weather like?', +}); +``` + +', + description: 'A text prompt.', + }, + { + name: 'messages', + type: 'Array', + description: 'A list of messages that represent a conversation.', + }, + { + name: 'providerMetadata', + type: 'ProviderMetadata', + isOptional: true, + description: + 'Additional provider-specific metadata. They are passed through from the provider to the AI SDK and enable provider-specific results that can be fully encapsulated in the provider.', + }, + { + name: 'providerOptions', + type: 'ProviderOptions', + isOptional: true, + description: + 'Additional provider-specific metadata. They are passed through to the provider from the AI SDK and enable provider-specific functionality that can be fully encapsulated in the provider.', + }, + { + name: 'system', + type: 'string', + isOptional: true, + description: + 'The system prompt to use that specifies the behavior of the model.', + }, + ]} +/> + +#### Returns + +The `generate()` method returns a `GenerateTextResult` object with the same properties as [`generateText`](/docs/reference/ai-sdk-core/generate-text#returns). + +### `stream()` + +Streams text and calls tools for a given prompt. Returns a `StreamTextResult` that can be used to iterate over the stream. + +```ts +const stream = agent.stream({ + prompt: 'Tell me a story about a robot.', +}); + +for await (const chunk of stream.textStream) { + console.log(chunk); +} +``` + +', + description: 'A text prompt.', + }, + { + name: 'messages', + type: 'Array', + description: 'A list of messages that represent a conversation.', + }, + { + name: 'providerMetadata', + type: 'ProviderMetadata', + isOptional: true, + description: + 'Additional provider-specific metadata. They are passed through from the provider to the AI SDK and enable provider-specific results that can be fully encapsulated in the provider.', + }, + { + name: 'providerOptions', + type: 'ProviderOptions', + isOptional: true, + description: + 'Additional provider-specific metadata. They are passed through to the provider from the AI SDK and enable provider-specific functionality that can be fully encapsulated in the provider.', + }, + { + name: 'system', + type: 'string', + isOptional: true, + description: + 'The system prompt to use that specifies the behavior of the model.', + }, + ]} +/> + +#### Returns + +The `stream()` method returns a `StreamTextResult` object with the same properties as [`streamText`](/docs/reference/ai-sdk-core/stream-text#returns). + +### `respond()` + +Creates a Response object that streams UI messages to the client. This method is particularly useful for building chat interfaces in web applications. + +```ts +export async function POST(request: Request) { + const { messages } = await request.json(); + + return agent.respond({ + messages, + }); +} +``` + + + +#### Returns + +Returns a `Response` object that streams UI messages to the client in the format expected by the `useChat` hook and other UI integrations. + +## Types + +### `InferAgentUIMessage` + +Infers the UI message type of an agent, useful for type-safe message handling in TypeScript applications. + +```ts +import { + Experimental_Agent as Agent, + Experimental_InferAgentUIMessage as InferAgentUIMessage, +} from 'ai'; + +const weatherAgent = new Agent({ + model: 'openai/gpt-4o', + tools: { weather: weatherTool }, +}); + +type WeatherAgentUIMessage = InferAgentUIMessage; +``` + +## Examples + +### Basic Agent with Tools + +Create an agent that can use multiple tools to answer questions: + +```ts +import { Experimental_Agent as Agent, stepCountIs } from 'ai'; +import { weatherTool, calculatorTool } from './tools'; + +const assistant = new Agent({ + model: 'openai/gpt-4o', + system: 'You are a helpful assistant.', + tools: { + weather: weatherTool, + calculator: calculatorTool, + }, + stopWhen: stepCountIs(3), +}); + +// Generate a response +const result = await assistant.generate({ + prompt: 'What is the weather in NYC and what is 100 * 25?', +}); + +console.log(result.text); +console.log(result.steps); // Array of all steps taken +``` + +### Streaming Agent Response + +Stream responses for real-time interaction: + +```ts +const agent = new Agent({ + model: 'openai/gpt-4o', + system: 'You are a creative storyteller.', +}); + +const stream = agent.stream({ + prompt: 'Tell me a short story about a time traveler.', +}); + +for await (const chunk of stream.textStream) { + process.stdout.write(chunk); +} +``` + +### Agent with Output Parsing + +Parse structured output from agent responses: + +```ts +import { z } from 'zod'; + +const analysisAgent = new Agent({ + model: 'openai/gpt-4o', + experimental_output: { + schema: z.object({ + sentiment: z.enum(['positive', 'negative', 'neutral']), + score: z.number(), + summary: z.string(), + }), + }, +}); + +const result = await analysisAgent.generate({ + prompt: 'Analyze this review: "The product exceeded my expectations!"', +}); + +console.log(result.experimental_output); // Typed as { sentiment: 'positive' | 'negative' | 'neutral', score: number, summary: string } +``` + +### Next.js Route Handler + +Use an agent in a Next.js API route: + +```ts +// app/api/chat/route.ts +import { Experimental_Agent as Agent } from 'ai'; + +const agent = new Agent({ + model: 'openai/gpt-4o', + system: 'You are a helpful assistant.', + tools: { + // your tools here + }, +}); + +export async function POST(request: Request) { + const { messages } = await request.json(); + + return agent.respond({ + messages, + }); +} +``` diff --git a/content/docs/07-reference/01-ai-sdk-core/10-generate-image.mdx b/content/docs/07-reference/01-ai-sdk-core/10-generate-image.mdx index 289313607a02..fb0b9bf104d1 100644 --- a/content/docs/07-reference/01-ai-sdk-core/10-generate-image.mdx +++ b/content/docs/07-reference/01-ai-sdk-core/10-generate-image.mdx @@ -40,7 +40,7 @@ console.log(images); content={[ { name: 'model', - type: 'ImageModelV2', + type: 'ImageModelV3', description: 'The image model to use.', }, { diff --git a/content/docs/07-reference/01-ai-sdk-core/33-safe-validate-ui-messages.mdx b/content/docs/07-reference/01-ai-sdk-core/33-safe-validate-ui-messages.mdx new file mode 100644 index 000000000000..2a4bd4a45c38 --- /dev/null +++ b/content/docs/07-reference/01-ai-sdk-core/33-safe-validate-ui-messages.mdx @@ -0,0 +1,113 @@ +--- +title: safeValidateUIMessages +description: API Reference for safeValidateUIMessages +--- + +# `safeValidateUIMessages` + +`safeValidateUIMessages` is an async function that validates UI messages like [`validateUIMessages`](https://ai-sdk.dev/docs/reference/ai-sdk-core/validate-ui-messages), but instead of throwing it returns an object with a `success` key and either `data` or `error`. + +## Basic Usage + +Simple validation without custom schemas: + +```typescript +import { safeValidateUIMessages } from 'ai'; + +const messages = [ + { + id: '1', + role: 'user', + parts: [{ type: 'text', text: 'Hello!' }], + }, +]; + +const result = await safeValidateUIMessages({ + messages, +}); + +if (!result.success) { + console.error(result.error.message); +} else { + const validatedMessages = result.data; +} +``` + +## Advanced Usage + +Comprehensive validation with custom metadata, data parts, and tools: + +```typescript +import { safeValidateUIMessages, tool } from 'ai'; +import { z } from 'zod'; + +// Define schemas +const metadataSchema = z.object({ + timestamp: z.string().datetime(), + userId: z.string(), +}); + +const dataSchemas = { + chart: z.object({ + data: z.array(z.number()), + labels: z.array(z.string()), + }), + image: z.object({ + url: z.string().url(), + caption: z.string(), + }), +}; + +const tools = { + weather: tool({ + description: 'Get weather info', + parameters: z.object({ + location: z.string(), + }), + execute: async ({ location }) => `Weather in ${location}: sunny`, + }), +}; + +// Messages with custom parts +const messages = [ + { + id: '1', + role: 'user', + metadata: { timestamp: '2024-01-01T00:00:00Z', userId: 'user123' }, + parts: [ + { type: 'text', text: 'Show me a chart' }, + { + type: 'data-chart', + data: { data: [1, 2, 3], labels: ['A', 'B', 'C'] }, + }, + ], + }, + { + id: '2', + role: 'assistant', + parts: [ + { + type: 'tool-weather', + toolCallId: 'call_123', + state: 'output-available', + input: { location: 'San Francisco' }, + output: 'Weather in San Francisco: sunny', + }, + ], + }, +]; + +// Validate with all schemas +const result = await safeValidateUIMessages({ + messages, + metadataSchema, + dataSchemas, + tools, +}); + +if (!result.success) { + console.error(result.error.message); +} else { + const validatedMessages = result.data; +} +``` diff --git a/content/docs/07-reference/01-ai-sdk-core/42-custom-provider.mdx b/content/docs/07-reference/01-ai-sdk-core/42-custom-provider.mdx index abaca7e1ab7c..03ceb44f89bb 100644 --- a/content/docs/07-reference/01-ai-sdk-core/42-custom-provider.mdx +++ b/content/docs/07-reference/01-ai-sdk-core/42-custom-provider.mdx @@ -81,7 +81,7 @@ export const myOpenAI = customProvider({ type: 'Record', isOptional: true, description: - 'A record of image models, where keys are model IDs and values are ImageModelV2 instances.', + 'A record of image models, where keys are model IDs and values are image model instances.', }, { name: 'fallbackProvider', diff --git a/content/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx b/content/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx index a1772855b0d8..794ac8a2599a 100644 --- a/content/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx +++ b/content/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx @@ -419,7 +419,7 @@ Allows you to easily create a conversational user interface for your chatbot app }, { name: 'addToolResult', - type: '(options: { tool: string; toolCallId: string; output: unknown }) => void', + type: '(options: { tool: string; toolCallId: string; output: unknown } | { tool: string; toolCallId: string; state: "output-error", errorText: string }) => void', description: 'Function to add a tool result to the chat. This will update the chat messages with the tool result. If sendAutomaticallyWhen is configured, it may trigger an automatic submission.', }, diff --git a/content/docs/07-reference/02-ai-sdk-ui/03-use-object.mdx b/content/docs/07-reference/02-ai-sdk-ui/03-use-object.mdx index c020866cec49..fff8793ca9f0 100644 --- a/content/docs/07-reference/02-ai-sdk-ui/03-use-object.mdx +++ b/content/docs/07-reference/02-ai-sdk-ui/03-use-object.mdx @@ -6,7 +6,8 @@ description: API reference for the useObject hook. # `experimental_useObject()` - `useObject` is an experimental feature and only available in React and Svelte. + `useObject` is an experimental feature and only available in React, Svelte, + and Vue. Allows you to consume text streams that represent a JSON object and parse them into a complete object based on a schema. diff --git a/content/docs/07-reference/04-stream-helpers/index.mdx b/content/docs/07-reference/04-stream-helpers/index.mdx index 63b303303061..74b9f027c85d 100644 --- a/content/docs/07-reference/04-stream-helpers/index.mdx +++ b/content/docs/07-reference/04-stream-helpers/index.mdx @@ -79,7 +79,7 @@ collapsed: true title: 'LangChainStream', description: "Transforms the response from LangChain's language models into a readable stream.", - href: '/docs/reference/stream-helpers/langchain-stream', + href: '/docs/reference/stream-helpers/langchain-adapter', }, { title: 'MistralStream', diff --git a/content/docs/08-migration-guides/26-migration-guide-5-0.mdx b/content/docs/08-migration-guides/26-migration-guide-5-0.mdx index af3b2f398352..6ad413016365 100644 --- a/content/docs/08-migration-guides/26-migration-guide-5-0.mdx +++ b/content/docs/08-migration-guides/26-migration-guide-5-0.mdx @@ -26,14 +26,22 @@ You need to update the following packages to the following versions in your `pac Additionally, you need to update the following peer dependencies: -- `zod` package: `3.25.0` or later +- `zod` package: `4.1.8` or later (recommended to avoid TypeScript performance issues) An example upgrade command would be: ``` -npm install ai @ai-sdk/react @ai-sdk/openai zod@3.25.0 +npm install ai @ai-sdk/react @ai-sdk/openai zod@^4.1.8 ``` + + If you encounter TypeScript performance issues after upgrading, ensure you're + using Zod 4.1.8 or later. If the issue persists, update your `tsconfig.json` + to use `moduleResolution: "nodenext"`. See the [TypeScript performance + troubleshooting guide](/docs/troubleshooting/typescript-performance-zod) for + more details. + + ## Codemods The AI SDK provides Codemod transformations to help upgrade your codebase when a @@ -3094,17 +3102,22 @@ import { ### TypeScript Performance Issues with Zod -If you experience TypeScript server crashes, slow type checking, or errors like "Type instantiation is excessively deep and possibly infinite" when using Zod with AI SDK 5.0, you need to use the Zod v3 import path: +If you experience TypeScript server crashes, slow type checking, or errors like "Type instantiation is excessively deep and possibly infinite" when using Zod with AI SDK 5.0: -```typescript -// ❌ Avoid: Standard import causes TypeScript issues -import { z } from 'zod'; +1. **First, ensure you're using Zod 4.1.8 or later** - this version includes a fix for module resolution issues that cause TypeScript performance problems. -// ✅ Use: v3-specific import for AI SDK 5.0 compatibility -import { z } from 'zod/v3'; +2. If the issue persists, update your `tsconfig.json` to use `moduleResolution: "nodenext"`: + +```json +{ + "compilerOptions": { + "moduleResolution": "nodenext" + // ... other options + } +} ``` -This is particularly important when using `generateObject`, `tool`, or other AI SDK functions with Zod schemas. For detailed troubleshooting steps, see [TypeScript performance issues with Zod](/docs/troubleshooting/typescript-performance-zod). +This resolves the TypeScript performance issues while allowing you to continue using the standard Zod import. If this doesn't resolve the issue, you can try using a version-specific import path as an alternative solution. For detailed troubleshooting steps, see [TypeScript performance issues with Zod](/docs/troubleshooting/typescript-performance-zod). ## Codemod Table diff --git a/content/docs/09-troubleshooting/05-tool-invocation-missing-result.mdx b/content/docs/09-troubleshooting/05-tool-invocation-missing-result.mdx index 825a1b6e680a..bdf115542188 100644 --- a/content/docs/09-troubleshooting/05-tool-invocation-missing-result.mdx +++ b/content/docs/09-troubleshooting/05-tool-invocation-missing-result.mdx @@ -54,14 +54,24 @@ const { messages, sendMessage, addToolResult } = useChat({ // Handle tool calls in onToolCall onToolCall: async ({ toolCall }) => { if (toolCall.toolName === 'getLocation') { - const result = await getLocationData(); - - // Important: Don't await inside onToolCall to avoid deadlocks - addToolResult({ - tool: 'getLocation', - toolCallId: toolCall.toolCallId, - output: result, - }); + try { + const result = await getLocationData(); + + // Important: Don't await inside onToolCall to avoid deadlocks + addToolResult({ + tool: 'getLocation', + toolCallId: toolCall.toolCallId, + output: result, + }); + } catch (err) { + // Important: Don't await inside onToolCall to avoid deadlocks + addToolResult({ + tool: 'getLocation', + toolCallId: toolCall.toolCallId, + state: 'output-error', + errorText: 'Failed to get location', + }); + } } }, }); diff --git a/content/docs/09-troubleshooting/12-typescript-performance-zod.mdx b/content/docs/09-troubleshooting/12-typescript-performance-zod.mdx index 39d7814db1ff..6cbc3fc027e2 100644 --- a/content/docs/09-troubleshooting/12-typescript-performance-zod.mdx +++ b/content/docs/09-troubleshooting/12-typescript-performance-zod.mdx @@ -20,18 +20,27 @@ The AI SDK 5 has specific compatibility requirements with Zod versions. When imp ## Solution -### Use the Zod Version-Specific Import Path +### Upgrade Zod to 4.1.8 or Later -The recommended solution is to import Zod using a version-specific import path: +The primary solution is to upgrade to Zod version 4.1.8 or later, which includes a fix for this module resolution issue: -```typescript -// ❌ Avoid: Standard import causes TypeScript issues -import { z } from 'zod'; +```bash +pnpm add zod@^4.1.8 +``` + +This version resolves the underlying problem where different module resolution settings were causing TypeScript to load the same Zod declarations twice, leading to expensive structural comparisons. + +### Alternative: Update TypeScript Configuration + +If upgrading Zod isn't possible, you can update your `tsconfig.json` to use `moduleResolution: "nodenext"`: -// ✅ Use: version-specific import for AI SDK 5 compatibility -import { z } from 'zod/v3'; -// or -import { z } from 'zod/v4'; +```json +{ + "compilerOptions": { + "moduleResolution": "nodenext" + // ... other options + } +} ``` -After making this change, restart your TypeScript server (in VS Code: `Cmd/Ctrl + Shift + P` → "TypeScript: Restart TS Server"). +This resolves the TypeScript performance issues while allowing you to continue using the standard Zod import. diff --git a/content/docs/09-troubleshooting/30-model-is-not-assignable-to-type.mdx b/content/docs/09-troubleshooting/30-model-is-not-assignable-to-type.mdx index 4255a4c3e2fa..bd1b40a39c6f 100644 --- a/content/docs/09-troubleshooting/30-model-is-not-assignable-to-type.mdx +++ b/content/docs/09-troubleshooting/30-model-is-not-assignable-to-type.mdx @@ -9,7 +9,7 @@ description: Troubleshooting errors related to incompatible models. I have updated the AI SDK and now I get the following error: `Type 'SomeModel' is not assignable to type 'LanguageModelV1'.` -Similar errors can occur with `EmbeddingModelV2` as well. +Similar errors can occur with `EmbeddingModelV3` as well. ## Background diff --git a/content/providers/01-ai-sdk-providers/00-ai-gateway.mdx b/content/providers/01-ai-sdk-providers/00-ai-gateway.mdx index 56e7b13b3edf..2b568426b87b 100644 --- a/content/providers/01-ai-sdk-providers/00-ai-gateway.mdx +++ b/content/providers/01-ai-sdk-providers/00-ai-gateway.mdx @@ -207,6 +207,24 @@ const { text } = await generateText({ }); ``` +## Credit Usage + +You can check your team's current credit balance and usage: + +```ts +import { gateway } from 'ai'; + +const credits = await gateway.getCredits(); + +console.log(`Team balance: ${credits.balance} credits`); +console.log(`Team total used: ${credits.total_used} credits`); +``` + +The `getCredits()` method returns your team's credit information based on the authenticated API key or OIDC token: + +- **balance** _number_ - Your team's current available credit balance +- **total_used** _number_ - Total credits consumed by your team + ## Examples ### Basic Text Generation diff --git a/content/providers/01-ai-sdk-providers/01-xai.mdx b/content/providers/01-ai-sdk-providers/01-xai.mdx index 584f74ff8fce..b4fc64bcaf52 100644 --- a/content/providers/01-ai-sdk-providers/01-xai.mdx +++ b/content/providers/01-ai-sdk-providers/01-xai.mdx @@ -230,7 +230,10 @@ const result = await generateText({ sources: [ { type: 'x', - xHandles: ['grok', 'xai'], + includedXHandles: ['grok', 'xai'], + excludedXHandles: ['openai'], + postFavoriteCount: 10, + postViewCount: 100, }, ], }, @@ -241,7 +244,10 @@ const result = await generateText({ #### X source parameters -- **xHandles** _string[]_: Array of X handles to search (without @ symbol) +- **includedXHandles** _string[]_: Array of X handles to search (without @ symbol) +- **excludedXHandles** _string[]_: Array of X handles to exclude from search (without @ symbol) +- **postFavoriteCount** _number_: Minimum favorite count of the X posts to consider. +- **postViewCount** _number_: Minimum view count of the X posts to consider. #### News Search @@ -324,7 +330,7 @@ const result = await generateText({ }, { type: 'x', - xHandles: ['openai', 'deepmind'], + includedXHandles: ['openai', 'deepmind'], }, ], }, @@ -388,26 +394,28 @@ console.log('Sources:', await result.sources); ## Model Capabilities -| Model | Image Input | Object Generation | Tool Usage | Tool Streaming | Reasoning | -| ------------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | -| `grok-code-fast-1` | | | | | | -| `grok-4` | | | | | | -| `grok-3` | | | | | | -| `grok-3-latest` | | | | | | -| `grok-3-fast` | | | | | | -| `grok-3-fast-latest` | | | | | | -| `grok-3-mini` | | | | | | -| `grok-3-mini-latest` | | | | | | -| `grok-3-mini-fast` | | | | | | -| `grok-3-mini-fast-latest` | | | | | | -| `grok-2` | | | | | | -| `grok-2-latest` | | | | | | -| `grok-2-1212` | | | | | | -| `grok-2-vision` | | | | | | -| `grok-2-vision-latest` | | | | | | -| `grok-2-vision-1212` | | | | | | -| `grok-beta` | | | | | | -| `grok-vision-beta` | | | | | | +| Model | Image Input | Object Generation | Tool Usage | Tool Streaming | Reasoning | +| --------------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | +| `grok-4-fast-non-reasoning` | | | | | | +| `grok-4-fast-reasoning` | | | | | | +| `grok-code-fast-1` | | | | | | +| `grok-4` | | | | | | +| `grok-3` | | | | | | +| `grok-3-latest` | | | | | | +| `grok-3-fast` | | | | | | +| `grok-3-fast-latest` | | | | | | +| `grok-3-mini` | | | | | | +| `grok-3-mini-latest` | | | | | | +| `grok-3-mini-fast` | | | | | | +| `grok-3-mini-fast-latest` | | | | | | +| `grok-2` | | | | | | +| `grok-2-latest` | | | | | | +| `grok-2-1212` | | | | | | +| `grok-2-vision` | | | | | | +| `grok-2-vision-latest` | | | | | | +| `grok-2-vision-1212` | | | | | | +| `grok-beta` | | | | | | +| `grok-vision-beta` | | | | | | The table above lists popular models. Please see the [xAI diff --git a/content/providers/01-ai-sdk-providers/03-openai.mdx b/content/providers/01-ai-sdk-providers/03-openai.mdx index 94d7325dcc3f..4b5483d2d5f6 100644 --- a/content/providers/01-ai-sdk-providers/03-openai.mdx +++ b/content/providers/01-ai-sdk-providers/03-openai.mdx @@ -168,6 +168,11 @@ The following provider options are available: include `['reasoning.encrypted_content']` in the `include` option to ensure reasoning content is available across conversation steps. +- **maxToolCalls** _integer_ + The maximum number of total calls to built-in tools that can be processed in a response. + This maximum number applies across all built-in tool calls, not per individual tool. + Any further attempts to call a tool by the model will be ignored. + - **metadata** _Record<string, string>_ Additional metadata to store with the generation. @@ -234,33 +239,6 @@ The following OpenAI-specific metadata is returned: - **reasoningTokens** _number_ The number of reasoning tokens that the model generated. -#### Web Search - -The OpenAI responses API supports web search through the `openai.tools.webSearch` tool. - -```ts -const result = await generateText({ - model: openai('gpt-5'), - prompt: 'What happened in San Francisco last week?', - tools: { - web_search: openai.tools.webSearch({ - // optional configuration: - searchContextSize: 'high', - userLocation: { - type: 'approximate', - city: 'San Francisco', - region: 'California', - }, - }), - }, - // Force web search tool (optional): - toolChoice: { type: 'tool', toolName: 'web_search' }, -}); - -// URL sources -const sources = result.sources; -``` - #### Reasoning Output For reasoning models like `gpt-5`, you can enable reasoning summaries to see the model's thought process. Different models support different summarizers—for example, `o4-mini` supports detailed summaries. Set `reasoningSummary: "auto"` to automatically receive the richest level available. @@ -333,7 +311,34 @@ The `textVerbosity` parameter scales output length without changing the underlyi - `'medium'`: Balanced detail (default) - `'high'`: Verbose responses with comprehensive detail -#### File Search +#### Web Search Tool + +The OpenAI responses API supports web search through the `openai.tools.webSearch` tool. + +```ts +const result = await generateText({ + model: openai('gpt-5'), + prompt: 'What happened in San Francisco last week?', + tools: { + web_search: openai.tools.webSearch({ + // optional configuration: + searchContextSize: 'high', + userLocation: { + type: 'approximate', + city: 'San Francisco', + region: 'California', + }, + }), + }, + // Force web search tool (optional): + toolChoice: { type: 'tool', toolName: 'web_search' }, +}); + +// URL sources +const sources = result.sources; +``` + +#### File Search Tool The OpenAI responses API supports file search through the `openai.tools.fileSearch` tool. @@ -345,23 +350,26 @@ const result = await generateText({ prompt: 'What does the document say about user authentication?', tools: { file_search: openai.tools.fileSearch({ - // optional configuration: - vectorStoreIds: ['vs_123', 'vs_456'], - maxNumResults: 10, + vectorStoreIds: ['vs_123'], + // configuration below is optional: + maxNumResults: 5, + filters: { + key: 'author', + type: 'eq', + value: 'Jane Smith', + }, ranking: { ranker: 'auto', - }, - filters: { - type: 'and', - filters: [ - { key: 'author', type: 'eq', value: 'John Doe' }, - { key: 'date', type: 'gte', value: '2023-01-01' }, - ], + scoreThreshold: 0.5, }, }), }, - // Force file search tool: - toolChoice: { type: 'tool', toolName: 'file_search' }, + providerOptions: { + openai: { + // optional: include results + include: ['file_search_call.results'], + } satisfies OpenAIResponsesProviderOptions, + }, }); ``` @@ -371,7 +379,69 @@ const result = await generateText({ be customized. -#### Code Interpreter +#### Image Generation Tool + +OpenAI's Responses API supports multi-modal image generation as a provider-defined tool. +Availability is restricted to specific models (for example, `gpt-5` variants). + +You can use the image tool with either `generateText` or `streamText`: + +```ts +import { openai } from '@ai-sdk/openai'; +import { generateText } from 'ai'; + +const result = await generateText({ + model: openai('gpt-5'), + prompt: + 'Generate an image of an echidna swimming across the Mozambique channel.', + tools: { + image_generation: openai.tools.imageGeneration({ outputFormat: 'webp' }), + }, +}); + +for (const toolResult of result.staticToolResults) { + if (toolResult.toolName === 'image_generation') { + const base64Image = toolResult.output.result; + } +} +``` + +```ts +import { openai } from '@ai-sdk/openai'; +import { streamText } from 'ai'; + +const result = streamText({ + model: openai('gpt-5'), + prompt: + 'Generate an image of an echidna swimming across the Mozambique channel.', + tools: { + image_generation: openai.tools.imageGeneration({ + outputFormat: 'webp', + quality: 'low', + }), + }, +}); + +for await (const part of result.fullStream) { + if (part.type == 'tool-result' && !part.dynamic) { + const base64Image = part.output.result; + } +} +``` + + + When you set `store: false`, then previously generated images will not be + accessible by the model. We recommend using the image generation tool without + setting `store: false`. + + +For complete details on model availability, image quality controls, supported sizes, and tool-specific parameters, +refer to the OpenAI documentation: + +- Image generation overview and models: [OpenAI Image Generation](https://platform.openai.com/docs/guides/image-generation) +- Image generation tool parameters (background, size, quality, format, etc.): [Image Generation Tool Options](https://platform.openai.com/docs/guides/tools-image-generation#tool-options) + +#### Code Interpreter Tool The OpenAI responses API supports the code interpreter tool through the `openai.tools.codeInterpreter` tool. This allows models to write and execute Python code. @@ -403,7 +473,7 @@ The code interpreter tool can be configured with: be customized. -#### Image Support +#### Image Inputs The OpenAI Responses API supports Image inputs for appropriate models. You can pass Image files as part of the message content using the 'image' type: @@ -450,7 +520,7 @@ You can also pass the URL of an image. } ``` -#### PDF support +#### PDF Inputs The OpenAI Responses API supports reading PDF files. You can pass PDF files as part of the message content using the `file` type: @@ -554,6 +624,8 @@ OpenAI chat models support also some model specific provider options that are no You can pass them in the `providerOptions` argument: ```ts +import { openai, type OpenAIChatLanguageModelOptions } from '@ai-sdk/openai'; + const model = openai.chat('gpt-5'); await generateText({ @@ -565,7 +637,7 @@ await generateText({ '50256': -100, }, user: 'test-user', // optional unique user identifier - }, + } satisfies OpenAIChatLanguageModelOptions, }, }); ``` diff --git a/content/providers/01-ai-sdk-providers/04-azure.mdx b/content/providers/01-ai-sdk-providers/04-azure.mdx index 2d193a92be9d..100297abb9aa 100644 --- a/content/providers/01-ai-sdk-providers/04-azure.mdx +++ b/content/providers/01-ai-sdk-providers/04-azure.mdx @@ -198,7 +198,7 @@ const result = await generateText({ model: azure('your-deployment-name'), prompt: 'Write a short story about a robot.', providerOptions: { - azure: { + openai: { logitBias: { // optional likelihood for specific tokens '50256': -100, @@ -378,7 +378,7 @@ const result = await generateText({ model: azure.completion('your-gpt-35-turbo-instruct-deployment'), prompt: 'Write a haiku about coding.', providerOptions: { - azure: { + openai: { echo: true, // optional, echo the prompt in addition to the completion logitBias: { // optional likelihood for specific tokens @@ -453,7 +453,7 @@ const { embedding } = await embed({ model: azure.textEmbedding('your-embedding-deployment'), value: 'sunny day at the beach', providerOptions: { - azure: { + openai: { dimensions: 512, // optional, number of dimensions for the embedding user: 'test-user', // optional unique user identifier }, @@ -481,7 +481,7 @@ You can create models that call the Azure OpenAI image generation API (DALL-E) u const model = azure.image('your-dalle-deployment-name'); ``` -Azure OpenAI image models support several additional settings. You can pass them as `providerOptions.azure` when generating the image: +Azure OpenAI image models support several additional settings. You can pass them as `providerOptions.openai` when generating the image: ```ts await generateImage({ @@ -489,7 +489,7 @@ await generateImage({ prompt: 'A photorealistic image of a cat astronaut floating in space', size: '1024x1024', // '1024x1024', '1792x1024', or '1024x1792' for DALL-E 3 providerOptions: { - azure: { + openai: { user: 'test-user', // optional unique user identifier responseFormat: 'url', // 'url' or 'b64_json', defaults to 'url' }, @@ -567,7 +567,7 @@ import { readFile } from 'fs/promises'; const result = await transcribe({ model: azure.transcription('whisper-1'), audio: await readFile('audio.mp3'), - providerOptions: { azure: { language: 'en' } }, + providerOptions: { openai: { language: 'en' } }, }); ``` diff --git a/content/providers/01-ai-sdk-providers/05-anthropic.mdx b/content/providers/01-ai-sdk-providers/05-anthropic.mdx index d221f10e06d6..30c9302a8310 100644 --- a/content/providers/01-ai-sdk-providers/05-anthropic.mdx +++ b/content/providers/01-ai-sdk-providers/05-anthropic.mdx @@ -234,18 +234,13 @@ const result = await generateText({ #### Longer cache TTL -Anthropic also supports a longer 1-hour cache duration. At time of writing, -[this is currently in beta](https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching#1-hour-cache-duration), -so you must pass a `'anthropic-beta'` header set to `'extended-cache-ttl-2025-04-11'`. +Anthropic also supports a longer 1-hour cache duration. Here's an example: ```ts const result = await generateText({ model: anthropic('claude-3-5-haiku-latest'), - headers: { - 'anthropic-beta': 'extended-cache-ttl-2025-04-11', - }, messages: [ { role: 'user', diff --git a/content/providers/01-ai-sdk-providers/15-google-generative-ai.mdx b/content/providers/01-ai-sdk-providers/15-google-generative-ai.mdx index 80223208fe2b..9e15432e11fd 100644 --- a/content/providers/01-ai-sdk-providers/15-google-generative-ai.mdx +++ b/content/providers/01-ai-sdk-providers/15-google-generative-ai.mdx @@ -110,7 +110,6 @@ await generateText({ threshold: 'BLOCK_LOW_AND_ABOVE', }, ], - responseModalities: ['TEXT', 'IMAGE'], }, }, }); @@ -582,7 +581,6 @@ const urlContextMetadata = metadata?.urlContextMetadata; ### Image Outputs Gemini models with image generation capabilities (`gemini-2.5-flash-image-preview`) support image generation. Images are exposed as files in the response. -You need to enable image output in the provider options using the `responseModalities` option. ```ts import { google } from '@ai-sdk/google'; @@ -590,9 +588,6 @@ import { generateText } from 'ai'; const result = await generateText({ model: google('gemini-2.5-flash-image-preview'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, prompt: 'Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme', }); diff --git a/content/providers/01-ai-sdk-providers/170-baseten.mdx b/content/providers/01-ai-sdk-providers/170-baseten.mdx new file mode 100644 index 000000000000..4572af55b7f5 --- /dev/null +++ b/content/providers/01-ai-sdk-providers/170-baseten.mdx @@ -0,0 +1,248 @@ +--- +title: Baseten +description: Learn how to use Baseten models with the AI SDK. +--- + +# Baseten Provider + +[Baseten](https://baseten.co/) is an inference platform for serving frontier, enterprise-grade opensource AI models via their [API](https://docs.baseten.co/overview). + +## Setup + +The Baseten provider is available via the `@ai-sdk/baseten` module. You can install it with + + + + + + + + + + + + + +## Provider Instance + +You can import the default provider instance `baseten` from `@ai-sdk/baseten`: + +```ts +import { baseten } from '@ai-sdk/baseten'; +``` + +If you need a customized setup, you can import `createBaseten` from `@ai-sdk/baseten` +and create a provider instance with your settings: + +```ts +import { createBaseten } from '@ai-sdk/baseten'; + +const baseten = createBaseten({ + apiKey: process.env.BASETEN_API_KEY ?? '', +}); +``` + +You can use the following optional settings to customize the Baseten provider instance: + +- **baseURL** _string_ + + Use a different URL prefix for API calls, e.g. to use proxy servers. + The default prefix is `https://inference.baseten.co/v1`. + +- **apiKey** _string_ + + API key that is being sent using the `Authorization` header. It defaults to + the `BASETEN_API_KEY` environment variable. It is recommended you set the environment variable using `export` so you do not need to include the field everytime. + You can grab your Baseten API Key [here](https://app.baseten.co/settings/api_keys) + +- **modelURL** _string_ + + Custom model URL for specific models (chat or embeddings). If not provided, + the default Models API will be used. + +- **headers** _Record<string,string>_ + + Custom headers to include in the requests. + +- **fetch** _(input: RequestInfo, init?: RequestInit) => Promise<Response>_ + + Custom [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) implementation. + +## Models API + +You can select [Baseten models](https://www.baseten.co/products/model-apis/) using a provider instance. +The first argument is the model id, e.g. `'moonshotai/Kimi-K2-Instruct-0905'`: The complete supported models under models API can be found [here](https://docs.baseten.co/development/model-apis/overview#supported-models). + +```ts +const model = baseten('moonshotai/Kimi-K2-Instruct-0905'); +``` + +### Example + +You can use Baseten language models to generate text with the `generateText` function: + +```ts +import { baseten } from '@ai-sdk/baseten'; +import { generateText } from 'ai'; + +const { text } = await generateText({ + model: baseten('moonshotai/Kimi-K2-Instruct-0905'), + prompt: 'What is the meaning of life? Answer in one sentence.', +}); +``` + +Baseten language models can also be used in the `streamText` function +(see [AI SDK Core](/docs/ai-sdk-core)). + +## Dedicated Models + +Baseten supports dedicated model URLs for both chat and embedding models. You have to specify a `modelURL` when creating the provider: + +### OpenAI-Compatible Endpoints (`/sync/v1`) + +For models deployed with Baseten's OpenAI-compatible endpoints: + +```ts +import { createBaseten } from '@ai-sdk/baseten'; + +const baseten = createBaseten({ + modelURL: 'https://model-{MODEL_ID}.api.baseten.co/sync/v1', +}); +// No modelId is needed because we specified modelURL +const model = baseten(); +const { text } = await generateText({ + model: model, + prompt: 'Say hello from a Baseten chat model!', +}); +``` + +### `/predict` Endpoints + +`/predict` endpoints are currently NOT supported for chat models. You must use `/sync/v1` endpoints for chat functionality. + +## Embedding Models + +You can create models that call the Baseten embeddings API using the `.textEmbeddingModel()` factory method. The Baseten provider uses the high-performance `@basetenlabs/performance-client` for optimal embedding performance. + + + **Important:** Embedding models require a dedicated deployment with a custom + `modelURL`. Unlike chat models, embeddings cannot use Baseten's default Models + API and must specify a dedicated model endpoint. + + +```ts +import { createBaseten } from '@ai-sdk/baseten'; +import { embed, embedMany } from 'ai'; + +const baseten = createBaseten({ + modelURL: 'https://model-{MODEL_ID}.api.baseten.co/sync', +}); + +const embeddingModel = baseten.textEmbeddingModel(); + +// Single embedding +const { embedding } = await embed({ + model: embeddingModel, + value: 'sunny day at the beach', +}); + +// Batch embeddings +const { embeddings } = await embedMany({ + model: embeddingModel, + values: [ + 'sunny day at the beach', + 'rainy afternoon in the city', + 'snowy mountain peak', + ], +}); +``` + +### Endpoint Support for Embeddings + +**Supported:** + +- `/sync` endpoints (Performance Client automatically adds `/v1/embeddings`) +- `/sync/v1` endpoints (automatically strips `/v1` before passing to Performance Client) + +**Not Supported:** + +- `/predict` endpoints (not compatible with Performance Client) + +### Performance Features + +The embedding implementation includes: + +- **High-performance client**: Uses `@basetenlabs/performance-client` for optimal performance +- **Automatic batching**: Efficiently handles multiple texts in a single request +- **Connection reuse**: Performance Client is created once and reused for all requests +- **Built-in retries**: Automatic retry logic for failed requests + +## Error Handling + +The Baseten provider includes built-in error handling for common API errors: + +```ts +import { baseten } from '@ai-sdk/baseten'; +import { generateText } from 'ai'; + +try { + const { text } = await generateText({ + model: baseten('moonshotai/Kimi-K2-Instruct-0905'), + prompt: 'Hello, world!', + }); +} catch (error) { + console.error('Baseten API error:', error.message); +} +``` + +### Common Error Scenarios + +```ts +// Embeddings require a modelURL +try { + baseten.textEmbeddingModel(); +} catch (error) { + // Error: "No model URL provided for embeddings. Please set modelURL option for embeddings." +} + +// /predict endpoints are not supported for chat models +try { + const baseten = createBaseten({ + modelURL: + 'https://model-{MODEL_ID}.api.baseten.co/environments/production/predict', + }); + baseten(); // This will throw an error +} catch (error) { + // Error: "Not supported. You must use a /sync/v1 endpoint for chat models." +} + +// /sync/v1 endpoints are now supported for embeddings +const baseten = createBaseten({ + modelURL: + 'https://model-{MODEL_ID}.api.baseten.co/environments/production/sync/v1', +}); +const embeddingModel = baseten.textEmbeddingModel(); // This works fine! + +// /predict endpoints are not supported for embeddings +try { + const baseten = createBaseten({ + modelURL: + 'https://model-{MODEL_ID}.api.baseten.co/environments/production/predict', + }); + baseten.textEmbeddingModel(); // This will throw an error +} catch (error) { + // Error: "Not supported. You must use a /sync or /sync/v1 endpoint for embeddings." +} + +// Image models are not supported +try { + baseten.imageModel('test-model'); +} catch (error) { + // Error: NoSuchModelError for imageModel +} +``` + + + For more information about Baseten models and deployment options, see the + [Baseten documentation](https://docs.baseten.co/). + diff --git a/content/providers/01-ai-sdk-providers/20-mistral.mdx b/content/providers/01-ai-sdk-providers/20-mistral.mdx index 686b913e03b7..dafe5f2c730e 100644 --- a/content/providers/01-ai-sdk-providers/20-mistral.mdx +++ b/content/providers/01-ai-sdk-providers/20-mistral.mdx @@ -91,6 +91,7 @@ await generateText({ providerOptions: { mistral: { safePrompt: true, // optional safety prompt injection + parallelToolCalls: false, // disable parallel tool calls (one tool per response) } satisfies MistralLanguageModelOptions, }, }); @@ -124,6 +125,12 @@ The following optional provider options are available for Mistral models: Defaults to `true`. +- **parallelToolCalls** _boolean_ + + Whether to enable parallel function calling during tool use. When set to false, the model will use at most one tool per response. + + Defaults to `true`. + ### Document OCR Mistral chat models support document OCR for PDF files. @@ -221,7 +228,7 @@ with Zod, Valibot, or raw JSON Schema. The SDK sends your schema via Mistral's ` ```ts import { mistral } from '@ai-sdk/mistral'; import { generateObject } from 'ai'; -import { z } from 'zod/v3'; +import { z } from 'zod'; const result = await generateObject({ model: mistral('mistral-large-latest'), @@ -243,7 +250,7 @@ You can enable strict JSON Schema validation using a provider option: ```ts highlight="7-11" import { mistral } from '@ai-sdk/mistral'; import { generateObject } from 'ai'; -import { z } from 'zod/v3'; +import { z } from 'zod'; const result = await generateObject({ model: mistral('mistral-large-latest'), diff --git a/content/providers/01-ai-sdk-providers/index.mdx b/content/providers/01-ai-sdk-providers/index.mdx index 6ae9288352c5..490818a9c2b0 100644 --- a/content/providers/01-ai-sdk-providers/index.mdx +++ b/content/providers/01-ai-sdk-providers/index.mdx @@ -69,6 +69,16 @@ Not all providers support all AI SDK features. Here's a quick comparison of the | [Cerebras](/providers/ai-sdk-providers/cerebras) | `llama3.1-8b` | | | | | | [Cerebras](/providers/ai-sdk-providers/cerebras) | `llama3.3-70b` | | | | | | [Fireworks](/providers/ai-sdk-providers/fireworks) | `kimi-k2-instruct` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `openai/gpt-oss-120b` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `Qwen/Qwen3-235B-A22B-Instruct-2507` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `Qwen/Qwen3-Coder-480B-A35B-Instruct` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `moonshotai/Kimi-K2-Instruct-0905` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `moonshotai/Kimi-K2-Instruct` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `deepseek-ai/DeepSeek-V3.1` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `deepseek-ai/DeepSeek-R1-0528` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `deepseek-ai/DeepSeek-V3-0324` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `meta-llama/Llama-4-Maverick-17B-128E-Instruct` | | | | | +| [Baseten](/providers/ai-sdk-providers/baseten) | `meta-llama/Llama-4-Scout-17B-16E-Instruct` | | | | | This table is not exhaustive. Additional models can be found in the provider diff --git a/content/providers/02-openai-compatible-providers/01-custom-providers.mdx b/content/providers/02-openai-compatible-providers/01-custom-providers.mdx index 328966fa82f8..ef45c769704b 100644 --- a/content/providers/02-openai-compatible-providers/01-custom-providers.mdx +++ b/content/providers/02-openai-compatible-providers/01-custom-providers.mdx @@ -41,7 +41,7 @@ The completion, embedding, and image settings are implemented similarly to the c 2. **example-provider.ts** - Main provider implementation: ```ts -import { LanguageModelV1, EmbeddingModelV2 } from '@ai-sdk/provider'; +import { LanguageModelV1, EmbeddingModelV3 } from '@ai-sdk/provider'; import { OpenAICompatibleChatLanguageModel, OpenAICompatibleCompletionLanguageModel, @@ -110,7 +110,7 @@ Creates a text embedding model for text generation. textEmbeddingModel( modelId: ExampleEmbeddingModelId, settings?: ExampleEmbeddingSettings, - ): EmbeddingModelV2; + ): EmbeddingModelV3; /** Creates an image model for image generation. @@ -118,7 +118,7 @@ Creates an image model for image generation. imageModel( modelId: ExampleImageModelId, settings?: ExampleImageSettings, - ): ImageModelV2; + ): ImageModelV3; } export function createExample( diff --git a/content/providers/02-openai-compatible-providers/40-baseten.mdx b/content/providers/02-openai-compatible-providers/40-baseten.mdx deleted file mode 100644 index fd4784f8eeb6..000000000000 --- a/content/providers/02-openai-compatible-providers/40-baseten.mdx +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Baseten -description: Use a Baseten OpenAI compatible API with the AI SDK. ---- - -# Baseten Provider - -[Baseten](https://baseten.co/) is a platform for running and testing LLMs. -It allows you to deploy models that are OpenAI API compatible that you can use with the AI SDK. - -## Setup - -The Baseten provider is available via the `@ai-sdk/openai-compatible` module as it is compatible with the OpenAI API. -You can install it with - - - - - - - - - - - - - - - - - -## Provider Instance - -To use Baseten, you can create a custom provider instance with the `createOpenAICompatible` function from `@ai-sdk/openai-compatible`: - -```ts -import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; - -const BASETEN_MODEL_ID = ''; // e.g. 5q3z8xcw -const BASETEN_MODEL_URL = `https://model-${BASETEN_MODEL_ID}.api.baseten.co/environments/production/sync/v1`; - -const baseten = createOpenAICompatible({ - name: 'baseten', - baseURL: BASETEN_MODEL_URL, - headers: { - Authorization: `Bearer ${process.env.BASETEN_API_KEY ?? ''}`, - }, -}); -``` - -Be sure to have your `BASETEN_API_KEY` set in your environment and the model `` ready. The `` will be given after you have deployed the model on Baseten. - -## Language Models - -You can create [Baseten models](https://www.baseten.co/library/) using a provider instance. -The first argument is the served model name, e.g. `llama`. - -```ts -const model = baseten('llama'); -``` - -### Example - -You can use Baseten language models to generate text with the `generateText` function: - -```ts -import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; -import { generateText } from 'ai'; - -const BASETEN_MODEL_ID = ''; // e.g. 5q3z8xcw -const BASETEN_MODEL_URL = `https://model-${BASETEN_MODEL_ID}.api.baseten.co/environments/production/sync/v1`; - -const baseten = createOpenAICompatible({ - name: 'baseten', - baseURL: BASETEN_MODEL_URL, - headers: { - Authorization: `Bearer ${process.env.BASETEN_API_KEY ?? ''}`, - }, -}); - -const { text } = await generateText({ - model: baseten('llama'), - prompt: 'Tell me about yourself in one sentence', -}); - -console.log(text); -``` - -Baseten language models are also able to generate text in a streaming fashion with the `streamText` function: - -```ts -import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; -import { streamText } from 'ai'; - -const BASETEN_MODEL_ID = ''; // e.g. 5q3z8xcw -const BASETEN_MODEL_URL = `https://model-${BASETEN_MODEL_ID}.api.baseten.co/environments/production/sync/v1`; - -const baseten = createOpenAICompatible({ - name: 'baseten', - baseURL: BASETEN_MODEL_URL, - headers: { - Authorization: `Bearer ${process.env.BASETEN_API_KEY ?? ''}`, - }, -}); - -const result = streamText({ - model: baseten('llama'), - prompt: 'Tell me about yourself in one sentence', -}); - -for await (const message of result.textStream) { - console.log(message); -} -``` - -Baseten language models can also be used in the `generateObject`, and `streamObject` functions. diff --git a/content/providers/02-openai-compatible-providers/index.mdx b/content/providers/02-openai-compatible-providers/index.mdx index 678e87e531d1..309e1245e9b2 100644 --- a/content/providers/02-openai-compatible-providers/index.mdx +++ b/content/providers/02-openai-compatible-providers/index.mdx @@ -13,7 +13,6 @@ We provide detailed documentation for the following OpenAI compatible providers: - [LM Studio](/providers/openai-compatible-providers/lmstudio) - [NIM](/providers/openai-compatible-providers/nim) -- [Baseten](/providers/openai-compatible-providers/baseten) - [Heroku](/providers/openai-compatible-providers/heroku) The general setup and provider instance creation is the same for all of these providers. @@ -85,6 +84,10 @@ You can use the following optional settings to customize the provider instance: Include usage information in streaming responses. When enabled, usage data will be included in the response metadata for streaming requests. Defaults to `undefined` (`false`). +- **supportsStructuredOutputs** _boolean_ + + Set to true if the provider supports structured outputs. Only relevant for `provider()`, `provider.chatModel()`, and `provider.languageModel()`. + ## Language Models You can create provider models using a provider instance. diff --git a/content/providers/03-community-providers/01-custom-providers.mdx b/content/providers/03-community-providers/01-custom-providers.mdx index 4e2d77e064c7..b17649a78739 100644 --- a/content/providers/03-community-providers/01-custom-providers.mdx +++ b/content/providers/03-community-providers/01-custom-providers.mdx @@ -29,19 +29,19 @@ The Language Model Specification V2 creates a robust abstraction layer that work At its heart, the V2 specification defines three main interfaces: -1. **ProviderV2**: The top-level interface that serves as a factory for different model types +1. **ProviderV3**: The top-level interface that serves as a factory for different model types 2. **LanguageModelV2**: The primary interface for text generation models -3. **EmbeddingModelV2** and **ImageModelV2**: Interfaces for embeddings and image generation +3. **EmbeddingModelV3** and **ImageModelV3**: Interfaces for embeddings and image generation -### `ProviderV2` +### `ProviderV3` -The `ProviderV2` interface acts as the entry point: +The `ProviderV3` interface acts as the entry point: ```ts -interface ProviderV2 { +interface ProviderV3 { languageModel(modelId: string): LanguageModelV2; - textEmbeddingModel(modelId: string): EmbeddingModelV2; - imageModel(modelId: string): ImageModelV2; + textEmbeddingModel(modelId: string): EmbeddingModelV3; + imageModel(modelId: string): ImageModelV3; } ``` @@ -439,11 +439,11 @@ import { loadApiKey, withoutTrailingSlash, } from '@ai-sdk/provider-utils'; -import { ProviderV2 } from '@ai-sdk/provider'; +import { ProviderV3 } from '@ai-sdk/provider'; import { CustomChatLanguageModel } from './custom-chat-language-model'; -// Define your provider interface extending ProviderV2 -interface CustomProvider extends ProviderV2 { +// Define your provider interface extending ProviderV3 +interface CustomProvider extends ProviderV3 { (modelId: string, settings?: CustomChatSettings): CustomChatLanguageModel; // Add specific methods for different model types diff --git a/content/providers/05-observability/axiom.mdx b/content/providers/05-observability/axiom.mdx new file mode 100644 index 000000000000..d0373794f8a6 --- /dev/null +++ b/content/providers/05-observability/axiom.mdx @@ -0,0 +1,178 @@ +--- +title: Axiom +description: Measure, observe, and improve your AI SDK application with Axiom +--- + +# Axiom Observability + +**Axiom** is a data platform with specialized features for **AI engineering workflows**, helping you build sophisticated AI systems with confidence. + +Axiom’s integration with the AI SDK uses a model wrapper to automatically capture detailed traces for every LLM call, giving you immediate visibility into your application's performance, cost, and behavior. + +## Setup + +### 1. Configure Axiom + +First, you'll need an Axiom organization, a dataset to send traces to, and an API token. + +- [Create an Axiom organization](https://app.axiom.co/register). +- [Create a new dataset](https://app.axiom.co/datasets) (e.g., `my-ai-app`). +- [Create an API token](https://app.axiom.co/settings/api-tokens) with ingest permissions for your dataset. + +### 2. Install the Axiom SDK + +Install the Axiom package in your project: + + + + + + + + + + + + + + + + + +### 3. Set Environment Variables + +Configure your environment variables in a `.env` file. This uses the standard OpenTelemetry configuration to send traces directly to your Axiom dataset. + +```bash filename=".env" +# Axiom Configuration +AXIOM_TOKEN="YOUR_AXIOM_API_TOKEN" +AXIOM_DATASET="your-axiom-dataset-name" + +# Vercel and OpenTelemetry Configuration +OTEL_SERVICE_NAME="my-ai-app" +OTEL_EXPORTER_OTLP_ENDPOINT="https://api.axiom.co/v1/traces" +OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer YOUR_AXIOM_API_TOKEN,X-Axiom-Dataset=your-axiom-dataset-name" + +# Your AI Provider Key +OPENAI_API_KEY="YOUR_OPENAI_API_KEY" +``` + +Replace the placeholder values with your actual Axiom token and dataset name. + +### 4. Set Up Instrumentation + +To send data to Axiom, configure a tracer. For example, use a dedicated instrumentation file and load it before the rest of your app. An example configuration for a Node.js environment: + +1. Install dependencies: + + + + + + + + + + + + + + + + +2. Create instrumentation file: + +```typescript filename="src/instrumentation.ts" +import { trace } from '@opentelemetry/api'; +import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; +import type { Resource } from '@opentelemetry/resources'; +import { resourceFromAttributes } from '@opentelemetry/resources'; +import { NodeSDK } from '@opentelemetry/sdk-node'; +import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'; +import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; +import { initAxiomAI, RedactionPolicy } from 'axiom/ai'; + +const tracer = trace.getTracer('my-tracer'); + +const sdk = new NodeSDK({ + resource: resourceFromAttributes({ + [ATTR_SERVICE_NAME]: 'my-ai-app', + }) as Resource, + spanProcessor: new SimpleSpanProcessor( + new OTLPTraceExporter({ + url: `https://api.axiom.co/v1/traces`, + headers: { + Authorization: `Bearer ${process.env.AXIOM_TOKEN}`, + 'X-Axiom-Dataset': process.env.AXIOM_DATASET, + }, + }), + ), +}); + +sdk.start(); + +initAxiomAI({ tracer, redactionPolicy: RedactionPolicy.AxiomDefault }); +``` + +### 5. Wrap and Use the AI Model + +In your application code, import `wrapAISDKModel` from Axiom and use it to wrap your existing AI SDK model client. + +```typescript +import { createOpenAI } from '@ai-sdk/openai'; +import { generateText } from 'ai'; +import { wrapAISDKModel } from 'axiom/ai'; + +// 1. Create your standard AI model provider +const openaiProvider = createOpenAI({ + apiKey: process.env.OPENAI_API_KEY, +}); + +// 2. Wrap the model to enable automatic tracing +const tracedGpt4o = wrapAISDKModel(openaiProvider('gpt-4o')); + +// 3. Use the wrapped model as you normally would +const { text } = await generateText({ + model: tracedGpt4o, + prompt: 'What is the capital of Spain?', +}); + +console.log(text); +``` + +Any calls made using the `tracedGpt4o` model will now automatically send detailed traces to your Axiom dataset. + +## What You'll See in Axiom + +Once integrated, your Axiom dataset will include: + +- **AI Trace Waterfall:** A dedicated view to visualize single and multi-step LLM workflows. +- **Gen AI Dashboard:** A pre-built dashboard to monitor cost, latency, token usage, and error rates. +- **Detailed Spans:** Rich telemetry for every call, including the full prompt and completion, token counts, and model information. + +## Advanced Usage + +Axiom’s AI SDK offers more advanced instrumentation for deeper visibility: + +- **Business Context:** Use the `withSpan` function to group LLM calls under a specific business capability (e.g., `customer_support_agent`). +- **Tool Tracing:** Use the `wrapTool` helper to automatically trace the execution of tools your AI model calls. + +To learn more about these features, see the [Axiom AI SDK Instrumentation guide](https://axiom.co/docs/ai-engineering/observe/axiom-ai-sdk-instrumentation). + +## Additional Resources + +- [Axiom AI Engineering Documentation](https://axiom.co/docs/ai-engineering/overview) +- [Axiom AI SDK on GitHub](https://github.com/axiomhq/ai) +- [Full Quickstart Guide](https://axiom.co/docs/ai-engineering/quickstart) diff --git a/content/providers/05-observability/index.mdx b/content/providers/05-observability/index.mdx index 85b76221843b..5341c22b2686 100644 --- a/content/providers/05-observability/index.mdx +++ b/content/providers/05-observability/index.mdx @@ -7,10 +7,9 @@ description: AI SDK Integration for monitoring and tracing LLM applications Several LLM observability providers offer integrations with the AI SDK telemetry data: +- [Axiom](/providers/observability/axiom) - [Braintrust](/providers/observability/braintrust) - [Helicone](/providers/observability/helicone) -- [Traceloop](/providers/observability/traceloop) -- [Weave](/providers/observability/weave) - [Langfuse](/providers/observability/langfuse) - [LangSmith](/providers/observability/langsmith) - [Laminar](/providers/observability/laminar) @@ -19,6 +18,8 @@ Several LLM observability providers offer integrations with the AI SDK telemetry - [HoneyHive](https://docs.honeyhive.ai/integrations/vercel) - [Scorecard](/providers/observability/scorecard) - [SigNoz](/providers/observability/signoz) +- [Traceloop](/providers/observability/traceloop) +- [Weave](/providers/observability/weave) There are also providers that provide monitoring and tracing for the AI SDK through model wrappers: diff --git a/contributing/add-new-provider.md b/contributing/add-new-provider.md new file mode 100644 index 000000000000..d6923a084730 --- /dev/null +++ b/contributing/add-new-provider.md @@ -0,0 +1,25 @@ +# Add new provider + +## `@ai-sdk/` vs 3rd party package + +Every provider is welcome to create a 3rd party package. We are happy to link to it from our documentation. + +If you would prefer a 1st party `@ai-sdk/` package, please create an issue first to discuss. + +## Example + +https://github.com/vercel/ai/pull/8136/files + +## How + +1. Create new folder `packages/` +2. Set version in `packages//package.json` to `0.0.0` +3. Create changeset for new package with `major` +4. Add examples to `examples/ai-core/src/*/.ts` depending on what model types the provider supports +5. Add documentation in `content/providers/01-ai-sdk-providers/-.mdx` + +See also [providers.md](providers.md) + +## When in pre-release mode + +If `main` is set up to publish `beta` releases, no further action is necessary. Just make sure not to backport it to the `vX.Y` stable branch since it will result in an npm version conflict once we exit pre-release mode on `main` diff --git a/contributing/branches.md b/contributing/branches.md deleted file mode 100644 index 7d0145a5fcd0..000000000000 --- a/contributing/branches.md +++ /dev/null @@ -1,8 +0,0 @@ -# Branches - -`main` is always the development branch. - -When we start working on a new major or minor release, -the old stable release will be branched off, e.g. `v4` -and the changesets for `main` will enter pre-release mode, -e.g. `alpha` or `beta`. diff --git a/contributing/building-new-features.md b/contributing/building-new-features.md new file mode 100644 index 000000000000..81939b86bcef --- /dev/null +++ b/contributing/building-new-features.md @@ -0,0 +1,9 @@ +# Building new features + +1. Create/update generateText example +2. Create/update streamText example +3. Create/update UI tests (next-openai) + - always test follow up message + - consider testing with store: false + +Example: https://github.com/vercel/ai/pull/8691 diff --git a/contributing/documentation.md b/contributing/documentation.md new file mode 100644 index 000000000000..3e110778840f --- /dev/null +++ b/contributing/documentation.md @@ -0,0 +1,17 @@ +# Documentation + +## Making Changes + +To make changes to the documentation website (https://ai-sdk.dev), modify files in the `/content` directory. Please follow conventions of similar files. + +Note: There is currently no way to preview documentation changes locally before submitting. + +## Pull Request Guidelines + +All documentation PRs should be prefixed with `docs:` in the title. + +Run `npm run prettier-fix` to solve formatting issues. + +## Update Schedule + +Documentation is sourced and updated every 3 hours on the live site. diff --git a/contributing/releases.md b/contributing/releases.md index abc1b92f2889..2e46d0fd20d9 100644 --- a/contributing/releases.md +++ b/contributing/releases.md @@ -1,13 +1,42 @@ # Releases +We use [changesets](https://github.com/changesets/action) for automated releases. + ## Changesets -Each pull request that modifies production code (not examples/docs) needs to have a changeset. +- Every pull request that modifies production code (not `examples`/`docs`) must include a changeset. +- By default, use `patch` (non-breaking). +- To override, apply the `minor` or `major` label (CI enforces `patch` otherwise). + +## Regular Releases + +- The [Changesets action](https://github.com/changesets/action) automatically creates a **Version Packages** PR. +- Merging this PR triggers the release workflow, which publishes the npm packages. + +## Maintenance Releases + +- Enable the [`release` workflow](https://github.com/vercel/ai/blob/main/.github/workflows/release.yml) on the maintenance branch. +- Only `patch` releases are allowed. +- To release: + 1. Create a pull request against the maintenance branch. + 2. Merge it to trigger the release workflow. + +## Beta Releases + +- Create a maintenance branch for the current stable minor version (e.g., if latest is `5.0.24`, create `v5.0`). +- Enable the [`release` workflow](https://github.com/vercel/ai/blob/main/.github/workflows/release.yml) on that branch and set up branch protections. +- Switch `main` to beta release mode: + + ```bash + pnpm changeset pre enter beta + ``` -Unless a minor or major release is planned (often on a separate branch), changesets should be `patch` and non-breaking. + (This creates a PR like #8710). -## Releasing +- During beta: All PRs continue to target main. +- In order to backport pull requests to the stable release, add the `backport` label. This will create a new pull request with the same changes against the stable release branch. +- To exit the beta release mode, run: -Patch releases can be created by merging the `Version Packages` pull requests that are automatically created by the corresponding GitHub action. -You might need to close/reopen them to trigger the workflows. -Once merged, the release action will release the npm packages. + ```bash + pnpm changeset pre exit + ``` diff --git a/examples/ai-core/package.json b/examples/ai-core/package.json index 3c94cc4f3f75..5d30a9118bb3 100644 --- a/examples/ai-core/package.json +++ b/examples/ai-core/package.json @@ -7,6 +7,7 @@ "@ai-sdk/anthropic": "workspace:*", "@ai-sdk/assemblyai": "workspace:*", "@ai-sdk/azure": "workspace:*", + "@ai-sdk/baseten": "workspace:*", "@ai-sdk/cerebras": "workspace:*", "@ai-sdk/cohere": "workspace:*", "@ai-sdk/deepgram": "workspace:*", diff --git a/examples/ai-core/src/agent/openai-stream-tools.ts b/examples/ai-core/src/agent/openai-stream-tools.ts index ffdfdda67cc4..b044128e0659 100644 --- a/examples/ai-core/src/agent/openai-stream-tools.ts +++ b/examples/ai-core/src/agent/openai-stream-tools.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { Experimental_Agent as Agent, stepCountIs, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const agent = new Agent({ diff --git a/examples/ai-core/src/complex/math-agent/agent-required-tool-choice.ts b/examples/ai-core/src/complex/math-agent/agent-required-tool-choice.ts index 4b5b38e519af..d2d3a4109c5d 100644 --- a/examples/ai-core/src/complex/math-agent/agent-required-tool-choice.ts +++ b/examples/ai-core/src/complex/math-agent/agent-required-tool-choice.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, stepCountIs, tool } from 'ai'; import 'dotenv/config'; import * as mathjs from 'mathjs'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { toolCalls } = await generateText({ diff --git a/examples/ai-core/src/complex/math-agent/agent.ts b/examples/ai-core/src/complex/math-agent/agent.ts index 582a3986cae6..3a945d7aff8c 100644 --- a/examples/ai-core/src/complex/math-agent/agent.ts +++ b/examples/ai-core/src/complex/math-agent/agent.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, stepCountIs, tool } from 'ai'; import 'dotenv/config'; import * as mathjs from 'mathjs'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { text: answer } = await generateText({ diff --git a/examples/ai-core/src/e2e/feature-test-suite.ts b/examples/ai-core/src/e2e/feature-test-suite.ts index 3cb313391fd6..def2cbc67e30 100644 --- a/examples/ai-core/src/e2e/feature-test-suite.ts +++ b/examples/ai-core/src/e2e/feature-test-suite.ts @@ -1,7 +1,7 @@ import type { GoogleGenerativeAIProviderMetadata } from '@ai-sdk/google'; import type { - EmbeddingModelV2, - ImageModelV2, + EmbeddingModelV3, + ImageModelV3, LanguageModelV2, } from '@ai-sdk/provider'; import { @@ -17,7 +17,7 @@ import { } from 'ai'; import fs from 'fs'; import { describe, expect, it, vi } from 'vitest'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export type Capability = | 'audioInput' @@ -58,17 +58,17 @@ export const createLanguageModelWithCapabilities = ( }); export const createEmbeddingModelWithCapabilities = ( - model: EmbeddingModelV2, + model: EmbeddingModelV3, capabilities: ModelCapabilities = ['embedding'], -): ModelWithCapabilities> => ({ +): ModelWithCapabilities> => ({ model, capabilities, }); export const createImageModelWithCapabilities = ( - model: ImageModelV2, + model: ImageModelV3, capabilities: ModelCapabilities = ['imageGeneration'], -): ModelWithCapabilities => ({ +): ModelWithCapabilities => ({ model, capabilities, }); @@ -76,9 +76,9 @@ export const createImageModelWithCapabilities = ( export interface ModelVariants { invalidModel?: LanguageModelV2; languageModels?: ModelWithCapabilities[]; - embeddingModels?: ModelWithCapabilities>[]; - invalidImageModel?: ImageModelV2; - imageModels?: ModelWithCapabilities[]; + embeddingModels?: ModelWithCapabilities>[]; + invalidImageModel?: ImageModelV3; + imageModels?: ModelWithCapabilities[]; } export interface TestSuiteOptions { diff --git a/examples/ai-core/src/e2e/google-vertex.test.ts b/examples/ai-core/src/e2e/google-vertex.test.ts index 3f79e0d2eafb..b7c5ac7886b1 100644 --- a/examples/ai-core/src/e2e/google-vertex.test.ts +++ b/examples/ai-core/src/e2e/google-vertex.test.ts @@ -1,6 +1,6 @@ import { vertex as vertexNode } from '@ai-sdk/google-vertex'; import { vertex as vertexEdge } from '@ai-sdk/google-vertex/edge'; -import { ImageModelV2, LanguageModelV2 } from '@ai-sdk/provider'; +import { ImageModelV3, LanguageModelV2 } from '@ai-sdk/provider'; import { APICallError, experimental_generateImage as generateImage } from 'ai'; import 'dotenv/config'; import { describe, expect, it, vi } from 'vitest'; @@ -55,8 +55,8 @@ const createSearchGroundedModel = ( }); const createModelObject = ( - imageModel: ImageModelV2, -): { model: ImageModelV2; modelId: string } => ({ + imageModel: ImageModelV3, +): { model: ImageModelV3; modelId: string } => ({ model: imageModel, modelId: imageModel.modelId, }); @@ -64,8 +64,8 @@ const createModelObject = ( const createImageModel = ( vertex: typeof vertexNode | typeof vertexEdge, modelId: string, - additionalTests: ((model: ImageModelV2) => void)[] = [], -): ModelWithCapabilities => { + additionalTests: ((model: ImageModelV3) => void)[] = [], +): ModelWithCapabilities => { const model = vertex.image(modelId); if (additionalTests.length > 0) { @@ -151,7 +151,7 @@ function detectImageMediaType( return undefined; } -const imageTest = (model: ImageModelV2) => { +const imageTest = (model: ImageModelV3) => { vi.setConfig({ testTimeout: 10000 }); it('should generate an image with correct dimensions and format', async () => { diff --git a/examples/ai-core/src/e2e/google.test.ts b/examples/ai-core/src/e2e/google.test.ts index 3427e6db4016..6818c16713ba 100644 --- a/examples/ai-core/src/e2e/google.test.ts +++ b/examples/ai-core/src/e2e/google.test.ts @@ -1,5 +1,5 @@ import { GoogleErrorData, google as provider } from '@ai-sdk/google'; -import { APICallError, ImageModelV2, LanguageModelV2 } from '@ai-sdk/provider'; +import { APICallError, ImageModelV3, LanguageModelV2 } from '@ai-sdk/provider'; import 'dotenv/config'; import { expect } from 'vitest'; import { @@ -20,7 +20,7 @@ const createChatModel = ( const createImageModel = ( modelId: string, -): ModelWithCapabilities => +): ModelWithCapabilities => createImageModelWithCapabilities(provider.image(modelId)); const createSearchGroundedModel = ( diff --git a/examples/ai-core/src/embed-many/baseten.ts b/examples/ai-core/src/embed-many/baseten.ts new file mode 100644 index 000000000000..af2147d3a9c2 --- /dev/null +++ b/examples/ai-core/src/embed-many/baseten.ts @@ -0,0 +1,31 @@ +import { createBaseten } from '@ai-sdk/baseten'; +import { embedMany } from 'ai'; +import 'dotenv/config'; + +async function main() { + // Using Performance Client with custom model URL for batch embeddings + // Performance Client automatically handles batching and parallel processing + const EMBEDDING_MODEL_ID = ''; // e.g. 03y7n6e3 + const EMBEDDING_MODEL_URL = `https://model-${EMBEDDING_MODEL_ID}.api.baseten.co/environments/production/sync`; + + const baseten = createBaseten({ + modelURL: EMBEDDING_MODEL_URL, + }); + + const { embeddings, usage } = await embedMany({ + model: baseten.textEmbeddingModel(), + values: [ + 'sunny day at the beach', + 'rainy afternoon in the city', + 'snowy mountain peak', + 'foggy morning in the forest', + ], + }); + + console.log('Number of embeddings:', embeddings.length); + console.log('Embedding dimension:', embeddings[0].length); + console.log('First embedding (first 5 values):', embeddings[0].slice(0, 5)); + console.log('Usage:', usage); +} + +main().catch(console.error); diff --git a/examples/ai-core/src/embed/baseten.ts b/examples/ai-core/src/embed/baseten.ts new file mode 100644 index 000000000000..9732bc719e9a --- /dev/null +++ b/examples/ai-core/src/embed/baseten.ts @@ -0,0 +1,25 @@ +import { createBaseten } from '@ai-sdk/baseten'; +import { embed } from 'ai'; +import 'dotenv/config'; + +async function main() { + // Using Performance Client with custom model URL for embeddings + // Performance Client requires /sync endpoints and handles batching automatically + const EMBEDDING_MODEL_ID = ''; // e.g. 03y7n6e3 + const EMBEDDING_MODEL_URL = `https://model-${EMBEDDING_MODEL_ID}.api.baseten.co/environments/production/sync`; + + const baseten = createBaseten({ + modelURL: EMBEDDING_MODEL_URL, + }); + + const { embedding, usage } = await embed({ + model: baseten.textEmbeddingModel(), + value: 'sunny day at the beach', + }); + + console.log('Embedding dimension:', embedding.length); + console.log('First 5 values:', embedding.slice(0, 5)); + console.log('Usage:', usage); +} + +main().catch(console.error); diff --git a/examples/ai-core/src/generate-image/google-gemini-editing-url.ts b/examples/ai-core/src/generate-image/google-gemini-editing-url.ts new file mode 100644 index 000000000000..9248316d63c6 --- /dev/null +++ b/examples/ai-core/src/generate-image/google-gemini-editing-url.ts @@ -0,0 +1,44 @@ +import { google } from '@ai-sdk/google'; +import { generateText } from 'ai'; +import fs from 'node:fs'; +import 'dotenv/config'; + +async function editImage() { + const editResult = await generateText({ + model: google('gemini-2.5-flash-image-preview'), + prompt: [ + { + role: 'user', + content: [ + { + type: 'text', + text: 'Add a small wizard hat to this cat. Keep everything else the same.', + }, + { + type: 'image', + image: new URL( + 'https://raw.githubusercontent.com/vercel/ai/refs/heads/main/examples/ai-core/data/comic-cat.png', + ), + mediaType: 'image/jpeg', + }, + ], + }, + ], + }); + + // Save the edited image + const timestamp = Date.now(); + fs.mkdirSync('output', { recursive: true }); + + for (const file of editResult.files) { + if (file.mediaType.startsWith('image/')) { + await fs.promises.writeFile( + `output/edited-${timestamp}.png`, + file.uint8Array, + ); + console.log(`Saved edited image: output/edited-${timestamp}.png`); + } + } +} + +editImage().catch(console.error); diff --git a/examples/ai-core/src/generate-image/google-gemini-editing.ts b/examples/ai-core/src/generate-image/google-gemini-editing.ts index c4fe667d95ef..e15bf572c80b 100644 --- a/examples/ai-core/src/generate-image/google-gemini-editing.ts +++ b/examples/ai-core/src/generate-image/google-gemini-editing.ts @@ -7,9 +7,6 @@ async function main() { console.log('Generating base cat image...'); const baseResult = await generateText({ model: google('gemini-2.5-flash-image-preview'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, prompt: 'A photorealistic picture of a fluffy ginger cat sitting on a wooden table', }); @@ -38,9 +35,6 @@ async function main() { console.log('Adding wizard hat...'); const editResult = await generateText({ model: google('gemini-2.5-flash-image-preview'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, prompt: [ { role: 'user', diff --git a/examples/ai-core/src/generate-image/google-gemini-image.ts b/examples/ai-core/src/generate-image/google-gemini-image.ts index a28382131ad0..53163f9fee65 100644 --- a/examples/ai-core/src/generate-image/google-gemini-image.ts +++ b/examples/ai-core/src/generate-image/google-gemini-image.ts @@ -6,9 +6,6 @@ import 'dotenv/config'; async function main() { const result = await generateText({ model: google('gemini-2.5-flash-image-preview'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, prompt: 'Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme', }); diff --git a/examples/ai-core/src/generate-image/google-gemini-minimal.ts b/examples/ai-core/src/generate-image/google-gemini-minimal.ts index 310e4ffd269d..aeeb8586e5bd 100644 --- a/examples/ai-core/src/generate-image/google-gemini-minimal.ts +++ b/examples/ai-core/src/generate-image/google-gemini-minimal.ts @@ -5,9 +5,6 @@ import 'dotenv/config'; async function main() { const { files } = await generateText({ model: google('gemini-2.5-flash-image-preview'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, prompt: 'A nano banana in a fancy restaurant', }); diff --git a/examples/ai-core/src/generate-object/amazon-bedrock.ts b/examples/ai-core/src/generate-object/amazon-bedrock.ts index 3da48ae2f2be..5b120dd092bd 100644 --- a/examples/ai-core/src/generate-object/amazon-bedrock.ts +++ b/examples/ai-core/src/generate-object/amazon-bedrock.ts @@ -1,7 +1,7 @@ import { bedrock } from '@ai-sdk/amazon-bedrock'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/anthropic.ts b/examples/ai-core/src/generate-object/anthropic.ts index 33a77eb9f664..1c9756f612f2 100644 --- a/examples/ai-core/src/generate-object/anthropic.ts +++ b/examples/ai-core/src/generate-object/anthropic.ts @@ -1,7 +1,7 @@ import { anthropic } from '@ai-sdk/anthropic'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/azure.ts b/examples/ai-core/src/generate-object/azure.ts index b9b73c6f4263..59324627d027 100644 --- a/examples/ai-core/src/generate-object/azure.ts +++ b/examples/ai-core/src/generate-object/azure.ts @@ -1,7 +1,7 @@ import { azure } from '@ai-sdk/azure'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/cerebras.ts b/examples/ai-core/src/generate-object/cerebras.ts new file mode 100644 index 000000000000..599b59ef732f --- /dev/null +++ b/examples/ai-core/src/generate-object/cerebras.ts @@ -0,0 +1,30 @@ +import { cerebras } from '@ai-sdk/cerebras'; +import { generateObject } from 'ai'; +import 'dotenv/config'; +import { z } from 'zod'; + +async function main() { + const result = await generateObject({ + model: cerebras('gpt-oss-120b'), + schema: z.object({ + recipe: z.object({ + name: z.string(), + ingredients: z.array( + z.object({ + name: z.string(), + amount: z.string(), + }), + ), + steps: z.array(z.string()), + }), + }), + prompt: 'Generate a lasagna recipe.', + }); + + console.log(JSON.stringify(result.object.recipe, null, 2)); + console.log(); + console.log('Token usage:', result.usage); + console.log('Finish reason:', result.finishReason); +} + +main().catch(console.error); diff --git a/examples/ai-core/src/generate-object/cohere.ts b/examples/ai-core/src/generate-object/cohere.ts index ea5e60a5219a..daaef72de5f7 100644 --- a/examples/ai-core/src/generate-object/cohere.ts +++ b/examples/ai-core/src/generate-object/cohere.ts @@ -1,7 +1,7 @@ import { cohere } from '@ai-sdk/cohere'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/fireworks.ts b/examples/ai-core/src/generate-object/fireworks.ts index 4cd14b7a9487..73f64413cb78 100644 --- a/examples/ai-core/src/generate-object/fireworks.ts +++ b/examples/ai-core/src/generate-object/fireworks.ts @@ -1,7 +1,7 @@ import { fireworks } from '@ai-sdk/fireworks'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/gateway.ts b/examples/ai-core/src/generate-object/gateway.ts index 84945393d3be..e6e37821a760 100644 --- a/examples/ai-core/src/generate-object/gateway.ts +++ b/examples/ai-core/src/generate-object/gateway.ts @@ -1,6 +1,6 @@ import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/google-complex-1.ts b/examples/ai-core/src/generate-object/google-complex-1.ts index 17907cf08961..5895d7f094bc 100644 --- a/examples/ai-core/src/generate-object/google-complex-1.ts +++ b/examples/ai-core/src/generate-object/google-complex-1.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { // split schema support: diff --git a/examples/ai-core/src/generate-object/google-complex-2.ts b/examples/ai-core/src/generate-object/google-complex-2.ts index 2be33324159a..00d16fd7e8c8 100644 --- a/examples/ai-core/src/generate-object/google-complex-2.ts +++ b/examples/ai-core/src/generate-object/google-complex-2.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { // enum support: diff --git a/examples/ai-core/src/generate-object/google-gemini-files.ts b/examples/ai-core/src/generate-object/google-gemini-files.ts index 18cd10ef6799..04163bb357c5 100644 --- a/examples/ai-core/src/generate-object/google-gemini-files.ts +++ b/examples/ai-core/src/generate-object/google-gemini-files.ts @@ -3,7 +3,7 @@ import { google } from '@ai-sdk/google'; import { generateObject } from 'ai'; import path from 'path'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const fileManager = new GoogleAIFileManager( diff --git a/examples/ai-core/src/generate-object/google-no-structured-output.ts b/examples/ai-core/src/generate-object/google-no-structured-output.ts index 5f355c39d9ff..2c01e0b9ee46 100644 --- a/examples/ai-core/src/generate-object/google-no-structured-output.ts +++ b/examples/ai-core/src/generate-object/google-no-structured-output.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/google-pdf-url.ts b/examples/ai-core/src/generate-object/google-pdf-url.ts index 9318bea1cfef..3d44ad8b1262 100644 --- a/examples/ai-core/src/generate-object/google-pdf-url.ts +++ b/examples/ai-core/src/generate-object/google-pdf-url.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { object: summary } = await generateObject({ diff --git a/examples/ai-core/src/generate-object/google-vertex-anthropic.ts b/examples/ai-core/src/generate-object/google-vertex-anthropic.ts index b9bb9e56df9b..c61f983fa97d 100644 --- a/examples/ai-core/src/generate-object/google-vertex-anthropic.ts +++ b/examples/ai-core/src/generate-object/google-vertex-anthropic.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { vertexAnthropic } from '@ai-sdk/google-vertex/anthropic'; import { generateObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/google-vertex.ts b/examples/ai-core/src/generate-object/google-vertex.ts index 0d2484a850e5..70fac65124fc 100644 --- a/examples/ai-core/src/generate-object/google-vertex.ts +++ b/examples/ai-core/src/generate-object/google-vertex.ts @@ -1,7 +1,7 @@ import { vertex } from '@ai-sdk/google-vertex'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/google.ts b/examples/ai-core/src/generate-object/google.ts index 359c090f7278..06149bd45bf6 100644 --- a/examples/ai-core/src/generate-object/google.ts +++ b/examples/ai-core/src/generate-object/google.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/groq.ts b/examples/ai-core/src/generate-object/groq.ts index 70abd4685e52..8466665dc273 100644 --- a/examples/ai-core/src/generate-object/groq.ts +++ b/examples/ai-core/src/generate-object/groq.ts @@ -1,7 +1,7 @@ import { groq } from '@ai-sdk/groq'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/mistral.ts b/examples/ai-core/src/generate-object/mistral.ts index 5dbf095fc1ad..69136230d18a 100644 --- a/examples/ai-core/src/generate-object/mistral.ts +++ b/examples/ai-core/src/generate-object/mistral.ts @@ -1,7 +1,7 @@ import { mistral } from '@ai-sdk/mistral'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/mock-error.ts b/examples/ai-core/src/generate-object/mock-error.ts index 8812b7afe73b..d2c8fee769cb 100644 --- a/examples/ai-core/src/generate-object/mock-error.ts +++ b/examples/ai-core/src/generate-object/mock-error.ts @@ -1,7 +1,7 @@ import { generateObject, NoObjectGeneratedError } from 'ai'; import { MockLanguageModelV2 } from 'ai/test'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { try { diff --git a/examples/ai-core/src/generate-object/mock-repair-add-close.ts b/examples/ai-core/src/generate-object/mock-repair-add-close.ts index d00accf9133f..bd9a8cebe8c9 100644 --- a/examples/ai-core/src/generate-object/mock-repair-add-close.ts +++ b/examples/ai-core/src/generate-object/mock-repair-add-close.ts @@ -1,7 +1,7 @@ import { generateObject, JSONParseError } from 'ai'; import { MockLanguageModelV2 } from 'ai/test'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/mock.ts b/examples/ai-core/src/generate-object/mock.ts index 5da3d7ce921c..61f2bed65c7b 100644 --- a/examples/ai-core/src/generate-object/mock.ts +++ b/examples/ai-core/src/generate-object/mock.ts @@ -1,7 +1,7 @@ import { generateObject } from 'ai'; import { MockLanguageModelV2 } from 'ai/test'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { object, usage } = await generateObject({ diff --git a/examples/ai-core/src/generate-object/nim.ts b/examples/ai-core/src/generate-object/nim.ts index e2eed9137829..a0b53a37d764 100644 --- a/examples/ai-core/src/generate-object/nim.ts +++ b/examples/ai-core/src/generate-object/nim.ts @@ -1,6 +1,6 @@ import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; import { generateObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import 'dotenv/config'; async function main() { diff --git a/examples/ai-core/src/generate-object/openai-5-reasoning.ts b/examples/ai-core/src/generate-object/openai-5-reasoning.ts index d1db7d1bf7d7..f3a3b467c159 100644 --- a/examples/ai-core/src/generate-object/openai-5-reasoning.ts +++ b/examples/ai-core/src/generate-object/openai-5-reasoning.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai-array.ts b/examples/ai-core/src/generate-object/openai-array.ts index 74f42bda5bc4..9392bf40d657 100644 --- a/examples/ai-core/src/generate-object/openai-array.ts +++ b/examples/ai-core/src/generate-object/openai-array.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai-compatible-togetherai.ts b/examples/ai-core/src/generate-object/openai-compatible-togetherai.ts index e2d5064eeb0d..bb37f6a5db20 100644 --- a/examples/ai-core/src/generate-object/openai-compatible-togetherai.ts +++ b/examples/ai-core/src/generate-object/openai-compatible-togetherai.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; import { generateObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const togetherai = createOpenAICompatible({ @@ -10,6 +10,7 @@ async function main() { headers: { Authorization: `Bearer ${process.env.TOGETHER_AI_API_KEY}`, }, + supportsStructuredOutputs: true, }); const model = togetherai.chatModel('mistralai/Mistral-7B-Instruct-v0.1'); const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai-date-parsing.ts b/examples/ai-core/src/generate-object/openai-date-parsing.ts index b7eaff1b6fa4..b80416dedee8 100644 --- a/examples/ai-core/src/generate-object/openai-date-parsing.ts +++ b/examples/ai-core/src/generate-object/openai-date-parsing.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { diff --git a/examples/ai-core/src/generate-object/openai-full-result.ts b/examples/ai-core/src/generate-object/openai-full-result.ts index 0f34a1e61d07..f47c2323f311 100644 --- a/examples/ai-core/src/generate-object/openai-full-result.ts +++ b/examples/ai-core/src/generate-object/openai-full-result.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai-multimodal.ts b/examples/ai-core/src/generate-object/openai-multimodal.ts index 342faaf62445..1f3a1ec2da6e 100644 --- a/examples/ai-core/src/generate-object/openai-multimodal.ts +++ b/examples/ai-core/src/generate-object/openai-multimodal.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; import fs from 'node:fs'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { object } = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai-reasoning.ts b/examples/ai-core/src/generate-object/openai-reasoning.ts index bdc4209dea4b..d93468b1dcd3 100644 --- a/examples/ai-core/src/generate-object/openai-reasoning.ts +++ b/examples/ai-core/src/generate-object/openai-reasoning.ts @@ -1,7 +1,7 @@ import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai-request-body.ts b/examples/ai-core/src/generate-object/openai-request-body.ts index 14d4516cfe5e..88d609253fed 100644 --- a/examples/ai-core/src/generate-object/openai-request-body.ts +++ b/examples/ai-core/src/generate-object/openai-request-body.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { request } = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai-request-headers.ts b/examples/ai-core/src/generate-object/openai-request-headers.ts new file mode 100644 index 000000000000..81f02ff1ab04 --- /dev/null +++ b/examples/ai-core/src/generate-object/openai-request-headers.ts @@ -0,0 +1,39 @@ +import { createOpenAI } from '@ai-sdk/openai'; +import { generateObject } from 'ai'; +import 'dotenv/config'; +import { z } from 'zod'; + +async function main() { + let headers; + const openai = createOpenAI({ + fetch: (url, init) => { + headers = { + ...init?.headers, + authorization: 'REDACTED', + }; + return fetch(url, init); + }, + }); + const options = { + model: openai('gpt-4o-mini'), + schema: z.object({ + recipe: z.object({ + name: z.string(), + ingredients: z.array( + z.object({ + name: z.string(), + amount: z.string(), + }), + ), + steps: z.array(z.string()), + }), + }), + prompt: 'Generate a lasagna recipe.', + }; + await generateObject(options); + + console.log('REQUEST HEADERS'); + console.log(headers); +} + +main().catch(console.error); diff --git a/examples/ai-core/src/generate-object/openai-responses.ts b/examples/ai-core/src/generate-object/openai-responses.ts index 3d8fdcd5c6f1..a1643c8ca983 100644 --- a/examples/ai-core/src/generate-object/openai-responses.ts +++ b/examples/ai-core/src/generate-object/openai-responses.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai-store-generation.ts b/examples/ai-core/src/generate-object/openai-store-generation.ts index eea2671a0812..2e5b5e9ebdca 100644 --- a/examples/ai-core/src/generate-object/openai-store-generation.ts +++ b/examples/ai-core/src/generate-object/openai-store-generation.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai-structured-outputs-name-description.ts b/examples/ai-core/src/generate-object/openai-structured-outputs-name-description.ts index 3bf56da6257c..83d8681902f6 100644 --- a/examples/ai-core/src/generate-object/openai-structured-outputs-name-description.ts +++ b/examples/ai-core/src/generate-object/openai-structured-outputs-name-description.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/openai.ts b/examples/ai-core/src/generate-object/openai.ts index 96b77d7be669..813a23afdef5 100644 --- a/examples/ai-core/src/generate-object/openai.ts +++ b/examples/ai-core/src/generate-object/openai.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/perplexity.ts b/examples/ai-core/src/generate-object/perplexity.ts index 6ed2b29d9767..84ccb1e246c9 100644 --- a/examples/ai-core/src/generate-object/perplexity.ts +++ b/examples/ai-core/src/generate-object/perplexity.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { perplexity } from '@ai-sdk/perplexity'; import { generateObject, generateText } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/togetherai.ts b/examples/ai-core/src/generate-object/togetherai.ts index 37c77f7c68b4..6eae7344ca56 100644 --- a/examples/ai-core/src/generate-object/togetherai.ts +++ b/examples/ai-core/src/generate-object/togetherai.ts @@ -1,7 +1,7 @@ import { togetherai } from '@ai-sdk/togetherai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/vercel.ts b/examples/ai-core/src/generate-object/vercel.ts index d34ac3d254ad..d50fa4992dc2 100644 --- a/examples/ai-core/src/generate-object/vercel.ts +++ b/examples/ai-core/src/generate-object/vercel.ts @@ -1,7 +1,7 @@ import { vercel } from '@ai-sdk/vercel'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/xai-structured-outputs-name-description.ts b/examples/ai-core/src/generate-object/xai-structured-outputs-name-description.ts index a9ec93fc11dc..417cd065e74d 100644 --- a/examples/ai-core/src/generate-object/xai-structured-outputs-name-description.ts +++ b/examples/ai-core/src/generate-object/xai-structured-outputs-name-description.ts @@ -1,7 +1,7 @@ import { xai } from '@ai-sdk/xai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-object/xai.ts b/examples/ai-core/src/generate-object/xai.ts index e069b246f13c..fbed1c987ed7 100644 --- a/examples/ai-core/src/generate-object/xai.ts +++ b/examples/ai-core/src/generate-object/xai.ts @@ -1,7 +1,7 @@ import { xai } from '@ai-sdk/xai'; import { generateObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateObject({ diff --git a/examples/ai-core/src/generate-text/amazon-bedrock-cache-point-tool-call.ts b/examples/ai-core/src/generate-text/amazon-bedrock-cache-point-tool-call.ts index 9a4c70be57d5..476e32a9dced 100644 --- a/examples/ai-core/src/generate-text/amazon-bedrock-cache-point-tool-call.ts +++ b/examples/ai-core/src/generate-text/amazon-bedrock-cache-point-tool-call.ts @@ -1,6 +1,6 @@ import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { bedrock } from '@ai-sdk/amazon-bedrock'; const weatherTool = tool({ diff --git a/examples/ai-core/src/generate-text/amazon-bedrock-nova-tool-call.ts b/examples/ai-core/src/generate-text/amazon-bedrock-nova-tool-call.ts index e4017b41243c..1a237c2e0159 100644 --- a/examples/ai-core/src/generate-text/amazon-bedrock-nova-tool-call.ts +++ b/examples/ai-core/src/generate-text/amazon-bedrock-nova-tool-call.ts @@ -1,6 +1,6 @@ import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; import { bedrock } from '@ai-sdk/amazon-bedrock'; diff --git a/examples/ai-core/src/generate-text/amazon-bedrock-tool-call-image-result.ts b/examples/ai-core/src/generate-text/amazon-bedrock-tool-call-image-result.ts index a2a775c61a06..3cd34e7649fe 100644 --- a/examples/ai-core/src/generate-text/amazon-bedrock-tool-call-image-result.ts +++ b/examples/ai-core/src/generate-text/amazon-bedrock-tool-call-image-result.ts @@ -1,7 +1,7 @@ import { bedrock } from '@ai-sdk/amazon-bedrock'; import { generateText, stepCountIs, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateText({ diff --git a/examples/ai-core/src/generate-text/amazon-bedrock-tool-call.ts b/examples/ai-core/src/generate-text/amazon-bedrock-tool-call.ts index 4b34135e194e..0f8a29c8c8b9 100644 --- a/examples/ai-core/src/generate-text/amazon-bedrock-tool-call.ts +++ b/examples/ai-core/src/generate-text/amazon-bedrock-tool-call.ts @@ -1,6 +1,6 @@ import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; import { bedrock } from '@ai-sdk/amazon-bedrock'; diff --git a/examples/ai-core/src/generate-text/amazon-bedrock-tool-choice.ts b/examples/ai-core/src/generate-text/amazon-bedrock-tool-choice.ts index 15e16d388cf0..ddd6c29847d3 100644 --- a/examples/ai-core/src/generate-text/amazon-bedrock-tool-choice.ts +++ b/examples/ai-core/src/generate-text/amazon-bedrock-tool-choice.ts @@ -1,6 +1,6 @@ import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; import { bedrock } from '@ai-sdk/amazon-bedrock'; diff --git a/examples/ai-core/src/generate-text/anthropic-cache-control-beta-1h.ts b/examples/ai-core/src/generate-text/anthropic-cache-control-beta-1h.ts index f166f116912b..6abab3162ddc 100644 --- a/examples/ai-core/src/generate-text/anthropic-cache-control-beta-1h.ts +++ b/examples/ai-core/src/generate-text/anthropic-cache-control-beta-1h.ts @@ -1,4 +1,4 @@ -import { anthropic } from '@ai-sdk/anthropic'; +import { anthropic, AnthropicProviderOptions } from '@ai-sdk/anthropic'; import { generateText } from 'ai'; import 'dotenv/config'; import fs from 'node:fs'; @@ -27,7 +27,7 @@ async function main() { providerOptions: { anthropic: { cacheControl: { type: 'ephemeral', ttl: '1h' }, - }, + } satisfies AnthropicProviderOptions, }, }, { diff --git a/examples/ai-core/src/generate-text/anthropic-tool-call-cache.ts b/examples/ai-core/src/generate-text/anthropic-tool-call-cache.ts index ea7cb9884401..c2fdc3772d3f 100644 --- a/examples/ai-core/src/generate-text/anthropic-tool-call-cache.ts +++ b/examples/ai-core/src/generate-text/anthropic-tool-call-cache.ts @@ -1,7 +1,7 @@ import { anthropic } from '@ai-sdk/anthropic'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateText({ diff --git a/examples/ai-core/src/generate-text/anthropic-tool-call.ts b/examples/ai-core/src/generate-text/anthropic-tool-call.ts index 3b5a7058c080..0319d4f35478 100644 --- a/examples/ai-core/src/generate-text/anthropic-tool-call.ts +++ b/examples/ai-core/src/generate-text/anthropic-tool-call.ts @@ -1,7 +1,7 @@ import { anthropic } from '@ai-sdk/anthropic'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/anthropic-tool-choice.ts b/examples/ai-core/src/generate-text/anthropic-tool-choice.ts index ce5ebd50e3cb..b56375dffe70 100644 --- a/examples/ai-core/src/generate-text/anthropic-tool-choice.ts +++ b/examples/ai-core/src/generate-text/anthropic-tool-choice.ts @@ -1,7 +1,7 @@ import { anthropic } from '@ai-sdk/anthropic'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/baseten-custom-url.ts b/examples/ai-core/src/generate-text/baseten-custom-url.ts new file mode 100644 index 000000000000..eb28de86ae9f --- /dev/null +++ b/examples/ai-core/src/generate-text/baseten-custom-url.ts @@ -0,0 +1,24 @@ +import { createBaseten } from '@ai-sdk/baseten'; +import { generateText } from 'ai'; +import 'dotenv/config'; + +async function main() { + // Using custom model URL for chat/text generation + const CHAT_MODEL_ID = ''; // e.g. 6wg17egw + const CHAT_MODEL_URL = `https://model-${CHAT_MODEL_ID}.api.baseten.co/environments/production/sync/v1`; + + const baseten = createBaseten({ + modelURL: CHAT_MODEL_URL, + }); + + const { text, usage } = await generateText({ + model: baseten.languageModel(), + prompt: 'Explain quantum computing in simple terms.', + }); + + console.log(text); + console.log(); + console.log('Usage:', usage); +} + +main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/baseten.ts b/examples/ai-core/src/generate-text/baseten.ts new file mode 100644 index 000000000000..c9426301fb9a --- /dev/null +++ b/examples/ai-core/src/generate-text/baseten.ts @@ -0,0 +1,17 @@ +import { baseten } from '@ai-sdk/baseten'; +import { generateText } from 'ai'; +import 'dotenv/config'; + +async function main() { + // Using default Model APIs - works with hosted models on Baseten + const { text, usage } = await generateText({ + model: baseten('deepseek-ai/DeepSeek-V3-0324'), + prompt: 'What is the meaning of life? Answer in one sentence.', + }); + + console.log(text); + console.log(); + console.log('Usage:', usage); +} + +main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/cerebras-tool-call.ts b/examples/ai-core/src/generate-text/cerebras-tool-call.ts index 65da88a1eb2a..65267e8654e5 100644 --- a/examples/ai-core/src/generate-text/cerebras-tool-call.ts +++ b/examples/ai-core/src/generate-text/cerebras-tool-call.ts @@ -1,7 +1,7 @@ import { cerebras } from '@ai-sdk/cerebras'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/cohere-tool-call-empty-params.ts b/examples/ai-core/src/generate-text/cohere-tool-call-empty-params.ts index 1826eb26d916..9666c40c702d 100644 --- a/examples/ai-core/src/generate-text/cohere-tool-call-empty-params.ts +++ b/examples/ai-core/src/generate-text/cohere-tool-call-empty-params.ts @@ -1,7 +1,7 @@ import { cohere } from '@ai-sdk/cohere'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateText({ diff --git a/examples/ai-core/src/generate-text/cohere-tool-call.ts b/examples/ai-core/src/generate-text/cohere-tool-call.ts index 476a5d9d4ff4..c54d24f7a109 100644 --- a/examples/ai-core/src/generate-text/cohere-tool-call.ts +++ b/examples/ai-core/src/generate-text/cohere-tool-call.ts @@ -1,7 +1,7 @@ import { cohere } from '@ai-sdk/cohere'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/deepinfra-tool-call.ts b/examples/ai-core/src/generate-text/deepinfra-tool-call.ts index f6f140485f2f..8aaeb09f2abc 100644 --- a/examples/ai-core/src/generate-text/deepinfra-tool-call.ts +++ b/examples/ai-core/src/generate-text/deepinfra-tool-call.ts @@ -1,7 +1,7 @@ import { deepinfra } from '@ai-sdk/deepinfra'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/gateway-tool-call.ts b/examples/ai-core/src/generate-text/gateway-tool-call.ts index 3d32ae8f5a07..76e4ead4e1af 100644 --- a/examples/ai-core/src/generate-text/gateway-tool-call.ts +++ b/examples/ai-core/src/generate-text/gateway-tool-call.ts @@ -1,6 +1,6 @@ import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/google-image-output.ts b/examples/ai-core/src/generate-text/google-image-output.ts index d2d52e19da62..f26b2ac92711 100644 --- a/examples/ai-core/src/generate-text/google-image-output.ts +++ b/examples/ai-core/src/generate-text/google-image-output.ts @@ -7,9 +7,6 @@ async function main() { const result = await generateText({ model: google('gemini-2.0-flash-exp'), prompt: 'Generate an image of a comic cat', - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, }); console.log(result.text); diff --git a/examples/ai-core/src/generate-text/google-image-tool-results.ts b/examples/ai-core/src/generate-text/google-image-tool-results.ts index 31e14625aa46..9b2b3636ebdf 100644 --- a/examples/ai-core/src/generate-text/google-image-tool-results.ts +++ b/examples/ai-core/src/generate-text/google-image-tool-results.ts @@ -1,6 +1,6 @@ import { google } from '@ai-sdk/google'; import { generateText, stepCountIs, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import 'dotenv/config'; import * as fs from 'fs'; import * as path from 'path'; diff --git a/examples/ai-core/src/generate-text/google-image.ts b/examples/ai-core/src/generate-text/google-image.ts index 9092b0639944..1cf1e328e69b 100644 --- a/examples/ai-core/src/generate-text/google-image.ts +++ b/examples/ai-core/src/generate-text/google-image.ts @@ -1,4 +1,4 @@ -import { google, GoogleGenerativeAIProviderOptions } from '@ai-sdk/google'; +import { google } from '@ai-sdk/google'; import { generateText } from 'ai'; import 'dotenv/config'; import fs from 'node:fs'; @@ -15,11 +15,6 @@ async function main() { ], }, ], - providerOptions: { - google: { - responseModalities: ['TEXT', 'IMAGE'], - } satisfies GoogleGenerativeAIProviderOptions, - }, }); console.log(result.content); diff --git a/examples/ai-core/src/generate-text/google-multi-step.ts b/examples/ai-core/src/generate-text/google-multi-step.ts index aa41ac80e370..321511117a05 100644 --- a/examples/ai-core/src/generate-text/google-multi-step.ts +++ b/examples/ai-core/src/generate-text/google-multi-step.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { generateText, stepCountIs, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { text } = await generateText({ diff --git a/examples/ai-core/src/generate-text/google-output-object.ts b/examples/ai-core/src/generate-text/google-output-object.ts index 392be92fa367..a39c320a32a7 100644 --- a/examples/ai-core/src/generate-text/google-output-object.ts +++ b/examples/ai-core/src/generate-text/google-output-object.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { generateText, Output } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { experimental_output } = await generateText({ diff --git a/examples/ai-core/src/generate-text/google-tool-call.ts b/examples/ai-core/src/generate-text/google-tool-call.ts index 2c6971c18a27..e9ec40630c14 100644 --- a/examples/ai-core/src/generate-text/google-tool-call.ts +++ b/examples/ai-core/src/generate-text/google-tool-call.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/google-tool-choice.ts b/examples/ai-core/src/generate-text/google-tool-choice.ts index 90c325edd1b2..fe4670c055a9 100644 --- a/examples/ai-core/src/generate-text/google-tool-choice.ts +++ b/examples/ai-core/src/generate-text/google-tool-choice.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/google-vertex-anthropic-tool-call.ts b/examples/ai-core/src/generate-text/google-vertex-anthropic-tool-call.ts index 07f53f74d308..451ab78bd458 100644 --- a/examples/ai-core/src/generate-text/google-vertex-anthropic-tool-call.ts +++ b/examples/ai-core/src/generate-text/google-vertex-anthropic-tool-call.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { vertexAnthropic } from '@ai-sdk/google-vertex/anthropic'; import { generateText, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/google-vertex-anthropic-tool-choice.ts b/examples/ai-core/src/generate-text/google-vertex-anthropic-tool-choice.ts index d5d55449f75c..524c2178f78d 100644 --- a/examples/ai-core/src/generate-text/google-vertex-anthropic-tool-choice.ts +++ b/examples/ai-core/src/generate-text/google-vertex-anthropic-tool-choice.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { vertexAnthropic } from '@ai-sdk/google-vertex/anthropic'; import { generateText, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/google-vertex-multi-step.ts b/examples/ai-core/src/generate-text/google-vertex-multi-step.ts index e56432774c6b..7ab1b2431784 100644 --- a/examples/ai-core/src/generate-text/google-vertex-multi-step.ts +++ b/examples/ai-core/src/generate-text/google-vertex-multi-step.ts @@ -1,7 +1,7 @@ import { vertex } from '@ai-sdk/google-vertex'; import { generateText, stepCountIs, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { text } = await generateText({ diff --git a/examples/ai-core/src/generate-text/google-vertex-output-object.ts b/examples/ai-core/src/generate-text/google-vertex-output-object.ts index 702e2f6556de..403911c915dc 100644 --- a/examples/ai-core/src/generate-text/google-vertex-output-object.ts +++ b/examples/ai-core/src/generate-text/google-vertex-output-object.ts @@ -1,7 +1,7 @@ import { vertex } from '@ai-sdk/google-vertex'; import { generateText, Output } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { experimental_output } = await generateText({ diff --git a/examples/ai-core/src/generate-text/google-vertex-tool-call.ts b/examples/ai-core/src/generate-text/google-vertex-tool-call.ts index 68bf13865493..f9140b6f745a 100644 --- a/examples/ai-core/src/generate-text/google-vertex-tool-call.ts +++ b/examples/ai-core/src/generate-text/google-vertex-tool-call.ts @@ -1,7 +1,7 @@ import { vertex } from '@ai-sdk/google-vertex'; import { generateText, stepCountIs, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { text } = await generateText({ diff --git a/examples/ai-core/src/generate-text/google.ts b/examples/ai-core/src/generate-text/google.ts index a5eb68446547..54539b498b45 100644 --- a/examples/ai-core/src/generate-text/google.ts +++ b/examples/ai-core/src/generate-text/google.ts @@ -8,10 +8,16 @@ async function main() { prompt: 'Invent a new holiday and describe its traditions.', }); + const googleMetadata = result.providerMetadata?.google; + console.log(result.text); console.log(); console.log('Token usage:', result.usage); console.log('Finish reason:', result.finishReason); + console.log('Safety info:', { + promptFeedback: googleMetadata?.promptFeedback, + safetyRatings: googleMetadata?.safetyRatings, + }); } main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/mistral-tool-call.ts b/examples/ai-core/src/generate-text/mistral-tool-call.ts index 952dc5df24d4..7e2fea71967c 100644 --- a/examples/ai-core/src/generate-text/mistral-tool-call.ts +++ b/examples/ai-core/src/generate-text/mistral-tool-call.ts @@ -1,7 +1,7 @@ import { mistral } from '@ai-sdk/mistral'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/mistral-tool-choice.ts b/examples/ai-core/src/generate-text/mistral-tool-choice.ts index d96f9199e60d..53725b38b974 100644 --- a/examples/ai-core/src/generate-text/mistral-tool-choice.ts +++ b/examples/ai-core/src/generate-text/mistral-tool-choice.ts @@ -1,7 +1,7 @@ import { mistral } from '@ai-sdk/mistral'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/mock-invalid-tool-call.ts b/examples/ai-core/src/generate-text/mock-invalid-tool-call.ts index aec4a1b7c7e9..ece8183bbb7a 100644 --- a/examples/ai-core/src/generate-text/mock-invalid-tool-call.ts +++ b/examples/ai-core/src/generate-text/mock-invalid-tool-call.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, stepCountIs, tool } from 'ai'; import { MockLanguageModelV2 } from 'ai/test'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateText({ diff --git a/examples/ai-core/src/generate-text/mock-tool-call-repair-change-tool.ts b/examples/ai-core/src/generate-text/mock-tool-call-repair-change-tool.ts index 508455a697d1..bc3ada555002 100644 --- a/examples/ai-core/src/generate-text/mock-tool-call-repair-change-tool.ts +++ b/examples/ai-core/src/generate-text/mock-tool-call-repair-change-tool.ts @@ -1,7 +1,7 @@ import { generateText, tool } from 'ai'; import { MockLanguageModelV2 } from 'ai/test'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateText({ diff --git a/examples/ai-core/src/generate-text/mock-tool-call-repair-reask.ts b/examples/ai-core/src/generate-text/mock-tool-call-repair-reask.ts index 04faf0bd7164..cecbb0426225 100644 --- a/examples/ai-core/src/generate-text/mock-tool-call-repair-reask.ts +++ b/examples/ai-core/src/generate-text/mock-tool-call-repair-reask.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, tool } from 'ai'; import { MockLanguageModelV2 } from 'ai/test'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateText({ diff --git a/examples/ai-core/src/generate-text/mock-tool-call-repair-structured-model.ts b/examples/ai-core/src/generate-text/mock-tool-call-repair-structured-model.ts index 9f0555c5f583..9cf55ba61570 100644 --- a/examples/ai-core/src/generate-text/mock-tool-call-repair-structured-model.ts +++ b/examples/ai-core/src/generate-text/mock-tool-call-repair-structured-model.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { generateObject, generateText, NoSuchToolError, tool } from 'ai'; import { MockLanguageModelV2 } from 'ai/test'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateText({ diff --git a/examples/ai-core/src/generate-text/openai-active-tools.ts b/examples/ai-core/src/generate-text/openai-active-tools.ts index 914c59e8a92f..3fea36ea5a0e 100644 --- a/examples/ai-core/src/generate-text/openai-active-tools.ts +++ b/examples/ai-core/src/generate-text/openai-active-tools.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, stepCountIs, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/openai-code-interpreter-tool.ts b/examples/ai-core/src/generate-text/openai-code-interpreter-tool.ts index 096e111c1d8d..6c42f782eaca 100644 --- a/examples/ai-core/src/generate-text/openai-code-interpreter-tool.ts +++ b/examples/ai-core/src/generate-text/openai-code-interpreter-tool.ts @@ -12,5 +12,5 @@ run(async () => { 'Simulate rolling two dice 10000 times and and return the sum all the results.', }); - console.log(result.text); + console.dir(result.content, { depth: Infinity }); }); diff --git a/examples/ai-core/src/generate-text/openai-compatible-togetherai-tool-call.ts b/examples/ai-core/src/generate-text/openai-compatible-togetherai-tool-call.ts index 8f63077ebbda..7c5c76514e54 100644 --- a/examples/ai-core/src/generate-text/openai-compatible-togetherai-tool-call.ts +++ b/examples/ai-core/src/generate-text/openai-compatible-togetherai-tool-call.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; import { generateText, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/openai-dynamic-tool-call.ts b/examples/ai-core/src/generate-text/openai-dynamic-tool-call.ts index eeea02305033..34349e444266 100644 --- a/examples/ai-core/src/generate-text/openai-dynamic-tool-call.ts +++ b/examples/ai-core/src/generate-text/openai-dynamic-tool-call.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { dynamicTool, generateText, stepCountIs, ToolSet } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; function dynamicTools(): ToolSet { diff --git a/examples/ai-core/src/generate-text/openai-file-search-tool.ts b/examples/ai-core/src/generate-text/openai-file-search-tool.ts new file mode 100644 index 000000000000..30151491c7b9 --- /dev/null +++ b/examples/ai-core/src/generate-text/openai-file-search-tool.ts @@ -0,0 +1,26 @@ +import { openai } from '@ai-sdk/openai'; +import { generateText } from 'ai'; +import { run } from '../lib/run'; + +run(async () => { + const result = await generateText({ + model: openai('gpt-5-mini'), + prompt: 'What is an embedding model according to this document?', + tools: { + file_search: openai.tools.fileSearch({ + vectorStoreIds: ['vs_68caad8bd5d88191ab766cf043d89a18'], + }), + }, + providerOptions: { + openai: { + include: ['file_search_call.results'], + }, + }, + }); + + console.log(JSON.stringify(result.response.body, null, 2)); + console.dir(result.toolCalls, { depth: Infinity }); + console.dir(result.toolResults, { depth: Infinity }); + console.dir(result.sources, { depth: Infinity }); + console.log(result.text); +}); diff --git a/examples/ai-core/src/generate-text/openai-image-generation-tool.ts b/examples/ai-core/src/generate-text/openai-image-generation-tool.ts new file mode 100644 index 000000000000..28b86016d10a --- /dev/null +++ b/examples/ai-core/src/generate-text/openai-image-generation-tool.ts @@ -0,0 +1,31 @@ +import { openai } from '@ai-sdk/openai'; +import { generateText } from 'ai'; +import { presentImages } from '../lib/present-image'; +import { run } from '../lib/run'; +import { convertBase64ToUint8Array } from '../lib/convertBase64ToUint8Array'; + +run(async () => { + const result = await generateText({ + model: openai('gpt-5-nano'), + prompt: 'Generate an image of a cat.', + tools: { + image_generation: openai.tools.imageGeneration({ + outputFormat: 'webp', + quality: 'low', + size: '1024x1024', + }), + }, + }); + + for (const toolResult of result.staticToolResults) { + if (toolResult.toolName === 'image_generation') { + await presentImages([ + { + mediaType: 'image/webp', + base64: toolResult.output.result, + uint8Array: convertBase64ToUint8Array(toolResult.output.result), + }, + ]); + } + } +}); diff --git a/examples/ai-core/src/generate-text/openai-multi-step.ts b/examples/ai-core/src/generate-text/openai-multi-step.ts index 2ebd1ae99298..e63e67a1099b 100644 --- a/examples/ai-core/src/generate-text/openai-multi-step.ts +++ b/examples/ai-core/src/generate-text/openai-multi-step.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, stepCountIs, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { text, usage } = await generateText({ diff --git a/examples/ai-core/src/generate-text/openai-output-object.ts b/examples/ai-core/src/generate-text/openai-output-object.ts index 71137177e5b4..ef271dd95c35 100644 --- a/examples/ai-core/src/generate-text/openai-output-object.ts +++ b/examples/ai-core/src/generate-text/openai-output-object.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, stepCountIs, Output, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { experimental_output } = await generateText({ diff --git a/examples/ai-core/src/generate-text/openai-provider-defined-tools.ts b/examples/ai-core/src/generate-text/openai-provider-defined-tools.ts deleted file mode 100644 index 932e7cdeac86..000000000000 --- a/examples/ai-core/src/generate-text/openai-provider-defined-tools.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { generateText } from 'ai'; -import { openai } from '@ai-sdk/openai'; -import 'dotenv/config'; - -async function main() { - const result = await generateText({ - model: openai('gpt-4o-mini'), - prompt: 'Search for information about TypeScript best practices', - tools: { - web_search: openai.tools.webSearch({ - searchContextSize: 'medium', - userLocation: { - type: 'approximate', - city: 'San Francisco', - region: 'California', - country: 'US', - }, - }), - - file_search: openai.tools.fileSearch({ - maxNumResults: 5, - ranking: { - ranker: 'auto', - }, - }), - }, - }); - - console.log('Result:', result.text); - console.log('Tool calls made:', result.toolCalls.length); - - for (const toolCall of result.toolCalls) { - console.log(`\nTool Call:`); - console.log(`- Tool: ${toolCall.toolName}`); - console.log(`- Input:`, JSON.stringify(toolCall.input, null, 2)); - } -} - -main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/openai-provider-options.ts b/examples/ai-core/src/generate-text/openai-provider-options.ts new file mode 100644 index 000000000000..fdfc10c02019 --- /dev/null +++ b/examples/ai-core/src/generate-text/openai-provider-options.ts @@ -0,0 +1,33 @@ +import { openai, type OpenAIChatLanguageModelOptions } from '@ai-sdk/openai'; +import { generateText } from 'ai'; +import 'dotenv/config'; + +async function main() { + const { text, usage } = await generateText({ + model: openai.chat('gpt-4o'), + prompt: 'Invent a new holiday and describe its traditions.', + providerOptions: { + openai: { + logitBias: {}, + logprobs: 1, + user: '', + maxCompletionTokens: 100, + store: false, + structuredOutputs: false, + serviceTier: 'auto', + strictJsonSchema: false, + textVerbosity: 'medium', + promptCacheKey: '', + safetyIdentifier: '', + // @ts-expect-error + invalidOption: null, + } satisfies OpenAIChatLanguageModelOptions, + }, + }); + + console.log(text); + console.log(); + console.log('Usage:', usage); +} + +main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/openai-reasoning-tools.ts b/examples/ai-core/src/generate-text/openai-reasoning-tools.ts index bc51d5463c03..372a22b8d7eb 100644 --- a/examples/ai-core/src/generate-text/openai-reasoning-tools.ts +++ b/examples/ai-core/src/generate-text/openai-reasoning-tools.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/openai-responses-output-object.ts b/examples/ai-core/src/generate-text/openai-responses-output-object.ts index c887ecb8ea1c..d3e6a85d60c8 100644 --- a/examples/ai-core/src/generate-text/openai-responses-output-object.ts +++ b/examples/ai-core/src/generate-text/openai-responses-output-object.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, stepCountIs, Output, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { experimental_output } = await generateText({ diff --git a/examples/ai-core/src/generate-text/openai-responses-reasoning-summary.ts b/examples/ai-core/src/generate-text/openai-responses-reasoning-summary.ts deleted file mode 100644 index a6f3a2b55d3f..000000000000 --- a/examples/ai-core/src/generate-text/openai-responses-reasoning-summary.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; -import { generateText } from 'ai'; -import 'dotenv/config'; - -async function main() { - const result = await generateText({ - // supported: o4-mini, o3, o3-mini and o1 - model: openai.responses('o3-mini'), - prompt: - 'Tell me about the debate over Taqueria La Cumbre and El Farolito and who created the San Francisco Mission-style burrito.', - providerOptions: { - openai: { - // https://platform.openai.com/docs/guides/reasoning?api-mode=responses#reasoning-summaries - reasoningSummary: 'auto', // auto gives you the best available summary (detailed > auto > None) - } satisfies OpenAIResponsesProviderOptions, - }, - }); - - process.stdout.write('\x1b[34m'); - console.log(JSON.stringify(result.reasoning, null, 2)); - process.stdout.write('\x1b[0m'); - console.log(result.text); - console.log(); - console.log('Finish reason:', result.finishReason); - console.log('Usage:', result.usage); - console.log(); - console.log('Request body:', JSON.stringify(result.request.body, null, 2)); - console.log('Response body:', JSON.stringify(result.response.body, null, 2)); -} - -main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/openai-responses-reasoning-websearch.ts b/examples/ai-core/src/generate-text/openai-responses-reasoning-websearch.ts deleted file mode 100644 index 6f9962fb845e..000000000000 --- a/examples/ai-core/src/generate-text/openai-responses-reasoning-websearch.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { openai } from '@ai-sdk/openai'; -import { generateText } from 'ai'; -import 'dotenv/config'; - -async function main() { - const result = await generateText({ - model: openai.responses('gpt-5-mini'), - prompt: 'What happened in the world today?', - providerOptions: { - openai: { reasoningSummary: 'detailed', reasoningEffort: 'medium' }, - }, - tools: { - web_search: openai.tools.webSearch(), - }, - }); - - console.log(JSON.stringify(result.response?.messages, null, 2)); - - const result2 = await generateText({ - model: openai.responses('gpt-5-mini'), - messages: [ - ...result.response?.messages, - { role: 'user', content: 'Summarize in 2 sentences.' }, - ], - }); - - console.log(JSON.stringify(result2, null, 2)); -} - -main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/openai-responses-reasoning-zero-data-retention.ts b/examples/ai-core/src/generate-text/openai-responses-reasoning-zero-data-retention.ts deleted file mode 100644 index d7b3280eab06..000000000000 --- a/examples/ai-core/src/generate-text/openai-responses-reasoning-zero-data-retention.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; -import { generateText, UserModelMessage } from 'ai'; -import 'dotenv/config'; - -async function main() { - const result1 = await generateText({ - model: openai.responses('o3-mini'), - prompt: - 'Analyze the following encrypted data: U2VjcmV0UGFzc3dvcmQxMjM=. What type of encryption is this and what secret does it contain?', - providerOptions: { - openai: { - store: false, // No data retention - makes interaction stateless - reasoningEffort: 'medium', - reasoningSummary: 'auto', - include: ['reasoning.encrypted_content'], // Hence, we need to retrieve the model's encrypted reasoning to be able to pass it to follow-up requests - } satisfies OpenAIResponsesProviderOptions, - }, - }); - console.log('=== First request ==='); - process.stdout.write('\x1b[34m'); - console.log(JSON.stringify(result1.reasoning, null, 2)); - process.stdout.write('\x1b[0m'); - console.log(result1.text); - console.log(); - console.log('Finish reason:', result1.finishReason); - console.log('Usage:', result1.usage); - console.log(); - console.log('Request body:', JSON.stringify(result1.request.body, null, 2)); - console.log('Response body:', JSON.stringify(result1.response.body, null, 2)); - - const result2 = await generateText({ - model: openai.responses('o3-mini'), - prompt: [ - { - role: 'user', - content: [ - { - type: 'text', - text: 'Analyze the following encrypted data: U2VjcmV0UGFzc3dvcmQxMjM=. What type of encryption is this and what secret does it contain?', - }, - ], - }, - ...result1.response.messages, // Need to pass all previous messages to the follow-up request - { - role: 'user', - content: - 'Based on your previous analysis, what security recommendations would you make?', - } satisfies UserModelMessage, - ], - providerOptions: { - openai: { - store: false, // No data retention - makes interaction stateless - reasoningEffort: 'medium', - reasoningSummary: 'auto', - include: ['reasoning.encrypted_content'], // Hence, we need to retrieve the model's encrypted reasoning to be able to pass it to follow-up requests - } satisfies OpenAIResponsesProviderOptions, - }, - }); - - console.log('=== Second request ==='); - process.stdout.write('\x1b[34m'); - console.log(JSON.stringify(result2.reasoning, null, 2)); - process.stdout.write('\x1b[0m'); - console.log(result2.text); - console.log(); - console.log('Finish reason:', result2.finishReason); - console.log('Usage:', result2.usage); - console.log(); - console.log('Request body:', JSON.stringify(result2.request.body, null, 2)); - console.log('Response body:', JSON.stringify(result2.response.body, null, 2)); -} - -main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/openai-responses-reasoning.ts b/examples/ai-core/src/generate-text/openai-responses-reasoning.ts deleted file mode 100644 index b6c93c1cf92c..000000000000 --- a/examples/ai-core/src/generate-text/openai-responses-reasoning.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; -import { generateText } from 'ai'; -import 'dotenv/config'; - -async function main() { - const result = await generateText({ - model: openai.responses('o3-mini'), - prompt: 'How many "r"s are in the word "strawberry"?', - temperature: 0.5, // should get ignored (warning) - providerOptions: { - openai: { - reasoningEffort: 'low', - } satisfies OpenAIResponsesProviderOptions, - }, - }); - - process.stdout.write('\x1b[34m'); - console.log(JSON.stringify(result.reasoning, null, 2)); - process.stdout.write('\x1b[0m'); - console.log(result.text); - console.log(); - console.log('Finish reason:', result.finishReason); - console.log('Usage:', result.usage); - console.log(); - console.log('Request:', JSON.stringify(result.request, null, 2)); - console.log('Response:', JSON.stringify(result.response, null, 2)); -} - -main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/openai-responses-roundtrip-server-side-tools.ts b/examples/ai-core/src/generate-text/openai-responses-roundtrip-server-side-tools.ts index fcf1b8766257..3f56ddffa834 100644 --- a/examples/ai-core/src/generate-text/openai-responses-roundtrip-server-side-tools.ts +++ b/examples/ai-core/src/generate-text/openai-responses-roundtrip-server-side-tools.ts @@ -1,7 +1,7 @@ import { createOpenAI } from '@ai-sdk/openai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const openai = createOpenAI({ // Console log the API request body for debugging diff --git a/examples/ai-core/src/generate-text/openai-responses-tool-call.ts b/examples/ai-core/src/generate-text/openai-responses-tool-call.ts index d53b8c2e9579..9c087f1cfbf4 100644 --- a/examples/ai-core/src/generate-text/openai-responses-tool-call.ts +++ b/examples/ai-core/src/generate-text/openai-responses-tool-call.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/openai-tool-call-with-context.ts b/examples/ai-core/src/generate-text/openai-tool-call-with-context.ts index 08f1e07e3c95..b250a2b6be3a 100644 --- a/examples/ai-core/src/generate-text/openai-tool-call-with-context.ts +++ b/examples/ai-core/src/generate-text/openai-tool-call-with-context.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateText({ diff --git a/examples/ai-core/src/generate-text/openai-tool-call.ts b/examples/ai-core/src/generate-text/openai-tool-call.ts index f3d575a70336..a9879fb8da8d 100644 --- a/examples/ai-core/src/generate-text/openai-tool-call.ts +++ b/examples/ai-core/src/generate-text/openai-tool-call.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/openai-tool-choice.ts b/examples/ai-core/src/generate-text/openai-tool-choice.ts index e78f616d1b09..2c0ec526d841 100644 --- a/examples/ai-core/src/generate-text/openai-tool-choice.ts +++ b/examples/ai-core/src/generate-text/openai-tool-choice.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/openai-tool-execution-error.ts b/examples/ai-core/src/generate-text/openai-tool-execution-error.ts index f211f4bdf0f9..69e4563c066f 100644 --- a/examples/ai-core/src/generate-text/openai-tool-execution-error.ts +++ b/examples/ai-core/src/generate-text/openai-tool-execution-error.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = await generateText({ diff --git a/examples/ai-core/src/generate-text/openai-web-search-tool.ts b/examples/ai-core/src/generate-text/openai-web-search-tool.ts index 7703e4bb6ad5..fd063e7c97a9 100644 --- a/examples/ai-core/src/generate-text/openai-web-search-tool.ts +++ b/examples/ai-core/src/generate-text/openai-web-search-tool.ts @@ -1,10 +1,10 @@ import { openai } from '@ai-sdk/openai'; import { generateText } from 'ai'; -import 'dotenv/config'; +import { run } from '../lib/run'; -async function main() { +run(async () => { const result = await generateText({ - model: openai.responses('gpt-5'), + model: openai.responses('gpt-5-mini'), prompt: 'What happened in tech news today?', tools: { web_search: openai.tools.webSearch({ @@ -13,13 +13,9 @@ async function main() { }, }); - for (const toolCall of result.toolCalls) { - if (toolCall.toolName === 'web_search') { - console.log('Search query:', toolCall.input); - } - } - + console.dir(result.response.body, { depth: Infinity }); + console.dir(result.toolCalls, { depth: Infinity }); + console.dir(result.toolResults, { depth: Infinity }); + console.dir(result.sources, { depth: Infinity }); console.log(result.text); -} - -main().catch(console.error); +}); diff --git a/examples/ai-core/src/generate-text/provider-defined-tools-working.ts b/examples/ai-core/src/generate-text/provider-defined-tools-working.ts deleted file mode 100644 index 96ca0b0b6502..000000000000 --- a/examples/ai-core/src/generate-text/provider-defined-tools-working.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { generateText } from 'ai'; -import { anthropic } from '@ai-sdk/anthropic'; -import { openai } from '@ai-sdk/openai'; -import 'dotenv/config'; - -async function main() { - console.log('=== Demonstrating Refactored Provider-Defined Tools ===\n'); - - console.log('1. OpenAI Provider-Defined Tools (Successfully Refactored):'); - const openaiWebSearch = openai.tools.webSearch({ - searchContextSize: 'medium', - userLocation: { - type: 'approximate', - city: 'San Francisco', - region: 'California', - country: 'US', - }, - }); - - const openaiFileSearch = openai.tools.fileSearch({ - maxNumResults: 5, - ranking: { - ranker: 'auto', - }, - }); - - console.log('OpenAI Web Search Tool created successfully'); - console.log('OpenAI File Search Tool created successfully'); - - console.log('\n2. Anthropic Provider-Defined Tools (Working Example):'); - const result = await generateText({ - model: anthropic('claude-3-5-sonnet-20241022'), - prompt: 'Search for current weather in Tokyo', - tools: { - web_search: anthropic.tools.webSearch_20250305({ - maxUses: 2, - allowedDomains: ['weather.com', 'accuweather.com'], - userLocation: { - type: 'approximate', - city: 'Tokyo', - region: 'Tokyo', - country: 'JP', - }, - }), - }, - }); - - console.log('Anthropic Web Search Tool executed successfully'); - console.log('Tool calls made:', result.toolCalls.length); - - for (const toolCall of result.toolCalls) { - console.log(`\nTool Call:`); - console.log(`- Tool: ${toolCall.toolName}`); - console.log(`- Input:`, JSON.stringify(toolCall.input, null, 2)); - } - - console.log('\n=== Refactoring Summary ==='); - console.log( - 'OpenAI tools refactored to use createProviderDefinedToolFactory', - ); - console.log( - 'Anthropic tools refactored to use createProviderDefinedToolFactory', - ); - console.log( - 'All tools now follow consistent pattern like computer_20250124.ts', - ); - console.log('Type safety improved with better TypeScript inference'); - console.log('Anthropic tools working in production'); - console.log('Factory pattern provides cleaner, more maintainable API'); -} - -main().catch(console.error); diff --git a/examples/ai-core/src/generate-text/togetherai-tool-call.ts b/examples/ai-core/src/generate-text/togetherai-tool-call.ts index 67480e1a6038..75ad3bfe5648 100644 --- a/examples/ai-core/src/generate-text/togetherai-tool-call.ts +++ b/examples/ai-core/src/generate-text/togetherai-tool-call.ts @@ -1,7 +1,7 @@ import { togetherai } from '@ai-sdk/togetherai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/generate-text/xai-structured-output.ts b/examples/ai-core/src/generate-text/xai-structured-output.ts index a420f0d68fd1..d4b91778260c 100644 --- a/examples/ai-core/src/generate-text/xai-structured-output.ts +++ b/examples/ai-core/src/generate-text/xai-structured-output.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { generateText, Output } from 'ai'; import { xai } from '@ai-sdk/xai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { experimental_output } = await generateText({ diff --git a/examples/ai-core/src/generate-text/xai-tool-call.ts b/examples/ai-core/src/generate-text/xai-tool-call.ts index 5f4de2999d48..8be6818745d0 100644 --- a/examples/ai-core/src/generate-text/xai-tool-call.ts +++ b/examples/ai-core/src/generate-text/xai-tool-call.ts @@ -1,7 +1,7 @@ import { xai } from '@ai-sdk/xai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/lib/convertBase64ToUint8Array.ts b/examples/ai-core/src/lib/convertBase64ToUint8Array.ts new file mode 100644 index 000000000000..c4aba3375be3 --- /dev/null +++ b/examples/ai-core/src/lib/convertBase64ToUint8Array.ts @@ -0,0 +1,5 @@ +export function convertBase64ToUint8Array(base64String: string) { + const base64Url = base64String.replace(/-/g, '+').replace(/_/g, '/'); + const latin1string = atob(base64Url); + return Uint8Array.from(latin1string, byte => byte.codePointAt(0)!); +} diff --git a/examples/ai-core/src/lib/save-raw-chunks.ts b/examples/ai-core/src/lib/save-raw-chunks.ts new file mode 100644 index 000000000000..2bb0a0f8662f --- /dev/null +++ b/examples/ai-core/src/lib/save-raw-chunks.ts @@ -0,0 +1,22 @@ +import { StreamTextResult } from 'ai'; +import fs from 'fs'; + +export async function saveRawChunks({ + result, + filename, +}: { + result: StreamTextResult; + filename: string; +}) { + const rawChunks: unknown[] = []; + for await (const chunk of result.fullStream) { + if (chunk.type === 'raw') { + rawChunks.push(chunk.rawValue); + } + } + + fs.writeFileSync( + `output/${filename}.chunks.txt`, + rawChunks.map(chunk => JSON.stringify(chunk)).join('\n'), + ); +} diff --git a/examples/ai-core/src/stream-object/amazon-bedrock.ts b/examples/ai-core/src/stream-object/amazon-bedrock.ts index aaee002700ff..9f8466ed52d5 100644 --- a/examples/ai-core/src/stream-object/amazon-bedrock.ts +++ b/examples/ai-core/src/stream-object/amazon-bedrock.ts @@ -1,7 +1,7 @@ import { bedrock } from '@ai-sdk/amazon-bedrock'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/anthropic.ts b/examples/ai-core/src/stream-object/anthropic.ts index 126031f13026..bc8b8cf93d84 100644 --- a/examples/ai-core/src/stream-object/anthropic.ts +++ b/examples/ai-core/src/stream-object/anthropic.ts @@ -1,7 +1,7 @@ import { anthropic } from '@ai-sdk/anthropic'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/azure.ts b/examples/ai-core/src/stream-object/azure.ts index 95c6e69dfb64..2fd3335d9daa 100644 --- a/examples/ai-core/src/stream-object/azure.ts +++ b/examples/ai-core/src/stream-object/azure.ts @@ -1,7 +1,7 @@ import { azure } from '@ai-sdk/azure'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/cerebras.ts b/examples/ai-core/src/stream-object/cerebras.ts new file mode 100644 index 000000000000..dc22b5031643 --- /dev/null +++ b/examples/ai-core/src/stream-object/cerebras.ts @@ -0,0 +1,33 @@ +import { cerebras } from '@ai-sdk/cerebras'; +import { streamObject } from 'ai'; +import 'dotenv/config'; +import { z } from 'zod'; + +async function main() { + const result = streamObject({ + model: cerebras('gpt-oss-120b'), + schema: z.object({ + characters: z.array( + z.object({ + name: z.string(), + class: z + .string() + .describe('Character class, e.g. warrior, mage, or thief.'), + description: z.string(), + }), + ), + }), + prompt: + 'Generate 3 character descriptions for a fantasy role playing game.', + }); + + for await (const partialObject of result.partialObjectStream) { + console.clear(); + console.log(partialObject); + } + + console.log(); + console.log('Token usage:', await result.usage); +} + +main().catch(console.error); diff --git a/examples/ai-core/src/stream-object/fireworks.ts b/examples/ai-core/src/stream-object/fireworks.ts index 720e352b4d02..7e3e9a523e3b 100644 --- a/examples/ai-core/src/stream-object/fireworks.ts +++ b/examples/ai-core/src/stream-object/fireworks.ts @@ -1,7 +1,7 @@ import { fireworks } from '@ai-sdk/fireworks'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/gateway.ts b/examples/ai-core/src/stream-object/gateway.ts index 6a5c047b9c20..2fff05a89f3b 100644 --- a/examples/ai-core/src/stream-object/gateway.ts +++ b/examples/ai-core/src/stream-object/gateway.ts @@ -1,6 +1,6 @@ import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/google-vertex-anthropic.ts b/examples/ai-core/src/stream-object/google-vertex-anthropic.ts index 0ebbe7cf6ccd..27519f80e12e 100644 --- a/examples/ai-core/src/stream-object/google-vertex-anthropic.ts +++ b/examples/ai-core/src/stream-object/google-vertex-anthropic.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { vertexAnthropic } from '@ai-sdk/google-vertex/anthropic'; import { streamObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/google-vertex.ts b/examples/ai-core/src/stream-object/google-vertex.ts index 92eab5aab3cd..026c71cb585f 100644 --- a/examples/ai-core/src/stream-object/google-vertex.ts +++ b/examples/ai-core/src/stream-object/google-vertex.ts @@ -1,7 +1,7 @@ import { vertex } from '@ai-sdk/google-vertex'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/google.ts b/examples/ai-core/src/stream-object/google.ts index 10ca1c19bd40..6b42457d562a 100644 --- a/examples/ai-core/src/stream-object/google.ts +++ b/examples/ai-core/src/stream-object/google.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/groq.ts b/examples/ai-core/src/stream-object/groq.ts index fd211a3d24c9..e777aa57632b 100644 --- a/examples/ai-core/src/stream-object/groq.ts +++ b/examples/ai-core/src/stream-object/groq.ts @@ -1,7 +1,7 @@ import { groq } from '@ai-sdk/groq'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/mistral.ts b/examples/ai-core/src/stream-object/mistral.ts index 417e98956591..996b59a88147 100644 --- a/examples/ai-core/src/stream-object/mistral.ts +++ b/examples/ai-core/src/stream-object/mistral.ts @@ -1,7 +1,7 @@ import { mistral } from '@ai-sdk/mistral'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/mock.ts b/examples/ai-core/src/stream-object/mock.ts index 47d71f34ec2f..c5449223d4fa 100644 --- a/examples/ai-core/src/stream-object/mock.ts +++ b/examples/ai-core/src/stream-object/mock.ts @@ -1,7 +1,7 @@ import { streamObject } from 'ai'; import { convertArrayToReadableStream, MockLanguageModelV2 } from 'ai/test'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/nim.ts b/examples/ai-core/src/stream-object/nim.ts index 96b91f112588..a4dfaa778803 100644 --- a/examples/ai-core/src/stream-object/nim.ts +++ b/examples/ai-core/src/stream-object/nim.ts @@ -1,6 +1,6 @@ import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; import { streamObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import 'dotenv/config'; async function main() { diff --git a/examples/ai-core/src/stream-object/openai-5-reasoning.ts b/examples/ai-core/src/stream-object/openai-5-reasoning.ts index dc6ed0c3ed12..134ea1762f01 100644 --- a/examples/ai-core/src/stream-object/openai-5-reasoning.ts +++ b/examples/ai-core/src/stream-object/openai-5-reasoning.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-array.ts b/examples/ai-core/src/stream-object/openai-array.ts index fa71304d1835..5010e17a663d 100644 --- a/examples/ai-core/src/stream-object/openai-array.ts +++ b/examples/ai-core/src/stream-object/openai-array.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { elementStream: destinations } = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-compatible-togetherai.ts b/examples/ai-core/src/stream-object/openai-compatible-togetherai.ts index 07878e70ad3d..9fa464ba7bf7 100644 --- a/examples/ai-core/src/stream-object/openai-compatible-togetherai.ts +++ b/examples/ai-core/src/stream-object/openai-compatible-togetherai.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; import { streamObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const togetherai = createOpenAICompatible({ diff --git a/examples/ai-core/src/stream-object/openai-fullstream.ts b/examples/ai-core/src/stream-object/openai-fullstream.ts index 6216abbbe849..f7d33257f228 100644 --- a/examples/ai-core/src/stream-object/openai-fullstream.ts +++ b/examples/ai-core/src/stream-object/openai-fullstream.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-object.ts b/examples/ai-core/src/stream-object/openai-object.ts index 8959b2df3012..7ae7d8fb7a19 100644 --- a/examples/ai-core/src/stream-object/openai-object.ts +++ b/examples/ai-core/src/stream-object/openai-object.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-on-finish.ts b/examples/ai-core/src/stream-object/openai-on-finish.ts index 603dd7ce8b78..4047d2e1a7c3 100644 --- a/examples/ai-core/src/stream-object/openai-on-finish.ts +++ b/examples/ai-core/src/stream-object/openai-on-finish.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-reasoning.ts b/examples/ai-core/src/stream-object/openai-reasoning.ts index de77d440af1b..2046f0327081 100644 --- a/examples/ai-core/src/stream-object/openai-reasoning.ts +++ b/examples/ai-core/src/stream-object/openai-reasoning.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-request-body.ts b/examples/ai-core/src/stream-object/openai-request-body.ts index 058e1e509723..4db0c51266b5 100644 --- a/examples/ai-core/src/stream-object/openai-request-body.ts +++ b/examples/ai-core/src/stream-object/openai-request-body.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-responses.ts b/examples/ai-core/src/stream-object/openai-responses.ts index 131e1a6957ad..37e41e07b751 100644 --- a/examples/ai-core/src/stream-object/openai-responses.ts +++ b/examples/ai-core/src/stream-object/openai-responses.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-store-generation.ts b/examples/ai-core/src/stream-object/openai-store-generation.ts index 9a0c9750f73a..650a6612e370 100644 --- a/examples/ai-core/src/stream-object/openai-store-generation.ts +++ b/examples/ai-core/src/stream-object/openai-store-generation.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-stream-object-name-description.ts b/examples/ai-core/src/stream-object/openai-stream-object-name-description.ts index 33f1a72c44c4..f66e8e13e2fa 100644 --- a/examples/ai-core/src/stream-object/openai-stream-object-name-description.ts +++ b/examples/ai-core/src/stream-object/openai-stream-object-name-description.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-stream-object.ts b/examples/ai-core/src/stream-object/openai-stream-object.ts index df1a4d9df383..21667049c493 100644 --- a/examples/ai-core/src/stream-object/openai-stream-object.ts +++ b/examples/ai-core/src/stream-object/openai-stream-object.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-token-usage.ts b/examples/ai-core/src/stream-object/openai-token-usage.ts index 1b9622f670a0..a10e1ced652a 100644 --- a/examples/ai-core/src/stream-object/openai-token-usage.ts +++ b/examples/ai-core/src/stream-object/openai-token-usage.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject, LanguageModelUsage } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai-unstructured-output.ts b/examples/ai-core/src/stream-object/openai-unstructured-output.ts index 8672059e0809..4c011d0cb6cb 100644 --- a/examples/ai-core/src/stream-object/openai-unstructured-output.ts +++ b/examples/ai-core/src/stream-object/openai-unstructured-output.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/openai.ts b/examples/ai-core/src/stream-object/openai.ts index caf3ae46e8cc..2a8b8f5fb1d6 100644 --- a/examples/ai-core/src/stream-object/openai.ts +++ b/examples/ai-core/src/stream-object/openai.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v3'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/togetherai.ts b/examples/ai-core/src/stream-object/togetherai.ts index 536319ddd3f7..8cfb6b557379 100644 --- a/examples/ai-core/src/stream-object/togetherai.ts +++ b/examples/ai-core/src/stream-object/togetherai.ts @@ -1,7 +1,7 @@ import { togetherai } from '@ai-sdk/togetherai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/vercel.ts b/examples/ai-core/src/stream-object/vercel.ts index 94251c54eda9..ed55b743f853 100644 --- a/examples/ai-core/src/stream-object/vercel.ts +++ b/examples/ai-core/src/stream-object/vercel.ts @@ -1,7 +1,7 @@ import { vercel } from '@ai-sdk/vercel'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/xai-structured-outputs-name-description.ts b/examples/ai-core/src/stream-object/xai-structured-outputs-name-description.ts index cc3e53579b07..b74efa67e81a 100644 --- a/examples/ai-core/src/stream-object/xai-structured-outputs-name-description.ts +++ b/examples/ai-core/src/stream-object/xai-structured-outputs-name-description.ts @@ -1,7 +1,7 @@ import { xai } from '@ai-sdk/xai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-object/xai.ts b/examples/ai-core/src/stream-object/xai.ts index 5169ab298e4e..0504fbb6fa7c 100644 --- a/examples/ai-core/src/stream-object/xai.ts +++ b/examples/ai-core/src/stream-object/xai.ts @@ -1,7 +1,7 @@ import { xai } from '@ai-sdk/xai'; import { streamObject } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamObject({ diff --git a/examples/ai-core/src/stream-text/amazon-bedrock-cache-point-tool-call.ts b/examples/ai-core/src/stream-text/amazon-bedrock-cache-point-tool-call.ts index 0c53cb50f243..8232f6283acc 100644 --- a/examples/ai-core/src/stream-text/amazon-bedrock-cache-point-tool-call.ts +++ b/examples/ai-core/src/stream-text/amazon-bedrock-cache-point-tool-call.ts @@ -1,7 +1,7 @@ import { bedrock } from '@ai-sdk/amazon-bedrock'; import { streamText, tool, ModelMessage } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const messages: ModelMessage[] = []; diff --git a/examples/ai-core/src/stream-text/amazon-bedrock-chatbot.ts b/examples/ai-core/src/stream-text/amazon-bedrock-chatbot.ts index 3b3cb579498b..ec9cf5021b3e 100644 --- a/examples/ai-core/src/stream-text/amazon-bedrock-chatbot.ts +++ b/examples/ai-core/src/stream-text/amazon-bedrock-chatbot.ts @@ -2,7 +2,7 @@ import { bedrock } from '@ai-sdk/amazon-bedrock'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/amazon-bedrock-fullstream.ts b/examples/ai-core/src/stream-text/amazon-bedrock-fullstream.ts index f4f6ad1955e4..f582f47aab0e 100644 --- a/examples/ai-core/src/stream-text/amazon-bedrock-fullstream.ts +++ b/examples/ai-core/src/stream-text/amazon-bedrock-fullstream.ts @@ -1,7 +1,7 @@ import { bedrock } from '@ai-sdk/amazon-bedrock'; import { stepCountIs, streamText, ToolCallPart, ToolResultPart } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/stream-text/amazon-bedrock-reasoning-chatbot.ts b/examples/ai-core/src/stream-text/amazon-bedrock-reasoning-chatbot.ts index 5f4bd8a9ca07..4a7a152d57e6 100644 --- a/examples/ai-core/src/stream-text/amazon-bedrock-reasoning-chatbot.ts +++ b/examples/ai-core/src/stream-text/amazon-bedrock-reasoning-chatbot.ts @@ -2,7 +2,7 @@ import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const bedrock = createAmazonBedrock({ // example fetch wrapper that logs the input to the API call: diff --git a/examples/ai-core/src/stream-text/anthropic-chatbot.ts b/examples/ai-core/src/stream-text/anthropic-chatbot.ts index cbeea13db127..3ba55d204abe 100644 --- a/examples/ai-core/src/stream-text/anthropic-chatbot.ts +++ b/examples/ai-core/src/stream-text/anthropic-chatbot.ts @@ -2,7 +2,7 @@ import { anthropic } from '@ai-sdk/anthropic'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/anthropic-fullstream.ts b/examples/ai-core/src/stream-text/anthropic-fullstream.ts index 48aad985ede5..0736bf864d50 100644 --- a/examples/ai-core/src/stream-text/anthropic-fullstream.ts +++ b/examples/ai-core/src/stream-text/anthropic-fullstream.ts @@ -1,7 +1,7 @@ import { anthropic } from '@ai-sdk/anthropic'; import { streamText } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/stream-text/anthropic-reasoning-chatbot.ts b/examples/ai-core/src/stream-text/anthropic-reasoning-chatbot.ts index 731bee6b322b..eddeffdd5ca9 100644 --- a/examples/ai-core/src/stream-text/anthropic-reasoning-chatbot.ts +++ b/examples/ai-core/src/stream-text/anthropic-reasoning-chatbot.ts @@ -2,7 +2,7 @@ import { AnthropicProviderOptions, createAnthropic } from '@ai-sdk/anthropic'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const anthropic = createAnthropic({ // example fetch wrapper that logs the input to the API call: diff --git a/examples/ai-core/src/stream-text/azure-fullstream.ts b/examples/ai-core/src/stream-text/azure-fullstream.ts index f3e3a70e7e97..09603ea288a8 100644 --- a/examples/ai-core/src/stream-text/azure-fullstream.ts +++ b/examples/ai-core/src/stream-text/azure-fullstream.ts @@ -1,7 +1,7 @@ import { azure } from '@ai-sdk/azure'; import { streamText } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/stream-text/cohere-chatbot.ts b/examples/ai-core/src/stream-text/cohere-chatbot.ts index 17fff2b43b50..c20471aee0fa 100644 --- a/examples/ai-core/src/stream-text/cohere-chatbot.ts +++ b/examples/ai-core/src/stream-text/cohere-chatbot.ts @@ -2,7 +2,7 @@ import { cohere } from '@ai-sdk/cohere'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/cohere-tool-call-empty-params.ts b/examples/ai-core/src/stream-text/cohere-tool-call-empty-params.ts index f74b99a8447e..20de2baa87ed 100644 --- a/examples/ai-core/src/stream-text/cohere-tool-call-empty-params.ts +++ b/examples/ai-core/src/stream-text/cohere-tool-call-empty-params.ts @@ -7,7 +7,7 @@ import { tool, } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const messages: ModelMessage[] = []; diff --git a/examples/ai-core/src/stream-text/google-chatbot-image-output.ts b/examples/ai-core/src/stream-text/google-chatbot-image-output.ts index 158f5a2f8d16..e264b2bb7a8a 100644 --- a/examples/ai-core/src/stream-text/google-chatbot-image-output.ts +++ b/examples/ai-core/src/stream-text/google-chatbot-image-output.ts @@ -17,9 +17,6 @@ async function main() { const result = streamText({ model: google('gemini-2.0-flash-exp'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, messages, }); diff --git a/examples/ai-core/src/stream-text/google-chatbot.ts b/examples/ai-core/src/stream-text/google-chatbot.ts index 3e667f7ecfe7..491c318c66d0 100644 --- a/examples/ai-core/src/stream-text/google-chatbot.ts +++ b/examples/ai-core/src/stream-text/google-chatbot.ts @@ -2,7 +2,7 @@ import { google } from '@ai-sdk/google'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/google-fullstream.ts b/examples/ai-core/src/stream-text/google-fullstream.ts index e7e87992dce0..2019b50b2b46 100644 --- a/examples/ai-core/src/stream-text/google-fullstream.ts +++ b/examples/ai-core/src/stream-text/google-fullstream.ts @@ -1,7 +1,7 @@ import { google } from '@ai-sdk/google'; import { streamText } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/stream-text/google-gemini-2.5-flash-image-preview-chatbot.ts b/examples/ai-core/src/stream-text/google-gemini-2.5-flash-image-preview-chatbot.ts index 9a0eb5c4f65c..15394a00aed7 100644 --- a/examples/ai-core/src/stream-text/google-gemini-2.5-flash-image-preview-chatbot.ts +++ b/examples/ai-core/src/stream-text/google-gemini-2.5-flash-image-preview-chatbot.ts @@ -17,9 +17,6 @@ async function main() { const result = streamText({ model: google('gemini-2.5-flash-image-preview'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, messages, }); diff --git a/examples/ai-core/src/stream-text/google-image-output.ts b/examples/ai-core/src/stream-text/google-image-output.ts index 17650996a8e1..f86914958b91 100644 --- a/examples/ai-core/src/stream-text/google-image-output.ts +++ b/examples/ai-core/src/stream-text/google-image-output.ts @@ -7,9 +7,6 @@ async function main() { const result = streamText({ model: google('gemini-2.0-flash-exp'), prompt: 'Generate an image of a comic cat', - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, }); for await (const part of result.fullStream) { diff --git a/examples/ai-core/src/stream-text/google-vertex-anthropic-chatbot.ts b/examples/ai-core/src/stream-text/google-vertex-anthropic-chatbot.ts index 16e9e7717f17..49126fd4d221 100644 --- a/examples/ai-core/src/stream-text/google-vertex-anthropic-chatbot.ts +++ b/examples/ai-core/src/stream-text/google-vertex-anthropic-chatbot.ts @@ -2,7 +2,7 @@ import 'dotenv/config'; import { vertexAnthropic } from '@ai-sdk/google-vertex/anthropic'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/google-vertex-anthropic-fullstream.ts b/examples/ai-core/src/stream-text/google-vertex-anthropic-fullstream.ts index 74035bbf9e5c..016cc18a4da4 100644 --- a/examples/ai-core/src/stream-text/google-vertex-anthropic-fullstream.ts +++ b/examples/ai-core/src/stream-text/google-vertex-anthropic-fullstream.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { vertexAnthropic } from '@ai-sdk/google-vertex/anthropic'; import { streamText } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/stream-text/google-vertex-fullstream.ts b/examples/ai-core/src/stream-text/google-vertex-fullstream.ts index 7ad45bfe4c25..c4e7d4561336 100644 --- a/examples/ai-core/src/stream-text/google-vertex-fullstream.ts +++ b/examples/ai-core/src/stream-text/google-vertex-fullstream.ts @@ -1,7 +1,7 @@ import { vertex } from '@ai-sdk/google-vertex'; import { streamText } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/stream-text/google.ts b/examples/ai-core/src/stream-text/google.ts index 8b2faf47bd58..e7b82ff20706 100644 --- a/examples/ai-core/src/stream-text/google.ts +++ b/examples/ai-core/src/stream-text/google.ts @@ -13,9 +13,15 @@ async function main() { process.stdout.write(textPart); } + const googleMetadata = (await result.providerMetadata)?.google; + console.log(); console.log('Token usage:', await result.usage); console.log('Finish reason:', await result.finishReason); + console.log('Safety info:', { + promptFeedback: googleMetadata?.promptFeedback, + safetyRatings: googleMetadata?.safetyRatings, + }); } main().catch(console.error); diff --git a/examples/ai-core/src/stream-text/groq-chatbot.ts b/examples/ai-core/src/stream-text/groq-chatbot.ts index f4583ee8e3f0..12901cea40b2 100644 --- a/examples/ai-core/src/stream-text/groq-chatbot.ts +++ b/examples/ai-core/src/stream-text/groq-chatbot.ts @@ -2,7 +2,7 @@ import { groq } from '@ai-sdk/groq'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/mistral-chatbot.ts b/examples/ai-core/src/stream-text/mistral-chatbot.ts index 419ab466b6d5..b6a9126aed18 100644 --- a/examples/ai-core/src/stream-text/mistral-chatbot.ts +++ b/examples/ai-core/src/stream-text/mistral-chatbot.ts @@ -2,7 +2,7 @@ import { mistral } from '@ai-sdk/mistral'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/mistral-disable-parallel-tools.ts b/examples/ai-core/src/stream-text/mistral-disable-parallel-tools.ts new file mode 100644 index 000000000000..bab8efabbe63 --- /dev/null +++ b/examples/ai-core/src/stream-text/mistral-disable-parallel-tools.ts @@ -0,0 +1,54 @@ +import { streamText, tool } from 'ai'; +import { z } from 'zod'; +import 'dotenv/config'; +import { mistral } from '@ai-sdk/mistral'; + +async function main() { + const result = streamText({ + model: mistral('mistral-small-latest'), + prompt: 'What is the weather in Paris, France and London, UK?', + tools: { + getWeather: tool({ + description: 'Get the current weather for a location', + inputSchema: z.object({ + location: z + .string() + .describe('The city and state, e.g. San Francisco, CA'), + }), + execute: async ({ location }: { location: string }) => { + return `Weather in ${location}: 72°F, sunny`; + }, + }), + }, + providerOptions: { + mistral: { + parallelToolCalls: false, + }, + }, + }); + + for await (const chunk of result.fullStream) { + switch (chunk.type) { + case 'text-delta': { + process.stdout.write(chunk.text); + break; + } + case 'tool-call': { + console.log( + `\nTOOL CALL: ${chunk.toolName}(${JSON.stringify(chunk.input)})`, + ); + break; + } + case 'tool-result': { + console.log(`TOOL RESULT: ${JSON.stringify(chunk.output)}`); + break; + } + } + } + + console.log(); + console.log('Token usage:', await result.usage); + console.log('Finish reason:', await result.finishReason); +} + +main().catch(console.error); diff --git a/examples/ai-core/src/stream-text/mistral-fullstream.ts b/examples/ai-core/src/stream-text/mistral-fullstream.ts index 5ad619548310..d17d6be05e14 100644 --- a/examples/ai-core/src/stream-text/mistral-fullstream.ts +++ b/examples/ai-core/src/stream-text/mistral-fullstream.ts @@ -1,7 +1,7 @@ import { mistral } from '@ai-sdk/mistral'; import { streamText } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/stream-text/mock-tool-call-repair-change-tool.ts b/examples/ai-core/src/stream-text/mock-tool-call-repair-change-tool.ts index 8b74462a8f13..2ede4ea92b4f 100644 --- a/examples/ai-core/src/stream-text/mock-tool-call-repair-change-tool.ts +++ b/examples/ai-core/src/stream-text/mock-tool-call-repair-change-tool.ts @@ -1,7 +1,7 @@ import { streamText, tool } from 'ai'; import { convertArrayToReadableStream, MockLanguageModelV2 } from 'ai/test'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-5-reasoning.ts b/examples/ai-core/src/stream-text/openai-5-reasoning.ts deleted file mode 100644 index 066760773546..000000000000 --- a/examples/ai-core/src/stream-text/openai-5-reasoning.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { openai } from '@ai-sdk/openai'; -import { streamText } from 'ai'; -import 'dotenv/config'; -import { z } from 'zod/v4'; -import { weatherTool } from '../tools/weather-tool'; - -async function main() { - const result = streamText({ - model: openai('gpt-5'), - tools: { - weather: weatherTool, - cityAttractions: { - inputSchema: z.object({ city: z.string() }), - }, - }, - prompt: 'What is the weather in San Francisco?', - }); - - for await (const part of result.fullStream) { - switch (part.type) { - case 'text-delta': { - console.log('Text:', part.text); - break; - } - - case 'tool-call': { - if (part.dynamic) { - continue; - } - - switch (part.toolName) { - case 'cityAttractions': { - console.log('TOOL CALL cityAttractions'); - console.log(`city: ${part.input.city}`); // string - break; - } - - case 'weather': { - console.log('TOOL CALL weather'); - console.log(`location: ${part.input.location}`); // string - break; - } - } - - break; - } - - case 'tool-result': { - if (part.dynamic) { - continue; - } - - switch (part.toolName) { - // NOT AVAILABLE (NO EXECUTE METHOD) - // case 'cityAttractions': { - // console.log('TOOL RESULT cityAttractions'); - // console.log(`city: ${part.input.city}`); // string - // console.log(`result: ${part.result}`); - // break; - // } - - case 'weather': { - console.log('TOOL RESULT weather'); - console.log(`location: ${part.input.location}`); // string - console.log(`temperature: ${part.output.temperature}`); // number - break; - } - } - - break; - } - - case 'finish': { - console.log('Finish reason:', part.finishReason); - console.log('Total Usage:', part.totalUsage); - break; - } - - case 'error': - console.error('Error:', part.error); - break; - } - } -} - -main().catch(console.error); diff --git a/examples/ai-core/src/stream-text/openai-chatbot.ts b/examples/ai-core/src/stream-text/openai-chatbot.ts index f40675776da6..e603acbaa0da 100644 --- a/examples/ai-core/src/stream-text/openai-chatbot.ts +++ b/examples/ai-core/src/stream-text/openai-chatbot.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/openai-code-interpreter-tool.ts b/examples/ai-core/src/stream-text/openai-code-interpreter-tool.ts index bad0a0d73af3..8c664a4bc266 100644 --- a/examples/ai-core/src/stream-text/openai-code-interpreter-tool.ts +++ b/examples/ai-core/src/stream-text/openai-code-interpreter-tool.ts @@ -1,8 +1,8 @@ import { openai } from '@ai-sdk/openai'; import { streamText } from 'ai'; -import 'dotenv/config'; +import { run } from '../lib/run'; -async function main() { +run(async () => { const result = streamText({ model: openai.responses('gpt-5-nano'), tools: { @@ -10,16 +10,10 @@ async function main() { }, prompt: 'Simulate rolling two dice 10000 times and and return the sum all the results.', - // includeRawChunks: true, }); for await (const chunk of result.fullStream) { switch (chunk.type) { - case 'raw': { - console.log('Raw chunk:', JSON.stringify(chunk.rawValue)); - break; - } - case 'text-delta': { process.stdout.write(chunk.text); break; @@ -40,6 +34,4 @@ async function main() { break; } } -} - -main().catch(console.error); +}); diff --git a/examples/ai-core/src/stream-text/openai-dynamic-tool-call.ts b/examples/ai-core/src/stream-text/openai-dynamic-tool-call.ts index 4664a2bc90a9..b265e1194ded 100644 --- a/examples/ai-core/src/stream-text/openai-dynamic-tool-call.ts +++ b/examples/ai-core/src/stream-text/openai-dynamic-tool-call.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import 'dotenv/config'; import { weatherTool } from '../tools/weather-tool'; import { stepCountIs, streamText, dynamicTool, ToolSet } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; function dynamicTools(): ToolSet { return { diff --git a/examples/ai-core/src/stream-text/openai-file-search-tool.ts b/examples/ai-core/src/stream-text/openai-file-search-tool.ts new file mode 100644 index 000000000000..587015f93ef5 --- /dev/null +++ b/examples/ai-core/src/stream-text/openai-file-search-tool.ts @@ -0,0 +1,54 @@ +import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; +import { streamText } from 'ai'; +import { run } from '../lib/run'; + +run(async () => { + const result = streamText({ + model: openai('gpt-5-mini'), + prompt: 'What is an embedding model according to this document?', + tools: { + file_search: openai.tools.fileSearch({ + vectorStoreIds: ['vs_68caad8bd5d88191ab766cf043d89a18'], + }), + }, + providerOptions: { + openai: { + include: ['file_search_call.results'], + } satisfies OpenAIResponsesProviderOptions, + }, + }); + + for await (const chunk of result.fullStream) { + switch (chunk.type) { + case 'text-delta': { + process.stdout.write(chunk.text); + break; + } + + case 'tool-call': { + console.log( + `\x1b[32m\x1b[1mTool call:\x1b[22m ${JSON.stringify(chunk, null, 2)}\x1b[0m`, + ); + break; + } + + case 'tool-result': { + console.log( + `\x1b[32m\x1b[1mTool result:\x1b[22m ${JSON.stringify(chunk, null, 2)}\x1b[0m`, + ); + break; + } + + case 'source': { + process.stdout.write( + `\n\n\x1b[36mSource: ${chunk.title} (${JSON.stringify(chunk)})\x1b[0m\n\n`, + ); + break; + } + + case 'error': + console.error('Error:', chunk.error); + break; + } + } +}); diff --git a/examples/ai-core/src/stream-text/openai-fullstream.ts b/examples/ai-core/src/stream-text/openai-fullstream.ts index ed7aa9c9baa8..a97c7c9f6945 100644 --- a/examples/ai-core/src/stream-text/openai-fullstream.ts +++ b/examples/ai-core/src/stream-text/openai-fullstream.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamText } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/stream-text/openai-image-generation-tool.ts b/examples/ai-core/src/stream-text/openai-image-generation-tool.ts new file mode 100644 index 000000000000..d4570a41c675 --- /dev/null +++ b/examples/ai-core/src/stream-text/openai-image-generation-tool.ts @@ -0,0 +1,31 @@ +import { openai } from '@ai-sdk/openai'; +import { streamText } from 'ai'; +import { convertBase64ToUint8Array } from '../lib/convertBase64ToUint8Array'; +import { presentImages } from '../lib/present-image'; +import { run } from '../lib/run'; + +run(async () => { + const result = streamText({ + model: openai('gpt-5'), + prompt: + 'Generate an image of an echidna swimming across the Mozambique channel.', + tools: { + image_generation: openai.tools.imageGeneration({ + outputFormat: 'webp', + quality: 'low', + }), + }, + }); + + for await (const part of result.fullStream) { + if (part.type == 'tool-result' && !part.dynamic) { + await presentImages([ + { + mediaType: 'image/webp', + base64: part.output.result, + uint8Array: convertBase64ToUint8Array(part.output.result), + }, + ]); + } + } +}); diff --git a/examples/ai-core/src/stream-text/openai-multi-step.ts b/examples/ai-core/src/stream-text/openai-multi-step.ts index d44977e842ad..0e0d7af5f260 100644 --- a/examples/ai-core/src/stream-text/openai-multi-step.ts +++ b/examples/ai-core/src/stream-text/openai-multi-step.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-on-chunk-tool-call-streaming.ts b/examples/ai-core/src/stream-text/openai-on-chunk-tool-call-streaming.ts index 7c53467fb8d2..336471eb7b8b 100644 --- a/examples/ai-core/src/stream-text/openai-on-chunk-tool-call-streaming.ts +++ b/examples/ai-core/src/stream-text/openai-on-chunk-tool-call-streaming.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { streamText } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; async function main() { diff --git a/examples/ai-core/src/stream-text/openai-on-finish-response-messages.ts b/examples/ai-core/src/stream-text/openai-on-finish-response-messages.ts index b5498c718f21..14b2825f096f 100644 --- a/examples/ai-core/src/stream-text/openai-on-finish-response-messages.ts +++ b/examples/ai-core/src/stream-text/openai-on-finish-response-messages.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-on-finish-steps.ts b/examples/ai-core/src/stream-text/openai-on-finish-steps.ts index c3da4d22ea3f..c786ea755a79 100644 --- a/examples/ai-core/src/stream-text/openai-on-finish-steps.ts +++ b/examples/ai-core/src/stream-text/openai-on-finish-steps.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-on-step-finish.ts b/examples/ai-core/src/stream-text/openai-on-step-finish.ts index d950ac2f9c9f..96e448d03f99 100644 --- a/examples/ai-core/src/stream-text/openai-on-step-finish.ts +++ b/examples/ai-core/src/stream-text/openai-on-step-finish.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-output-object.ts b/examples/ai-core/src/stream-text/openai-output-object.ts index 52ec32cafe13..afcf6cdefcbd 100644 --- a/examples/ai-core/src/stream-text/openai-output-object.ts +++ b/examples/ai-core/src/stream-text/openai-output-object.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, Output, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const { experimental_partialOutputStream: partialOutputStream } = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-prepare-step.ts b/examples/ai-core/src/stream-text/openai-prepare-step.ts index fb21005ef2f3..bfb532d440b2 100644 --- a/examples/ai-core/src/stream-text/openai-prepare-step.ts +++ b/examples/ai-core/src/stream-text/openai-prepare-step.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const retrieveInformation = tool({ description: 'Retrieve information from the database', diff --git a/examples/ai-core/src/stream-text/openai-read-ui-message-stream.ts b/examples/ai-core/src/stream-text/openai-read-ui-message-stream.ts index 8e77a68cff7d..5319ddaa819d 100644 --- a/examples/ai-core/src/stream-text/openai-read-ui-message-stream.ts +++ b/examples/ai-core/src/stream-text/openai-read-ui-message-stream.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { readUIMessageStream, stepCountIs, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-responses-chatbot.ts b/examples/ai-core/src/stream-text/openai-responses-chatbot.ts index 4e5e8552e76f..0f1f049b8606 100644 --- a/examples/ai-core/src/stream-text/openai-responses-chatbot.ts +++ b/examples/ai-core/src/stream-text/openai-responses-chatbot.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/openai-responses-reasoning-chatbot.ts b/examples/ai-core/src/stream-text/openai-responses-reasoning-chatbot.ts index 6a0894a9605f..6724a3c2a25c 100644 --- a/examples/ai-core/src/stream-text/openai-responses-reasoning-chatbot.ts +++ b/examples/ai-core/src/stream-text/openai-responses-reasoning-chatbot.ts @@ -2,7 +2,7 @@ import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; import { stepCountIs, ModelMessage, streamText, tool, APICallError } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/openai-responses-reasoning-tool-call.ts b/examples/ai-core/src/stream-text/openai-responses-reasoning-tool-call.ts index 5c91bcc32777..42f09fa37782 100644 --- a/examples/ai-core/src/stream-text/openai-responses-reasoning-tool-call.ts +++ b/examples/ai-core/src/stream-text/openai-responses-reasoning-tool-call.ts @@ -1,7 +1,7 @@ import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; import { stepCountIs, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-responses-reasoning.ts b/examples/ai-core/src/stream-text/openai-responses-reasoning.ts deleted file mode 100644 index 463a8daaba89..000000000000 --- a/examples/ai-core/src/stream-text/openai-responses-reasoning.ts +++ /dev/null @@ -1,21 +0,0 @@ -import 'dotenv/config'; -import { openai } from '@ai-sdk/openai'; -import { streamText } from 'ai'; - -async function main() { - const result = streamText({ - model: openai.responses('o3-mini'), - system: 'You are a helpful assistant.', - prompt: 'Invent a new holiday and describe its traditions.', - }); - - for await (const textPart of result.textStream) { - process.stdout.write(textPart); - } - - console.log(); - console.log('Finish reason:', await result.finishReason); - console.log('Usage:', await result.usage); -} - -main().catch(console.error); diff --git a/examples/ai-core/src/stream-text/openai-responses-tool-call.ts b/examples/ai-core/src/stream-text/openai-responses-tool-call.ts index 3132e0ac513d..35072b5198a9 100644 --- a/examples/ai-core/src/stream-text/openai-responses-tool-call.ts +++ b/examples/ai-core/src/stream-text/openai-responses-tool-call.ts @@ -2,7 +2,7 @@ import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; import 'dotenv/config'; import { weatherTool } from '../tools/weather-tool'; import { stepCountIs, streamText, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-swarm.ts b/examples/ai-core/src/stream-text/openai-swarm.ts index 1e83cf550cca..37fd2b9d4a71 100644 --- a/examples/ai-core/src/stream-text/openai-swarm.ts +++ b/examples/ai-core/src/stream-text/openai-swarm.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; main().catch(console.error); diff --git a/examples/ai-core/src/stream-text/openai-tool-abort.ts b/examples/ai-core/src/stream-text/openai-tool-abort.ts index c2aadacfca58..ff940e42fe44 100644 --- a/examples/ai-core/src/stream-text/openai-tool-abort.ts +++ b/examples/ai-core/src/stream-text/openai-tool-abort.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, streamText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const abortController = new AbortController(); diff --git a/examples/ai-core/src/stream-text/openai-tool-call.ts b/examples/ai-core/src/stream-text/openai-tool-call.ts index 398e24019222..e74f866926f2 100644 --- a/examples/ai-core/src/stream-text/openai-tool-call.ts +++ b/examples/ai-core/src/stream-text/openai-tool-call.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import 'dotenv/config'; import { weatherTool } from '../tools/weather-tool'; import { stepCountIs, streamText, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-tool-output-stream.ts b/examples/ai-core/src/stream-text/openai-tool-output-stream.ts index b9b05729bc31..f5ec079c1199 100644 --- a/examples/ai-core/src/stream-text/openai-tool-output-stream.ts +++ b/examples/ai-core/src/stream-text/openai-tool-output-stream.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import 'dotenv/config'; import { stepCountIs, streamText, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { const result = streamText({ diff --git a/examples/ai-core/src/stream-text/openai-web-search-tool.ts b/examples/ai-core/src/stream-text/openai-web-search-tool.ts index 5a13c25b90f7..0133626b17c9 100644 --- a/examples/ai-core/src/stream-text/openai-web-search-tool.ts +++ b/examples/ai-core/src/stream-text/openai-web-search-tool.ts @@ -1,17 +1,16 @@ import { openai } from '@ai-sdk/openai'; -import { stepCountIs, streamText } from 'ai'; -import 'dotenv/config'; +import { streamText } from 'ai'; +import { run } from '../lib/run'; -async function main() { +run(async () => { const result = streamText({ - model: openai.responses('gpt-4o-mini'), + model: openai('gpt-5-mini'), + prompt: 'What happened in tech news today?', tools: { web_search: openai.tools.webSearch({ - searchContextSize: 'high', + searchContextSize: 'medium', }), }, - prompt: 'Look up the company that owns Sonny Angel', - stopWhen: stepCountIs(5), // note: should stop after a single step }); for await (const chunk of result.fullStream) { @@ -22,46 +21,31 @@ async function main() { } case 'tool-call': { - console.log('Tool call:', JSON.stringify(chunk, null, 2)); + console.log( + `\x1b[32m\x1b[1mTool call:\x1b[22m ${JSON.stringify(chunk, null, 2)}\x1b[0m`, + ); break; } case 'tool-result': { - console.log('Tool result:', JSON.stringify(chunk, null, 2)); + console.log( + `\x1b[32m\x1b[1mTool result:\x1b[22m ${JSON.stringify(chunk, null, 2)}\x1b[0m`, + ); break; } case 'source': { if (chunk.sourceType === 'url') { - process.stdout.write(`\n\n Source: ${chunk.title} (${chunk.url})`); - } else { - process.stdout.write(`\n\n Document: ${chunk.title}`); + process.stdout.write( + `\n\n\x1b[36mSource: ${chunk.title} (${chunk.url})\x1b[0m\n\n`, + ); } break; } - case 'finish-step': { - console.log(); - console.log(); - console.log('STEP FINISH'); - console.log('Finish reason:', chunk.finishReason); - console.log('Usage:', chunk.usage); - console.log(); - break; - } - - case 'finish': { - console.log('FINISH'); - console.log('Finish reason:', chunk.finishReason); - console.log('Total Usage:', chunk.totalUsage); - break; - } - case 'error': console.error('Error:', chunk.error); break; } } -} - -main().catch(console.error); +}); diff --git a/examples/ai-core/src/stream-text/vertex-gemini-2.5-flash-image-preview-chatbot.ts b/examples/ai-core/src/stream-text/vertex-gemini-2.5-flash-image-preview-chatbot.ts index c8a95f0c09c6..ba484aeb1f9c 100644 --- a/examples/ai-core/src/stream-text/vertex-gemini-2.5-flash-image-preview-chatbot.ts +++ b/examples/ai-core/src/stream-text/vertex-gemini-2.5-flash-image-preview-chatbot.ts @@ -17,9 +17,6 @@ async function main() { const result = streamText({ model: vertex('gemini-2.5-flash-image-preview'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, messages, }); diff --git a/examples/ai-core/src/stream-text/xai-chatbot.ts b/examples/ai-core/src/stream-text/xai-chatbot.ts index 4bc7467b0307..fdce2962177e 100644 --- a/examples/ai-core/src/stream-text/xai-chatbot.ts +++ b/examples/ai-core/src/stream-text/xai-chatbot.ts @@ -2,7 +2,7 @@ import { xai } from '@ai-sdk/xai'; import { stepCountIs, ModelMessage, streamText, tool } from 'ai'; import 'dotenv/config'; import * as readline from 'node:readline/promises'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const terminal = readline.createInterface({ input: process.stdin, diff --git a/examples/ai-core/src/stream-text/xai-search.ts b/examples/ai-core/src/stream-text/xai-search.ts index 45d3510a92c5..c18c17fa20bc 100644 --- a/examples/ai-core/src/stream-text/xai-search.ts +++ b/examples/ai-core/src/stream-text/xai-search.ts @@ -16,7 +16,7 @@ async function main() { sources: [ { type: 'x', - xHandles: ['nishimiya'], + includedXHandles: ['nishimiya'], }, ], }, diff --git a/examples/ai-core/src/telemetry/generate-object.ts b/examples/ai-core/src/telemetry/generate-object.ts index 1c793ee2cd81..dfa5214e1437 100644 --- a/examples/ai-core/src/telemetry/generate-object.ts +++ b/examples/ai-core/src/telemetry/generate-object.ts @@ -5,7 +5,7 @@ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentation import { NodeSDK } from '@opentelemetry/sdk-node'; import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node'; import { generateObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const sdk = new NodeSDK({ traceExporter: new ConsoleSpanExporter(), diff --git a/examples/ai-core/src/telemetry/generate-text-tool-call.ts b/examples/ai-core/src/telemetry/generate-text-tool-call.ts index 705419bcf20c..c26e221b35da 100644 --- a/examples/ai-core/src/telemetry/generate-text-tool-call.ts +++ b/examples/ai-core/src/telemetry/generate-text-tool-call.ts @@ -1,7 +1,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText, tool } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; import { weatherTool } from '../tools/weather-tool'; import { NodeSDK } from '@opentelemetry/sdk-node'; diff --git a/examples/ai-core/src/telemetry/stream-object.ts b/examples/ai-core/src/telemetry/stream-object.ts index 1b5eb480007e..12ab6af6bbee 100644 --- a/examples/ai-core/src/telemetry/stream-object.ts +++ b/examples/ai-core/src/telemetry/stream-object.ts @@ -5,7 +5,7 @@ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentation import { NodeSDK } from '@opentelemetry/sdk-node'; import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node'; import { streamObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const sdk = new NodeSDK({ traceExporter: new ConsoleSpanExporter(), diff --git a/examples/ai-core/src/tools/weather-tool.ts b/examples/ai-core/src/tools/weather-tool.ts index a4588a9adbe7..83fceab490d1 100644 --- a/examples/ai-core/src/tools/weather-tool.ts +++ b/examples/ai-core/src/tools/weather-tool.ts @@ -1,5 +1,5 @@ import { tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export const weatherTool = tool({ description: 'Get the weather in a location', diff --git a/examples/ai-core/src/types/tool-set.ts b/examples/ai-core/src/types/tool-set.ts index b9a2dee6ec71..c4c49490990c 100644 --- a/examples/ai-core/src/types/tool-set.ts +++ b/examples/ai-core/src/types/tool-set.ts @@ -1,6 +1,6 @@ import { openai } from '@ai-sdk/openai'; import { StaticToolCall, StaticToolResult, generateText, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const myToolSet = { firstTool: tool({ diff --git a/examples/mcp/src/stdio/client.ts b/examples/mcp/src/stdio/client.ts index e0f83cdf0075..b3f5e137e27a 100644 --- a/examples/mcp/src/stdio/client.ts +++ b/examples/mcp/src/stdio/client.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; import { experimental_createMCPClient, generateText, stepCountIs } from 'ai'; import 'dotenv/config'; -import { z } from 'zod/v4'; +import { z } from 'zod'; async function main() { let mcpClient; diff --git a/examples/next-agent/tool/weather-tool.ts b/examples/next-agent/tool/weather-tool.ts index 14350de8c14c..05b2491476cb 100644 --- a/examples/next-agent/tool/weather-tool.ts +++ b/examples/next-agent/tool/weather-tool.ts @@ -1,5 +1,5 @@ import { UIToolInvocation, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export const weatherTool = tool({ description: 'Get the weather in a location', diff --git a/examples/next-openai-pages/app/api/call-tool/route.ts b/examples/next-openai-pages/app/api/call-tool/route.ts index e7bb0c046c0d..a406610d06f7 100644 --- a/examples/next-openai-pages/app/api/call-tool/route.ts +++ b/examples/next-openai-pages/app/api/call-tool/route.ts @@ -1,6 +1,6 @@ import { convertToModelMessages, streamText, UIMessage } from 'ai'; import { openai } from '@ai-sdk/openai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json(); diff --git a/examples/next-openai-pages/app/api/generate-object/route.ts b/examples/next-openai-pages/app/api/generate-object/route.ts index 3a3a5e6d677f..cabff4128d87 100644 --- a/examples/next-openai-pages/app/api/generate-object/route.ts +++ b/examples/next-openai-pages/app/api/generate-object/route.ts @@ -1,6 +1,6 @@ import { generateObject } from 'ai'; import { openai } from '@ai-sdk/openai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export async function POST(req: Request) { const { prompt }: { prompt: string } = await req.json(); diff --git a/examples/next-openai-pages/app/api/stream-object/route.ts b/examples/next-openai-pages/app/api/stream-object/route.ts index 2bc0b6e8662f..e8570b33b9a3 100644 --- a/examples/next-openai-pages/app/api/stream-object/route.ts +++ b/examples/next-openai-pages/app/api/stream-object/route.ts @@ -1,6 +1,6 @@ import { openai } from '@ai-sdk/openai'; import { streamObject } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export const maxDuration = 30; diff --git a/examples/next-openai/app/api/chat-openai-code-interpreter/route.ts b/examples/next-openai/app/api/chat-openai-code-interpreter/route.ts new file mode 100644 index 000000000000..5e863f2f5e96 --- /dev/null +++ b/examples/next-openai/app/api/chat-openai-code-interpreter/route.ts @@ -0,0 +1,42 @@ +import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; +import { + convertToModelMessages, + InferUITools, + streamText, + ToolSet, + UIDataTypes, + UIMessage, + validateUIMessages, +} from 'ai'; + +const tools = { + code_interpreter: openai.tools.codeInterpreter(), +} satisfies ToolSet; + +export type OpenAICodeInterpreterMessage = UIMessage< + never, + UIDataTypes, + InferUITools +>; + +export async function POST(req: Request) { + const { messages } = await req.json(); + const uiMessages = await validateUIMessages({ messages }); + + const result = streamText({ + model: openai('gpt-5-nano'), + tools, + messages: convertToModelMessages(uiMessages), + onStepFinish: ({ request }) => { + console.log(JSON.stringify(request.body, null, 2)); + }, + providerOptions: { + openai: { + store: false, + include: ['reasoning.encrypted_content'], + } satisfies OpenAIResponsesProviderOptions, + }, + }); + + return result.toUIMessageStreamResponse(); +} diff --git a/examples/next-openai/app/api/chat-openai-file-search/route.ts b/examples/next-openai/app/api/chat-openai-file-search/route.ts index 5fe5d3f2c5f0..23dd1c5ea9db 100644 --- a/examples/next-openai/app/api/chat-openai-file-search/route.ts +++ b/examples/next-openai/app/api/chat-openai-file-search/route.ts @@ -1,38 +1,44 @@ -import { openai } from '@ai-sdk/openai'; +import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; import { convertToModelMessages, - InferUITool, + InferUITools, streamText, + ToolSet, UIDataTypes, UIMessage, + validateUIMessages, } from 'ai'; export const maxDuration = 30; +const tools = { + file_search: openai.tools.fileSearch({ + vectorStoreIds: ['vs_68caad8bd5d88191ab766cf043d89a18'], + }), +} satisfies ToolSet; + export type OpenAIFileSearchMessage = UIMessage< never, UIDataTypes, - { - file_search: InferUITool>; - } + InferUITools >; export async function POST(req: Request) { const { messages } = await req.json(); + const uiMessages = await validateUIMessages({ messages }); const result = streamText({ - model: openai.responses('gpt-4o-mini'), - tools: { - file_search: openai.tools.fileSearch({ - maxNumResults: 10, - ranking: { - ranker: 'auto', - }, - // vectorStoreIds: ['vs_123'], // optional: specify vector store IDs - // filters: { key: 'category', type: 'eq', value: 'technical' }, // optional: filter results - }), + model: openai('gpt-5-nano'), + tools, + messages: convertToModelMessages(uiMessages), + onStepFinish: ({ request }) => { + console.log(JSON.stringify(request.body, null, 2)); + }, + providerOptions: { + openai: { + include: ['file_search_call.results'], + } satisfies OpenAIResponsesProviderOptions, }, - messages: convertToModelMessages(messages), }); return result.toUIMessageStreamResponse({ diff --git a/examples/next-openai/app/api/chat-openai-image-generation/route.ts b/examples/next-openai/app/api/chat-openai-image-generation/route.ts new file mode 100644 index 000000000000..4c5e63eb1d77 --- /dev/null +++ b/examples/next-openai/app/api/chat-openai-image-generation/route.ts @@ -0,0 +1,42 @@ +import { openai } from '@ai-sdk/openai'; +import { + convertToModelMessages, + InferUITools, + streamText, + ToolSet, + UIDataTypes, + UIMessage, + validateUIMessages, +} from 'ai'; + +const tools = { + image_generation: openai.tools.imageGeneration(), +} satisfies ToolSet; + +export type OpenAIImageGenerationMessage = UIMessage< + never, + UIDataTypes, + InferUITools +>; + +export async function POST(req: Request) { + const { messages } = await req.json(); + const uiMessages = await validateUIMessages({ messages }); + + const result = streamText({ + model: openai('gpt-5-nano'), + tools, + messages: convertToModelMessages(uiMessages), + onStepFinish: ({ request }) => { + console.log(JSON.stringify(request.body, null, 2)); + }, + providerOptions: { + // openai: { + // store: false, + // include: ['reasoning.encrypted_content'], + // } satisfies OpenAIResponsesProviderOptions, + }, + }); + + return result.toUIMessageStreamResponse(); +} diff --git a/examples/next-openai/app/api/chat-openai-web-search/route.ts b/examples/next-openai/app/api/chat-openai-web-search/route.ts index dcecffbff058..f859869715fa 100644 --- a/examples/next-openai/app/api/chat-openai-web-search/route.ts +++ b/examples/next-openai/app/api/chat-openai-web-search/route.ts @@ -1,40 +1,49 @@ -import { openai } from '@ai-sdk/openai'; +import { openai, OpenAIResponsesProviderOptions } from '@ai-sdk/openai'; import { convertToModelMessages, - InferUITool, + InferUITools, streamText, + ToolSet, UIDataTypes, UIMessage, + validateUIMessages, } from 'ai'; -// Allow streaming responses up to 30 seconds -export const maxDuration = 30; +const tools = { + web_search: openai.tools.webSearch({ + searchContextSize: 'low', + userLocation: { + type: 'approximate', + city: 'San Francisco', + region: 'California', + country: 'US', + }, + }), +} satisfies ToolSet; export type OpenAIWebSearchMessage = UIMessage< never, UIDataTypes, - { - web_search: InferUITool>; - } + InferUITools >; export async function POST(req: Request) { const { messages } = await req.json(); + const uiMessages = await validateUIMessages({ messages }); const result = streamText({ - model: openai.responses('gpt-4o-mini'), - tools: { - web_search: openai.tools.webSearch({ - searchContextSize: 'high', - userLocation: { - type: 'approximate', - city: 'San Francisco', - region: 'California', - country: 'US', - }, - }), + model: openai('gpt-5-nano'), + tools, + messages: convertToModelMessages(uiMessages), + onStepFinish: ({ request }) => { + console.log(JSON.stringify(request.body, null, 2)); + }, + providerOptions: { + openai: { + store: false, + include: ['reasoning.encrypted_content'], + } satisfies OpenAIResponsesProviderOptions, }, - messages: convertToModelMessages(messages), }); return result.toUIMessageStreamResponse({ diff --git a/examples/next-openai/app/api/dynamic-tools/route.ts b/examples/next-openai/app/api/dynamic-tools/route.ts index c5a4a2c06538..93cb898401db 100644 --- a/examples/next-openai/app/api/dynamic-tools/route.ts +++ b/examples/next-openai/app/api/dynamic-tools/route.ts @@ -10,7 +10,7 @@ import { UIDataTypes, UIMessage, } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; // Allow streaming responses up to 30 seconds export const maxDuration = 30; diff --git a/examples/next-openai/app/api/test-invalid-tool-call/route.ts b/examples/next-openai/app/api/test-invalid-tool-call/route.ts index bd7d3deb4e31..3ae474401271 100644 --- a/examples/next-openai/app/api/test-invalid-tool-call/route.ts +++ b/examples/next-openai/app/api/test-invalid-tool-call/route.ts @@ -9,7 +9,7 @@ import { UIMessage, } from 'ai'; import { convertArrayToReadableStream, MockLanguageModelV2 } from 'ai/test'; -import { z } from 'zod/v4'; +import { z } from 'zod'; // Allow streaming responses up to 30 seconds export const maxDuration = 30; diff --git a/examples/next-openai/app/api/use-chat-data-ui-parts/route.ts b/examples/next-openai/app/api/use-chat-data-ui-parts/route.ts index c2799f32fecd..4a148f53c63d 100644 --- a/examples/next-openai/app/api/use-chat-data-ui-parts/route.ts +++ b/examples/next-openai/app/api/use-chat-data-ui-parts/route.ts @@ -7,7 +7,7 @@ import { stepCountIs, streamText, } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export async function POST(req: Request) { const { messages } = await req.json(); diff --git a/examples/next-openai/app/api/use-chat-image-output/route.ts b/examples/next-openai/app/api/use-chat-image-output/route.ts index c7e1b442a084..c1b7b979a163 100644 --- a/examples/next-openai/app/api/use-chat-image-output/route.ts +++ b/examples/next-openai/app/api/use-chat-image-output/route.ts @@ -8,9 +8,6 @@ export async function POST(req: Request) { const result = streamText({ model: google('gemini-2.0-flash-exp'), - providerOptions: { - google: { responseModalities: ['TEXT', 'IMAGE'] }, - }, messages: convertToModelMessages(messages), }); diff --git a/examples/next-openai/app/api/use-chat-message-metadata/example-metadata-schema.ts b/examples/next-openai/app/api/use-chat-message-metadata/example-metadata-schema.ts index aa2be9ecb2f1..9821f9e2083d 100644 --- a/examples/next-openai/app/api/use-chat-message-metadata/example-metadata-schema.ts +++ b/examples/next-openai/app/api/use-chat-message-metadata/example-metadata-schema.ts @@ -1,4 +1,4 @@ -import { z } from 'zod/v4'; +import { z } from 'zod'; export const exampleMetadataSchema = z.object({ createdAt: z.number().optional(), diff --git a/examples/next-openai/app/api/use-chat-streaming-tool-calls/route.ts b/examples/next-openai/app/api/use-chat-streaming-tool-calls/route.ts index 2144c3038ddb..666cf065e6a9 100644 --- a/examples/next-openai/app/api/use-chat-streaming-tool-calls/route.ts +++ b/examples/next-openai/app/api/use-chat-streaming-tool-calls/route.ts @@ -1,6 +1,6 @@ import { openai } from '@ai-sdk/openai'; import { convertToModelMessages, streamText, UIDataTypes, UIMessage } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; // Allow streaming responses up to 30 seconds export const maxDuration = 30; @@ -44,7 +44,7 @@ export async function POST(req: Request) { }; }, }, - // client-side tool that displays whether information to the user: + // client-side tool that displays weather information to the user: showWeatherInformation: { description: 'Show the weather information to the user. Always use this tool to tell weather information to the user.', diff --git a/examples/next-openai/app/api/use-chat-tools/route.ts b/examples/next-openai/app/api/use-chat-tools/route.ts index 56392ba54446..b584fed7b569 100644 --- a/examples/next-openai/app/api/use-chat-tools/route.ts +++ b/examples/next-openai/app/api/use-chat-tools/route.ts @@ -9,7 +9,7 @@ import { UIMessage, validateUIMessages, } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; // Allow streaming responses up to 30 seconds export const maxDuration = 30; diff --git a/examples/next-openai/app/api/use-completion-server-side-multi-step/route.ts b/examples/next-openai/app/api/use-completion-server-side-multi-step/route.ts index 82466c4a5c52..3b6aad2473d2 100644 --- a/examples/next-openai/app/api/use-completion-server-side-multi-step/route.ts +++ b/examples/next-openai/app/api/use-completion-server-side-multi-step/route.ts @@ -1,6 +1,6 @@ import { openai } from '@ai-sdk/openai'; import { stepCountIs, streamText, tool } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; // Allow streaming responses up to 60 seconds export const maxDuration = 60; diff --git a/examples/next-openai/app/api/use-object-expense-tracker/schema.ts b/examples/next-openai/app/api/use-object-expense-tracker/schema.ts index aeb533e06478..9f7ebd952fd4 100644 --- a/examples/next-openai/app/api/use-object-expense-tracker/schema.ts +++ b/examples/next-openai/app/api/use-object-expense-tracker/schema.ts @@ -1,5 +1,5 @@ import { DeepPartial } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export const expenseSchema = z.object({ expense: z.object({ diff --git a/examples/next-openai/app/api/use-object/schema.ts b/examples/next-openai/app/api/use-object/schema.ts index 37fd5ca61f44..e63dc963f8cf 100644 --- a/examples/next-openai/app/api/use-object/schema.ts +++ b/examples/next-openai/app/api/use-object/schema.ts @@ -1,5 +1,5 @@ import { DeepPartial } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; // define a schema for the notifications export const notificationSchema = z.object({ diff --git a/examples/next-openai/app/stream-object/schema.ts b/examples/next-openai/app/stream-object/schema.ts index 37fd5ca61f44..e63dc963f8cf 100644 --- a/examples/next-openai/app/stream-object/schema.ts +++ b/examples/next-openai/app/stream-object/schema.ts @@ -1,5 +1,5 @@ import { DeepPartial } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; // define a schema for the notifications export const notificationSchema = z.object({ diff --git a/examples/next-openai/app/test-openai-code-interpreter/page.tsx b/examples/next-openai/app/test-openai-code-interpreter/page.tsx new file mode 100644 index 000000000000..00bc1ee84819 --- /dev/null +++ b/examples/next-openai/app/test-openai-code-interpreter/page.tsx @@ -0,0 +1,38 @@ +'use client'; + +import { useChat } from '@ai-sdk/react'; +import { DefaultChatTransport } from 'ai'; +import ChatInput from '@/component/chat-input'; +import { OpenAICodeInterpreterMessage } from '@/app/api/chat-openai-code-interpreter/route'; +import CodeInterpreterView from '@/component/openai-code-interpreter-view'; + +export default function TestOpenAIWebSearch() { + const { status, sendMessage, messages } = + useChat({ + transport: new DefaultChatTransport({ + api: '/api/chat-openai-code-interpreter', + }), + }); + + return ( +
+

OpenAI Code Interpreter Test

+ + {messages.map(message => ( +
+ {message.role === 'user' ? 'User: ' : 'AI: '} + {message.parts.map((part, index) => { + switch (part.type) { + case 'text': + return
{part.text}
; + case 'tool-code_interpreter': + return ; + } + })} +
+ ))} + + sendMessage({ text })} /> +
+ ); +} diff --git a/examples/next-openai/app/test-openai-file-search/page.tsx b/examples/next-openai/app/test-openai-file-search/page.tsx index 266deec05497..777b67d1f28d 100644 --- a/examples/next-openai/app/test-openai-file-search/page.tsx +++ b/examples/next-openai/app/test-openai-file-search/page.tsx @@ -1,116 +1,36 @@ 'use client'; +import ChatInput from '@/component/chat-input'; +import FileSearchView from '@/component/openai-file-search-view'; import { useChat } from '@ai-sdk/react'; import { DefaultChatTransport } from 'ai'; -import ChatInput from '@/component/chat-input'; -import { OpenAIFileSearchMessage } from '@/app/api/chat-openai-file-search/route'; +import { OpenAIFileSearchMessage } from '../api/chat-openai-file-search/route'; export default function TestOpenAIFileSearch() { - const { error, status, sendMessage, messages, regenerate, stop } = - useChat({ - transport: new DefaultChatTransport({ - api: '/api/chat-openai-file-search', - }), - }); + const { status, sendMessage, messages } = useChat({ + transport: new DefaultChatTransport({ + api: '/api/chat-openai-file-search', + }), + }); return ( -
-

- OpenAI File Search Block-Based Streaming Test -

+
+

OpenAI File Search Test

{messages.map(message => (
{message.role === 'user' ? 'User: ' : 'AI: '} {message.parts.map((part, index) => { - if (part.type === 'text') { - return
{part.text}
; - } - - if (part.type === 'tool-file_search') { - if (part.state === 'input-available') { - return ( -
-                    {JSON.stringify(part.input, null, 2)}
-                  
- ); - } - if (part.state === 'output-available') { - return ( -
-                    {JSON.stringify(part.input, null, 2)}
-                    {`\n\nDONE - File search completed`}
-                  
- ); - } + switch (part.type) { + case 'text': + return
{part.text}
; + case 'tool-file_search': + return ; } - - if (part.type === 'source-document') { - return ( - - [ - - {part.title || part.filename || 'Document'} - - ] - - ); - } - - if (part.type === 'source-url') { - return ( - - [ - - {part.title ?? new URL(part.url).hostname} - - ] - - ); - } - - return null; })}
))} - {(status === 'submitted' || status === 'streaming') && ( -
- {status === 'submitted' &&
Loading...
} - -
- )} - - {error && ( -
-
An error occurred.
- -
- )} - sendMessage({ text })} />
); diff --git a/examples/next-openai/app/test-openai-image-generation/page.tsx b/examples/next-openai/app/test-openai-image-generation/page.tsx new file mode 100644 index 000000000000..76f5f707551e --- /dev/null +++ b/examples/next-openai/app/test-openai-image-generation/page.tsx @@ -0,0 +1,38 @@ +'use client'; + +import { OpenAIImageGenerationMessage } from '@/app/api/chat-openai-image-generation/route'; +import ChatInput from '@/component/chat-input'; +import ImageGenerationView from '@/component/openai-image-generation-view'; +import { useChat } from '@ai-sdk/react'; +import { DefaultChatTransport } from 'ai'; + +export default function TestOpenAIWebSearch() { + const { status, sendMessage, messages } = + useChat({ + transport: new DefaultChatTransport({ + api: '/api/chat-openai-image-generation', + }), + }); + + return ( +
+

OpenAI Image Generation Test

+ + {messages.map(message => ( +
+ {message.role === 'user' ? 'User: ' : 'AI: '} + {message.parts.map((part, index) => { + switch (part.type) { + case 'text': + return
{part.text}
; + case 'tool-image_generation': + return ; + } + })} +
+ ))} + + sendMessage({ text })} /> +
+ ); +} diff --git a/examples/next-openai/component/openai-code-interpreter-view.tsx b/examples/next-openai/component/openai-code-interpreter-view.tsx new file mode 100644 index 000000000000..6289f5e3a639 --- /dev/null +++ b/examples/next-openai/component/openai-code-interpreter-view.tsx @@ -0,0 +1,52 @@ +import { openai } from '@ai-sdk/openai'; +import { UIToolInvocation } from 'ai'; + +export default function CodeInterpreterView({ + invocation, +}: { + invocation: UIToolInvocation>; +}) { + switch (invocation.state) { + case 'output-available': + return ( +
+
+
+ {invocation.input.containerId} +
+
+ +
+
+
+ Code: +
+
+                {invocation.input.code}
+              
+
+ +
+
+ Output: +
+
+ {invocation.output.outputs?.map((output, index) => ( +
+ {output.type === 'logs' && ( +
+ + {output.logs} + +
+ )} + {output.type === 'image' && } +
+ ))} +
+
+
+
+ ); + } +} diff --git a/examples/next-openai/component/openai-file-search-view.tsx b/examples/next-openai/component/openai-file-search-view.tsx new file mode 100644 index 000000000000..b27e34c5d0f9 --- /dev/null +++ b/examples/next-openai/component/openai-file-search-view.tsx @@ -0,0 +1,42 @@ +import { openai } from '@ai-sdk/openai'; +import { UIToolInvocation } from 'ai'; + +export default function FileSearchView({ + invocation, +}: { + invocation: UIToolInvocation>; +}) { + switch (invocation.state) { + case 'input-available': + return ( +
+ Searching... +
+ ); + case 'output-available': + return ( +
+
+ Queries: +
    + {invocation.output.queries.map((query, index) => ( +
  • - {query}
  • + ))} +
+
+
+ Results: +
+ {invocation.output.results?.map((result, index) => ( +
+
+                    {JSON.stringify(result, null, 2)}
+                  
+
+ ))} +
+
+
+ ); + } +} diff --git a/examples/next-openai/component/openai-image-generation-view.tsx b/examples/next-openai/component/openai-image-generation-view.tsx new file mode 100644 index 000000000000..f4c4b1e8ced4 --- /dev/null +++ b/examples/next-openai/component/openai-image-generation-view.tsx @@ -0,0 +1,23 @@ +import { openai } from '@ai-sdk/openai'; +import { UIToolInvocation } from 'ai'; + +export default function ImageGenerationView({ + invocation, +}: { + invocation: UIToolInvocation>; +}) { + switch (invocation.state) { + case 'input-available': + return ( +
+ Generating image... +
+ ); + case 'output-available': + return ( +
+ +
+ ); + } +} diff --git a/examples/next/app/api/chat/route.ts b/examples/next/app/api/chat/route.ts index 54b5b11e46c6..1ec9ee37f75c 100644 --- a/examples/next/app/api/chat/route.ts +++ b/examples/next/app/api/chat/route.ts @@ -1,5 +1,4 @@ import type { MyUIMessage } from '@/util/chat-schema'; -import { openai } from '@ai-sdk/openai'; import { readChat, saveChat } from '@util/chat-store'; import { convertToModelMessages, generateId, streamText } from 'ai'; import { after } from 'next/server'; @@ -57,7 +56,7 @@ export async function POST(req: Request) { saveChat({ id, messages, activeStreamId: null }); const result = streamText({ - model: openai('gpt-4o-mini'), + model: 'openai/gpt-5-mini', messages: convertToModelMessages(messages), abortSignal: req.signal, }); diff --git a/examples/next/package.json b/examples/next/package.json index b8d07801f9c7..1a336b3a68d7 100644 --- a/examples/next/package.json +++ b/examples/next/package.json @@ -9,7 +9,6 @@ "lint": "next lint" }, "dependencies": { - "@ai-sdk/openai": "workspace:*", "@ai-sdk/react": "workspace:*", "@vercel/blob": "^0.26.0", "ai": "workspace:*", diff --git a/examples/next/util/chat-schema.ts b/examples/next/util/chat-schema.ts index 8c49a52f5fce..ff6e30930578 100644 --- a/examples/next/util/chat-schema.ts +++ b/examples/next/util/chat-schema.ts @@ -1,5 +1,5 @@ import { UIDataTypes, UIMessage } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export const myMessageMetadataSchema = z.object({ createdAt: z.number(), diff --git a/examples/nuxt-openai/pages/use-object/index.vue b/examples/nuxt-openai/pages/use-object/index.vue new file mode 100644 index 000000000000..737b01067ee2 --- /dev/null +++ b/examples/nuxt-openai/pages/use-object/index.vue @@ -0,0 +1,69 @@ + + + diff --git a/examples/nuxt-openai/server/api/use-chat-tools.ts b/examples/nuxt-openai/server/api/use-chat-tools.ts index 71c4d1f3dfb0..d4d0c32fc436 100644 --- a/examples/nuxt-openai/server/api/use-chat-tools.ts +++ b/examples/nuxt-openai/server/api/use-chat-tools.ts @@ -1,6 +1,6 @@ import { createOpenAI } from '@ai-sdk/openai'; import { convertToModelMessages, stepCountIs, streamText } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; export default defineLazyEventHandler(async () => { const openai = createOpenAI({ diff --git a/examples/nuxt-openai/server/api/use-object.ts b/examples/nuxt-openai/server/api/use-object.ts new file mode 100644 index 000000000000..4e7a59deb3e3 --- /dev/null +++ b/examples/nuxt-openai/server/api/use-object.ts @@ -0,0 +1,22 @@ +import { createOpenAI } from '@ai-sdk/openai'; +import { streamObject } from 'ai'; +import { notificationSchema } from '~/shared/notification-schema'; + +export default defineLazyEventHandler(async () => { + const apiKey = useRuntimeConfig().openaiApiKey; + if (!apiKey) throw new Error('Missing OpenAI API key'); + const openai = createOpenAI({ apiKey }); + + return defineEventHandler(async (event: any) => { + const context = await readBody(event); + + // Stream generated notifications as objects + const result = streamObject({ + model: openai('gpt-4.1'), + prompt: `Generate 5 notifications for a messages app in this context: ${context}`, + schema: notificationSchema, + }); + + return result.toTextStreamResponse(); + }); +}); diff --git a/examples/nuxt-openai/shared/notification-schema.ts b/examples/nuxt-openai/shared/notification-schema.ts new file mode 100644 index 000000000000..932f6eb3de7f --- /dev/null +++ b/examples/nuxt-openai/shared/notification-schema.ts @@ -0,0 +1,11 @@ +import { z } from 'zod'; + +export const notificationSchema = z.object({ + notifications: z.array( + z.object({ + name: z.string().describe('Name of a fictional person.'), + message: z.string().describe('Message. Do not use emojis or links.'), + minutesAgo: z.number(), + }), + ), +}); diff --git a/examples/sveltekit-openai/src/routes/api/chat/+server.ts b/examples/sveltekit-openai/src/routes/api/chat/+server.ts index c191f3a45716..1446b9e0fe5a 100644 --- a/examples/sveltekit-openai/src/routes/api/chat/+server.ts +++ b/examples/sveltekit-openai/src/routes/api/chat/+server.ts @@ -1,7 +1,7 @@ import { env } from '$env/dynamic/private'; import { createOpenAI } from '@ai-sdk/openai'; import { convertToModelMessages, streamText, stepCountIs } from 'ai'; -import { z } from 'zod/v4'; +import { z } from 'zod'; const openai = createOpenAI({ apiKey: env?.OPENAI_API_KEY, diff --git a/examples/sveltekit-openai/src/routes/structured-object/schema.ts b/examples/sveltekit-openai/src/routes/structured-object/schema.ts index 539f51299117..72104f1e8b25 100644 --- a/examples/sveltekit-openai/src/routes/structured-object/schema.ts +++ b/examples/sveltekit-openai/src/routes/structured-object/schema.ts @@ -1,4 +1,4 @@ -import { z } from 'zod/v4'; +import { z } from 'zod'; // define a schema for the notifications export const notificationSchema = z.object({ diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 7318ca092ec9..ca74e89ccdff 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -1,5 +1,138 @@ # ai +## 5.1.0-beta.9 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 177b475: fix(ai): download files when intermediate file cannot be downloaded +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [aaf5ebf] +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/gateway@1.1.0-beta.6 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 5.1.0-beta.8 + +### Patch Changes + +- 7eca093: fix(ai): update `uiMessageChunkSchema` to satisfy the `UIMessageChunk` type + +## 5.1.0-beta.7 + +### Patch Changes + +- 5a4e732: Export `parseJsonEventStream` and `uiMessageChunkSchema` from "ai" package + +## 5.1.0-beta.6 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- Updated dependencies [5d21222] +- Updated dependencies [0c4822d] +- Updated dependencies [1cad0ab] + - @ai-sdk/gateway@1.1.0-beta.5 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 5.1.0-beta.5 + +### Patch Changes + +- Updated dependencies [7ccb36f] +- Updated dependencies [6c766ef] + - @ai-sdk/gateway@1.1.0-beta.4 + +## 5.1.0-beta.4 + +### Patch Changes + +- Updated dependencies [ea9ca31] + - @ai-sdk/gateway@1.1.0-beta.3 + +## 5.1.0-beta.3 + +### Patch Changes + +- Updated dependencies [3e83633] +- Updated dependencies [f83903d] + - @ai-sdk/gateway@1.1.0-beta.2 + +## 5.1.0-beta.2 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/gateway@1.1.0-beta.1 + +## 5.1.0-beta.1 + +### Patch Changes + +- a7f6f81: Add safeValidateUIMessages utility to validate UI messages without throwing, returning a success/failure result object like Zod’s safeParse + +## 5.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/gateway@1.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 5.0.45 + +### Patch Changes + +- 76024fc: fix(ai): fix static tool call and result detection when dynamic is undefined +- 93d8b60: fix(ai): do not filter zero-length text parts that have provider options +- d8eb31f: fix(ai): fix webp image detection from base64 + +## 5.0.44 + +### Patch Changes + +- Updated dependencies [f49f924] + - @ai-sdk/gateway@1.0.23 + +## 5.0.43 + +### Patch Changes + +- 0294b58: feat(ai): set `ai`, `@ai-sdk/provider-utils`, and runtime in `user-agent` header +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/gateway@1.0.22 + +## 5.0.42 + +### Patch Changes + +- de5c066: fix(ai): forwarded providerExecuted flag in validateUIMessages + +## 5.0.41 + +### Patch Changes + +- cd91e4b: fix(ai): use correct type for reasoning outputs + +## 5.0.40 + +### Patch Changes + +- Updated dependencies [4ee3719] + - @ai-sdk/gateway@1.0.21 + ## 5.0.39 ### Patch Changes diff --git a/packages/ai/package.json b/packages/ai/package.json index 1857be2eb7ce..760a58fa96a7 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "ai", - "version": "5.0.39", + "version": "5.1.0-beta.9", "description": "AI SDK by Vercel - The AI Toolkit for TypeScript and JavaScript", "license": "Apache-2.0", "sideEffects": false, @@ -54,6 +54,7 @@ } }, "dependencies": { + "@ai-sdk/test-server": "workspace:*", "@ai-sdk/gateway": "workspace:*", "@ai-sdk/provider": "workspace:*", "@ai-sdk/provider-utils": "workspace:*", diff --git a/packages/ai/src/embed/__snapshots__/embed-many.test.ts.snap b/packages/ai/src/embed/__snapshots__/embed-many.test.ts.snap index 449bc194042b..e028b64865ec 100644 --- a/packages/ai/src/embed/__snapshots__/embed-many.test.ts.snap +++ b/packages/ai/src/embed/__snapshots__/embed-many.test.ts.snap @@ -27,6 +27,7 @@ exports[`telemetry > should not record telemetry inputs / outputs when disabled "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embedMany", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.usage.tokens": 10, "operation.name": "ai.embedMany", @@ -39,6 +40,7 @@ exports[`telemetry > should not record telemetry inputs / outputs when disabled "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embedMany.doEmbed", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.usage.tokens": 10, "operation.name": "ai.embedMany.doEmbed", @@ -61,6 +63,7 @@ exports[`telemetry > should record telemetry data when enabled (multiple calls p "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embedMany", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.telemetry.functionId": "test-function-id", "ai.telemetry.metadata.test1": "value1", @@ -86,6 +89,7 @@ exports[`telemetry > should record telemetry data when enabled (multiple calls p "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embedMany.doEmbed", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.telemetry.functionId": "test-function-id", "ai.telemetry.metadata.test1": "value1", @@ -109,6 +113,7 @@ exports[`telemetry > should record telemetry data when enabled (multiple calls p "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embedMany.doEmbed", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.telemetry.functionId": "test-function-id", "ai.telemetry.metadata.test1": "value1", @@ -138,6 +143,7 @@ exports[`telemetry > should record telemetry data when enabled (single call path "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embedMany", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.telemetry.functionId": "test-function-id", "ai.telemetry.metadata.test1": "value1", @@ -164,6 +170,7 @@ exports[`telemetry > should record telemetry data when enabled (single call path "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embedMany.doEmbed", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.telemetry.functionId": "test-function-id", "ai.telemetry.metadata.test1": "value1", diff --git a/packages/ai/src/embed/__snapshots__/embed.test.ts.snap b/packages/ai/src/embed/__snapshots__/embed.test.ts.snap index cb41f8f95dba..eb32140c247c 100644 --- a/packages/ai/src/embed/__snapshots__/embed.test.ts.snap +++ b/packages/ai/src/embed/__snapshots__/embed.test.ts.snap @@ -9,6 +9,7 @@ exports[`telemetry > should not record telemetry inputs / outputs when disabled "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embed", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.usage.tokens": 10, "operation.name": "ai.embed", @@ -21,6 +22,7 @@ exports[`telemetry > should not record telemetry inputs / outputs when disabled "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embed.doEmbed", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.usage.tokens": 10, "operation.name": "ai.embed.doEmbed", @@ -39,6 +41,7 @@ exports[`telemetry > should record telemetry data when enabled 1`] = ` "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embed", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.telemetry.functionId": "test-function-id", "ai.telemetry.metadata.test1": "value1", @@ -59,6 +62,7 @@ exports[`telemetry > should record telemetry data when enabled 1`] = ` "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.embed.doEmbed", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.settings.maxRetries": 2, "ai.telemetry.functionId": "test-function-id", "ai.telemetry.metadata.test1": "value1", diff --git a/packages/ai/src/embed/embed-many.test.ts b/packages/ai/src/embed/embed-many.test.ts index 4acc73d736e4..05227a2f90c6 100644 --- a/packages/ai/src/embed/embed-many.test.ts +++ b/packages/ai/src/embed/embed-many.test.ts @@ -1,12 +1,18 @@ -import { EmbeddingModelV2 } from '@ai-sdk/provider'; +import { EmbeddingModelV3 } from '@ai-sdk/provider'; import assert from 'node:assert'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { MockEmbeddingModelV2 } from '../test/mock-embedding-model-v2'; +import { MockEmbeddingModelV3 } from '../test/mock-embedding-model-v3'; import { MockTracer } from '../test/mock-tracer'; import { Embedding, EmbeddingModelUsage } from '../types'; import { createResolvablePromise } from '../util/create-resolvable-promise'; import { embedMany } from './embed-many'; +vi.mock('../version', () => { + return { + VERSION: '0.0.0-test', + }; +}); + const dummyEmbeddings = [ [0.1, 0.2, 0.3], [0.4, 0.5, 0.6], @@ -31,7 +37,7 @@ describe('model.supportsParallelCalls', () => { ]; const embedManyPromise = embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ supportsParallelCalls: false, maxEmbeddingsPerCall: 1, doEmbed: async () => { @@ -79,7 +85,7 @@ describe('model.supportsParallelCalls', () => { ]; const embedManyPromise = embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ supportsParallelCalls: true, maxEmbeddingsPerCall: 1, doEmbed: async () => { @@ -128,7 +134,7 @@ describe('model.supportsParallelCalls', () => { const embedManyPromise = embedMany({ maxParallelCalls: 2, - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ supportsParallelCalls: true, maxEmbeddingsPerCall: 1, doEmbed: async () => { @@ -169,7 +175,7 @@ describe('model.supportsParallelCalls', () => { describe('result.embedding', () => { it('should generate embeddings', async () => { const result = await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: 5, doEmbed: mockEmbed(testValues, dummyEmbeddings), }), @@ -183,7 +189,7 @@ describe('result.embedding', () => { let callCount = 0; const result = await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: 2, doEmbed: async ({ values }) => { switch (callCount++) { @@ -209,7 +215,7 @@ describe('result.responses', () => { it('should include responses in the result', async () => { let callCount = 0; const result = await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: 1, doEmbed: async ({ values }) => { @@ -253,7 +259,7 @@ describe('result.responses', () => { describe('result.values', () => { it('should include values in the result', async () => { const result = await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: 5, doEmbed: mockEmbed(testValues, dummyEmbeddings), }), @@ -269,7 +275,7 @@ describe('result.usage', () => { let callCount = 0; const result = await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: 2, doEmbed: async () => { switch (callCount++) { @@ -298,18 +304,21 @@ describe('result.usage', () => { describe('options.headers', () => { it('should set headers', async () => { const result = await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: 5, doEmbed: async ({ headers }) => { assert.deepStrictEqual(headers, { 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', }); return { embeddings: dummyEmbeddings }; }, }), values: testValues, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + }, }); assert.deepStrictEqual(result.embeddings, dummyEmbeddings); @@ -318,7 +327,7 @@ describe('options.headers', () => { describe('options.providerOptions', () => { it('should pass provider options to model', async () => { - const model = new MockEmbeddingModelV2({ + const model = new MockEmbeddingModelV3({ doEmbed: async ({ providerOptions }) => { return { embeddings: [[1, 2, 3]] }; }, @@ -336,7 +345,9 @@ describe('options.providerOptions', () => { expect(model.doEmbed).toHaveBeenCalledWith({ abortSignal: undefined, - headers: undefined, + headers: { + 'user-agent': 'ai/0.0.0-test', + }, providerOptions: { aProvider: { someKey: 'someValue' }, }, @@ -354,7 +365,7 @@ describe('telemetry', () => { it('should not record any telemetry data when not explicitly enabled', async () => { await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: 5, doEmbed: mockEmbed(testValues, dummyEmbeddings), }), @@ -368,7 +379,7 @@ describe('telemetry', () => { let callCount = 0; await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: 2, doEmbed: async ({ values }) => { switch (callCount++) { @@ -406,7 +417,7 @@ describe('telemetry', () => { it('should record telemetry data when enabled (single call path)', async () => { await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: null, doEmbed: mockEmbed(testValues, dummyEmbeddings, { tokens: 10 }), }), @@ -427,7 +438,7 @@ describe('telemetry', () => { it('should not record telemetry inputs / outputs when disabled', async () => { await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ maxEmbeddingsPerCall: null, doEmbed: mockEmbed(testValues, dummyEmbeddings, { tokens: 10 }), }), @@ -451,7 +462,7 @@ describe('result.providerMetadata', () => { }; const result = await embedMany({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ supportsParallelCalls: false, maxEmbeddingsPerCall: 3, doEmbed: mockEmbed( @@ -477,12 +488,12 @@ function mockEmbed( embeddings: Array, usage?: EmbeddingModelUsage, response: Awaited< - ReturnType['doEmbed']> + ReturnType['doEmbed']> >['response'] = { headers: {}, body: {} }, providerMetadata?: Awaited< - ReturnType['doEmbed']> + ReturnType['doEmbed']> >['providerMetadata'], -): EmbeddingModelV2['doEmbed'] { +): EmbeddingModelV3['doEmbed'] { return async ({ values }) => { assert.deepStrictEqual(expectedValues, values); return { embeddings, usage, response, providerMetadata }; diff --git a/packages/ai/src/embed/embed-many.ts b/packages/ai/src/embed/embed-many.ts index 98cd420a63da..1fbe717a880e 100644 --- a/packages/ai/src/embed/embed-many.ts +++ b/packages/ai/src/embed/embed-many.ts @@ -1,4 +1,4 @@ -import { ProviderOptions } from '@ai-sdk/provider-utils'; +import { ProviderOptions, withUserAgentSuffix } from '@ai-sdk/provider-utils'; import { prepareRetries } from '../util/prepare-retries'; import { splitArray } from '../util/split-array'; import { UnsupportedModelVersionError } from '../error/unsupported-model-version-error'; @@ -11,6 +11,7 @@ import { TelemetrySettings } from '../telemetry/telemetry-settings'; import { Embedding, EmbeddingModel, ProviderMetadata } from '../types'; import { resolveEmbeddingModel } from '../model/resolve-model'; import { EmbedManyResult } from './embed-many-result'; +import { VERSION } from '../version'; /** Embed several values using an embedding model. The type of the value is defined @@ -92,10 +93,15 @@ Only applicable for HTTP-based providers. abortSignal, }); + const headersWithUserAgent = withUserAgentSuffix( + headers ?? {}, + `ai/${VERSION}`, + ); + const baseTelemetryAttributes = getBaseTelemetryAttributes({ model, telemetry, - headers, + headers: headersWithUserAgent, settings: { maxRetries }, }); @@ -148,7 +154,7 @@ Only applicable for HTTP-based providers. const modelResponse = await model.doEmbed({ values, abortSignal, - headers, + headers: headersWithUserAgent, providerOptions, }); @@ -249,7 +255,7 @@ Only applicable for HTTP-based providers. const modelResponse = await model.doEmbed({ values: chunk, abortSignal, - headers, + headers: headersWithUserAgent, providerOptions, }); diff --git a/packages/ai/src/embed/embed.test.ts b/packages/ai/src/embed/embed.test.ts index 1138acb82f93..b6a3776bae3f 100644 --- a/packages/ai/src/embed/embed.test.ts +++ b/packages/ai/src/embed/embed.test.ts @@ -1,7 +1,7 @@ -import { EmbeddingModelV2 } from '@ai-sdk/provider'; +import { EmbeddingModelV3 } from '@ai-sdk/provider'; import assert from 'node:assert'; -import { beforeEach, describe, expect, it } from 'vitest'; -import { MockEmbeddingModelV2 } from '../test/mock-embedding-model-v2'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { MockEmbeddingModelV3 } from '../test/mock-embedding-model-v3'; import { MockTracer } from '../test/mock-tracer'; import { Embedding, EmbeddingModelUsage } from '../types'; import { embed } from './embed'; @@ -9,10 +9,16 @@ import { embed } from './embed'; const dummyEmbedding = [0.1, 0.2, 0.3]; const testValue = 'sunny day at the beach'; +vi.mock('../version', () => { + return { + VERSION: '0.0.0-test', + }; +}); + describe('result.embedding', () => { it('should generate embedding', async () => { const result = await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: mockEmbed([testValue], [dummyEmbedding]), }), value: testValue, @@ -25,7 +31,7 @@ describe('result.embedding', () => { describe('result.response', () => { it('should include response in the result', async () => { const result = await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: mockEmbed([testValue], [dummyEmbedding], undefined, { body: { foo: 'bar' }, headers: { foo: 'bar' }, @@ -50,7 +56,7 @@ describe('result.response', () => { describe('result.value', () => { it('should include value in the result', async () => { const result = await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: mockEmbed([testValue], [dummyEmbedding]), }), value: testValue, @@ -63,7 +69,7 @@ describe('result.value', () => { describe('result.usage', () => { it('should include usage in the result', async () => { const result = await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: mockEmbed([testValue], [dummyEmbedding], { tokens: 10 }), }), value: testValue, @@ -84,7 +90,7 @@ describe('result.providerMetadata', () => { }; const result = await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: mockEmbed( [testValue], [dummyEmbedding], @@ -106,17 +112,20 @@ describe('result.providerMetadata', () => { describe('options.headers', () => { it('should set headers', async () => { const result = await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: async ({ headers }) => { assert.deepStrictEqual(headers, { 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', }); return { embeddings: [dummyEmbedding] }; }, }), value: testValue, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + }, }); assert.deepStrictEqual(result.embedding, dummyEmbedding); @@ -126,7 +135,7 @@ describe('options.headers', () => { describe('options.providerOptions', () => { it('should pass provider options to model', async () => { const result = await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: async ({ providerOptions }) => { expect(providerOptions).toStrictEqual({ aProvider: { someKey: 'someValue' }, @@ -154,7 +163,7 @@ describe('telemetry', () => { it('should not record any telemetry data when not explicitly enabled', async () => { await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: mockEmbed([testValue], [dummyEmbedding]), }), value: testValue, @@ -166,7 +175,7 @@ describe('telemetry', () => { it('should record telemetry data when enabled', async () => { await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: mockEmbed([testValue], [dummyEmbedding], { tokens: 10 }), }), value: testValue, @@ -186,7 +195,7 @@ describe('telemetry', () => { it('should not record telemetry inputs / outputs when disabled', async () => { await embed({ - model: new MockEmbeddingModelV2({ + model: new MockEmbeddingModelV3({ doEmbed: mockEmbed([testValue], [dummyEmbedding], { tokens: 10 }), }), value: testValue, @@ -207,12 +216,12 @@ function mockEmbed( embeddings: Array, usage?: EmbeddingModelUsage, response: Awaited< - ReturnType['doEmbed']> + ReturnType['doEmbed']> >['response'] = { headers: {}, body: {} }, providerMetadata?: Awaited< - ReturnType['doEmbed']> + ReturnType['doEmbed']> >['providerMetadata'], -): EmbeddingModelV2['doEmbed'] { +): EmbeddingModelV3['doEmbed'] { return async ({ values }) => { assert.deepStrictEqual(expectedValues, values); return { embeddings, usage, response, providerMetadata }; diff --git a/packages/ai/src/embed/embed.ts b/packages/ai/src/embed/embed.ts index 7d547540475c..6c3027ad1d03 100644 --- a/packages/ai/src/embed/embed.ts +++ b/packages/ai/src/embed/embed.ts @@ -1,4 +1,4 @@ -import { ProviderOptions } from '@ai-sdk/provider-utils'; +import { ProviderOptions, withUserAgentSuffix } from '@ai-sdk/provider-utils'; import { resolveEmbeddingModel } from '../model/resolve-model'; import { assembleOperationName } from '../telemetry/assemble-operation-name'; import { getBaseTelemetryAttributes } from '../telemetry/get-base-telemetry-attributes'; @@ -9,6 +9,7 @@ import { TelemetrySettings } from '../telemetry/telemetry-settings'; import { EmbeddingModel } from '../types'; import { prepareRetries } from '../util/prepare-retries'; import { EmbedResult } from './embed-result'; +import { VERSION } from '../version'; /** Embed a value using an embedding model. The type of the value is defined by the embedding model. @@ -78,10 +79,15 @@ Only applicable for HTTP-based providers. abortSignal, }); + const headersWithUserAgent = withUserAgentSuffix( + headers ?? {}, + `ai/${VERSION}`, + ); + const baseTelemetryAttributes = getBaseTelemetryAttributes({ model: model, telemetry, - headers, + headers: headersWithUserAgent, settings: { maxRetries }, }); @@ -120,7 +126,7 @@ Only applicable for HTTP-based providers. const modelResponse = await model.doEmbed({ values: [value], abortSignal, - headers, + headers: headersWithUserAgent, providerOptions, }); diff --git a/packages/ai/src/generate-image/generate-image.test.ts b/packages/ai/src/generate-image/generate-image.test.ts index a08683a65483..3972b5bae25b 100644 --- a/packages/ai/src/generate-image/generate-image.test.ts +++ b/packages/ai/src/generate-image/generate-image.test.ts @@ -1,7 +1,7 @@ import { - ImageModelV2, - ImageModelV2CallWarning, - ImageModelV2ProviderMetadata, + ImageModelV3, + ImageModelV3CallWarning, + ImageModelV3ProviderMetadata, } from '@ai-sdk/provider'; import { convertBase64ToUint8Array, @@ -14,10 +14,11 @@ import { expect, it, test, + vi, vitest, } from 'vitest'; import * as logWarningsModule from '../logger/log-warnings'; -import { MockImageModelV2 } from '../test/mock-image-model-v2'; +import { MockImageModelV3 } from '../test/mock-image-model-v3'; import { generateImage } from './generate-image'; const prompt = 'sunny day at the beach'; @@ -29,12 +30,18 @@ const jpegBase64 = '/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k='; // 1x1 black JPEG const gifBase64 = 'R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='; // 1x1 transparent GIF +vi.mock('../version', () => { + return { + VERSION: '0.0.0-test', + }; +}); + const createMockResponse = (options: { images: string[] | Uint8Array[]; - warnings?: ImageModelV2CallWarning[]; + warnings?: ImageModelV3CallWarning[]; timestamp?: Date; modelId?: string; - providerMetaData?: ImageModelV2ProviderMetadata; + providerMetaData?: ImageModelV3ProviderMetadata; headers?: Record; }) => ({ images: options.images, @@ -68,10 +75,10 @@ describe('generateImage', () => { const abortController = new AbortController(); const abortSignal = abortController.signal; - let capturedArgs!: Parameters[0]; + let capturedArgs!: Parameters[0]; await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async args => { capturedArgs = args; return createMockResponse({ @@ -88,7 +95,9 @@ describe('generateImage', () => { style: 'vivid', }, }, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + }, abortSignal, }); @@ -99,14 +108,17 @@ describe('generateImage', () => { aspectRatio: '16:9', seed: 12345, providerOptions: { 'mock-provider': { style: 'vivid' } }, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', + }, abortSignal, }); }); it('should return warnings', async () => { const result = await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: [pngBase64], @@ -130,7 +142,7 @@ describe('generateImage', () => { }); it('should call logWarnings with the correct warnings', async () => { - const expectedWarnings: ImageModelV2CallWarning[] = [ + const expectedWarnings: ImageModelV3CallWarning[] = [ { type: 'other', message: 'Setting is not supported', @@ -143,7 +155,7 @@ describe('generateImage', () => { ]; await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: [pngBase64], @@ -158,11 +170,11 @@ describe('generateImage', () => { }); it('should call logWarnings with aggregated warnings from multiple calls', async () => { - const warning1: ImageModelV2CallWarning = { + const warning1: ImageModelV3CallWarning = { type: 'other', message: 'Warning from call 1', }; - const warning2: ImageModelV2CallWarning = { + const warning2: ImageModelV3CallWarning = { type: 'other', message: 'Warning from call 2', }; @@ -171,7 +183,7 @@ describe('generateImage', () => { let callCount = 0; await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ maxImagesPerCall: 1, doGenerate: async () => { switch (callCount++) { @@ -200,7 +212,7 @@ describe('generateImage', () => { it('should call logWarnings with empty array when no warnings are present', async () => { await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: [pngBase64], @@ -217,7 +229,7 @@ describe('generateImage', () => { describe('base64 image data', () => { it('should return generated images with correct mime types', async () => { const result = await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: [pngBase64, jpegBase64], @@ -248,7 +260,7 @@ describe('generateImage', () => { it('should return the first image with correct mime type', async () => { const result = await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: [pngBase64, jpegBase64], @@ -277,7 +289,7 @@ describe('generateImage', () => { ]; const result = await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: uint8ArrayImages, @@ -311,7 +323,7 @@ describe('generateImage', () => { let callCount = 0; const result = await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ maxImagesPerCall: 2, doGenerate: async options => { switch (callCount++) { @@ -325,7 +337,10 @@ describe('generateImage', () => { providerOptions: { 'mock-provider': { style: 'vivid' }, }, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', + }, abortSignal: undefined, }); return createMockResponse({ @@ -339,7 +354,10 @@ describe('generateImage', () => { size: '1024x1024', aspectRatio: '16:9', providerOptions: { 'mock-provider': { style: 'vivid' } }, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', + }, abortSignal: undefined, }); return createMockResponse({ @@ -356,7 +374,9 @@ describe('generateImage', () => { aspectRatio: '16:9', seed: 12345, providerOptions: { 'mock-provider': { style: 'vivid' } }, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + }, }); expect(result.images.map(image => image.base64)).toStrictEqual( @@ -370,7 +390,7 @@ describe('generateImage', () => { let callCount = 0; const result = await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ maxImagesPerCall: 2, doGenerate: async options => { switch (callCount++) { @@ -382,7 +402,10 @@ describe('generateImage', () => { size: '1024x1024', aspectRatio: '16:9', providerOptions: { 'mock-provider': { style: 'vivid' } }, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', + }, abortSignal: undefined, }); return createMockResponse({ @@ -397,7 +420,10 @@ describe('generateImage', () => { size: '1024x1024', aspectRatio: '16:9', providerOptions: { 'mock-provider': { style: 'vivid' } }, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', + }, abortSignal: undefined, }); return createMockResponse({ @@ -415,7 +441,9 @@ describe('generateImage', () => { aspectRatio: '16:9', seed: 12345, providerOptions: { 'mock-provider': { style: 'vivid' } }, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + }, }); expect(result.warnings).toStrictEqual([ @@ -436,7 +464,7 @@ describe('generateImage', () => { const maxImagesPerCallMock = vitest.fn(maxImagesPerCall); const result = await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ maxImagesPerCall: maxImagesPerCallMock, doGenerate: async options => { switch (callCount++) { @@ -452,6 +480,7 @@ describe('generateImage', () => { }, headers: { 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', }, abortSignal: undefined, }); @@ -468,6 +497,7 @@ describe('generateImage', () => { providerOptions: { 'mock-provider': { style: 'vivid' } }, headers: { 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', }, abortSignal: undefined, }); @@ -485,7 +515,9 @@ describe('generateImage', () => { aspectRatio: '16:9', seed: 12345, providerOptions: { 'mock-provider': { style: 'vivid' } }, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + }, }); expect(result.images.map(image => image.base64)).toStrictEqual( @@ -503,7 +535,7 @@ describe('generateImage', () => { it('should throw NoImageGeneratedError when no images are returned', async () => { await expect( generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: [], @@ -527,13 +559,14 @@ describe('generateImage', () => { it('should include response headers in error when no images generated', async () => { await expect( generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: [], timestamp: testDate, headers: { 'custom-response-header': 'response-header-value', + 'user-agent': 'ai/0.0.0-test', }, }), }), @@ -548,6 +581,7 @@ describe('generateImage', () => { modelId: expect.any(String), headers: { 'custom-response-header': 'response-header-value', + 'user-agent': 'ai/0.0.0-test', }, }, ], @@ -559,7 +593,7 @@ describe('generateImage', () => { const testHeaders = { 'x-test': 'value' }; const result = await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: [pngBase64], @@ -582,7 +616,7 @@ describe('generateImage', () => { it('should return provider metadata', async () => { const result = await generateImage({ - model: new MockImageModelV2({ + model: new MockImageModelV3({ doGenerate: async () => createMockResponse({ images: [pngBase64, pngBase64], diff --git a/packages/ai/src/generate-image/generate-image.ts b/packages/ai/src/generate-image/generate-image.ts index 8f938b9b0e00..eda33302caa2 100644 --- a/packages/ai/src/generate-image/generate-image.ts +++ b/packages/ai/src/generate-image/generate-image.ts @@ -1,5 +1,5 @@ -import { ImageModelV2, ImageModelV2ProviderMetadata } from '@ai-sdk/provider'; -import { ProviderOptions } from '@ai-sdk/provider-utils'; +import { ImageModelV3, ImageModelV3ProviderMetadata } from '@ai-sdk/provider'; +import { ProviderOptions, withUserAgentSuffix } from '@ai-sdk/provider-utils'; import { NoImageGeneratedError } from '../error/no-image-generated-error'; import { detectMediaType, @@ -15,6 +15,7 @@ import { ImageGenerationWarning } from '../types/image-model'; import { ImageModelResponseMetadata } from '../types/image-model-response-metadata'; import { GenerateImageResult } from './generate-image-result'; import { logWarnings } from '../logger/log-warnings'; +import { VERSION } from '../version'; /** Generates images using an image model. @@ -49,7 +50,7 @@ export async function generateImage({ /** The image model to use. */ - model: ImageModelV2; + model: ImageModelV3; /** The prompt that should be used to generate the image. @@ -115,7 +116,7 @@ Only applicable for HTTP-based providers. */ headers?: Record; }): Promise { - if (model.specificationVersion !== 'v2') { + if (model.specificationVersion !== 'v3') { throw new UnsupportedModelVersionError({ version: model.specificationVersion, provider: model.provider, @@ -123,6 +124,11 @@ Only applicable for HTTP-based providers. }); } + const headersWithUserAgent = withUserAgentSuffix( + headers ?? {}, + `ai/${VERSION}`, + ); + const { retry } = prepareRetries({ maxRetries: maxRetriesArg, abortSignal, @@ -151,7 +157,7 @@ Only applicable for HTTP-based providers. prompt, n: callImageCount, abortSignal, - headers, + headers: headersWithUserAgent, size, aspectRatio, seed, @@ -165,7 +171,7 @@ Only applicable for HTTP-based providers. const images: Array = []; const warnings: Array = []; const responses: Array = []; - const providerMetadata: ImageModelV2ProviderMetadata = {}; + const providerMetadata: ImageModelV3ProviderMetadata = {}; for (const result of results) { images.push( ...result.images.map( @@ -214,13 +220,13 @@ class DefaultGenerateImageResult implements GenerateImageResult { readonly images: Array; readonly warnings: Array; readonly responses: Array; - readonly providerMetadata: ImageModelV2ProviderMetadata; + readonly providerMetadata: ImageModelV3ProviderMetadata; constructor(options: { images: Array; warnings: Array; responses: Array; - providerMetadata: ImageModelV2ProviderMetadata; + providerMetadata: ImageModelV3ProviderMetadata; }) { this.images = options.images; this.warnings = options.warnings; @@ -233,7 +239,7 @@ class DefaultGenerateImageResult implements GenerateImageResult { } } -async function invokeModelMaxImagesPerCall(model: ImageModelV2) { +async function invokeModelMaxImagesPerCall(model: ImageModelV3) { const isFunction = model.maxImagesPerCall instanceof Function; if (!isFunction) { diff --git a/packages/ai/src/generate-object/__snapshots__/generate-object.test.ts.snap b/packages/ai/src/generate-object/__snapshots__/generate-object.test.ts.snap index e5d90ec7e305..dcd7676a2e73 100644 --- a/packages/ai/src/generate-object/__snapshots__/generate-object.test.ts.snap +++ b/packages/ai/src/generate-object/__snapshots__/generate-object.test.ts.snap @@ -7,6 +7,7 @@ exports[`generateObject > telemetry > should not record telemetry inputs / outpu "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.generateObject", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.settings.maxRetries": 2, "ai.settings.output": "object", @@ -22,6 +23,7 @@ exports[`generateObject > telemetry > should not record telemetry inputs / outpu "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.generateObject.doGenerate", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.response.id": "test-id-from-model", "ai.response.model": "test-response-model-id", @@ -56,6 +58,7 @@ exports[`generateObject > telemetry > should record telemetry data when enabled "ai.prompt": "{"prompt":"prompt"}", "ai.request.headers.header1": "value1", "ai.request.headers.header2": "value2", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.response.object": "{"content":"Hello, world!"}", "ai.response.providerMetadata": "{"testProvider":{"testKey":"testValue"}}", @@ -88,6 +91,7 @@ exports[`generateObject > telemetry > should record telemetry data when enabled "ai.prompt.messages": "[{"role":"user","content":[{"type":"text","text":"prompt"}]}]", "ai.request.headers.header1": "value1", "ai.request.headers.header2": "value2", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.response.id": "test-id-from-model", "ai.response.model": "test-response-model-id", diff --git a/packages/ai/src/generate-object/generate-object.test.ts b/packages/ai/src/generate-object/generate-object.test.ts index 4481fa566f9c..f995d76d0e6c 100644 --- a/packages/ai/src/generate-object/generate-object.test.ts +++ b/packages/ai/src/generate-object/generate-object.test.ts @@ -6,7 +6,15 @@ import { import { jsonSchema } from '@ai-sdk/provider-utils'; import { convertReadableStreamToArray } from '@ai-sdk/provider-utils/test'; import assert, { fail } from 'node:assert'; -import { afterEach, beforeEach, describe, expect, it, vitest } from 'vitest'; +import { + afterEach, + beforeEach, + describe, + expect, + it, + vitest, + vi, +} from 'vitest'; import { z } from 'zod/v4'; import { verifyNoObjectGeneratedError as originalVerifyNoObjectGeneratedError } from '../error/verify-no-object-generated-error'; import * as logWarningsModule from '../logger/log-warnings'; @@ -14,6 +22,12 @@ import { MockLanguageModelV2 } from '../test/mock-language-model-v2'; import { MockTracer } from '../test/mock-tracer'; import { generateObject } from './generate-object'; +vi.mock('../version', () => { + return { + VERSION: '0.0.0-test', + }; +}); + const dummyResponseValues = { finishReason: 'stop' as const, usage: { @@ -250,6 +264,7 @@ describe('generateObject', () => { modelId: 'test-response-model-id', headers: { 'custom-response-header': 'response-header-value', + 'user-agent': 'ai/0.0.0-test', }, body: 'test body', }, @@ -265,6 +280,7 @@ describe('generateObject', () => { modelId: 'test-response-model-id', headers: { 'custom-response-header': 'response-header-value', + 'user-agent': 'ai/0.0.0-test', }, body: 'test body', }); @@ -523,6 +539,7 @@ describe('generateObject', () => { doGenerate: async ({ headers }) => { expect(headers).toStrictEqual({ 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', }); return { diff --git a/packages/ai/src/generate-object/generate-object.ts b/packages/ai/src/generate-object/generate-object.ts index 9a1e6925f5c2..4fc552aa0156 100644 --- a/packages/ai/src/generate-object/generate-object.ts +++ b/packages/ai/src/generate-object/generate-object.ts @@ -4,6 +4,7 @@ import { InferSchema, ProviderOptions, Schema, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import * as z3 from 'zod/v3'; import * as z4 from 'zod/v4'; @@ -42,6 +43,7 @@ import { getOutputStrategy } from './output-strategy'; import { parseAndValidateObjectResultWithRepair } from './parse-and-validate-object-result'; import { RepairTextFunction } from './repair-text'; import { validateObjectGenerationInput } from './validate-object-generation-input'; +import { VERSION } from '../version'; const originalGenerateId = createIdGenerator({ prefix: 'aiobj', size: 24 }); @@ -262,10 +264,15 @@ Default and recommended: 'auto' (best mode for the model). const callSettings = prepareCallSettings(settings); + const headersWithUserAgent = withUserAgentSuffix( + headers ?? {}, + `ai/${VERSION}`, + ); + const baseTelemetryAttributes = getBaseTelemetryAttributes({ model, telemetry, - headers, + headers: headersWithUserAgent, settings: { ...callSettings, maxRetries }, }); @@ -358,7 +365,7 @@ Default and recommended: 'auto' (best mode for the model). prompt: promptMessages, providerOptions, abortSignal, - headers, + headers: headersWithUserAgent, }); const responseData = { diff --git a/packages/ai/src/generate-speech/generate-speech.test.ts b/packages/ai/src/generate-speech/generate-speech.test.ts index bf781d25eeee..66812fb5db7c 100644 --- a/packages/ai/src/generate-speech/generate-speech.test.ts +++ b/packages/ai/src/generate-speech/generate-speech.test.ts @@ -3,7 +3,15 @@ import { SpeechModelV2, SpeechModelV2CallWarning, } from '@ai-sdk/provider'; -import { afterEach, beforeEach, describe, expect, it, vitest } from 'vitest'; +import { + afterEach, + beforeEach, + describe, + expect, + it, + vitest, + vi, +} from 'vitest'; import * as logWarningsModule from '../logger/log-warnings'; import { MockSpeechModelV2 } from '../test/mock-speech-model-v2'; import { generateSpeech } from './generate-speech'; @@ -21,6 +29,12 @@ const mockFile = new DefaultGeneratedAudioFile({ const sampleText = 'This is a sample text to convert to speech.'; +vi.mock('../version', () => { + return { + VERSION: '0.0.0-test', + }; +}); + const createMockResponse = (options: { audio: GeneratedAudioFile; warnings?: SpeechModelV2CallWarning[]; @@ -69,14 +83,19 @@ describe('generateSpeech', () => { }), text: sampleText, voice: 'test-voice', - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + }, abortSignal, }); expect(capturedArgs).toStrictEqual({ text: sampleText, voice: 'test-voice', - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', + }, abortSignal, providerOptions: {}, outputFormat: undefined, @@ -226,6 +245,7 @@ describe('generateSpeech', () => { timestamp: testDate, headers: { 'custom-response-header': 'response-header-value', + 'user-agent': 'ai/0.0.0-test', }, }), }), @@ -240,6 +260,7 @@ describe('generateSpeech', () => { modelId: expect.any(String), headers: { 'custom-response-header': 'response-header-value', + 'user-agent': 'ai/0.0.0-test', }, }, ], diff --git a/packages/ai/src/generate-speech/generate-speech.ts b/packages/ai/src/generate-speech/generate-speech.ts index e65067ce21ac..ddcfbaaabc5b 100644 --- a/packages/ai/src/generate-speech/generate-speech.ts +++ b/packages/ai/src/generate-speech/generate-speech.ts @@ -1,5 +1,5 @@ import { JSONValue, SpeechModelV2 } from '@ai-sdk/provider'; -import { ProviderOptions } from '@ai-sdk/provider-utils'; +import { ProviderOptions, withUserAgentSuffix } from '@ai-sdk/provider-utils'; import { NoSpeechGeneratedError } from '../error/no-speech-generated-error'; import { UnsupportedModelVersionError } from '../error/unsupported-model-version-error'; import { logWarnings } from '../logger/log-warnings'; @@ -15,7 +15,7 @@ import { DefaultGeneratedAudioFile, GeneratedAudioFile, } from './generated-audio-file'; - +import { VERSION } from '../version'; /** Generates speech audio using a speech model. @@ -122,6 +122,11 @@ Only applicable for HTTP-based providers. }); } + const headersWithUserAgent = withUserAgentSuffix( + headers ?? {}, + `ai/${VERSION}`, + ); + const { retry } = prepareRetries({ maxRetries: maxRetriesArg, abortSignal, @@ -136,7 +141,7 @@ Only applicable for HTTP-based providers. speed, language, abortSignal, - headers, + headers: headersWithUserAgent, providerOptions, }), ); diff --git a/packages/ai/src/generate-text/__snapshots__/generate-text.test.ts.snap b/packages/ai/src/generate-text/__snapshots__/generate-text.test.ts.snap index bc5598da45d0..6bcedcbfd064 100644 --- a/packages/ai/src/generate-text/__snapshots__/generate-text.test.ts.snap +++ b/packages/ai/src/generate-text/__snapshots__/generate-text.test.ts.snap @@ -1091,6 +1091,7 @@ exports[`generateText > telemetry > should not record telemetry inputs / outputs "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.generateText", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.settings.maxRetries": 2, "ai.usage.completionTokens": 10, @@ -1105,6 +1106,7 @@ exports[`generateText > telemetry > should not record telemetry inputs / outputs "ai.model.id": "mock-model-id", "ai.model.provider": "mock-provider", "ai.operationId": "ai.generateText.doGenerate", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.response.id": "test-id", "ai.response.model": "mock-model-id", @@ -1149,6 +1151,7 @@ exports[`generateText > telemetry > should record telemetry data when enabled 1` "ai.prompt": "{"prompt":"prompt"}", "ai.request.headers.header1": "value1", "ai.request.headers.header2": "value2", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.response.providerMetadata": "{"testProvider":{"testKey":"testValue"}}", "ai.response.text": "Hello, world!", @@ -1180,6 +1183,7 @@ exports[`generateText > telemetry > should record telemetry data when enabled 1` "ai.prompt.messages": "[{"role":"user","content":[{"type":"text","text":"prompt"}]}]", "ai.request.headers.header1": "value1", "ai.request.headers.header2": "value2", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.response.id": "test-id-from-model", "ai.response.model": "test-response-model-id", diff --git a/packages/ai/src/generate-text/content-part.ts b/packages/ai/src/generate-text/content-part.ts index 81509a200dc7..e1cfb5d14290 100644 --- a/packages/ai/src/generate-text/content-part.ts +++ b/packages/ai/src/generate-text/content-part.ts @@ -1,6 +1,7 @@ import { ProviderMetadata } from '../types'; import { Source } from '../types/language-model'; import { GeneratedFile } from './generated-file'; +import { ReasoningOutput } from './reasoning-output'; import { TypedToolCall } from './tool-call'; import { TypedToolError } from './tool-error'; import { TypedToolResult } from './tool-result'; @@ -8,7 +9,7 @@ import { ToolSet } from './tool-set'; export type ContentPart = | { type: 'text'; text: string; providerMetadata?: ProviderMetadata } - | { type: 'reasoning'; text: string; providerMetadata?: ProviderMetadata } + | ReasoningOutput | ({ type: 'source' } & Source) | { type: 'file'; file: GeneratedFile; providerMetadata?: ProviderMetadata } // different because of GeneratedFile object | ({ type: 'tool-call' } & TypedToolCall & { diff --git a/packages/ai/src/generate-text/generate-text-result.ts b/packages/ai/src/generate-text/generate-text-result.ts index c9bac1a6c4ff..61ef021bf50f 100644 --- a/packages/ai/src/generate-text/generate-text-result.ts +++ b/packages/ai/src/generate-text/generate-text-result.ts @@ -1,4 +1,3 @@ -import { ReasoningPart } from '@ai-sdk/provider-utils'; import { CallWarning, FinishReason, ProviderMetadata } from '../types'; import { Source } from '../types/language-model'; import { LanguageModelRequestMetadata } from '../types/language-model-request-metadata'; @@ -6,6 +5,7 @@ import { LanguageModelResponseMetadata } from '../types/language-model-response- import { LanguageModelUsage } from '../types/usage'; import { ContentPart } from './content-part'; import { GeneratedFile } from './generated-file'; +import { ReasoningOutput } from './reasoning-output'; import { ResponseMessage } from './response-message'; import { StepResult } from './step-result'; import { DynamicToolCall, StaticToolCall, TypedToolCall } from './tool-call'; @@ -34,7 +34,7 @@ The text that was generated in the last step. /** The full reasoning that the model has generated in the last step. */ - readonly reasoning: Array; + readonly reasoning: Array; /** The reasoning text that the model has generated in the last step. Can be undefined if the model diff --git a/packages/ai/src/generate-text/generate-text.test.ts b/packages/ai/src/generate-text/generate-text.test.ts index 502cb088e1ee..e0c6402da3b0 100644 --- a/packages/ai/src/generate-text/generate-text.test.ts +++ b/packages/ai/src/generate-text/generate-text.test.ts @@ -31,6 +31,12 @@ import { GenerateTextResult } from './generate-text-result'; import { StepResult } from './step-result'; import { stepCountIs } from './stop-condition'; +vi.mock('../version', () => { + return { + VERSION: '0.0.0-test', + }; +}); + const dummyResponseValues = { finishReason: 'stop' as const, usage: { @@ -1677,9 +1683,10 @@ describe('generateText', () => { const result = await generateText({ model: new MockLanguageModelV2({ doGenerate: async ({ headers }) => { - assert.deepStrictEqual(headers, { - 'custom-request-header': 'request-header-value', - }); + assert.equal( + headers?.['custom-request-header'], + 'request-header-value', + ); return { ...dummyResponseValues, @@ -1930,6 +1937,7 @@ describe('generateText', () => { "ai.model.provider": "mock-provider", "ai.operationId": "ai.generateText", "ai.prompt": "{"prompt":"test-input"}", + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.response.toolCalls": "[{"toolCallId":"call-1","toolName":"tool1","input":"{ \\"value\\": \\"value\\" }"}]", "ai.settings.maxRetries": 2, @@ -1950,6 +1958,7 @@ describe('generateText', () => { "ai.prompt.tools": [ "{"type":"function","name":"tool1","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","properties":{"value":{"type":"string"}},"required":["value"],"additionalProperties":false}}", ], + "ai.request.headers.user-agent": "ai/0.0.0-test", "ai.response.finishReason": "stop", "ai.response.id": "test-id", "ai.response.model": "mock-model-id", @@ -2266,7 +2275,7 @@ describe('generateText', () => { }); describe('provider-executed tools', () => { - describe('single provider-executed tool call and result', () => { + describe('two provider-executed tool calls and results', () => { let result: GenerateTextResult; beforeEach(async () => { @@ -2370,6 +2379,51 @@ describe('generateText', () => { `); }); + it('should include provider-executed tool calls in staticToolCalls', async () => { + expect(result.staticToolCalls).toMatchInlineSnapshot(` + [ + { + "input": { + "value": "value", + }, + "providerExecuted": true, + "providerMetadata": undefined, + "toolCallId": "call-1", + "toolName": "web_search", + "type": "tool-call", + }, + { + "input": { + "value": "value", + }, + "providerExecuted": true, + "providerMetadata": undefined, + "toolCallId": "call-2", + "toolName": "web_search", + "type": "tool-call", + }, + ] + `); + }); + + it('should include provider-executed results in staticToolResults (errors excluded)', async () => { + expect(result.staticToolResults).toMatchInlineSnapshot(` + [ + { + "dynamic": undefined, + "input": { + "value": "value", + }, + "output": "{ "value": "result1" }", + "providerExecuted": true, + "toolCallId": "call-1", + "toolName": "web_search", + "type": "tool-result", + }, + ] + `); + }); + it('should only execute a single step', async () => { expect(result.steps.length).toBe(1); }); @@ -2470,37 +2524,39 @@ describe('generateText', () => { }); expect(callOptions!).toMatchInlineSnapshot(` - { - "abortSignal": undefined, - "frequencyPenalty": undefined, - "headers": undefined, - "maxOutputTokens": undefined, - "presencePenalty": undefined, - "prompt": [ - { - "content": [ - { - "text": "prompt", - "type": "text", - }, - ], - "providerOptions": undefined, - "role": "user", - }, - ], - "providerOptions": undefined, - "responseFormat": { - "type": "text", - }, - "seed": undefined, - "stopSequences": undefined, - "temperature": undefined, - "toolChoice": undefined, - "tools": undefined, - "topK": undefined, - "topP": undefined, - } - `); + { + "abortSignal": undefined, + "frequencyPenalty": undefined, + "headers": { + "user-agent": "ai/0.0.0-test", + }, + "maxOutputTokens": undefined, + "presencePenalty": undefined, + "prompt": [ + { + "content": [ + { + "text": "prompt", + "type": "text", + }, + ], + "providerOptions": undefined, + "role": "user", + }, + ], + "providerOptions": undefined, + "responseFormat": { + "type": "text", + }, + "seed": undefined, + "stopSequences": undefined, + "temperature": undefined, + "toolChoice": undefined, + "tools": undefined, + "topK": undefined, + "topP": undefined, + } + `); }); }); @@ -2542,50 +2598,52 @@ describe('generateText', () => { }); expect(callOptions!).toMatchInlineSnapshot(` - { - "abortSignal": undefined, - "frequencyPenalty": undefined, - "headers": undefined, - "maxOutputTokens": undefined, - "presencePenalty": undefined, - "prompt": [ - { - "content": [ - { - "text": "prompt", - "type": "text", - }, - ], - "providerOptions": undefined, - "role": "user", - }, - ], - "providerOptions": undefined, - "responseFormat": { - "schema": { - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "value": { - "type": "string", + { + "abortSignal": undefined, + "frequencyPenalty": undefined, + "headers": { + "user-agent": "ai/0.0.0-test", + }, + "maxOutputTokens": undefined, + "presencePenalty": undefined, + "prompt": [ + { + "content": [ + { + "text": "prompt", + "type": "text", + }, + ], + "providerOptions": undefined, + "role": "user", + }, + ], + "providerOptions": undefined, + "responseFormat": { + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "value": { + "type": "string", + }, }, + "required": [ + "value", + ], + "type": "object", }, - "required": [ - "value", - ], - "type": "object", - }, - "type": "json", - }, - "seed": undefined, - "stopSequences": undefined, - "temperature": undefined, - "toolChoice": undefined, - "tools": undefined, - "topK": undefined, - "topP": undefined, - } - `); + "type": "json", + }, + "seed": undefined, + "stopSequences": undefined, + "temperature": undefined, + "toolChoice": undefined, + "tools": undefined, + "topK": undefined, + "topP": undefined, + } + `); }); }); }); diff --git a/packages/ai/src/generate-text/generate-text.ts b/packages/ai/src/generate-text/generate-text.ts index ebfbb3c944b5..94a87ce382ca 100644 --- a/packages/ai/src/generate-text/generate-text.ts +++ b/packages/ai/src/generate-text/generate-text.ts @@ -9,6 +9,7 @@ import { getErrorMessage, IdGenerator, ProviderOptions, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { Tracer } from '@opentelemetry/api'; import { NoOutputSpecifiedError } from '../error/no-output-specified-error'; @@ -55,6 +56,7 @@ import { TypedToolError } from './tool-error'; import { ToolOutput } from './tool-output'; import { TypedToolResult } from './tool-result'; import { ToolSet } from './tool-set'; +import { VERSION } from '../version'; const originalGenerateId = createIdGenerator({ prefix: 'aitxt', @@ -255,10 +257,15 @@ A function that attempts to repair a tool call that failed to parse. const callSettings = prepareCallSettings(settings); + const headersWithUserAgent = withUserAgentSuffix( + headers ?? {}, + `ai/${VERSION}`, + ); + const baseTelemetryAttributes = getBaseTelemetryAttributes({ model, telemetry, - headers, + headers: headersWithUserAgent, settings: { ...callSettings, maxRetries }, }); @@ -387,7 +394,7 @@ A function that attempts to repair a tool call that failed to parse. prompt: promptMessages, providerOptions, abortSignal, - headers, + headers: headersWithUserAgent, }); // Fill in default values: diff --git a/packages/ai/src/generate-text/index.ts b/packages/ai/src/generate-text/index.ts index 5f36dd698cd2..ba890f16d76d 100644 --- a/packages/ai/src/generate-text/index.ts +++ b/packages/ai/src/generate-text/index.ts @@ -7,6 +7,7 @@ export type { } from './generated-file'; export * as Output from './output'; export type { PrepareStepFunction, PrepareStepResult } from './prepare-step'; +export type { ReasoningOutput } from './reasoning-output'; export { smoothStream, type ChunkDetector } from './smooth-stream'; export type { StepResult } from './step-result'; export { hasToolCall, stepCountIs, type StopCondition } from './stop-condition'; diff --git a/packages/ai/src/generate-text/reasoning-output.ts b/packages/ai/src/generate-text/reasoning-output.ts new file mode 100644 index 000000000000..85c03103bc34 --- /dev/null +++ b/packages/ai/src/generate-text/reasoning-output.ts @@ -0,0 +1,20 @@ +import { ProviderMetadata } from '../types/provider-metadata'; + +/** + * Reasoning output of a text generation. It contains a reasoning. + */ +export interface ReasoningOutput { + type: 'reasoning'; + + /** + * The reasoning text. + */ + text: string; + + /** + * Additional provider-specific metadata. They are passed through + * to the provider from the AI SDK and enable provider-specific + * functionality that can be fully encapsulated in the provider. + */ + providerMetadata?: ProviderMetadata; +} diff --git a/packages/ai/src/generate-text/step-result.ts b/packages/ai/src/generate-text/step-result.ts index 6ea9f4c688f4..5c5ec1004263 100644 --- a/packages/ai/src/generate-text/step-result.ts +++ b/packages/ai/src/generate-text/step-result.ts @@ -199,7 +199,7 @@ export class DefaultStepResult get staticToolCalls() { return this.toolCalls.filter( (toolCall): toolCall is StaticToolCall => - toolCall.dynamic === false, + toolCall.dynamic !== true, ); } @@ -216,7 +216,7 @@ export class DefaultStepResult get staticToolResults() { return this.toolResults.filter( (toolResult): toolResult is StaticToolResult => - toolResult.dynamic === false, + toolResult.dynamic !== true, ); } diff --git a/packages/ai/src/generate-text/stream-text-result.ts b/packages/ai/src/generate-text/stream-text-result.ts index 6080a9e42510..236d0e5cb422 100644 --- a/packages/ai/src/generate-text/stream-text-result.ts +++ b/packages/ai/src/generate-text/stream-text-result.ts @@ -1,10 +1,5 @@ -import { IdGenerator, ReasoningPart } from '@ai-sdk/provider-utils'; +import { IdGenerator } from '@ai-sdk/provider-utils'; import { ServerResponse } from 'node:http'; -import { InferUIMessageChunk } from '../ui-message-stream/ui-message-chunks'; -import { UIMessageStreamResponseInit } from '../ui-message-stream/ui-message-stream-response-init'; -import { InferUIMessageMetadata, UIMessage } from '../ui/ui-messages'; -import { AsyncIterableStream } from '../util/async-iterable-stream'; -import { ErrorHandler } from '../util/error-handler'; import { CallWarning, FinishReason, @@ -14,9 +9,15 @@ import { import { Source } from '../types/language-model'; import { LanguageModelResponseMetadata } from '../types/language-model-response-metadata'; import { LanguageModelUsage } from '../types/usage'; +import { InferUIMessageChunk } from '../ui-message-stream/ui-message-chunks'; import { UIMessageStreamOnFinishCallback } from '../ui-message-stream/ui-message-stream-on-finish-callback'; +import { UIMessageStreamResponseInit } from '../ui-message-stream/ui-message-stream-response-init'; +import { InferUIMessageMetadata, UIMessage } from '../ui/ui-messages'; +import { AsyncIterableStream } from '../util/async-iterable-stream'; +import { ErrorHandler } from '../util/error-handler'; import { ContentPart } from './content-part'; import { GeneratedFile } from './generated-file'; +import { ReasoningOutput } from './reasoning-output'; import { ResponseMessage } from './response-message'; import { StepResult } from './step-result'; import { DynamicToolCall, StaticToolCall, TypedToolCall } from './tool-call'; @@ -117,7 +118,7 @@ The full reasoning that the model has generated. Automatically consumes the stream. */ - readonly reasoning: Promise>; + readonly reasoning: Promise>; /** The reasoning that has been generated by the last step. diff --git a/packages/ai/src/generate-text/stream-text.test.ts b/packages/ai/src/generate-text/stream-text.test.ts index 24b562f82efc..ccb3b3091209 100644 --- a/packages/ai/src/generate-text/stream-text.test.ts +++ b/packages/ai/src/generate-text/stream-text.test.ts @@ -4824,8 +4824,31 @@ describe('streamText', () => { "timestamp": 1970-01-01T00:00:00.000Z, }, "sources": [], - "staticToolCalls": [], - "staticToolResults": [], + "staticToolCalls": [ + { + "input": { + "value": "value", + }, + "providerExecuted": undefined, + "providerMetadata": undefined, + "toolCallId": "call-1", + "toolName": "tool1", + "type": "tool-call", + }, + ], + "staticToolResults": [ + { + "input": { + "value": "value", + }, + "output": "value-result", + "providerExecuted": undefined, + "providerMetadata": undefined, + "toolCallId": "call-1", + "toolName": "tool1", + "type": "tool-result", + }, + ], "steps": [ DefaultStepResult { "content": [ @@ -10623,8 +10646,31 @@ describe('streamText', () => { "timestamp": 1970-01-01T00:00:00.000Z, }, "sources": [], - "staticToolCalls": [], - "staticToolResults": [], + "staticToolCalls": [ + { + "input": { + "value": "VALUE", + }, + "providerExecuted": undefined, + "providerMetadata": undefined, + "toolCallId": "call-1", + "toolName": "tool1", + "type": "tool-call", + }, + ], + "staticToolResults": [ + { + "input": { + "value": "VALUE", + }, + "output": "VALUE-RESULT", + "providerExecuted": undefined, + "providerMetadata": undefined, + "toolCallId": "call-1", + "toolName": "tool1", + "type": "tool-result", + }, + ], "steps": [ DefaultStepResult { "content": [ diff --git a/packages/ai/src/global.ts b/packages/ai/src/global.ts index 5bc6c6ffc1aa..72557a9a1686 100644 --- a/packages/ai/src/global.ts +++ b/packages/ai/src/global.ts @@ -1,4 +1,4 @@ -import { ProviderV2 } from '@ai-sdk/provider'; +import { ProviderV3 } from '@ai-sdk/provider'; import { LogWarningsFunction } from './logger/log-warnings'; // add AI SDK default provider to the globalThis object @@ -11,7 +11,7 @@ declare global { * * @see https://ai-sdk.dev/docs/ai-sdk-core/provider-management#global-provider-configuration */ - var AI_SDK_DEFAULT_PROVIDER: ProviderV2 | undefined; + var AI_SDK_DEFAULT_PROVIDER: ProviderV3 | undefined; /** * The warning logger to use for the AI SDK. diff --git a/packages/ai/src/index.ts b/packages/ai/src/index.ts index 6d4cfca5a69f..d842c896f241 100644 --- a/packages/ai/src/index.ts +++ b/packages/ai/src/index.ts @@ -6,6 +6,7 @@ export { dynamicTool, generateId, jsonSchema, + parseJsonEventStream, tool, zodSchema, type IdGenerator, diff --git a/packages/ai/src/logger/log-warnings.test.ts b/packages/ai/src/logger/log-warnings.test.ts index 43873aee310c..5a748386dd36 100644 --- a/packages/ai/src/logger/log-warnings.test.ts +++ b/packages/ai/src/logger/log-warnings.test.ts @@ -7,7 +7,7 @@ import { } from './log-warnings'; import type { LanguageModelV2CallWarning, - ImageModelV2CallWarning, + ImageModelV3CallWarning, SpeechModelV2CallWarning, TranscriptionModelV2CallWarning, } from '@ai-sdk/provider'; @@ -55,7 +55,7 @@ describe('logWarnings', () => { { type: 'other', message: 'Test warning 2', - } as ImageModelV2CallWarning, + } as ImageModelV3CallWarning, ]; logWarnings(warnings); @@ -96,7 +96,7 @@ describe('logWarnings', () => { { type: 'other', message: 'Another warning', - } as ImageModelV2CallWarning, + } as ImageModelV3CallWarning, ]; logWarnings(warnings); @@ -141,7 +141,7 @@ describe('logWarnings', () => { type: 'other', message: 'First warning', }; - const warning2: ImageModelV2CallWarning = { + const warning2: ImageModelV3CallWarning = { type: 'unsupported-setting', setting: 'size', details: 'Size parameter not supported', @@ -210,8 +210,8 @@ describe('logWarnings', () => { ); }); - it('should log ImageModelV2CallWarning', () => { - const warning: ImageModelV2CallWarning = { + it('should log image model call warning', () => { + const warning: ImageModelV3CallWarning = { type: 'unsupported-setting', setting: 'size', details: 'Image size setting not supported', @@ -266,7 +266,7 @@ describe('logWarnings', () => { type: 'other', message: 'Language model warning', }; - const imageWarning: ImageModelV2CallWarning = { + const imageWarning: ImageModelV3CallWarning = { type: 'other', message: 'Image model warning', }; diff --git a/packages/ai/src/logger/log-warnings.ts b/packages/ai/src/logger/log-warnings.ts index a283cb143700..fe460aa8c70b 100644 --- a/packages/ai/src/logger/log-warnings.ts +++ b/packages/ai/src/logger/log-warnings.ts @@ -1,5 +1,5 @@ import { - ImageModelV2CallWarning, + ImageModelV3CallWarning, LanguageModelV2CallWarning, SpeechModelV2CallWarning, TranscriptionModelV2CallWarning, @@ -7,7 +7,7 @@ import { export type Warning = | LanguageModelV2CallWarning - | ImageModelV2CallWarning + | ImageModelV3CallWarning | SpeechModelV2CallWarning | TranscriptionModelV2CallWarning; diff --git a/packages/ai/src/middleware/wrap-provider.test.ts b/packages/ai/src/middleware/wrap-provider.test.ts index 7d6efb7faae5..6b2cda1769f8 100644 --- a/packages/ai/src/middleware/wrap-provider.test.ts +++ b/packages/ai/src/middleware/wrap-provider.test.ts @@ -1,5 +1,5 @@ import { MockLanguageModelV2 } from '../test/mock-language-model-v2'; -import { MockProviderV2 } from '../test/mock-provider-v2'; +import { MockProviderV3 } from '../test/mock-provider-v3'; import { wrapProvider } from './wrap-provider'; import { describe, it, expect, vi } from 'vitest'; @@ -9,7 +9,7 @@ describe('wrapProvider', () => { const model2 = new MockLanguageModelV2({ modelId: 'model-2' }); const model3 = new MockLanguageModelV2({ modelId: 'model-3' }); - const provider = new MockProviderV2({ + const provider = new MockProviderV3({ languageModels: { 'model-1': model1, 'model-2': model2, diff --git a/packages/ai/src/middleware/wrap-provider.ts b/packages/ai/src/middleware/wrap-provider.ts index b57151e66331..2af57aee5f34 100644 --- a/packages/ai/src/middleware/wrap-provider.ts +++ b/packages/ai/src/middleware/wrap-provider.ts @@ -1,25 +1,25 @@ -import type { ProviderV2 } from '@ai-sdk/provider'; +import type { ProviderV3 } from '@ai-sdk/provider'; import { LanguageModelMiddleware } from '../types/language-model-middleware'; import { wrapLanguageModel } from './wrap-language-model'; /** - * Wraps a ProviderV2 instance with middleware functionality. + * Wraps a ProviderV3 instance with middleware functionality. * This function allows you to apply middleware to all language models * from the provider, enabling you to transform parameters, wrap generate * operations, and wrap stream operations for every language model. * * @param options - Configuration options for wrapping the provider. - * @param options.provider - The original ProviderV2 instance to be wrapped. + * @param options.provider - The original ProviderV3 instance to be wrapped. * @param options.languageModelMiddleware - The middleware to be applied to all language models from the provider. When multiple middlewares are provided, the first middleware will transform the input first, and the last middleware will be wrapped directly around the model. - * @returns A new ProviderV2 instance with middleware applied to all language models. + * @returns A new ProviderV3 instance with middleware applied to all language models. */ export function wrapProvider({ provider, languageModelMiddleware, }: { - provider: ProviderV2; + provider: ProviderV3; languageModelMiddleware: LanguageModelMiddleware | LanguageModelMiddleware[]; -}): ProviderV2 { +}): ProviderV3 { const wrappedProvider = { languageModel(modelId: string) { let model = provider.languageModel(modelId); diff --git a/packages/ai/src/model/resolve-model.test.ts b/packages/ai/src/model/resolve-model.test.ts index f47de854c78f..6f2c85539974 100644 --- a/packages/ai/src/model/resolve-model.test.ts +++ b/packages/ai/src/model/resolve-model.test.ts @@ -1,5 +1,5 @@ import { customProvider } from '../registry/custom-provider'; -import { MockEmbeddingModelV2 } from '../test/mock-embedding-model-v2'; +import { MockEmbeddingModelV3 } from '../test/mock-embedding-model-v3'; import { MockLanguageModelV2 } from '../test/mock-language-model-v2'; import { resolveEmbeddingModel, resolveLanguageModel } from './resolve-model'; import { beforeEach, afterEach, describe, expect, it } from 'vitest'; @@ -57,7 +57,7 @@ describe('resolveEmbeddingModel', () => { describe('when a embedding model v2 is provided', () => { it('should return the embedding model v2', () => { const resolvedModel = resolveEmbeddingModel( - new MockEmbeddingModelV2({ + new MockEmbeddingModelV3({ provider: 'test-provider', modelId: 'test-model-id', }), @@ -81,7 +81,7 @@ describe('resolveEmbeddingModel', () => { beforeEach(() => { globalThis.AI_SDK_DEFAULT_PROVIDER = customProvider({ textEmbeddingModels: { - 'test-model-id': new MockEmbeddingModelV2({ + 'test-model-id': new MockEmbeddingModelV3({ provider: 'global-test-provider', modelId: 'actual-test-model-id', }), diff --git a/packages/ai/src/model/resolve-model.ts b/packages/ai/src/model/resolve-model.ts index cd95bf217041..4cdb0fc20f82 100644 --- a/packages/ai/src/model/resolve-model.ts +++ b/packages/ai/src/model/resolve-model.ts @@ -1,8 +1,8 @@ import { gateway } from '@ai-sdk/gateway'; import { - EmbeddingModelV2, + EmbeddingModelV3, LanguageModelV2, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { UnsupportedModelVersionError } from '../error'; import { EmbeddingModel } from '../types/embedding-model'; @@ -26,9 +26,9 @@ export function resolveLanguageModel(model: LanguageModel): LanguageModelV2 { export function resolveEmbeddingModel( model: EmbeddingModel, -): EmbeddingModelV2 { +): EmbeddingModelV3 { if (typeof model !== 'string') { - if (model.specificationVersion !== 'v2') { + if (model.specificationVersion !== 'v3') { throw new UnsupportedModelVersionError({ version: model.specificationVersion, provider: model.provider, @@ -42,9 +42,9 @@ export function resolveEmbeddingModel( // TODO AI SDK 6: figure out how to cleanly support different generic types return getGlobalProvider().textEmbeddingModel( model, - ) as EmbeddingModelV2; + ) as EmbeddingModelV3; } -function getGlobalProvider(): ProviderV2 { +function getGlobalProvider(): ProviderV3 { return globalThis.AI_SDK_DEFAULT_PROVIDER ?? gateway; } diff --git a/packages/ai/src/prompt/convert-to-language-model-prompt.test.ts b/packages/ai/src/prompt/convert-to-language-model-prompt.test.ts index 80b1ce7608ff..5401b1b65366 100644 --- a/packages/ai/src/prompt/convert-to-language-model-prompt.test.ts +++ b/packages/ai/src/prompt/convert-to-language-model-prompt.test.ts @@ -673,6 +673,101 @@ describe('convertToLanguageModelPrompt', () => { ]); }); }); + + it('should download files when intermediate file cannot be downloaded', async () => { + const imageUrlA = `http://example.com/my-image-A.png`; // supported + const fileUrl = `http://127.0.0.1:3000/file`; // unsupported + const imageUrlB = `http://example.com/my-image-B.png`; // supported + + const mockDownload = vi.fn().mockResolvedValue([ + { + url: new URL(imageUrlA), + data: new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10, 0]), // empty png and 0 + mediaType: 'image/png', + }, + null, + { + url: new URL(imageUrlB), + data: new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10, 1]), // empty png and 1 + mediaType: 'image/png', + }, + ]); + + const result = await convertToLanguageModelPrompt({ + prompt: { + messages: [ + { + role: 'user', + content: [ + { type: 'image', image: imageUrlA, mediaType: 'image/png' }, + { + type: 'file', + data: new URL(fileUrl), + mediaType: 'application/octet-stream', + }, + { type: 'image', image: imageUrlB, mediaType: 'image/png' }, + ], + }, + ], + }, + supportedUrls: { + '*': [/^https:\/\/.*$/], + }, + download: mockDownload, + }); + + expect(result).toMatchInlineSnapshot(` + [ + { + "content": [ + { + "data": Uint8Array [ + 137, + 80, + 78, + 71, + 13, + 10, + 26, + 10, + 0, + ], + "filename": undefined, + "mediaType": "image/png", + "providerOptions": undefined, + "type": "file", + }, + { + "data": "http://127.0.0.1:3000/file", + "filename": undefined, + "mediaType": "application/octet-stream", + "providerOptions": undefined, + "type": "file", + }, + { + "data": Uint8Array [ + 137, + 80, + 78, + 71, + 13, + 10, + 26, + 10, + 1, + ], + "filename": undefined, + "mediaType": "image/png", + "providerOptions": undefined, + "type": "file", + }, + ], + "providerOptions": undefined, + "role": "user", + }, + ] + `); + }); }); describe('custom download function', () => { @@ -899,7 +994,7 @@ describe('convertToLanguageModelMessage', () => { describe('assistant message', () => { describe('text parts', () => { - it('should ignore empty text parts', async () => { + it('should ignore empty text parts when there are no provider options', async () => { const result = convertToLanguageModelMessage({ message: { role: 'assistant', @@ -931,6 +1026,58 @@ describe('convertToLanguageModelMessage', () => { ], }); }); + + it('should include empty text parts when there are provider options', async () => { + const result = convertToLanguageModelMessage({ + message: { + role: 'assistant', + content: [ + { + type: 'text', + text: '', + providerOptions: { + 'test-provider': { + 'key-a': 'test-value-1', + }, + }, + }, + { + type: 'tool-call', + toolName: 'toolName', + toolCallId: 'toolCallId', + input: {}, + }, + ], + }, + downloadedAssets: {}, + }); + + expect(result).toMatchInlineSnapshot(` + { + "content": [ + { + "providerOptions": { + "test-provider": { + "key-a": "test-value-1", + }, + }, + "text": "", + "type": "text", + }, + { + "input": {}, + "providerExecuted": undefined, + "providerOptions": undefined, + "toolCallId": "toolCallId", + "toolName": "toolName", + "type": "tool-call", + }, + ], + "providerOptions": undefined, + "role": "assistant", + } + `); + }); }); describe('reasoning parts', () => { diff --git a/packages/ai/src/prompt/convert-to-language-model-prompt.ts b/packages/ai/src/prompt/convert-to-language-model-prompt.ts index f08152a4c3d4..13e726f4289e 100644 --- a/packages/ai/src/prompt/convert-to-language-model-prompt.ts +++ b/packages/ai/src/prompt/convert-to-language-model-prompt.ts @@ -108,8 +108,11 @@ export function convertToLanguageModelMessage({ role: 'assistant', content: message.content .filter( - // remove empty text parts: - part => part.type !== 'text' || part.text !== '', + // remove empty text parts (no text, and no provider options): + part => + part.type !== 'text' || + part.text !== '' || + part.providerOptions != null, ) .map(part => { const providerOptions = part.providerOptions; @@ -242,18 +245,15 @@ async function downloadAssets( return Object.fromEntries( downloadedFiles - .filter( - ( - downloadedFile, - ): downloadedFile is { - mediaType: string | undefined; - data: Uint8Array; - } => downloadedFile?.data != null, + .map((file, index) => + file == null + ? null + : [ + plannedDownloads[index].url.toString(), + { data: file.data, mediaType: file.mediaType }, + ], ) - .map(({ data, mediaType }, index) => [ - plannedDownloads[index].url.toString(), - { data, mediaType }, - ]), + .filter(file => file != null), ); } diff --git a/packages/ai/src/registry/custom-provider.test.ts b/packages/ai/src/registry/custom-provider.test.ts index 8a4a0986454a..e3b417161e58 100644 --- a/packages/ai/src/registry/custom-provider.test.ts +++ b/packages/ai/src/registry/custom-provider.test.ts @@ -1,14 +1,14 @@ import { NoSuchModelError } from '@ai-sdk/provider'; import { describe, expect, it, vi } from 'vitest'; -import { MockEmbeddingModelV2 } from '../test/mock-embedding-model-v2'; -import { MockImageModelV2 } from '../test/mock-image-model-v2'; +import { MockEmbeddingModelV3 } from '../test/mock-embedding-model-v3'; +import { MockImageModelV3 } from '../test/mock-image-model-v3'; import { MockLanguageModelV2 } from '../test/mock-language-model-v2'; import { MockTranscriptionModelV2 } from '../test/mock-transcription-model-v2'; import { MockSpeechModelV2 } from '../test/mock-speech-model-v2'; import { customProvider } from './custom-provider'; const mockLanguageModel = new MockLanguageModelV2(); -const mockEmbeddingModel = new MockEmbeddingModelV2(); +const mockEmbeddingModel = new MockEmbeddingModelV3(); const mockFallbackProvider = { languageModel: vi.fn(), textEmbeddingModel: vi.fn(), @@ -79,7 +79,7 @@ describe('textEmbeddingModel', () => { }); describe('imageModel', () => { - const mockImageModel = new MockImageModelV2(); + const mockImageModel = new MockImageModelV3(); it('should return the image model if it exists', () => { const provider = customProvider({ diff --git a/packages/ai/src/registry/custom-provider.ts b/packages/ai/src/registry/custom-provider.ts index b235d5e7c26c..8bc5fad834a6 100644 --- a/packages/ai/src/registry/custom-provider.ts +++ b/packages/ai/src/registry/custom-provider.ts @@ -1,9 +1,9 @@ import { - EmbeddingModelV2, - ImageModelV2, + EmbeddingModelV3, + ImageModelV3, LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, SpeechModelV2, TranscriptionModelV2, } from '@ai-sdk/provider'; @@ -24,8 +24,8 @@ import { */ export function customProvider< LANGUAGE_MODELS extends Record, - EMBEDDING_MODELS extends Record>, - IMAGE_MODELS extends Record, + EMBEDDING_MODELS extends Record>, + IMAGE_MODELS extends Record, TRANSCRIPTION_MODELS extends Record, SPEECH_MODELS extends Record, >({ @@ -41,13 +41,13 @@ export function customProvider< imageModels?: IMAGE_MODELS; transcriptionModels?: TRANSCRIPTION_MODELS; speechModels?: SPEECH_MODELS; - fallbackProvider?: ProviderV2; -}): ProviderV2 & { + fallbackProvider?: ProviderV3; +}): ProviderV3 & { languageModel(modelId: ExtractModelId): LanguageModelV2; textEmbeddingModel( modelId: ExtractModelId, - ): EmbeddingModelV2; - imageModel(modelId: ExtractModelId): ImageModelV2; + ): EmbeddingModelV3; + imageModel(modelId: ExtractModelId): ImageModelV3; transcriptionModel( modelId: ExtractModelId, ): TranscriptionModelV2; @@ -68,7 +68,7 @@ export function customProvider< textEmbeddingModel( modelId: ExtractModelId, - ): EmbeddingModelV2 { + ): EmbeddingModelV3 { if (textEmbeddingModels != null && modelId in textEmbeddingModels) { return textEmbeddingModels[modelId]; } @@ -80,7 +80,7 @@ export function customProvider< throw new NoSuchModelError({ modelId, modelType: 'textEmbeddingModel' }); }, - imageModel(modelId: ExtractModelId): ImageModelV2 { + imageModel(modelId: ExtractModelId): ImageModelV3 { if (imageModels != null && modelId in imageModels) { return imageModels[modelId]; } diff --git a/packages/ai/src/registry/provider-registry.test.ts b/packages/ai/src/registry/provider-registry.test.ts index 6ada32d2a854..6b23d5f84a7c 100644 --- a/packages/ai/src/registry/provider-registry.test.ts +++ b/packages/ai/src/registry/provider-registry.test.ts @@ -1,12 +1,12 @@ import { NoSuchModelError } from '@ai-sdk/provider'; -import { MockEmbeddingModelV2 } from '../test/mock-embedding-model-v2'; +import { MockEmbeddingModelV3 } from '../test/mock-embedding-model-v3'; import { MockLanguageModelV2 } from '../test/mock-language-model-v2'; import { NoSuchProviderError } from './no-such-provider-error'; import { createProviderRegistry } from './provider-registry'; -import { MockImageModelV2 } from '../test/mock-image-model-v2'; +import { MockImageModelV3 } from '../test/mock-image-model-v3'; import { MockTranscriptionModelV2 } from '../test/mock-transcription-model-v2'; import { MockSpeechModelV2 } from '../test/mock-speech-model-v2'; -import { MockProviderV2 } from '../test/mock-provider-v2'; +import { MockProviderV3 } from '../test/mock-provider-v3'; import { describe, it, expect, vi } from 'vitest'; describe('languageModel', () => { @@ -159,7 +159,7 @@ describe('languageModel', () => { describe('textEmbeddingModel', () => { it('should return embedding model from provider using textEmbeddingModel', () => { - const model = new MockEmbeddingModelV2(); + const model = new MockEmbeddingModelV3(); const modelRegistry = createProviderRegistry({ provider: { @@ -224,7 +224,7 @@ describe('textEmbeddingModel', () => { }); it('should support custom separator', () => { - const model = new MockEmbeddingModelV2(); + const model = new MockEmbeddingModelV3(); const modelRegistry = createProviderRegistry( { @@ -256,7 +256,7 @@ describe('textEmbeddingModel', () => { describe('imageModel', () => { it('should return image model from provider', () => { - const model = new MockImageModelV2(); + const model = new MockImageModelV3(); const modelRegistry = createProviderRegistry({ provider: { @@ -305,7 +305,7 @@ describe('imageModel', () => { }); it('should support custom separator', () => { - const model = new MockImageModelV2(); + const model = new MockImageModelV3(); const modelRegistry = createProviderRegistry( { @@ -435,14 +435,14 @@ describe('middleware functionality', () => { const model2 = new MockLanguageModelV2({ modelId: 'model-2' }); const model3 = new MockLanguageModelV2({ modelId: 'model-3' }); - const provider1 = new MockProviderV2({ + const provider1 = new MockProviderV3({ languageModels: { 'model-1': model1, 'model-2': model2, }, }); - const provider2 = new MockProviderV2({ + const provider2 = new MockProviderV3({ languageModels: { 'model-3': model3, }, diff --git a/packages/ai/src/registry/provider-registry.ts b/packages/ai/src/registry/provider-registry.ts index 929b0d428c17..0e4f21f0425e 100644 --- a/packages/ai/src/registry/provider-registry.ts +++ b/packages/ai/src/registry/provider-registry.ts @@ -1,9 +1,9 @@ import { - EmbeddingModelV2, - ImageModelV2, + EmbeddingModelV3, + ImageModelV3, LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, SpeechModelV2, TranscriptionModelV2, } from '@ai-sdk/provider'; @@ -18,7 +18,7 @@ type ExtractLiteralUnion = T extends string : never; export interface ProviderRegistryProvider< - PROVIDERS extends Record = Record, + PROVIDERS extends Record = Record, SEPARATOR extends string = ':', > { languageModel( @@ -34,19 +34,19 @@ export interface ProviderRegistryProvider< id: KEY extends string ? `${KEY & string}${SEPARATOR}${ExtractLiteralUnion>[0]>}` : never, - ): EmbeddingModelV2; + ): EmbeddingModelV3; textEmbeddingModel( id: KEY extends string ? `${KEY & string}${SEPARATOR}${string}` : never, - ): EmbeddingModelV2; + ): EmbeddingModelV3; imageModel( id: KEY extends string ? `${KEY & string}${SEPARATOR}${ExtractLiteralUnion>[0]>}` : never, - ): ImageModelV2; + ): ImageModelV3; imageModel( id: KEY extends string ? `${KEY & string}${SEPARATOR}${string}` : never, - ): ImageModelV2; + ): ImageModelV3; transcriptionModel( id: KEY extends string @@ -80,7 +80,7 @@ export interface ProviderRegistryProvider< * @returns A new ProviderRegistryProvider instance that provides access to all registered providers with optional middleware applied to language models. */ export function createProviderRegistry< - PROVIDERS extends Record, + PROVIDERS extends Record, SEPARATOR extends string = ':', >( providers: PROVIDERS, @@ -115,7 +115,7 @@ export function createProviderRegistry< export const experimental_createProviderRegistry = createProviderRegistry; class DefaultProviderRegistry< - PROVIDERS extends Record, + PROVIDERS extends Record, SEPARATOR extends string, > implements ProviderRegistryProvider { @@ -156,7 +156,7 @@ class DefaultProviderRegistry< | 'imageModel' | 'transcriptionModel' | 'speechModel', - ): ProviderV2 { + ): ProviderV3 { const provider = this.providers[id as keyof PROVIDERS]; if (provider == null) { @@ -219,7 +219,7 @@ class DefaultProviderRegistry< textEmbeddingModel( id: `${KEY & string}${SEPARATOR}${string}`, - ): EmbeddingModelV2 { + ): EmbeddingModelV3 { const [providerId, modelId] = this.splitId(id, 'textEmbeddingModel'); const provider = this.getProvider(providerId, 'textEmbeddingModel'); @@ -237,7 +237,7 @@ class DefaultProviderRegistry< imageModel( id: `${KEY & string}${SEPARATOR}${string}`, - ): ImageModelV2 { + ): ImageModelV3 { const [providerId, modelId] = this.splitId(id, 'imageModel'); const provider = this.getProvider(providerId, 'imageModel'); diff --git a/packages/ai/src/test/mock-embedding-model-v2.ts b/packages/ai/src/test/mock-embedding-model-v2.ts deleted file mode 100644 index 0dccd1734de7..000000000000 --- a/packages/ai/src/test/mock-embedding-model-v2.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { EmbeddingModelV2 } from '@ai-sdk/provider'; -import { notImplemented } from './not-implemented'; - -export class MockEmbeddingModelV2 implements EmbeddingModelV2 { - readonly specificationVersion = 'v2'; - - readonly provider: EmbeddingModelV2['provider']; - readonly modelId: EmbeddingModelV2['modelId']; - readonly maxEmbeddingsPerCall: EmbeddingModelV2['maxEmbeddingsPerCall']; - readonly supportsParallelCalls: EmbeddingModelV2['supportsParallelCalls']; - - doEmbed: EmbeddingModelV2['doEmbed']; - - constructor({ - provider = 'mock-provider', - modelId = 'mock-model-id', - maxEmbeddingsPerCall = 1, - supportsParallelCalls = false, - doEmbed = notImplemented, - }: { - provider?: EmbeddingModelV2['provider']; - modelId?: EmbeddingModelV2['modelId']; - maxEmbeddingsPerCall?: - | EmbeddingModelV2['maxEmbeddingsPerCall'] - | null; - supportsParallelCalls?: EmbeddingModelV2['supportsParallelCalls']; - doEmbed?: EmbeddingModelV2['doEmbed']; - } = {}) { - this.provider = provider; - this.modelId = modelId; - this.maxEmbeddingsPerCall = maxEmbeddingsPerCall ?? undefined; - this.supportsParallelCalls = supportsParallelCalls; - this.doEmbed = doEmbed; - } -} diff --git a/packages/ai/src/test/mock-embedding-model-v3.ts b/packages/ai/src/test/mock-embedding-model-v3.ts new file mode 100644 index 000000000000..409a329c91b9 --- /dev/null +++ b/packages/ai/src/test/mock-embedding-model-v3.ts @@ -0,0 +1,35 @@ +import { EmbeddingModelV3 } from '@ai-sdk/provider'; +import { notImplemented } from './not-implemented'; + +export class MockEmbeddingModelV3 implements EmbeddingModelV3 { + readonly specificationVersion = 'v3'; + + readonly provider: EmbeddingModelV3['provider']; + readonly modelId: EmbeddingModelV3['modelId']; + readonly maxEmbeddingsPerCall: EmbeddingModelV3['maxEmbeddingsPerCall']; + readonly supportsParallelCalls: EmbeddingModelV3['supportsParallelCalls']; + + doEmbed: EmbeddingModelV3['doEmbed']; + + constructor({ + provider = 'mock-provider', + modelId = 'mock-model-id', + maxEmbeddingsPerCall = 1, + supportsParallelCalls = false, + doEmbed = notImplemented, + }: { + provider?: EmbeddingModelV3['provider']; + modelId?: EmbeddingModelV3['modelId']; + maxEmbeddingsPerCall?: + | EmbeddingModelV3['maxEmbeddingsPerCall'] + | null; + supportsParallelCalls?: EmbeddingModelV3['supportsParallelCalls']; + doEmbed?: EmbeddingModelV3['doEmbed']; + } = {}) { + this.provider = provider; + this.modelId = modelId; + this.maxEmbeddingsPerCall = maxEmbeddingsPerCall ?? undefined; + this.supportsParallelCalls = supportsParallelCalls; + this.doEmbed = doEmbed; + } +} diff --git a/packages/ai/src/test/mock-image-model-v2.ts b/packages/ai/src/test/mock-image-model-v2.ts deleted file mode 100644 index 73876b4c44ea..000000000000 --- a/packages/ai/src/test/mock-image-model-v2.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ImageModelV2 } from '@ai-sdk/provider'; -import { notImplemented } from './not-implemented'; - -export class MockImageModelV2 implements ImageModelV2 { - readonly specificationVersion = 'v2'; - readonly provider: ImageModelV2['provider']; - readonly modelId: ImageModelV2['modelId']; - readonly maxImagesPerCall: ImageModelV2['maxImagesPerCall']; - - doGenerate: ImageModelV2['doGenerate']; - - constructor({ - provider = 'mock-provider', - modelId = 'mock-model-id', - maxImagesPerCall = 1, - doGenerate = notImplemented, - }: { - provider?: ImageModelV2['provider']; - modelId?: ImageModelV2['modelId']; - maxImagesPerCall?: ImageModelV2['maxImagesPerCall']; - doGenerate?: ImageModelV2['doGenerate']; - } = {}) { - this.provider = provider; - this.modelId = modelId; - this.maxImagesPerCall = maxImagesPerCall; - this.doGenerate = doGenerate; - } -} diff --git a/packages/ai/src/test/mock-image-model-v3.ts b/packages/ai/src/test/mock-image-model-v3.ts new file mode 100644 index 000000000000..96d599abd438 --- /dev/null +++ b/packages/ai/src/test/mock-image-model-v3.ts @@ -0,0 +1,28 @@ +import { ImageModelV3 } from '@ai-sdk/provider'; +import { notImplemented } from './not-implemented'; + +export class MockImageModelV3 implements ImageModelV3 { + readonly specificationVersion = 'v3'; + readonly provider: ImageModelV3['provider']; + readonly modelId: ImageModelV3['modelId']; + readonly maxImagesPerCall: ImageModelV3['maxImagesPerCall']; + + doGenerate: ImageModelV3['doGenerate']; + + constructor({ + provider = 'mock-provider', + modelId = 'mock-model-id', + maxImagesPerCall = 1, + doGenerate = notImplemented, + }: { + provider?: ImageModelV3['provider']; + modelId?: ImageModelV3['modelId']; + maxImagesPerCall?: ImageModelV3['maxImagesPerCall']; + doGenerate?: ImageModelV3['doGenerate']; + } = {}) { + this.provider = provider; + this.modelId = modelId; + this.maxImagesPerCall = maxImagesPerCall; + this.doGenerate = doGenerate; + } +} diff --git a/packages/ai/src/test/mock-provider-v2.ts b/packages/ai/src/test/mock-provider-v3.ts similarity index 77% rename from packages/ai/src/test/mock-provider-v2.ts rename to packages/ai/src/test/mock-provider-v3.ts index a07974b1ea13..249c85265060 100644 --- a/packages/ai/src/test/mock-provider-v2.ts +++ b/packages/ai/src/test/mock-provider-v3.ts @@ -1,19 +1,19 @@ import { - EmbeddingModelV2, - ImageModelV2, + EmbeddingModelV3, + ImageModelV3, LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, SpeechModelV2, TranscriptionModelV2, } from '@ai-sdk/provider'; -export class MockProviderV2 implements ProviderV2 { - languageModel: ProviderV2['languageModel']; - textEmbeddingModel: ProviderV2['textEmbeddingModel']; - imageModel: ProviderV2['imageModel']; - transcriptionModel: ProviderV2['transcriptionModel']; - speechModel: ProviderV2['speechModel']; +export class MockProviderV3 implements ProviderV3 { + languageModel: ProviderV3['languageModel']; + textEmbeddingModel: ProviderV3['textEmbeddingModel']; + imageModel: ProviderV3['imageModel']; + transcriptionModel: ProviderV3['transcriptionModel']; + speechModel: ProviderV3['speechModel']; constructor({ languageModels, @@ -23,8 +23,8 @@ export class MockProviderV2 implements ProviderV2 { speechModels, }: { languageModels?: Record; - embeddingModels?: Record>; - imageModels?: Record; + embeddingModels?: Record>; + imageModels?: Record; transcriptionModels?: Record; speechModels?: Record; } = {}) { diff --git a/packages/ai/src/tool/mcp/mcp-sse-transport.test.ts b/packages/ai/src/tool/mcp/mcp-sse-transport.test.ts index c6470b5eb59d..4fafb87718e4 100644 --- a/packages/ai/src/tool/mcp/mcp-sse-transport.test.ts +++ b/packages/ai/src/tool/mcp/mcp-sse-transport.test.ts @@ -1,7 +1,7 @@ import { createTestServer, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; import { MCPClientError } from '../../error/mcp-client-error'; import { SseMCPTransport } from './mcp-sse-transport'; import { beforeEach, describe, expect, it } from 'vitest'; @@ -269,12 +269,14 @@ describe('SseMCPTransport', () => { accept: 'text/event-stream', ...customHeaders, }); + expect(server.calls[0].requestUserAgent).toContain('ai-sdk/'); // Verify POST request headers expect(server.calls[1].requestHeaders).toEqual({ 'content-type': 'application/json', ...customHeaders, }); + expect(server.calls[1].requestUserAgent).toContain('ai-sdk/'); await transport.close(); }); diff --git a/packages/ai/src/tool/mcp/mcp-sse-transport.ts b/packages/ai/src/tool/mcp/mcp-sse-transport.ts index 1fd2ddc7ff14..5ca2be0b93f4 100644 --- a/packages/ai/src/tool/mcp/mcp-sse-transport.ts +++ b/packages/ai/src/tool/mcp/mcp-sse-transport.ts @@ -1,7 +1,12 @@ -import { EventSourceParserStream } from '@ai-sdk/provider-utils'; +import { + EventSourceParserStream, + withUserAgentSuffix, + getRuntimeEnvironmentUserAgent, +} from '@ai-sdk/provider-utils'; import { MCPClientError } from '../../error/mcp-client-error'; import { JSONRPCMessage, JSONRPCMessageSchema } from './json-rpc-message'; import { MCPTransport } from './mcp-transport'; +import { VERSION } from '../../version'; export class SseMCPTransport implements MCPTransport { private endpoint?: URL; @@ -38,8 +43,14 @@ export class SseMCPTransport implements MCPTransport { const establishConnection = async () => { try { - const headers = new Headers(this.headers); - headers.set('Accept', 'text/event-stream'); + const headers = withUserAgentSuffix( + { + ...this.headers, + Accept: 'text/event-stream', + }, + `ai-sdk/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ); const response = await fetch(this.url.href, { headers, signal: this.abortController?.signal, @@ -149,8 +160,14 @@ export class SseMCPTransport implements MCPTransport { } try { - const headers = new Headers(this.headers); - headers.set('Content-Type', 'application/json'); + const headers = withUserAgentSuffix( + { + ...this.headers, + 'Content-Type': 'application/json', + }, + `ai-sdk/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ); const init = { method: 'POST', headers, diff --git a/packages/ai/src/transcribe/transcribe.test.ts b/packages/ai/src/transcribe/transcribe.test.ts index 9be4f6ee6db1..9160da6bb7f0 100644 --- a/packages/ai/src/transcribe/transcribe.test.ts +++ b/packages/ai/src/transcribe/transcribe.test.ts @@ -3,11 +3,25 @@ import { TranscriptionModelV2, TranscriptionModelV2CallWarning, } from '@ai-sdk/provider'; -import { afterEach, beforeEach, describe, expect, it, vitest } from 'vitest'; +import { + afterEach, + beforeEach, + describe, + expect, + it, + vitest, + vi, +} from 'vitest'; import * as logWarningsModule from '../logger/log-warnings'; import { MockTranscriptionModelV2 } from '../test/mock-transcription-model-v2'; import { transcribe } from './transcribe'; +vi.mock('../version', () => { + return { + VERSION: '0.0.0-test', + }; +}); + const audioData = new Uint8Array([1, 2, 3, 4]); // Sample audio data const testDate = new Date(2024, 0, 1); @@ -86,14 +100,19 @@ describe('transcribe', () => { }, }), audio: audioData, - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + }, abortSignal, }); expect(capturedArgs).toStrictEqual({ audio: audioData, mediaType: 'audio/wav', - headers: { 'custom-request-header': 'request-header-value' }, + headers: { + 'custom-request-header': 'request-header-value', + 'user-agent': 'ai/0.0.0-test', + }, abortSignal, providerOptions: {}, }); @@ -239,6 +258,7 @@ describe('transcribe', () => { timestamp: testDate, headers: { 'custom-response-header': 'response-header-value', + 'user-agent': 'ai/0.0.0-test', }, }), }), @@ -253,6 +273,7 @@ describe('transcribe', () => { modelId: expect.any(String), headers: { 'custom-response-header': 'response-header-value', + 'user-agent': 'ai/0.0.0-test', }, }, ], diff --git a/packages/ai/src/transcribe/transcribe.ts b/packages/ai/src/transcribe/transcribe.ts index 7e36d8e4e13c..bbf19b89eb4d 100644 --- a/packages/ai/src/transcribe/transcribe.ts +++ b/packages/ai/src/transcribe/transcribe.ts @@ -1,5 +1,5 @@ import { JSONValue, TranscriptionModelV2 } from '@ai-sdk/provider'; -import { ProviderOptions } from '@ai-sdk/provider-utils'; +import { ProviderOptions, withUserAgentSuffix } from '@ai-sdk/provider-utils'; import { NoTranscriptGeneratedError } from '../error/no-transcript-generated-error'; import { UnsupportedModelVersionError } from '../error/unsupported-model-version-error'; import { logWarnings } from '../logger/log-warnings'; @@ -14,7 +14,7 @@ import { import { download } from '../util/download/download'; import { prepareRetries } from '../util/prepare-retries'; import { TranscriptionResult } from './transcribe-result'; - +import { VERSION } from '../version'; /** Generates transcripts using a transcription model. @@ -93,6 +93,11 @@ Only applicable for HTTP-based providers. abortSignal, }); + const headersWithUserAgent = withUserAgentSuffix( + headers ?? {}, + `ai/${VERSION}`, + ); + const audioData = audio instanceof URL ? (await download({ url: audio })).data @@ -102,7 +107,7 @@ Only applicable for HTTP-based providers. model.doGenerate({ audio: audioData, abortSignal, - headers, + headers: headersWithUserAgent, providerOptions, mediaType: detectMediaType({ diff --git a/packages/ai/src/types/embedding-model.ts b/packages/ai/src/types/embedding-model.ts index d2788c2ad5cc..6dd7d26a0cc8 100644 --- a/packages/ai/src/types/embedding-model.ts +++ b/packages/ai/src/types/embedding-model.ts @@ -1,11 +1,11 @@ -import { EmbeddingModelV2, EmbeddingModelV2Embedding } from '@ai-sdk/provider'; +import { EmbeddingModelV3, EmbeddingModelV3Embedding } from '@ai-sdk/provider'; /** Embedding model that is used by the AI SDK Core functions. */ -export type EmbeddingModel = string | EmbeddingModelV2; +export type EmbeddingModel = string | EmbeddingModelV3; /** Embedding. */ -export type Embedding = EmbeddingModelV2Embedding; +export type Embedding = EmbeddingModelV3Embedding; diff --git a/packages/ai/src/types/image-model.ts b/packages/ai/src/types/image-model.ts index efec355395f8..e8ab40cfc376 100644 --- a/packages/ai/src/types/image-model.ts +++ b/packages/ai/src/types/image-model.ts @@ -1,21 +1,21 @@ import { - ImageModelV2, - ImageModelV2CallWarning, - ImageModelV2ProviderMetadata, + ImageModelV3, + ImageModelV3CallWarning, + ImageModelV3ProviderMetadata, } from '@ai-sdk/provider'; /** Image model that is used by the AI SDK Core functions. */ -export type ImageModel = ImageModelV2; +export type ImageModel = ImageModelV3; /** Warning from the model provider for this call. The call will proceed, but e.g. some settings might not be supported, which can lead to suboptimal results. */ -export type ImageGenerationWarning = ImageModelV2CallWarning; +export type ImageGenerationWarning = ImageModelV3CallWarning; /** Metadata from the model provider for this call */ -export type ImageModelProviderMetadata = ImageModelV2ProviderMetadata; +export type ImageModelProviderMetadata = ImageModelV3ProviderMetadata; diff --git a/packages/ai/src/types/usage.ts b/packages/ai/src/types/usage.ts index af045f39b014..4f82d6b274f4 100644 --- a/packages/ai/src/types/usage.ts +++ b/packages/ai/src/types/usage.ts @@ -8,7 +8,7 @@ export type LanguageModelUsage = LanguageModelV2Usage; /** Represents the number of tokens used in an embedding. */ -// TODO replace with EmbeddingModelV2Usage +// TODO replace with EmbeddingModelV3Usage export type EmbeddingModelUsage = { /** The number of tokens used in the embedding. diff --git a/packages/ai/src/ui-message-stream/index.ts b/packages/ai/src/ui-message-stream/index.ts index 29da2f00ff7b..83876a7ac744 100644 --- a/packages/ai/src/ui-message-stream/index.ts +++ b/packages/ai/src/ui-message-stream/index.ts @@ -3,7 +3,11 @@ export { createUIMessageStreamResponse } from './create-ui-message-stream-respon export { JsonToSseTransformStream } from './json-to-sse-transform-stream'; export { pipeUIMessageStreamToResponse } from './pipe-ui-message-stream-to-response'; export { readUIMessageStream } from './read-ui-message-stream'; -export type { InferUIMessageChunk, UIMessageChunk } from './ui-message-chunks'; +export { + uiMessageChunkSchema, + type InferUIMessageChunk, + type UIMessageChunk, +} from './ui-message-chunks'; export { UI_MESSAGE_STREAM_HEADERS } from './ui-message-stream-headers'; export type { UIMessageStreamOnFinishCallback } from './ui-message-stream-on-finish-callback'; export type { UIMessageStreamWriter } from './ui-message-stream-writer'; diff --git a/packages/ai/src/ui-message-stream/ui-message-chunks.test-d.ts b/packages/ai/src/ui-message-stream/ui-message-chunks.test-d.ts new file mode 100644 index 000000000000..df83b5da3039 --- /dev/null +++ b/packages/ai/src/ui-message-stream/ui-message-chunks.test-d.ts @@ -0,0 +1,14 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import { UIMessageChunk, uiMessageChunkSchema } from './ui-message-chunks'; + +describe('UI message chunks type', () => { + it('parsed UI message chunk should have UIMessageChunk type', () => { + const chunk = uiMessageChunkSchema.parse({ + type: 'text-delta', + delta: 'Hello, world!', + id: '123', + }); + + expectTypeOf(chunk).toEqualTypeOf(); + }); +}); diff --git a/packages/ai/src/ui-message-stream/ui-message-chunks.ts b/packages/ai/src/ui-message-stream/ui-message-chunks.ts index ebda56cc21d5..aad82429aa62 100644 --- a/packages/ai/src/ui-message-stream/ui-message-chunks.ts +++ b/packages/ai/src/ui-message-stream/ui-message-chunks.ts @@ -78,11 +78,6 @@ export const uiMessageChunkSchema = z.union([ providerExecuted: z.boolean().optional(), dynamic: z.boolean().optional(), }), - z.strictObject({ - type: z.literal('reasoning'), - text: z.string(), - providerMetadata: providerMetadataSchema.optional(), - }), z.strictObject({ type: z.literal('reasoning-start'), id: z.string(), @@ -99,9 +94,6 @@ export const uiMessageChunkSchema = z.union([ id: z.string(), providerMetadata: providerMetadataSchema.optional(), }), - z.strictObject({ - type: z.literal('reasoning-part-finish'), - }), z.strictObject({ type: z.literal('source-url'), sourceId: z.string(), @@ -124,7 +116,11 @@ export const uiMessageChunkSchema = z.union([ providerMetadata: providerMetadataSchema.optional(), }), z.strictObject({ - type: z.string().startsWith('data-'), + type: z.custom<`data-${string}`>( + (value): value is `data-${string}` => + typeof value === 'string' && value.startsWith('data-'), + { message: 'Type must start with "data-"' }, + ), id: z.string().optional(), data: z.unknown(), transient: z.boolean().optional(), @@ -267,6 +263,7 @@ export type UIMessageChunk< type: 'file'; url: string; mediaType: string; + providerMetadata?: ProviderMetadata; } | DataUIMessageChunk | { diff --git a/packages/ai/src/ui/call-completion-api.ts b/packages/ai/src/ui/call-completion-api.ts index 2af1196e1df9..8174dac67ac2 100644 --- a/packages/ai/src/ui/call-completion-api.ts +++ b/packages/ai/src/ui/call-completion-api.ts @@ -1,10 +1,16 @@ -import { parseJsonEventStream, ParseResult } from '@ai-sdk/provider-utils'; +import { + parseJsonEventStream, + ParseResult, + withUserAgentSuffix, + getRuntimeEnvironmentUserAgent, +} from '@ai-sdk/provider-utils'; import { UIMessageChunk, uiMessageChunkSchema, } from '../ui-message-stream/ui-message-chunks'; import { consumeStream } from '../util/consume-stream'; import { processTextStream } from './process-text-stream'; +import { VERSION } from '../version'; // use function to allow for mocking in tests: const getOriginalFetch = () => fetch; @@ -55,10 +61,14 @@ export async function callCompletionApi({ ...body, }), credentials, - headers: { - 'Content-Type': 'application/json', - ...headers, - }, + headers: withUserAgentSuffix( + { + 'Content-Type': 'application/json', + ...headers, + }, + `ai-sdk/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ), signal: abortController.signal, }).catch(err => { throw err; diff --git a/packages/ai/src/ui/chat.test.ts b/packages/ai/src/ui/chat.test.ts index 6d95f9c7134e..81afc12e6707 100644 --- a/packages/ai/src/ui/chat.test.ts +++ b/packages/ai/src/ui/chat.test.ts @@ -1,8 +1,8 @@ import { createTestServer, - mockId, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; +import { mockId } from '@ai-sdk/provider-utils/test'; import { createResolvablePromise } from '../util/create-resolvable-promise'; import { AbstractChat, ChatInit, ChatState, ChatStatus } from './chat'; import { UIMessage } from './ui-messages'; @@ -1742,6 +1742,149 @@ describe('Chat', () => { `); }); + it('should send message when a tool error result is submitted', async () => { + server.urls['http://localhost:3000/api/chat'].response = [ + { + type: 'stream-chunks', + chunks: [ + formatChunk({ type: 'start' }), + formatChunk({ type: 'start-step' }), + formatChunk({ + type: 'tool-input-available', + toolCallId: 'tool-call-0', + toolName: 'test-tool', + input: { testArg: 'test-value' }, + }), + formatChunk({ type: 'finish-step' }), + formatChunk({ type: 'finish' }), + ], + }, + { + type: 'stream-chunks', + chunks: [ + formatChunk({ type: 'start' }), + formatChunk({ type: 'start-step' }), + formatChunk({ type: 'finish-step' }), + formatChunk({ type: 'finish' }), + ], + }, + ]; + + let callCount = 0; + const onFinishPromise = createResolvablePromise(); + + const chat = new TestChat({ + id: '123', + generateId: mockId(), + transport: new DefaultChatTransport({ + api: 'http://localhost:3000/api/chat', + }), + sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls, + onFinish: () => { + callCount++; + if (callCount === 2) { + onFinishPromise.resolve(); + } + }, + }); + + await chat.sendMessage({ + text: 'Hello, world!', + }); + + // user submits the tool result + await chat.addToolResult({ + state: 'output-error', + tool: 'test-tool', + toolCallId: 'tool-call-0', + errorText: 'test-error', + }); + + // UI should show the tool result + expect(chat.messages).toMatchInlineSnapshot(` + [ + { + "id": "id-0", + "metadata": undefined, + "parts": [ + { + "text": "Hello, world!", + "type": "text", + }, + ], + "role": "user", + }, + { + "id": "id-1", + "metadata": undefined, + "parts": [ + { + "type": "step-start", + }, + { + "errorText": "test-error", + "input": { + "testArg": "test-value", + }, + "output": undefined, + "preliminary": undefined, + "providerExecuted": undefined, + "rawInput": undefined, + "state": "output-error", + "toolCallId": "tool-call-0", + "type": "tool-test-tool", + }, + ], + "role": "assistant", + }, + ] + `); + + await onFinishPromise.promise; + + // 2nd call should happen after the stream is finished + expect(server.calls.length).toBe(2); + + // check details of the 2nd call + expect(await server.calls[1].requestBodyJson).toMatchInlineSnapshot(` + { + "id": "123", + "messageId": "id-1", + "messages": [ + { + "id": "id-0", + "parts": [ + { + "text": "Hello, world!", + "type": "text", + }, + ], + "role": "user", + }, + { + "id": "id-1", + "parts": [ + { + "type": "step-start", + }, + { + "errorText": "test-error", + "input": { + "testArg": "test-value", + }, + "state": "output-error", + "toolCallId": "tool-call-0", + "type": "tool-test-tool", + }, + ], + "role": "assistant", + }, + ], + "trigger": "submit-message", + } + `); + }); + it('should send message when a dynamic tool result is submitted', async () => { server.urls['http://localhost:3000/api/chat'].response = [ { @@ -1795,6 +1938,7 @@ describe('Chat', () => { // user submits the tool result await chat.addToolResult({ + state: 'output-available', tool: 'test-tool', toolCallId: 'tool-call-0', output: 'test-result', diff --git a/packages/ai/src/ui/chat.ts b/packages/ai/src/ui/chat.ts index f1f94192211d..65831e407219 100644 --- a/packages/ai/src/ui/chat.ts +++ b/packages/ai/src/ui/chat.ts @@ -18,6 +18,7 @@ import { import { InferUIMessageToolCall, isToolOrDynamicToolUIPart, + ToolUIPart, type DataUIPart, type FileUIPart, type InferUIMessageData, @@ -414,14 +415,26 @@ export abstract class AbstractChat { }; addToolResult = async >({ + state = 'output-available', tool, toolCallId, output, - }: { - tool: TOOL; - toolCallId: string; - output: InferUIMessageTools[TOOL]['output']; - }) => + errorText, + }: + | { + state?: 'output-available'; + tool: TOOL; + toolCallId: string; + output: InferUIMessageTools[TOOL]['output']; + errorText?: never; + } + | { + state: 'output-error'; + tool: TOOL; + toolCallId: string; + output?: never; + errorText: string; + }) => this.jobExecutor.run(async () => { const messages = this.state.messages; const lastMessage = messages[messages.length - 1]; @@ -430,7 +443,7 @@ export abstract class AbstractChat { ...lastMessage, parts: lastMessage.parts.map(part => isToolOrDynamicToolUIPart(part) && part.toolCallId === toolCallId - ? { ...part, state: 'output-available', output } + ? { ...part, state, output, errorText } : part, ), }); @@ -440,12 +453,12 @@ export abstract class AbstractChat { this.activeResponse.state.message.parts = this.activeResponse.state.message.parts.map(part => isToolOrDynamicToolUIPart(part) && part.toolCallId === toolCallId - ? { + ? ({ ...part, - state: 'output-available', + state, output, - errorText: undefined, - } + errorText, + } as ToolUIPart>) : part, ); } diff --git a/packages/ai/src/ui/http-chat-transport.test.ts b/packages/ai/src/ui/http-chat-transport.test.ts index 031f537baff9..820dd4d0fc7c 100644 --- a/packages/ai/src/ui/http-chat-transport.test.ts +++ b/packages/ai/src/ui/http-chat-transport.test.ts @@ -1,4 +1,4 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { UIMessageChunk } from '../ui-message-stream/ui-message-chunks'; import { HttpChatTransport, @@ -148,6 +148,7 @@ describe('HttpChatTransport', () => { expect(server.calls[0].requestHeaders['x-test-header']).toBe( 'test-value', ); + expect(server.calls[0].requestUserAgent).toContain('ai-sdk/'); }); it('should include headers in the request when a function is provided', async () => { @@ -178,6 +179,7 @@ describe('HttpChatTransport', () => { expect(server.calls[0].requestHeaders['x-test-header']).toBe( 'test-value-fn', ); + expect(server.calls[0].requestUserAgent).toContain('ai-sdk/'); }); }); }); diff --git a/packages/ai/src/ui/http-chat-transport.ts b/packages/ai/src/ui/http-chat-transport.ts index b0ed429eb5c6..d304e4f794cf 100644 --- a/packages/ai/src/ui/http-chat-transport.ts +++ b/packages/ai/src/ui/http-chat-transport.ts @@ -1,7 +1,14 @@ -import { FetchFunction, Resolvable, resolve } from '@ai-sdk/provider-utils'; +import { + FetchFunction, + Resolvable, + resolve, + withUserAgentSuffix, + getRuntimeEnvironmentUserAgent, +} from '@ai-sdk/provider-utils'; import { UIMessageChunk } from '../ui-message-stream/ui-message-chunks'; import { ChatTransport } from './chat-transport'; import { UIMessage } from './ui-messages'; +import { VERSION } from '../version'; export type PrepareSendMessagesRequest = ( options: { @@ -188,10 +195,14 @@ export abstract class HttpChatTransport const response = await fetch(api, { method: 'POST', - headers: { - 'Content-Type': 'application/json', - ...headers, - }, + headers: withUserAgentSuffix( + { + 'Content-Type': 'application/json', + ...headers, + }, + `ai-sdk/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ), body: JSON.stringify(body), credentials, signal: abortSignal, @@ -238,7 +249,11 @@ export abstract class HttpChatTransport const response = await fetch(api, { method: 'GET', - headers, + headers: withUserAgentSuffix( + headers, + `ai-sdk/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ), credentials, }); diff --git a/packages/ai/src/ui/index.ts b/packages/ai/src/ui/index.ts index 90eeffd5d51d..2bf6e0a1e13f 100644 --- a/packages/ai/src/ui/index.ts +++ b/packages/ai/src/ui/index.ts @@ -55,4 +55,8 @@ export { type CompletionRequestOptions, type UseCompletionOptions, } from './use-completion'; -export { validateUIMessages } from './validate-ui-messages'; +export { + validateUIMessages, + safeValidateUIMessages, + type SafeValidateUIMessagesResult, +} from './validate-ui-messages'; diff --git a/packages/ai/src/ui/last-assistant-message-is-complete-with-tool-calls.test.ts b/packages/ai/src/ui/last-assistant-message-is-complete-with-tool-calls.test.ts index 526ab4172664..cf9b759099d3 100644 --- a/packages/ai/src/ui/last-assistant-message-is-complete-with-tool-calls.test.ts +++ b/packages/ai/src/ui/last-assistant-message-is-complete-with-tool-calls.test.ts @@ -2,7 +2,7 @@ import { lastAssistantMessageIsCompleteWithToolCalls } from './last-assistant-me import { describe, it, expect } from 'vitest'; describe('lastAssistantMessageIsCompleteWithToolCalls', () => { - it('should return false if the last step of a multi-step sequency only has text', () => { + it('should return false if the last step of a multi-step sequence only has text', () => { expect( lastAssistantMessageIsCompleteWithToolCalls({ messages: [ @@ -61,6 +61,36 @@ describe('lastAssistantMessageIsCompleteWithToolCalls', () => { ).toBe(true); }); + it('should return true when the tool has a output-error state', () => { + expect( + lastAssistantMessageIsCompleteWithToolCalls({ + messages: [ + { + id: '1', + role: 'assistant', + parts: [ + { type: 'step-start' }, + { + type: 'tool-getWeatherInformation', + toolCallId: 'call_6iy0GxZ9R4VDI5MKohXxV48y', + state: 'output-error', + input: { + city: 'New York', + }, + errorText: 'Unable to get weather information', + }, + { + type: 'text', + text: 'The current weather in New York is windy.', + state: 'done', + }, + ], + }, + ], + }), + ).toBe(true); + }); + it('should return true when dynamic tool call is complete', () => { expect( lastAssistantMessageIsCompleteWithToolCalls({ @@ -137,7 +167,7 @@ describe('lastAssistantMessageIsCompleteWithToolCalls', () => { ).toBe(false); }); - it('should return false when dynamic tool call has an error', () => { + it('should return true when dynamic tool call has an error', () => { expect( lastAssistantMessageIsCompleteWithToolCalls({ messages: [ @@ -160,7 +190,7 @@ describe('lastAssistantMessageIsCompleteWithToolCalls', () => { }, ], }), - ).toBe(false); + ).toBe(true); }); it('should return true when mixing regular and dynamic tool calls and all are complete', () => { diff --git a/packages/ai/src/ui/last-assistant-message-is-complete-with-tool-calls.ts b/packages/ai/src/ui/last-assistant-message-is-complete-with-tool-calls.ts index da7b2c386a2f..613430ac1a20 100644 --- a/packages/ai/src/ui/last-assistant-message-is-complete-with-tool-calls.ts +++ b/packages/ai/src/ui/last-assistant-message-is-complete-with-tool-calls.ts @@ -1,4 +1,4 @@ -import { isToolOrDynamicToolUIPart, UIMessage } from './ui-messages'; +import { isToolOrDynamicToolUIPart, type UIMessage } from './ui-messages'; /** Check if the message is an assistant message with completed tool calls. @@ -30,6 +30,9 @@ export function lastAssistantMessageIsCompleteWithToolCalls({ return ( lastStepToolInvocations.length > 0 && - lastStepToolInvocations.every(part => part.state === 'output-available') + lastStepToolInvocations.every( + part => + part.state === 'output-available' || part.state === 'output-error', + ) ); } diff --git a/packages/ai/src/ui/validate-ui-messages.test.ts b/packages/ai/src/ui/validate-ui-messages.test.ts index c413768bf93c..00ecd018d23b 100644 --- a/packages/ai/src/ui/validate-ui-messages.test.ts +++ b/packages/ai/src/ui/validate-ui-messages.test.ts @@ -1,6 +1,9 @@ import { z } from 'zod/v4'; import { InferUITool, UIMessage } from './ui-messages'; -import { validateUIMessages } from './validate-ui-messages'; +import { + safeValidateUIMessages, + validateUIMessages, +} from './validate-ui-messages'; import { describe, it, expect, expectTypeOf } from 'vitest'; describe('validateUIMessages', () => { @@ -678,6 +681,7 @@ describe('validateUIMessages', () => { toolCallId: '1', state: 'input-streaming', input: { foo: 'bar' }, + providerExecuted: true, }, ], }, @@ -695,6 +699,7 @@ describe('validateUIMessages', () => { "input": { "foo": "bar", }, + "providerExecuted": true, "state": "input-streaming", "toolCallId": "1", "type": "tool-foo", @@ -718,6 +723,7 @@ describe('validateUIMessages', () => { toolCallId: '1', state: 'input-available', input: { foo: 'bar' }, + providerExecuted: true, }, ], }, @@ -735,6 +741,7 @@ describe('validateUIMessages', () => { "input": { "foo": "bar", }, + "providerExecuted": true, "state": "input-available", "toolCallId": "1", "type": "tool-foo", @@ -759,6 +766,7 @@ describe('validateUIMessages', () => { state: 'output-available', input: { foo: 'bar' }, output: { result: 'success' }, + providerExecuted: true, }, ], }, @@ -779,6 +787,7 @@ describe('validateUIMessages', () => { "output": { "result": "success", }, + "providerExecuted": true, "state": "output-available", "toolCallId": "1", "type": "tool-foo", @@ -803,6 +812,7 @@ describe('validateUIMessages', () => { state: 'output-error', input: { foo: 'bar' }, errorText: 'Tool execution failed', + providerExecuted: true, }, ], }, @@ -821,6 +831,7 @@ describe('validateUIMessages', () => { "input": { "foo": "bar", }, + "providerExecuted": true, "state": "output-error", "toolCallId": "1", "type": "tool-foo", @@ -844,6 +855,7 @@ describe('validateUIMessages', () => { toolCallId: '1', state: 'input-available', input: { foo: 'bar' }, + providerExecuted: true, }, ], }, @@ -855,23 +867,24 @@ describe('validateUIMessages', () => { expectTypeOf(messages).toEqualTypeOf>(); expect(messages).toMatchInlineSnapshot(` - [ - { - "id": "1", - "parts": [ - { - "input": { - "foo": "bar", + [ + { + "id": "1", + "parts": [ + { + "input": { + "foo": "bar", + }, + "providerExecuted": true, + "state": "input-available", + "toolCallId": "1", + "type": "tool-foo", }, - "state": "input-available", - "toolCallId": "1", - "type": "tool-foo", - }, - ], - "role": "assistant", - }, - ] - `); + ], + "role": "assistant", + }, + ] + `); }); it('should validate tool input and output when state is output-available', async () => { @@ -933,6 +946,7 @@ describe('validateUIMessages', () => { state: 'output-error', input: { foo: 'bar' }, errorText: 'Tool execution failed', + providerExecuted: true, }, ], }, @@ -953,6 +967,7 @@ describe('validateUIMessages', () => { "input": { "foo": "bar", }, + "providerExecuted": true, "state": "output-error", "toolCallId": "1", "type": "tool-foo", @@ -977,6 +992,7 @@ describe('validateUIMessages', () => { toolCallId: '1', state: 'input-available', input: { foo: 'bar' }, + providerExecuted: true, }, ], }, @@ -1004,6 +1020,7 @@ describe('validateUIMessages', () => { toolCallId: '1', state: 'input-available', input: { foo: 123 }, // wrong type + providerExecuted: true, }, ], }, @@ -1030,6 +1047,7 @@ describe('validateUIMessages', () => { type: 'tool-foo', toolCallId: '1', state: 'output-available', + providerExecuted: true, input: { foo: 'bar' }, output: { result: 123 }, // wrong type }, @@ -1058,6 +1076,7 @@ describe('validateUIMessages', () => { toolCallId: '1', state: 'input-streaming', input: { foo: 123 }, // wrong type but should not be validated + providerExecuted: true, }, ], }, @@ -1077,6 +1096,7 @@ describe('validateUIMessages', () => { "input": { "foo": 123, }, + "providerExecuted": true, "state": "input-streaming", "toolCallId": "1", "type": "tool-foo", @@ -1089,3 +1109,135 @@ describe('validateUIMessages', () => { }); }); }); + +export function expectToBe( + value: boolean, + expected: T, +): asserts value is T { + expect(value).toBe(expected); +} + +describe('safeValidateUIMessages', () => { + it('should return success result for valid messages', async () => { + const result = await safeValidateUIMessages({ + messages: [ + { + id: '1', + role: 'user', + parts: [{ type: 'text', text: 'Hello, world!' }], + }, + ], + }); + + expectToBe(result.success, true); + expect(result.data).toMatchInlineSnapshot(` + [ + { + "id": "1", + "parts": [ + { + "text": "Hello, world!", + "type": "text", + }, + ], + "role": "user", + }, + ] + `); + }); + + it('should return failure result when messages parameter is null', async () => { + const result = await safeValidateUIMessages({ + messages: null, + }); + + expectToBe(result.success, false); + expect(result.error.name).toBe('AI_InvalidArgumentError'); + expect(result.error.message).toBe( + 'Invalid argument for parameter messages: messages parameter must be provided', + ); + }); + + it('should return failure result when metadata validation fails', async () => { + const result = await safeValidateUIMessages>({ + messages: [ + { + id: '1', + role: 'user', + metadata: { foo: 123 }, + parts: [{ type: 'text', text: 'Hello, world!' }], + }, + ], + metadataSchema: z.object({ foo: z.string() }), + }); + + expectToBe(result.success, false); + expect(result.error.name).toBe('AI_TypeValidationError'); + expect(result.error.message).toContain('Type validation failed'); + }); + + it('should return failure result when tool input validation fails', async () => { + const testTool = { + name: 'foo', + inputSchema: z.object({ foo: z.string() }), + outputSchema: z.object({ result: z.string() }), + }; + + const result = await safeValidateUIMessages({ + messages: [ + { + id: '1', + role: 'assistant', + parts: [ + { + type: 'tool-foo', + toolCallId: '1', + state: 'input-available', + input: { foo: 123 }, + providerExecuted: true, + }, + ], + }, + ], + tools: { foo: testTool }, + }); + + expectToBe(result.success, false); + expect(result.error.name).toBe('AI_TypeValidationError'); + expect(result.error.message).toContain('Type validation failed'); + }); + + it('should return failure result when data schema is missing', async () => { + const result = await safeValidateUIMessages({ + messages: [ + { + id: '1', + role: 'assistant', + parts: [{ type: 'data-bar', data: { foo: 'bar' } }], + }, + ], + dataSchemas: { + foo: z.object({ foo: z.string() }), + }, + }); + + expectToBe(result.success, false); + expect(result.error.name).toBe('AI_TypeValidationError'); + expect(result.error.message).toContain( + 'No data schema found for data part bar', + ); + }); + + it('should return failure result for invalid message structure', async () => { + const result = await safeValidateUIMessages({ + messages: [ + { + role: 'user', + }, + ], + }); + + expectToBe(result.success, false); + expect(result.error.name).toBe('AI_TypeValidationError'); + }); +}); diff --git a/packages/ai/src/ui/validate-ui-messages.ts b/packages/ai/src/ui/validate-ui-messages.ts index 131d4e9d43b2..c82a6e11c00b 100644 --- a/packages/ai/src/ui/validate-ui-messages.ts +++ b/packages/ai/src/ui/validate-ui-messages.ts @@ -113,6 +113,7 @@ const toolUIPartSchemas = [ type: z.string().startsWith('tool-'), toolCallId: z.string(), state: z.literal('input-streaming'), + providerExecuted: z.boolean().optional(), input: z.unknown().optional(), output: z.never().optional(), errorText: z.never().optional(), @@ -121,6 +122,7 @@ const toolUIPartSchemas = [ type: z.string().startsWith('tool-'), toolCallId: z.string(), state: z.literal('input-available'), + providerExecuted: z.boolean().optional(), input: z.unknown(), output: z.never().optional(), errorText: z.never().optional(), @@ -130,6 +132,7 @@ const toolUIPartSchemas = [ type: z.string().startsWith('tool-'), toolCallId: z.string(), state: z.literal('output-available'), + providerExecuted: z.boolean().optional(), input: z.unknown(), output: z.unknown(), errorText: z.never().optional(), @@ -140,6 +143,7 @@ const toolUIPartSchemas = [ type: z.string().startsWith('tool-'), toolCallId: z.string(), state: z.literal('output-error'), + providerExecuted: z.boolean().optional(), input: z.unknown(), output: z.never().optional(), errorText: z.string(), @@ -166,14 +170,22 @@ const uiMessageSchema = z.object({ ), }); +export type SafeValidateUIMessagesResult = + | { + success: true; + data: Array; + } + | { + success: false; + error: Error; + }; + /** - * Validates a list of UI messages. - * - * Metadata, data parts, and generic tool call structures are only validated if - * the corresponding schemas are provided. Otherwise, they are assumed to be - * valid. + * Validates a list of UI messages like `validateUIMessages`, + * but instead of throwing it returns `{ success: true, data }` + * or `{ success: false, error }`. */ -export async function validateUIMessages({ +export async function safeValidateUIMessages({ messages, metadataSchema, dataSchemas, @@ -194,91 +206,153 @@ export async function validateUIMessages({ InferUIMessageTools[NAME]['output'] >; }; -}): Promise> { - if (messages == null) { - throw new InvalidArgumentError({ - parameter: 'messages', +}): Promise> { + try { + if (messages == null) { + return { + success: false, + error: new InvalidArgumentError({ + parameter: 'messages', + value: messages, + message: 'messages parameter must be provided', + }), + }; + } + + const validatedMessages = await validateTypes({ value: messages, - message: 'messages parameter must be provided', + schema: z.array(uiMessageSchema), }); - } - - const validatedMessages = await validateTypes({ - value: messages, - schema: z.array(uiMessageSchema), - }); - if (metadataSchema) { - for (const message of validatedMessages) { - await validateTypes({ - value: message.metadata, - schema: metadataSchema, - }); + if (metadataSchema) { + for (const message of validatedMessages) { + await validateTypes({ + value: message.metadata, + schema: metadataSchema, + }); + } } - } - if (dataSchemas) { - for (const message of validatedMessages) { - const dataParts = message.parts.filter(part => - part.type.startsWith('data-'), - ) as DataUIPart>[]; + if (dataSchemas) { + for (const message of validatedMessages) { + const dataParts = message.parts.filter(part => + part.type.startsWith('data-'), + ) as DataUIPart>[]; + + for (const dataPart of dataParts) { + const dataName = dataPart.type.slice(5); + const dataSchema = dataSchemas[dataName]; - for (const dataPart of dataParts) { - const dataName = dataPart.type.slice(5); - const dataSchema = dataSchemas[dataName]; + if (!dataSchema) { + return { + success: false, + error: new TypeValidationError({ + value: dataPart.data, + cause: `No data schema found for data part ${dataName}`, + }), + }; + } - if (!dataSchema) { - throw new TypeValidationError({ + await validateTypes({ value: dataPart.data, - cause: `No data schema found for data part ${dataName}`, + schema: dataSchema, }); } - - await validateTypes({ - value: dataPart.data, - schema: dataSchema, - }); } } - } - if (tools) { - for (const message of validatedMessages) { - const toolParts = message.parts.filter(part => - part.type.startsWith('tool-'), - ) as ToolUIPart>[]; + if (tools) { + for (const message of validatedMessages) { + const toolParts = message.parts.filter(part => + part.type.startsWith('tool-'), + ) as ToolUIPart>[]; - for (const toolPart of toolParts) { - const toolName = toolPart.type.slice(5); - const tool = tools[toolName]; + for (const toolPart of toolParts) { + const toolName = toolPart.type.slice(5); + const tool = tools[toolName]; - if (!tool) { - throw new TypeValidationError({ - value: toolPart.input, - cause: `No tool schema found for tool part ${toolName}`, - }); - } + if (!tool) { + return { + success: false, + error: new TypeValidationError({ + value: toolPart.input, + cause: `No tool schema found for tool part ${toolName}`, + }), + }; + } - if ( - toolPart.state === 'input-available' || - toolPart.state === 'output-available' || - toolPart.state === 'output-error' - ) { - await validateTypes({ - value: toolPart.input, - schema: tool.inputSchema, - }); - } + if ( + toolPart.state === 'input-available' || + toolPart.state === 'output-available' || + toolPart.state === 'output-error' + ) { + await validateTypes({ + value: toolPart.input, + schema: tool.inputSchema, + }); + } - if (toolPart.state === 'output-available' && tool.outputSchema) { - await validateTypes({ - value: toolPart.output, - schema: tool.outputSchema, - }); + if (toolPart.state === 'output-available' && tool.outputSchema) { + await validateTypes({ + value: toolPart.output, + schema: tool.outputSchema, + }); + } } } } + + return { + success: true, + data: validatedMessages as Array, + }; + } catch (error) { + const err = error as Error; + + return { + success: false, + error: err, + }; } +} + +/** + * Validates a list of UI messages. + * + * Metadata, data parts, and generic tool call structures are only validated if + * the corresponding schemas are provided. Otherwise, they are assumed to be + * valid. + */ +export async function validateUIMessages({ + messages, + metadataSchema, + dataSchemas, + tools, +}: { + messages: unknown; + metadataSchema?: + | Validator + | StandardSchemaV1; + dataSchemas?: { + [NAME in keyof InferUIMessageData & string]?: + | Validator[NAME]> + | StandardSchemaV1[NAME]>; + }; + tools?: { + [NAME in keyof InferUIMessageTools & string]?: Tool< + InferUIMessageTools[NAME]['input'], + InferUIMessageTools[NAME]['output'] + >; + }; +}): Promise> { + const response = await safeValidateUIMessages({ + messages, + metadataSchema, + dataSchemas, + tools, + }); + + if (!response.success) throw response.error; - return validatedMessages as Array; + return response.data; } diff --git a/packages/ai/src/util/detect-media-type.test.ts b/packages/ai/src/util/detect-media-type.test.ts index f127ea819e89..0962f08aa47a 100644 --- a/packages/ai/src/util/detect-media-type.test.ts +++ b/packages/ai/src/util/detect-media-type.test.ts @@ -74,8 +74,26 @@ describe('detectMediaType', () => { }); describe('WebP', () => { - it('should detect WebP from bytes', () => { - const webpBytes = new Uint8Array([0x52, 0x49, 0x46, 0x46, 0xff, 0xff]); + it('should detect WebP from bytes (positive webp image uint8)', () => { + // WebP format: RIFF + 4 bytes file size + WEBP + const webpBytes = new Uint8Array([ + 0x52, + 0x49, + 0x46, + 0x46, // "RIFF" + 0x24, + 0x00, + 0x00, + 0x00, // file size (example: 36 bytes) + 0x57, + 0x45, + 0x42, + 0x50, // "WEBP" + 0x56, + 0x50, + 0x38, + 0x20, // VP8 chunk (additional WebP data) + ]); expect( detectMediaType({ data: webpBytes, @@ -84,8 +102,27 @@ describe('detectMediaType', () => { ).toBe('image/webp'); }); - it('should detect WebP from base64', () => { - const webpBase64 = 'UklGRgabc123'; // Base64 string starting with WebP signature + it('should detect WebP from base64 (positive webp image base64)', () => { + // WebP: RIFF + file size + WEBP encoded to base64 + const webpBytes = new Uint8Array([ + 0x52, + 0x49, + 0x46, + 0x46, // "RIFF" + 0x24, + 0x00, + 0x00, + 0x00, // file size + 0x57, + 0x45, + 0x42, + 0x50, // "WEBP" + 0x56, + 0x50, + 0x38, + 0x20, // VP8 chunk + ]); + const webpBase64 = convertUint8ArrayToBase64(webpBytes); expect( detectMediaType({ data: webpBase64, @@ -93,6 +130,63 @@ describe('detectMediaType', () => { }), ).toBe('image/webp'); }); + + it('should NOT detect RIFF audio as WebP from bytes (negative riff audio uint8)', () => { + // WAV format: RIFF + file size + WAVE (not WEBP) + const wavBytes = new Uint8Array([ + 0x52, + 0x49, + 0x46, + 0x46, // "RIFF" + 0x24, + 0x00, + 0x00, + 0x00, // file size + 0x57, + 0x41, + 0x56, + 0x45, // "WAVE" (not "WEBP") + 0x66, + 0x6d, + 0x74, + 0x20, // fmt chunk + ]); + expect( + detectMediaType({ + data: wavBytes, + signatures: imageMediaTypeSignatures, + }), + ).toBeUndefined(); // Should not detect as WebP + }); + + it('should NOT detect RIFF audio as WebP from base64 (negative riff audio base64)', () => { + // WAV format encoded to base64 + const wavBytes = new Uint8Array([ + 0x52, + 0x49, + 0x46, + 0x46, // "RIFF" + 0x24, + 0x00, + 0x00, + 0x00, // file size + 0x57, + 0x41, + 0x56, + 0x45, // "WAVE" (not "WEBP") + 0x66, + 0x6d, + 0x74, + 0x20, // fmt chunk + ]); + const wavBase64 = convertUint8ArrayToBase64(wavBytes); + expect( + detectMediaType({ + data: wavBase64, + signatures: imageMediaTypeSignatures, + }), + ).toBeUndefined(); // Should not detect as WebP + }); }); describe('BMP', () => { @@ -107,10 +201,10 @@ describe('detectMediaType', () => { }); it('should detect BMP from base64', () => { - const bmpBase64 = 'Qkabc123'; // Base64 string starting with BMP signature + const bmpBytes = new Uint8Array([0x42, 0x4d, 0xff, 0xff]); expect( detectMediaType({ - data: bmpBase64, + data: convertUint8ArrayToBase64(bmpBytes), signatures: imageMediaTypeSignatures, }), ).toBe('image/bmp'); @@ -306,8 +400,46 @@ describe('detectMediaType', () => { }); describe('WAV', () => { + // WebP format: RIFF + 4 bytes file size + WEBP + const webpBytes = new Uint8Array([ + 0x52, + 0x49, + 0x46, + 0x46, // "RIFF" + 0x24, + 0x00, + 0x00, + 0x00, // file size (example: 36 bytes) + 0x57, + 0x45, + 0x42, + 0x50, // "WEBP" + 0x56, + 0x50, + 0x38, + 0x20, // VP8 chunk (additional WebP data) + ]); + + const wavBytes = new Uint8Array([ + 0x52, + 0x49, + 0x46, + 0x46, // "RIFF" + 0x24, + 0x00, + 0x00, + 0x00, // file size (example: 36 bytes) + 0x57, + 0x41, + 0x56, + 0x45, // "WAVE" (not "WEBP") + 0x66, + 0x6d, + 0x74, + 0x20, // fmt chunk + ]); + it('should detect WAV from bytes', () => { - const wavBytes = new Uint8Array([0x52, 0x49, 0x46, 0x46]); expect( detectMediaType({ data: wavBytes, @@ -317,14 +449,31 @@ describe('detectMediaType', () => { }); it('should detect WAV from base64', () => { - const wavBase64 = 'UklGRiQ='; // Base64 string starting with WAV signature expect( detectMediaType({ - data: wavBase64, + data: convertUint8ArrayToBase64(wavBytes), signatures: audioMediaTypeSignatures, }), ).toBe('audio/wav'); }); + + it('should NOT detect WebP as WAV from bytes (negative webp image uint8)', () => { + expect( + detectMediaType({ + data: webpBytes, + signatures: audioMediaTypeSignatures, + }), + ).toBeUndefined(); // Should not detect as WAV + }); + + it('should NOT detect WebP as WAV from base64 (negative webp image base64)', () => { + expect( + detectMediaType({ + data: convertUint8ArrayToBase64(webpBytes), + signatures: audioMediaTypeSignatures, + }), + ).toBeUndefined(); // Should not detect as WAV + }); }); describe('OGG', () => { @@ -383,10 +532,10 @@ describe('detectMediaType', () => { }); it('should detect AAC from base64', () => { - const aacBase64 = 'QBUA'; // Base64 string starting with AAC signature + const aacBytes = new Uint8Array([0x40, 0x15, 0x00, 0x00]); expect( detectMediaType({ - data: aacBase64, + data: convertUint8ArrayToBase64(aacBytes), signatures: audioMediaTypeSignatures, }), ).toBe('audio/aac'); diff --git a/packages/ai/src/util/detect-media-type.ts b/packages/ai/src/util/detect-media-type.ts index d36b2393411f..49a3ed237f4a 100644 --- a/packages/ai/src/util/detect-media-type.ts +++ b/packages/ai/src/util/detect-media-type.ts @@ -3,52 +3,56 @@ import { convertBase64ToUint8Array } from '@ai-sdk/provider-utils'; export const imageMediaTypeSignatures = [ { mediaType: 'image/gif' as const, - bytesPrefix: [0x47, 0x49, 0x46], - base64Prefix: 'R0lG', + bytesPrefix: [0x47, 0x49, 0x46], // GIF }, { mediaType: 'image/png' as const, - bytesPrefix: [0x89, 0x50, 0x4e, 0x47], - base64Prefix: 'iVBORw', + bytesPrefix: [0x89, 0x50, 0x4e, 0x47], // PNG }, { mediaType: 'image/jpeg' as const, - bytesPrefix: [0xff, 0xd8], - base64Prefix: '/9j/', + bytesPrefix: [0xff, 0xd8], // JPEG }, { mediaType: 'image/webp' as const, - bytesPrefix: [0x52, 0x49, 0x46, 0x46], - base64Prefix: 'UklGRg', + bytesPrefix: [ + 0x52, + 0x49, + 0x46, + 0x46, // "RIFF" + null, + null, + null, + null, // file size (variable) + 0x57, + 0x45, + 0x42, + 0x50, // "WEBP" + ], }, { mediaType: 'image/bmp' as const, bytesPrefix: [0x42, 0x4d], - base64Prefix: 'Qk', }, { mediaType: 'image/tiff' as const, bytesPrefix: [0x49, 0x49, 0x2a, 0x00], - base64Prefix: 'SUkqAA', }, { mediaType: 'image/tiff' as const, bytesPrefix: [0x4d, 0x4d, 0x00, 0x2a], - base64Prefix: 'TU0AKg', }, { mediaType: 'image/avif' as const, bytesPrefix: [ 0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x66, ], - base64Prefix: 'AAAAIGZ0eXBhdmlm', }, { mediaType: 'image/heic' as const, bytesPrefix: [ 0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63, ], - base64Prefix: 'AAAAIGZ0eXBoZWlj', }, ] as const; @@ -56,62 +60,63 @@ export const audioMediaTypeSignatures = [ { mediaType: 'audio/mpeg' as const, bytesPrefix: [0xff, 0xfb], - base64Prefix: '//s=', }, { mediaType: 'audio/mpeg' as const, bytesPrefix: [0xff, 0xfa], - base64Prefix: '//o=', }, { mediaType: 'audio/mpeg' as const, bytesPrefix: [0xff, 0xf3], - base64Prefix: '//M=', }, { mediaType: 'audio/mpeg' as const, bytesPrefix: [0xff, 0xf2], - base64Prefix: '//I=', }, { mediaType: 'audio/mpeg' as const, bytesPrefix: [0xff, 0xe3], - base64Prefix: '/+M=', }, { mediaType: 'audio/mpeg' as const, bytesPrefix: [0xff, 0xe2], - base64Prefix: '/+I=', }, { mediaType: 'audio/wav' as const, - bytesPrefix: [0x52, 0x49, 0x46, 0x46], - base64Prefix: 'UklGR', + bytesPrefix: [ + 0x52, // R + 0x49, // I + 0x46, // F + 0x46, // F + null, + null, + null, + null, + 0x57, // W + 0x41, // A + 0x56, // V + 0x45, // E + ], }, { mediaType: 'audio/ogg' as const, bytesPrefix: [0x4f, 0x67, 0x67, 0x53], - base64Prefix: 'T2dnUw', }, { mediaType: 'audio/flac' as const, bytesPrefix: [0x66, 0x4c, 0x61, 0x43], - base64Prefix: 'ZkxhQw', }, { mediaType: 'audio/aac' as const, bytesPrefix: [0x40, 0x15, 0x00, 0x00], - base64Prefix: 'QBUA', }, { mediaType: 'audio/mp4' as const, bytesPrefix: [0x66, 0x74, 0x79, 0x70], - base64Prefix: 'ZnR5cA', }, { mediaType: 'audio/webm', bytesPrefix: [0x1a, 0x45, 0xdf, 0xa3], - base64Prefix: 'GkXf', }, ] as const; @@ -156,14 +161,20 @@ export function detectMediaType({ }): (typeof signatures)[number]['mediaType'] | undefined { const processedData = stripID3TagsIfPresent(data); + // Convert the first ~18 bytes (24 base64 chars) for consistent detection logic: + const bytes = + typeof processedData === 'string' + ? convertBase64ToUint8Array( + processedData.substring(0, Math.min(processedData.length, 24)), + ) + : processedData; + for (const signature of signatures) { if ( - typeof processedData === 'string' - ? processedData.startsWith(signature.base64Prefix) - : processedData.length >= signature.bytesPrefix.length && - signature.bytesPrefix.every( - (byte, index) => processedData[index] === byte, - ) + bytes.length >= signature.bytesPrefix.length && + signature.bytesPrefix.every( + (byte, index) => byte === null || bytes[index] === byte, + ) ) { return signature.mediaType; } diff --git a/packages/ai/src/util/download/download.test.ts b/packages/ai/src/util/download/download.test.ts index 8f483ed88e79..d239b4be5acf 100644 --- a/packages/ai/src/util/download/download.test.ts +++ b/packages/ai/src/util/download/download.test.ts @@ -1,4 +1,4 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { download } from './download'; import { DownloadError } from './download-error'; import { describe, it, expect } from 'vitest'; @@ -26,6 +26,9 @@ describe('download', () => { expect(result).not.toBeNull(); expect(result!.data).toEqual(expectedBytes); expect(result!.mediaType).toBe('application/octet-stream'); + + // UA header assertion + expect(server.calls[0].requestUserAgent).toContain('ai-sdk/'); }); it('should throw DownloadError when response is not ok', async () => { diff --git a/packages/ai/src/util/download/download.ts b/packages/ai/src/util/download/download.ts index 84ae6d6db0de..57b3ca2bcd7b 100644 --- a/packages/ai/src/util/download/download.ts +++ b/packages/ai/src/util/download/download.ts @@ -1,4 +1,9 @@ import { DownloadError } from './download-error'; +import { + withUserAgentSuffix, + getRuntimeEnvironmentUserAgent, +} from '@ai-sdk/provider-utils'; +import { VERSION } from '../../version'; /** * Download a file from a URL. @@ -11,7 +16,13 @@ import { DownloadError } from './download-error'; export const download = async ({ url }: { url: URL }) => { const urlText = url.toString(); try { - const response = await fetch(urlText); + const response = await fetch(urlText, { + headers: withUserAgentSuffix( + {}, + `ai-sdk/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ), + }); if (!response.ok) { throw new DownloadError({ diff --git a/packages/ai/src/version.ts b/packages/ai/src/version.ts new file mode 100644 index 000000000000..8fda877d6d33 --- /dev/null +++ b/packages/ai/src/version.ts @@ -0,0 +1,5 @@ +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/ai/test/index.ts b/packages/ai/test/index.ts index 4068a8a2814f..fe6aedf7bbce 100644 --- a/packages/ai/test/index.ts +++ b/packages/ai/test/index.ts @@ -4,10 +4,10 @@ export { convertReadableStreamToArray, mockId, } from '@ai-sdk/provider-utils/test'; -export { MockEmbeddingModelV2 } from '../src/test/mock-embedding-model-v2'; -export { MockImageModelV2 } from '../src/test/mock-image-model-v2'; +export { MockEmbeddingModelV3 } from '../src/test/mock-embedding-model-v3'; +export { MockImageModelV3 } from '../src/test/mock-image-model-v3'; export { MockLanguageModelV2 } from '../src/test/mock-language-model-v2'; -export { MockProviderV2 } from '../src/test/mock-provider-v2'; +export { MockProviderV3 } from '../src/test/mock-provider-v3'; export { MockSpeechModelV2 } from '../src/test/mock-speech-model-v2'; export { MockTranscriptionModelV2 } from '../src/test/mock-transcription-model-v2'; export { mockValues } from '../src/test/mock-values'; diff --git a/packages/ai/tsconfig.json b/packages/ai/tsconfig.json index 7ac521e7e88f..7dedfdb70326 100644 --- a/packages/ai/tsconfig.json +++ b/packages/ai/tsconfig.json @@ -27,6 +27,9 @@ }, { "path": "../gateway" + }, + { + "path": "../test-server" } ] } diff --git a/packages/ai/tsup.config.ts b/packages/ai/tsup.config.ts index 6efc434cff45..40b286074930 100644 --- a/packages/ai/tsup.config.ts +++ b/packages/ai/tsup.config.ts @@ -10,6 +10,12 @@ export default defineConfig([ sourcemap: true, target: 'es2018', platform: 'node', + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, // Internal APIs { @@ -21,6 +27,12 @@ export default defineConfig([ sourcemap: true, target: 'es2018', platform: 'node', + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, // Test utilities { @@ -43,6 +55,12 @@ export default defineConfig([ // Allow BigInt in tests target: 'es2020', platform: 'node', + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, // MCP stdio { @@ -54,5 +72,11 @@ export default defineConfig([ sourcemap: true, target: 'es2018', platform: 'node', + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/ai/vitest.edge.config.js b/packages/ai/vitest.edge.config.js index 32fbed1c6dae..ab1a7969f6a8 100644 --- a/packages/ai/vitest.edge.config.js +++ b/packages/ai/vitest.edge.config.js @@ -1,7 +1,15 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; + +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, test: { environment: 'edge-runtime', include: ['**/*.test.ts{,x}'], diff --git a/packages/ai/vitest.node.config.js b/packages/ai/vitest.node.config.js index 2518577b8137..091e0fbe8374 100644 --- a/packages/ai/vitest.node.config.js +++ b/packages/ai/vitest.node.config.js @@ -1,7 +1,15 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; + +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, test: { environment: 'node', include: ['**/*.test.ts{,x}'], diff --git a/packages/amazon-bedrock/CHANGELOG.md b/packages/amazon-bedrock/CHANGELOG.md index 8ebb51169aed..eb3a98465487 100644 --- a/packages/amazon-bedrock/CHANGELOG.md +++ b/packages/amazon-bedrock/CHANGELOG.md @@ -1,5 +1,73 @@ # @ai-sdk/amazon-bedrock +## 3.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/anthropic@2.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 3.1.0-beta.2 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] +- Updated dependencies [1cad0ab] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/anthropic@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 3.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/anthropic@2.1.0-beta.1 + +## 3.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/anthropic@2.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 3.0.22 + +### Patch Changes + +- 32f3cef: feat: adding user-agent to all packages that use global fetch directly + +## 3.0.21 + +### Patch Changes + +- Updated dependencies [da92132] + - @ai-sdk/anthropic@2.0.17 + +## 3.0.20 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/anthropic@2.0.16 + ## 3.0.19 ### Patch Changes diff --git a/packages/amazon-bedrock/package.json b/packages/amazon-bedrock/package.json index 16f6603a7546..965f9321b34e 100644 --- a/packages/amazon-bedrock/package.json +++ b/packages/amazon-bedrock/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/amazon-bedrock", - "version": "3.0.19", + "version": "3.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -35,6 +35,7 @@ "@ai-sdk/anthropic": "workspace:*", "@ai-sdk/provider": "workspace:*", "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" diff --git a/packages/amazon-bedrock/src/bedrock-chat-language-model.test.ts b/packages/amazon-bedrock/src/bedrock-chat-language-model.test.ts index 8379ec0fa1f0..f5bcbe933e58 100644 --- a/packages/amazon-bedrock/src/bedrock-chat-language-model.test.ts +++ b/packages/amazon-bedrock/src/bedrock-chat-language-model.test.ts @@ -1,8 +1,6 @@ import { LanguageModelV2Prompt } from '@ai-sdk/provider'; -import { - createTestServer, - convertReadableStreamToArray, -} from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; +import { convertReadableStreamToArray } from '@ai-sdk/provider-utils/test'; import { BedrockChatLanguageModel } from './bedrock-chat-language-model'; import { beforeEach, describe, expect, vi, it } from 'vitest'; import { injectFetchHeaders } from './inject-fetch-headers'; diff --git a/packages/amazon-bedrock/src/bedrock-embedding-model.test.ts b/packages/amazon-bedrock/src/bedrock-embedding-model.test.ts index bff436d1533a..0fb10b6dc3ec 100644 --- a/packages/amazon-bedrock/src/bedrock-embedding-model.test.ts +++ b/packages/amazon-bedrock/src/bedrock-embedding-model.test.ts @@ -1,4 +1,4 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { BedrockEmbeddingModel } from './bedrock-embedding-model'; import { injectFetchHeaders } from './inject-fetch-headers'; import { beforeEach, describe, expect, it } from 'vitest'; diff --git a/packages/amazon-bedrock/src/bedrock-embedding-model.ts b/packages/amazon-bedrock/src/bedrock-embedding-model.ts index 66953ccb4760..bdcb2453689d 100644 --- a/packages/amazon-bedrock/src/bedrock-embedding-model.ts +++ b/packages/amazon-bedrock/src/bedrock-embedding-model.ts @@ -1,5 +1,5 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, TooManyEmbeddingValuesForCallError, } from '@ai-sdk/provider'; import { @@ -25,10 +25,10 @@ type BedrockEmbeddingConfig = { fetch?: FetchFunction; }; -type DoEmbedResponse = Awaited['doEmbed']>>; +type DoEmbedResponse = Awaited['doEmbed']>>; -export class BedrockEmbeddingModel implements EmbeddingModelV2 { - readonly specificationVersion = 'v2'; +export class BedrockEmbeddingModel implements EmbeddingModelV3 { + readonly specificationVersion = 'v3'; readonly provider = 'amazon-bedrock'; readonly maxEmbeddingsPerCall = 1; readonly supportsParallelCalls = true; @@ -49,7 +49,7 @@ export class BedrockEmbeddingModel implements EmbeddingModelV2 { abortSignal, providerOptions, }: Parameters< - EmbeddingModelV2['doEmbed'] + EmbeddingModelV3['doEmbed'] >[0]): Promise { if (values.length > this.maxEmbeddingsPerCall) { throw new TooManyEmbeddingValuesForCallError({ diff --git a/packages/amazon-bedrock/src/bedrock-image-model.test.ts b/packages/amazon-bedrock/src/bedrock-image-model.test.ts index ac935b38ff51..8dcbcfc14b5b 100644 --- a/packages/amazon-bedrock/src/bedrock-image-model.test.ts +++ b/packages/amazon-bedrock/src/bedrock-image-model.test.ts @@ -1,4 +1,4 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createAmazonBedrock } from './bedrock-provider'; import { BedrockImageModel } from './bedrock-image-model'; import { injectFetchHeaders } from './inject-fetch-headers'; diff --git a/packages/amazon-bedrock/src/bedrock-image-model.ts b/packages/amazon-bedrock/src/bedrock-image-model.ts index 966580a763d1..cd5a08ba9e14 100644 --- a/packages/amazon-bedrock/src/bedrock-image-model.ts +++ b/packages/amazon-bedrock/src/bedrock-image-model.ts @@ -1,4 +1,4 @@ -import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider'; +import { ImageModelV3, ImageModelV3CallWarning } from '@ai-sdk/provider'; import { FetchFunction, Resolvable, @@ -24,8 +24,8 @@ type BedrockImageModelConfig = { }; }; -export class BedrockImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class BedrockImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; readonly provider = 'amazon-bedrock'; get maxImagesPerCall(): number { @@ -51,10 +51,10 @@ export class BedrockImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; const [width, height] = size ? size.split('x').map(Number) : []; const args = { taskType: 'TEXT_IMAGE', diff --git a/packages/amazon-bedrock/src/bedrock-provider.test.ts b/packages/amazon-bedrock/src/bedrock-provider.test.ts index 978d121e8946..1bdb3298e8d3 100644 --- a/packages/amazon-bedrock/src/bedrock-provider.test.ts +++ b/packages/amazon-bedrock/src/bedrock-provider.test.ts @@ -60,6 +60,10 @@ vi.mock('@ai-sdk/provider-utils', async importOriginal => { }; }); +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); + // Import mocked modules to get references import { createSigV4FetchFunction, @@ -89,14 +93,17 @@ describe('AmazonBedrockProvider', () => { const constructorCall = BedrockChatLanguageModelMock.mock.calls[0]; expect(constructorCall[0]).toBe('anthropic.claude-v2'); - expect(constructorCall[1].headers).toEqual({}); + expect(constructorCall[1].headers()).toMatchObject({}); + expect(constructorCall[1].headers()['user-agent']).toContain( + 'ai-sdk/amazon-bedrock/0.0.0-test', + ); expect(constructorCall[1].baseUrl()).toBe( 'https://bedrock-runtime.us-east-1.amazonaws.com', ); }); it('should create a provider instance with custom options', () => { - const customHeaders = { 'Custom-Header': 'value' }; + const customHeaders = { 'custom-header': 'value' }; const options = { region: 'eu-west-1', baseURL: 'https://custom.url', @@ -107,7 +114,10 @@ describe('AmazonBedrockProvider', () => { provider('anthropic.claude-v2'); const constructorCall = BedrockChatLanguageModelMock.mock.calls[0]; - expect(constructorCall[1].headers).toEqual(customHeaders); + expect(constructorCall[1].headers()).toMatchObject(customHeaders); + expect(constructorCall[1].headers()['user-agent']).toContain( + 'ai-sdk/amazon-bedrock/0.0.0-test', + ); expect(constructorCall[1].baseUrl()).toBe('https://custom.url'); }); @@ -126,7 +136,10 @@ describe('AmazonBedrockProvider', () => { const constructorCall = BedrockChatLanguageModelMock.mock.calls[0]; expect(constructorCall[0]).toBe('anthropic.claude-v2'); - expect(constructorCall[1].headers).toEqual({}); + expect(constructorCall[1].headers()).toMatchObject({}); + expect(constructorCall[1].headers()['user-agent']).toContain( + 'ai-sdk/amazon-bedrock/0.0.0-test', + ); expect(constructorCall[1].baseUrl()).toBe( 'https://bedrock-runtime.us-east-1.amazonaws.com', ); @@ -152,7 +165,7 @@ describe('AmazonBedrockProvider', () => { }); it('should pass headers to embedding model', () => { - const customHeaders = { 'Custom-Header': 'value' }; + const customHeaders = { 'custom-header': 'value' }; const provider = createAmazonBedrock({ headers: customHeaders, }); @@ -160,7 +173,10 @@ describe('AmazonBedrockProvider', () => { provider.embedding('amazon.titan-embed-text-v1'); const constructorCall = BedrockEmbeddingModelMock.mock.calls[0]; - expect(constructorCall[1].headers).toEqual(customHeaders); + expect(constructorCall[1].headers()).toMatchObject(customHeaders); + expect(constructorCall[1].headers()['user-agent']).toContain( + 'ai-sdk/amazon-bedrock/0.0.0-test', + ); }); it('should throw error when called with new keyword', () => { @@ -190,7 +206,10 @@ describe('AmazonBedrockProvider', () => { const constructorCall = BedrockChatLanguageModelMock.mock.calls[0]; expect(constructorCall[0]).toBe('anthropic.claude-v2'); - expect(constructorCall[1].headers).toEqual({}); + expect(constructorCall[1].headers()).toMatchObject({}); + expect(constructorCall[1].headers()['user-agent']).toContain( + 'ai-sdk/amazon-bedrock/', + ); expect(constructorCall[1].baseUrl()).toBe( 'https://bedrock-runtime.us-east-1.amazonaws.com', ); @@ -306,16 +325,19 @@ describe('AmazonBedrockProvider', () => { const provider = createAmazonBedrock({ apiKey: 'test-api-key', region: 'us-east-1', - headers: { 'Custom-Header': 'value' }, + headers: { 'custom-header': 'value' }, }); provider.embedding('amazon.titan-embed-text-v1'); const constructorCall = BedrockEmbeddingModelMock.mock.calls[0]; expect(constructorCall[0]).toBe('amazon.titan-embed-text-v1'); - expect(constructorCall[1].headers).toEqual({ - 'Custom-Header': 'value', + expect(constructorCall[1].headers()).toMatchObject({ + 'custom-header': 'value', }); + expect(constructorCall[1].headers()['user-agent']).toContain( + 'ai-sdk/amazon-bedrock/0.0.0-test', + ); expect(mockCreateApiKeyFetchFunction).toHaveBeenCalledWith( 'test-api-key', undefined, @@ -326,16 +348,19 @@ describe('AmazonBedrockProvider', () => { const provider = createAmazonBedrock({ apiKey: 'test-api-key', region: 'us-east-1', - headers: { 'Custom-Header': 'value' }, + headers: { 'custom-header': 'value' }, }); provider.image('amazon.titan-image-generator'); const constructorCall = BedrockImageModelMock.mock.calls[0]; expect(constructorCall[0]).toBe('amazon.titan-image-generator'); - expect(constructorCall[1].headers).toEqual({ - 'Custom-Header': 'value', + expect(constructorCall[1].headers()).toMatchObject({ + 'custom-header': 'value', }); + expect(constructorCall[1].headers()['user-agent']).toContain( + 'ai-sdk/amazon-bedrock/0.0.0-test', + ); expect(mockCreateApiKeyFetchFunction).toHaveBeenCalledWith( 'test-api-key', undefined, diff --git a/packages/amazon-bedrock/src/bedrock-provider.ts b/packages/amazon-bedrock/src/bedrock-provider.ts index 5c58f8a5e732..7fca538d04bb 100644 --- a/packages/amazon-bedrock/src/bedrock-provider.ts +++ b/packages/amazon-bedrock/src/bedrock-provider.ts @@ -1,8 +1,8 @@ import { - EmbeddingModelV2, - ImageModelV2, + EmbeddingModelV3, + ImageModelV3, LanguageModelV2, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, @@ -10,7 +10,9 @@ import { loadOptionalSetting, loadSetting, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; +import { VERSION } from './version'; import { anthropicTools } from '@ai-sdk/anthropic/internal'; import { BedrockChatLanguageModel } from './bedrock-chat-language-model'; import { BedrockChatModelId } from './bedrock-chat-options'; @@ -102,22 +104,22 @@ and `sessionToken` settings. generateId?: () => string; } -export interface AmazonBedrockProvider extends ProviderV2 { +export interface AmazonBedrockProvider extends ProviderV3 { (modelId: BedrockChatModelId): LanguageModelV2; languageModel(modelId: BedrockChatModelId): LanguageModelV2; - embedding(modelId: BedrockEmbeddingModelId): EmbeddingModelV2; + embedding(modelId: BedrockEmbeddingModelId): EmbeddingModelV3; /** Creates a model for image generation. */ - image(modelId: BedrockImageModelId): ImageModelV2; + image(modelId: BedrockImageModelId): ImageModelV3; /** Creates a model for image generation. */ - imageModel(modelId: BedrockImageModelId): ImageModelV2; + imageModel(modelId: BedrockImageModelId): ImageModelV3; /** Anthropic-specific tools that can be used with Anthropic models on Bedrock. @@ -236,10 +238,15 @@ export function createAmazonBedrock( })}.amazonaws.com`, ) ?? `https://bedrock-runtime.us-east-1.amazonaws.com`; + const getHeaders = () => { + const baseHeaders = options.headers ?? {}; + return withUserAgentSuffix(baseHeaders, `ai-sdk/amazon-bedrock/${VERSION}`); + }; + const createChatModel = (modelId: BedrockChatModelId) => new BedrockChatLanguageModel(modelId, { baseUrl: getBaseUrl, - headers: options.headers ?? {}, + headers: getHeaders, fetch: fetchFunction, generateId, }); @@ -257,14 +264,14 @@ export function createAmazonBedrock( const createEmbeddingModel = (modelId: BedrockEmbeddingModelId) => new BedrockEmbeddingModel(modelId, { baseUrl: getBaseUrl, - headers: options.headers ?? {}, + headers: getHeaders, fetch: fetchFunction, }); const createImageModel = (modelId: BedrockImageModelId) => new BedrockImageModel(modelId, { baseUrl: getBaseUrl, - headers: options.headers ?? {}, + headers: getHeaders, fetch: fetchFunction, }); diff --git a/packages/amazon-bedrock/src/bedrock-sigv4-fetch.test.ts b/packages/amazon-bedrock/src/bedrock-sigv4-fetch.test.ts index b832d06109ac..b7ee239352bd 100644 --- a/packages/amazon-bedrock/src/bedrock-sigv4-fetch.test.ts +++ b/packages/amazon-bedrock/src/bedrock-sigv4-fetch.test.ts @@ -4,6 +4,20 @@ import { } from './bedrock-sigv4-fetch'; import { vi, describe, it, expect, afterEach } from 'vitest'; +// Mock the version module +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); + +// Mock provider-utils to control runtime environment detection +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + getRuntimeEnvironmentUserAgent: vi.fn(() => 'runtime/testenv'), + }; +}); + // Mock AwsV4Signer so that no real crypto calls are made. vi.mock('aws4fetch', () => { class MockAwsV4Signer { @@ -48,6 +62,9 @@ describe('createSigV4FetchFunction', () => { const response = await fetchFn('http://example.com', { method: 'GET' }); expect(dummyFetch).toHaveBeenCalledWith('http://example.com', { method: 'GET', + headers: { + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', + }, }); expect(response).toBe(dummyResponse); }); @@ -60,11 +77,14 @@ describe('createSigV4FetchFunction', () => { const response = await fetchFn('http://example.com', { method: 'POST' }); expect(dummyFetch).toHaveBeenCalledWith('http://example.com', { method: 'POST', + headers: { + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', + }, }); expect(response).toBe(dummyResponse); }); - it('should handle a POST request with a string body and merge signed headers', async () => { + it('should handle a POST request with a string body and merge signed headers including user-agent', async () => { const dummyResponse = new Response('Signed', { status: 200 }); const dummyFetch = vi.fn().mockResolvedValue(dummyResponse); @@ -103,6 +123,9 @@ describe('createSigV4FetchFunction', () => { 'AWS4-HMAC-SHA256 Credential=test', ); expect(headers['x-amz-security-token']).toEqual('test-session-token'); + expect(headers['user-agent']).toEqual( + 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', + ); // Body is left unmodified for a string body. expect(calledInit.body).toEqual('{"test": "data"}'); }); @@ -222,7 +245,11 @@ describe('createSigV4FetchFunction', () => { const fetchFn = createFetchFunction(dummyFetch); const response = await fetchFn('http://example.com'); - expect(dummyFetch).toHaveBeenCalledWith('http://example.com', undefined); + expect(dummyFetch).toHaveBeenCalledWith('http://example.com', { + headers: { + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', + }, + }); expect(response).toBe(dummyResponse); }); @@ -297,7 +324,7 @@ describe('createApiKeyFetchFunction', () => { vi.restoreAllMocks(); }); - it('should add Authorization header with Bearer token', async () => { + it('should add Authorization header with Bearer token and user-agent', async () => { const dummyResponse = new Response('OK', { status: 200 }); const dummyFetch = vi.fn().mockResolvedValue(dummyResponse); const apiKey = 'test-api-key-123'; @@ -318,6 +345,7 @@ describe('createApiKeyFetchFunction', () => { headers: { 'content-type': 'application/json', Authorization: 'Bearer test-api-key-123', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); expect(response).toBe(dummyResponse); @@ -348,6 +376,7 @@ describe('createApiKeyFetchFunction', () => { 'custom-header': 'custom-value', 'x-request-id': 'req-123', Authorization: 'Bearer test-api-key-456', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); }); @@ -376,6 +405,7 @@ describe('createApiKeyFetchFunction', () => { 'content-type': 'application/json', 'x-custom': 'value', Authorization: 'Bearer test-api-key-789', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); }); @@ -405,6 +435,7 @@ describe('createApiKeyFetchFunction', () => { 'content-type': 'application/json', 'x-array-header': 'array-value', Authorization: 'Bearer test-api-key-array', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); }); @@ -428,6 +459,7 @@ describe('createApiKeyFetchFunction', () => { headers: { accept: 'application/json', Authorization: 'Bearer test-api-key-get', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); }); @@ -449,6 +481,7 @@ describe('createApiKeyFetchFunction', () => { body: '{"test": "data"}', headers: { Authorization: 'Bearer test-api-key-no-headers', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); }); @@ -465,6 +498,7 @@ describe('createApiKeyFetchFunction', () => { expect(dummyFetch).toHaveBeenCalledWith('http://example.com', { headers: { Authorization: 'Bearer test-api-key-undefined', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); }); @@ -492,6 +526,7 @@ describe('createApiKeyFetchFunction', () => { 'content-type': 'application/json', Authorization: 'Bearer test-api-key-override', authorization: 'Bearer old-token', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); }); @@ -515,6 +550,7 @@ describe('createApiKeyFetchFunction', () => { body: '{"test": "data"}', headers: { Authorization: 'Bearer test-api-key-default', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); } finally { @@ -539,6 +575,7 @@ describe('createApiKeyFetchFunction', () => { body: '{"test": "data"}', headers: { Authorization: 'Bearer ', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, }); }); @@ -567,6 +604,7 @@ describe('createApiKeyFetchFunction', () => { headers: { 'content-type': 'application/json', Authorization: 'Bearer test-api-key-preserve', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', }, credentials: 'include', cache: 'no-cache', diff --git a/packages/amazon-bedrock/src/bedrock-sigv4-fetch.ts b/packages/amazon-bedrock/src/bedrock-sigv4-fetch.ts index 9398345c96be..5e6ddfdd34ce 100644 --- a/packages/amazon-bedrock/src/bedrock-sigv4-fetch.ts +++ b/packages/amazon-bedrock/src/bedrock-sigv4-fetch.ts @@ -2,9 +2,11 @@ import { convertHeadersToRecord, extractHeaders } from './headers-utils'; import { FetchFunction, combineHeaders, - removeUndefinedEntries, + withUserAgentSuffix, + getRuntimeEnvironmentUserAgent, } from '@ai-sdk/provider-utils'; import { AwsV4Signer } from 'aws4fetch'; +import { VERSION } from './version'; export interface BedrockCredentials { region: string; @@ -28,8 +30,18 @@ export function createSigV4FetchFunction( input: RequestInfo | URL, init?: RequestInit, ): Promise => { + const originalHeaders = extractHeaders(init?.headers); + const headersWithUserAgent = withUserAgentSuffix( + originalHeaders, + `ai-sdk/amazon-bedrock/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ); + if (init?.method?.toUpperCase() !== 'POST' || !init?.body) { - return fetch(input, init); + return fetch(input, { + ...init, + headers: headersWithUserAgent as HeadersInit, + }); } const url = @@ -39,13 +51,12 @@ export function createSigV4FetchFunction( ? input.href : input.url; - const originalHeaders = extractHeaders(init.headers); const body = prepareBodyString(init.body); const credentials = await getCredentials(); const signer = new AwsV4Signer({ url, method: 'POST', - headers: Object.entries(removeUndefinedEntries(originalHeaders)), + headers: Object.entries(headersWithUserAgent), body, region: credentials.region, accessKeyId: credentials.accessKeyId, @@ -56,12 +67,14 @@ export function createSigV4FetchFunction( const signingResult = await signer.sign(); const signedHeaders = convertHeadersToRecord(signingResult.headers); + + // Use the combined headers directly as HeadersInit + const combinedHeaders = combineHeaders(headersWithUserAgent, signedHeaders); + return fetch(input, { ...init, body, - headers: removeUndefinedEntries( - combineHeaders(originalHeaders, signedHeaders), - ), + headers: combinedHeaders as HeadersInit, }); }; } @@ -94,14 +107,19 @@ export function createApiKeyFetchFunction( init?: RequestInit, ): Promise => { const originalHeaders = extractHeaders(init?.headers); + const headersWithUserAgent = withUserAgentSuffix( + originalHeaders, + `ai-sdk/amazon-bedrock/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ); + + const finalHeaders = combineHeaders(headersWithUserAgent, { + Authorization: `Bearer ${apiKey}`, + }); return fetch(input, { ...init, - headers: removeUndefinedEntries( - combineHeaders(originalHeaders, { - Authorization: `Bearer ${apiKey}`, - }), - ), + headers: finalHeaders as HeadersInit, }); }; } diff --git a/packages/amazon-bedrock/src/index.ts b/packages/amazon-bedrock/src/index.ts index 2fda4e2a9e85..9e1fc9bbfcd5 100644 --- a/packages/amazon-bedrock/src/index.ts +++ b/packages/amazon-bedrock/src/index.ts @@ -4,3 +4,4 @@ export type { AmazonBedrockProviderSettings, } from './bedrock-provider'; export type { BedrockProviderOptions } from './bedrock-chat-options'; +export { VERSION } from './version'; diff --git a/packages/amazon-bedrock/src/inject-fetch-headers.test.ts b/packages/amazon-bedrock/src/inject-fetch-headers.test.ts index bd5294699e9d..72b79d1cb40c 100644 --- a/packages/amazon-bedrock/src/inject-fetch-headers.test.ts +++ b/packages/amazon-bedrock/src/inject-fetch-headers.test.ts @@ -1,6 +1,20 @@ import { injectFetchHeaders } from './inject-fetch-headers'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +// Mock the version module +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); + +// // Mock provider-utils to control runtime environment detection +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + getRuntimeEnvironmentUserAgent: vi.fn(() => 'runtime/testenv'), + }; +}); + describe('injectFetchHeaders', () => { const originalFetch = globalThis.fetch; @@ -18,8 +32,8 @@ describe('injectFetchHeaders', () => { globalThis.fetch = mockFetch; const customHeaders = { - 'X-Custom-Header': 'custom-value', - Authorization: 'Bearer token', + 'x-custom-header': 'custom-value', + authorization: 'Bearer token', }; const enhancedFetch = injectFetchHeaders(customHeaders); @@ -28,7 +42,11 @@ describe('injectFetchHeaders', () => { expect(mockFetch).toHaveBeenCalledWith( 'https://api.example.com', expect.objectContaining({ - headers: customHeaders, + headers: expect.objectContaining({ + 'x-custom-header': 'custom-value', + authorization: 'Bearer token', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', + }), }), ); }); @@ -38,7 +56,7 @@ describe('injectFetchHeaders', () => { globalThis.fetch = mockFetch; const customHeaders = { - 'X-Custom-Header': 'custom-value', + 'x-custom-header': 'custom-value', }; const existingHeaders = { @@ -53,10 +71,11 @@ describe('injectFetchHeaders', () => { expect(mockFetch).toHaveBeenCalledWith( 'https://api.example.com', expect.objectContaining({ - headers: { + headers: expect.objectContaining({ 'content-type': 'application/json', - 'X-Custom-Header': 'custom-value', - }, + 'x-custom-header': 'custom-value', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', + }), }), ); }); @@ -66,7 +85,7 @@ describe('injectFetchHeaders', () => { globalThis.fetch = mockFetch; const customHeaders = { - 'X-Custom-Header': 'custom-value', + 'x-custom-header': 'custom-value', }; const enhancedFetch = injectFetchHeaders(customHeaders); @@ -77,7 +96,10 @@ describe('injectFetchHeaders', () => { expect(mockFetch).toHaveBeenCalledWith( 'https://api.example.com', expect.objectContaining({ - headers: customHeaders, + headers: expect.objectContaining({ + 'x-custom-header': 'custom-value', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', + }), }), ); }); @@ -87,7 +109,7 @@ describe('injectFetchHeaders', () => { globalThis.fetch = mockFetch; const customHeaders = { - 'X-Custom-Header': 'custom-value', + 'x-custom-header': 'custom-value', }; const existingHeaders = new Headers({ @@ -102,10 +124,11 @@ describe('injectFetchHeaders', () => { expect(mockFetch).toHaveBeenCalledWith( 'https://api.example.com', expect.objectContaining({ - headers: { + headers: expect.objectContaining({ 'content-type': 'application/json', - 'X-Custom-Header': 'custom-value', - }, + 'x-custom-header': 'custom-value', + 'user-agent': 'ai-sdk/amazon-bedrock/0.0.0-test runtime/testenv', + }), }), ); }); diff --git a/packages/amazon-bedrock/src/inject-fetch-headers.ts b/packages/amazon-bedrock/src/inject-fetch-headers.ts index 9f0edcf72fd8..91310ea4accb 100644 --- a/packages/amazon-bedrock/src/inject-fetch-headers.ts +++ b/packages/amazon-bedrock/src/inject-fetch-headers.ts @@ -1,5 +1,11 @@ import { extractHeaders } from './headers-utils'; -import { FetchFunction, removeUndefinedEntries } from '@ai-sdk/provider-utils'; +import { + FetchFunction, + removeUndefinedEntries, + withUserAgentSuffix, + getRuntimeEnvironmentUserAgent, +} from '@ai-sdk/provider-utils'; +import { VERSION } from './version'; /** * Test helper to inject custom headers into a fetch request. @@ -9,12 +15,19 @@ import { FetchFunction, removeUndefinedEntries } from '@ai-sdk/provider-utils'; export function injectFetchHeaders( customHeaders: Record, ): FetchFunction { - return async (input, init = {}) => - await globalThis.fetch(input, { - ...init, - headers: removeUndefinedEntries({ + return async (input, init = {}) => { + const headers = withUserAgentSuffix( + { ...extractHeaders(init.headers), ...customHeaders, - }), + }, + `ai-sdk/amazon-bedrock/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ); + + return await globalThis.fetch(input, { + ...init, + headers: removeUndefinedEntries(headers), }); + }; } diff --git a/packages/amazon-bedrock/src/version.ts b/packages/amazon-bedrock/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/amazon-bedrock/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/amazon-bedrock/tsup.config.ts b/packages/amazon-bedrock/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/amazon-bedrock/tsup.config.ts +++ b/packages/amazon-bedrock/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/amazon-bedrock/vitest.edge.config.js b/packages/amazon-bedrock/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/amazon-bedrock/vitest.edge.config.js +++ b/packages/amazon-bedrock/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/amazon-bedrock/vitest.node.config.js b/packages/amazon-bedrock/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/amazon-bedrock/vitest.node.config.js +++ b/packages/amazon-bedrock/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/angular/CHANGELOG.md b/packages/angular/CHANGELOG.md index 50f3d718bd99..7d91cbd3f044 100644 --- a/packages/angular/CHANGELOG.md +++ b/packages/angular/CHANGELOG.md @@ -1,5 +1,127 @@ # @ai-sdk/angular +## 1.1.0-beta.9 + +### Patch Changes + +- Updated dependencies [ed329cb] +- Updated dependencies [177b475] +- Updated dependencies [522f6b8] + - ai@5.1.0-beta.9 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.8 + +### Patch Changes + +- Updated dependencies [7eca093] + - ai@5.1.0-beta.8 + +## 1.1.0-beta.7 + +### Patch Changes + +- Updated dependencies [5a4e732] + - ai@5.1.0-beta.7 + +## 1.1.0-beta.6 + +### Patch Changes + +- Updated dependencies [0c4822d] + - ai@5.1.0-beta.6 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.5 + +### Patch Changes + +- ai@5.1.0-beta.5 + +## 1.1.0-beta.4 + +### Patch Changes + +- ai@5.1.0-beta.4 + +## 1.1.0-beta.3 + +### Patch Changes + +- ai@5.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - ai@5.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [a7f6f81] + - ai@5.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - ai@5.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.45 + +### Patch Changes + +- Updated dependencies [76024fc] +- Updated dependencies [93d8b60] +- Updated dependencies [d8eb31f] + - ai@5.0.45 + +## 1.0.44 + +### Patch Changes + +- ai@5.0.44 + +## 1.0.43 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - ai@5.0.43 + +## 1.0.42 + +### Patch Changes + +- Updated dependencies [de5c066] + - ai@5.0.42 + +## 1.0.41 + +### Patch Changes + +- Updated dependencies [cd91e4b] + - ai@5.0.41 + +## 1.0.40 + +### Patch Changes + +- ai@5.0.40 + ## 1.0.39 ### Patch Changes diff --git a/packages/angular/package.json b/packages/angular/package.json index 4d7a3a2fff9f..df47bacecdbc 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/angular", - "version": "1.0.39", + "version": "1.1.0-beta.9", "description": "Angular implementation of ai-sdk.", "license": "Apache-2.0", "main": "dist/index.cjs", @@ -31,6 +31,7 @@ ], "dependencies": { "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*", "ai": "workspace:*" }, "devDependencies": { diff --git a/packages/angular/src/lib/chat.ng.test.ts b/packages/angular/src/lib/chat.ng.test.ts index 6c39f3d1c79e..428b60c877f2 100644 --- a/packages/angular/src/lib/chat.ng.test.ts +++ b/packages/angular/src/lib/chat.ng.test.ts @@ -1,8 +1,8 @@ import { createTestServer, - mockId, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; +import { mockId } from '@ai-sdk/provider-utils/test'; import { DefaultChatTransport, isToolUIPart, diff --git a/packages/angular/src/lib/completion.ng.test.ts b/packages/angular/src/lib/completion.ng.test.ts index 2c8f10710a8d..1dee1f33b984 100644 --- a/packages/angular/src/lib/completion.ng.test.ts +++ b/packages/angular/src/lib/completion.ng.test.ts @@ -1,7 +1,7 @@ import { createTestServer, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; import { Completion } from './completion.ng'; import { beforeAll } from 'vitest'; import { describe, it, expect, vi } from 'vitest'; diff --git a/packages/angular/src/lib/structured-object.ng.test.ts b/packages/angular/src/lib/structured-object.ng.test.ts index d749aba174cc..78e6c5d943ee 100644 --- a/packages/angular/src/lib/structured-object.ng.test.ts +++ b/packages/angular/src/lib/structured-object.ng.test.ts @@ -1,7 +1,7 @@ import { createTestServer, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; import { z } from 'zod/v4'; import { StructuredObject } from './structured-object.ng'; import { beforeEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/anthropic/CHANGELOG.md b/packages/anthropic/CHANGELOG.md index 5c8197960cfc..978e84d37d08 100644 --- a/packages/anthropic/CHANGELOG.md +++ b/packages/anthropic/CHANGELOG.md @@ -1,5 +1,58 @@ # @ai-sdk/anthropic +## 2.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.17 + +### Patch Changes + +- da92132: fix(provider/anthorpic): add cacheControl to AnthropicProviderOptions + +## 2.0.16 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 2.0.15 ### Patch Changes diff --git a/packages/anthropic/package.json b/packages/anthropic/package.json index 11f72a482f88..044837d4c3b3 100644 --- a/packages/anthropic/package.json +++ b/packages/anthropic/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/anthropic", - "version": "2.0.15", + "version": "2.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -40,7 +40,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/anthropic/src/anthropic-messages-language-model.test.ts b/packages/anthropic/src/anthropic-messages-language-model.test.ts index 42921806531c..45bac53bc781 100644 --- a/packages/anthropic/src/anthropic-messages-language-model.test.ts +++ b/packages/anthropic/src/anthropic-messages-language-model.test.ts @@ -3,15 +3,19 @@ import { LanguageModelV2StreamPart, JSONValue, } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, mockId, } from '@ai-sdk/provider-utils/test'; import { AnthropicProviderOptions } from './anthropic-messages-options'; import { createAnthropic } from './anthropic-provider'; import { type DocumentCitation } from './anthropic-messages-language-model'; -import { describe, it, expect, beforeEach } from 'vitest'; +import { describe, it, expect, beforeEach, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const TEST_PROMPT: LanguageModelV2Prompt = [ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, @@ -395,6 +399,9 @@ describe('AnthropicMessagesLanguageModel', () => { // custom header 'test-header': 'test-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/anthropic/0.0.0-test`, + ); }); it('should send the model id and settings', async () => { @@ -553,7 +560,7 @@ describe('AnthropicMessagesLanguageModel', () => { providerOptions: { anthropic: { cacheControl: { type: 'ephemeral' }, - }, + } satisfies AnthropicProviderOptions, }, }, ], @@ -679,9 +686,6 @@ describe('AnthropicMessagesLanguageModel', () => { const model = provider('claude-3-haiku-20240307'); const result = await model.doGenerate({ - headers: { - 'anthropic-beta': 'extended-cache-ttl-2025-04-11', - }, prompt: [ { role: 'user', @@ -689,7 +693,7 @@ describe('AnthropicMessagesLanguageModel', () => { providerOptions: { anthropic: { cacheControl: { type: 'ephemeral', ttl: '1h' }, - }, + } satisfies AnthropicProviderOptions, }, }, ], @@ -2534,9 +2538,6 @@ describe('AnthropicMessagesLanguageModel', () => { const { stream } = await model.doStream({ prompt: TEST_PROMPT, - headers: { - 'anthropic-beta': 'extended-cache-ttl-2025-04-11', - }, }); expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(` diff --git a/packages/anthropic/src/anthropic-messages-options.ts b/packages/anthropic/src/anthropic-messages-options.ts index f702eed6a893..746dd39f7f2a 100644 --- a/packages/anthropic/src/anthropic-messages-options.ts +++ b/packages/anthropic/src/anthropic-messages-options.ts @@ -67,6 +67,17 @@ export const anthropicProviderOptions = z.object({ * When set to true, Claude will use at most one tool per response. */ disableParallelToolUse: z.boolean().optional(), + + /** + * Cache control settings for this message. + * See https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching + */ + cacheControl: z + .object({ + type: z.literal('ephemeral'), + ttl: z.union([z.literal('5m'), z.literal('1h')]).optional(), + }) + .optional(), }); export type AnthropicProviderOptions = z.infer; diff --git a/packages/anthropic/src/anthropic-provider.ts b/packages/anthropic/src/anthropic-provider.ts index 5f9a0e750a75..21d1c501cd85 100644 --- a/packages/anthropic/src/anthropic-provider.ts +++ b/packages/anthropic/src/anthropic-provider.ts @@ -1,19 +1,21 @@ import { LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, generateId, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; +import { VERSION } from './version'; import { AnthropicMessagesLanguageModel } from './anthropic-messages-language-model'; import { AnthropicMessagesModelId } from './anthropic-messages-options'; import { anthropicTools } from './anthropic-tools'; -export interface AnthropicProvider extends ProviderV2 { +export interface AnthropicProvider extends ProviderV3 { /** Creates a model for text generation. */ @@ -70,15 +72,19 @@ export function createAnthropic( const baseURL = withoutTrailingSlash(options.baseURL) ?? 'https://api.anthropic.com/v1'; - const getHeaders = () => ({ - 'anthropic-version': '2023-06-01', - 'x-api-key': loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'ANTHROPIC_API_KEY', - description: 'Anthropic', - }), - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + 'anthropic-version': '2023-06-01', + 'x-api-key': loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'ANTHROPIC_API_KEY', + description: 'Anthropic', + }), + ...options.headers, + }, + `ai-sdk/anthropic/${VERSION}`, + ); const createChatModel = (modelId: AnthropicMessagesModelId) => new AnthropicMessagesLanguageModel(modelId, { diff --git a/packages/anthropic/src/index.ts b/packages/anthropic/src/index.ts index 2581ae4017d3..85c69f614610 100644 --- a/packages/anthropic/src/index.ts +++ b/packages/anthropic/src/index.ts @@ -4,3 +4,4 @@ export type { AnthropicProvider, AnthropicProviderSettings, } from './anthropic-provider'; +export { VERSION } from './version'; diff --git a/packages/anthropic/src/version.ts b/packages/anthropic/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/anthropic/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/anthropic/tsup.config.ts b/packages/anthropic/tsup.config.ts index 87efcf0d5720..d0b56a7122cd 100644 --- a/packages/anthropic/tsup.config.ts +++ b/packages/anthropic/tsup.config.ts @@ -6,6 +6,12 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, { entry: ['src/internal/index.ts'], @@ -13,5 +19,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/anthropic/vitest.edge.config.js b/packages/anthropic/vitest.edge.config.js index 3dc49ba29774..82e68f1229bd 100644 --- a/packages/anthropic/vitest.edge.config.js +++ b/packages/anthropic/vitest.edge.config.js @@ -1,4 +1,9 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; + +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +11,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, }); diff --git a/packages/anthropic/vitest.node.config.js b/packages/anthropic/vitest.node.config.js index b7e4a9cabd48..740ecb8018f4 100644 --- a/packages/anthropic/vitest.node.config.js +++ b/packages/anthropic/vitest.node.config.js @@ -1,4 +1,9 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; + +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +11,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, }); diff --git a/packages/assemblyai/CHANGELOG.md b/packages/assemblyai/CHANGELOG.md index 2e25b8fcff35..910c12e7e8bc 100644 --- a/packages/assemblyai/CHANGELOG.md +++ b/packages/assemblyai/CHANGELOG.md @@ -1,5 +1,52 @@ # @ai-sdk/assemblyai +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.8 ### Patch Changes diff --git a/packages/assemblyai/package.json b/packages/assemblyai/package.json index 0754317b7f8f..cbdbb591bdcb 100644 --- a/packages/assemblyai/package.json +++ b/packages/assemblyai/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/assemblyai", - "version": "1.0.8", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -18,6 +18,7 @@ "type-check": "tsc --build", "prettier-check": "prettier --check \"./**/*.ts*\"", "test": "pnpm test:node && pnpm test:edge", + "test:watch": "vitest --config vitest.node.config.js", "test:edge": "vitest --config vitest.edge.config.js --run", "test:node": "vitest --config vitest.node.config.js --run", "test:node:watch": "vitest --config vitest.node.config.js --watch" @@ -32,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/assemblyai/src/assemblyai-provider.ts b/packages/assemblyai/src/assemblyai-provider.ts index 45282dd416be..c9a5991c60e2 100644 --- a/packages/assemblyai/src/assemblyai-provider.ts +++ b/packages/assemblyai/src/assemblyai-provider.ts @@ -1,13 +1,18 @@ import { TranscriptionModelV2, - ProviderV2, + ProviderV3, NoSuchModelError, } from '@ai-sdk/provider'; -import { FetchFunction, loadApiKey } from '@ai-sdk/provider-utils'; +import { + FetchFunction, + loadApiKey, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; import { AssemblyAITranscriptionModel } from './assemblyai-transcription-model'; import { AssemblyAITranscriptionModelId } from './assemblyai-transcription-settings'; +import { VERSION } from './version'; -export interface AssemblyAIProvider extends ProviderV2 { +export interface AssemblyAIProvider extends ProviderV3 { ( modelId: 'best', settings?: {}, @@ -45,14 +50,18 @@ Create an AssemblyAI provider instance. export function createAssemblyAI( options: AssemblyAIProviderSettings = {}, ): AssemblyAIProvider { - const getHeaders = () => ({ - authorization: loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'ASSEMBLYAI_API_KEY', - description: 'AssemblyAI', - }), - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + authorization: loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'ASSEMBLYAI_API_KEY', + description: 'AssemblyAI', + }), + ...options.headers, + }, + `ai-sdk/assemblyai/${VERSION}`, + ); const createTranscriptionModel = (modelId: AssemblyAITranscriptionModelId) => new AssemblyAITranscriptionModel(modelId, { diff --git a/packages/assemblyai/src/assemblyai-transcription-model.test.ts b/packages/assemblyai/src/assemblyai-transcription-model.test.ts index 2d28de6420eb..fcd3a34de689 100644 --- a/packages/assemblyai/src/assemblyai-transcription-model.test.ts +++ b/packages/assemblyai/src/assemblyai-transcription-model.test.ts @@ -1,9 +1,13 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { AssemblyAITranscriptionModel } from './assemblyai-transcription-model'; import { createAssemblyAI } from './assemblyai-provider'; import { readFile } from 'node:fs/promises'; import path from 'node:path'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const audioData = await readFile(path.join(__dirname, 'transcript-test.mp3')); const provider = createAssemblyAI({ apiKey: 'test-api-key' }); @@ -280,6 +284,9 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/assemblyai/0.0.0-test`, + ); }); it('should extract the transcription text', async () => { diff --git a/packages/assemblyai/src/index.ts b/packages/assemblyai/src/index.ts index 6c90fa17c72b..6346cee20197 100644 --- a/packages/assemblyai/src/index.ts +++ b/packages/assemblyai/src/index.ts @@ -3,3 +3,4 @@ export type { AssemblyAIProvider, AssemblyAIProviderSettings, } from './assemblyai-provider'; +export { VERSION } from './version'; diff --git a/packages/assemblyai/src/version.ts b/packages/assemblyai/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/assemblyai/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/assemblyai/tsup.config.ts b/packages/assemblyai/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/assemblyai/tsup.config.ts +++ b/packages/assemblyai/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/assemblyai/vitest.edge.config.js b/packages/assemblyai/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/assemblyai/vitest.edge.config.js +++ b/packages/assemblyai/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/assemblyai/vitest.node.config.js b/packages/assemblyai/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/assemblyai/vitest.node.config.js +++ b/packages/assemblyai/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/azure/CHANGELOG.md b/packages/azure/CHANGELOG.md index ec0490aca5b9..d5fc3215dabd 100644 --- a/packages/azure/CHANGELOG.md +++ b/packages/azure/CHANGELOG.md @@ -1,5 +1,100 @@ # @ai-sdk/azure +## 2.1.0-beta.4 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/openai@2.1.0-beta.4 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.3 + +### Patch Changes + +- Updated dependencies [2e86082] + - @ai-sdk/openai@2.1.0-beta.3 + +## 2.1.0-beta.2 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [4920119] +- Updated dependencies [0c4822d] +- Updated dependencies [1cad0ab] + - @ai-sdk/openai@2.1.0-beta.2 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/openai@2.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/openai@2.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.32 + +### Patch Changes + +- Updated dependencies [1cf857d] +- Updated dependencies [01de47f] + - @ai-sdk/openai@2.0.32 + +## 2.0.31 + +### Patch Changes + +- Updated dependencies [bb94467] +- Updated dependencies [4a2b70e] +- Updated dependencies [643711d] + - @ai-sdk/openai@2.0.31 + +## 2.0.30 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/openai@2.0.30 + +## 2.0.29 + +### Patch Changes + +- Updated dependencies [4235eb3] + - @ai-sdk/openai@2.0.29 + +## 2.0.28 + +### Patch Changes + +- Updated dependencies [4c2bb77] +- Updated dependencies [561e8b0] + - @ai-sdk/openai@2.0.28 + ## 2.0.27 ### Patch Changes diff --git a/packages/azure/package.json b/packages/azure/package.json index b131f096ad5c..a42b8fb88fa9 100644 --- a/packages/azure/package.json +++ b/packages/azure/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/azure", - "version": "2.0.27", + "version": "2.1.0-beta.4", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -34,7 +34,8 @@ "dependencies": { "@ai-sdk/openai": "workspace:*", "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/azure/src/azure-openai-provider.test.ts b/packages/azure/src/azure-openai-provider.test.ts index 6ac9e812bb05..b6c6d6b34f00 100644 --- a/packages/azure/src/azure-openai-provider.test.ts +++ b/packages/azure/src/azure-openai-provider.test.ts @@ -1,10 +1,14 @@ import { - EmbeddingModelV2Embedding, + EmbeddingModelV3Embedding, LanguageModelV2Prompt, } from '@ai-sdk/provider'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createAzure } from './azure-openai-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const TEST_PROMPT: LanguageModelV2Prompt = [ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, @@ -113,6 +117,9 @@ describe('chat', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/azure/0.0.0-test`, + ); }); it('should use the baseURL correctly', async () => { @@ -208,6 +215,9 @@ describe('completion', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/azure/0.0.0-test`, + ); }); }); }); @@ -302,7 +312,7 @@ describe('embedding', () => { function prepareJsonResponse({ embeddings = dummyEmbeddings, }: { - embeddings?: EmbeddingModelV2Embedding[]; + embeddings?: EmbeddingModelV3Embedding[]; } = {}) { server.urls[ 'https://test-resource.openai.azure.com/openai/v1/embeddings' @@ -356,6 +366,9 @@ describe('embedding', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/azure/0.0.0-test`, + ); }); }); }); @@ -450,6 +463,9 @@ describe('image', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/azure/0.0.0-test`, + ); }); it('should use the baseURL correctly', async () => { @@ -600,6 +616,9 @@ describe('responses', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/azure/0.0.0-test`, + ); }); it('should use the baseURL correctly', async () => { diff --git a/packages/azure/src/azure-openai-provider.ts b/packages/azure/src/azure-openai-provider.ts index a7332d79f285..9355ee796d7d 100644 --- a/packages/azure/src/azure-openai-provider.ts +++ b/packages/azure/src/azure-openai-provider.ts @@ -8,16 +8,22 @@ import { OpenAITranscriptionModel, } from '@ai-sdk/openai/internal'; import { - EmbeddingModelV2, + EmbeddingModelV3, LanguageModelV2, - ProviderV2, - ImageModelV2, + ProviderV3, + ImageModelV3, SpeechModelV2, TranscriptionModelV2, } from '@ai-sdk/provider'; -import { FetchFunction, loadApiKey, loadSetting } from '@ai-sdk/provider-utils'; - -export interface AzureOpenAIProvider extends ProviderV2 { +import { + FetchFunction, + loadApiKey, + loadSetting, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; +import { VERSION } from './version'; + +export interface AzureOpenAIProvider extends ProviderV3 { (deploymentId: string): LanguageModelV2; /** @@ -43,24 +49,24 @@ Creates an Azure OpenAI completion model for text generation. /** @deprecated Use `textEmbedding` instead. */ - embedding(deploymentId: string): EmbeddingModelV2; + embedding(deploymentId: string): EmbeddingModelV3; /** * Creates an Azure OpenAI DALL-E model for image generation. */ - image(deploymentId: string): ImageModelV2; + image(deploymentId: string): ImageModelV3; /** * Creates an Azure OpenAI DALL-E model for image generation. */ - imageModel(deploymentId: string): ImageModelV2; + imageModel(deploymentId: string): ImageModelV3; - textEmbedding(deploymentId: string): EmbeddingModelV2; + textEmbedding(deploymentId: string): EmbeddingModelV3; /** Creates an Azure OpenAI model for text embeddings. */ - textEmbeddingModel(deploymentId: string): EmbeddingModelV2; + textEmbeddingModel(deploymentId: string): EmbeddingModelV3; /** * Creates an Azure OpenAI model for audio transcription. @@ -124,14 +130,17 @@ Create an Azure OpenAI provider instance. export function createAzure( options: AzureOpenAIProviderSettings = {}, ): AzureOpenAIProvider { - const getHeaders = () => ({ - 'api-key': loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'AZURE_API_KEY', - description: 'Azure OpenAI', - }), - ...options.headers, - }); + const getHeaders = () => { + const baseHeaders = { + 'api-key': loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'AZURE_API_KEY', + description: 'Azure OpenAI', + }), + ...options.headers, + }; + return withUserAgentSuffix(baseHeaders, `ai-sdk/azure/${VERSION}`); + }; const getResourceName = () => loadSetting({ diff --git a/packages/azure/src/index.ts b/packages/azure/src/index.ts index d3462582558c..cf834dd34f3e 100644 --- a/packages/azure/src/index.ts +++ b/packages/azure/src/index.ts @@ -3,3 +3,4 @@ export type { AzureOpenAIProvider, AzureOpenAIProviderSettings, } from './azure-openai-provider'; +export { VERSION } from './version'; diff --git a/packages/azure/src/version.ts b/packages/azure/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/azure/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/azure/tsup.config.ts b/packages/azure/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/azure/tsup.config.ts +++ b/packages/azure/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/azure/vitest.edge.config.js b/packages/azure/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/azure/vitest.edge.config.js +++ b/packages/azure/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/azure/vitest.node.config.js b/packages/azure/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/azure/vitest.node.config.js +++ b/packages/azure/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/baseten/.prettierignore b/packages/baseten/.prettierignore new file mode 100644 index 000000000000..5e9e46f88301 --- /dev/null +++ b/packages/baseten/.prettierignore @@ -0,0 +1,4 @@ +dist/ +node_modules/ +*.tsbuildinfo +.turbo/ \ No newline at end of file diff --git a/packages/baseten/CHANGELOG.md b/packages/baseten/CHANGELOG.md new file mode 100644 index 000000000000..f579468bff49 --- /dev/null +++ b/packages/baseten/CHANGELOG.md @@ -0,0 +1,37 @@ +# @ai-sdk/baseten + +## 1.0.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/openai-compatible@1.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/openai-compatible@1.1.0-beta.2 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- Updated dependencies [cbb1d35] + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/openai-compatible@1.1.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- 6cc9cd0: Added Baseten as a Provider for AI SDK diff --git a/packages/baseten/README.md b/packages/baseten/README.md new file mode 100644 index 000000000000..4de7a5d97110 --- /dev/null +++ b/packages/baseten/README.md @@ -0,0 +1,35 @@ +# AI SDK - Baseten Provider + +The **[Baseten provider](https://ai-sdk.dev/providers/ai-sdk-providers/baseten)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model and embedding model support for the [Baseten](https://baseten.co) platform. + +## Setup + +The Baseten provider is available in the `@ai-sdk/baseten` module. You can install it with + +```bash +npm i @ai-sdk/baseten +``` + +## Provider Instance + +You can import the default provider instance `baseten` from `@ai-sdk/baseten`: + +```ts +import { baseten } from '@ai-sdk/baseten'; +``` + +## Language Model Example (Model APIs) + +```ts +import { baseten } from '@ai-sdk/baseten'; +import { generateText } from 'ai'; + +const { text } = await generateText({ + model: baseten('deepseek-ai/DeepSeek-V3-0324'), + prompt: 'What is the meaning of life?', +}); +``` + +## Documentation + +Please check out the **[Baseten provider](https://ai-sdk.dev/providers/ai-sdk-providers/baseten)** for more information. diff --git a/packages/baseten/package.json b/packages/baseten/package.json new file mode 100644 index 000000000000..35b3d43a60b1 --- /dev/null +++ b/packages/baseten/package.json @@ -0,0 +1,67 @@ +{ + "name": "@ai-sdk/baseten", + "version": "1.0.0-beta.3", + "license": "Apache-2.0", + "sideEffects": false, + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist/**/*", + "CHANGELOG.md" + ], + "scripts": { + "build": "pnpm clean && tsup --tsconfig tsconfig.build.json", + "build:watch": "pnpm clean && tsup --watch", + "clean": "rm -rf dist *.tsbuildinfo", + "lint": "eslint \"./**/*.ts*\"", + "type-check": "tsc --build", + "prettier-check": "prettier --check \"./**/*.ts*\"", + "test": "pnpm test:node && pnpm test:edge", + "test:update": "pnpm test:node -u", + "test:watch": "vitest --config vitest.node.config.js", + "test:edge": "vitest --config vitest.edge.config.js --run", + "test:node": "vitest --config vitest.node.config.js --run" + }, + "exports": { + "./package.json": "./package.json", + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.js" + } + }, + "dependencies": { + "@ai-sdk/openai-compatible": "workspace:*", + "@ai-sdk/provider": "workspace:*", + "@ai-sdk/provider-utils": "workspace:*", + "@basetenlabs/performance-client": "^0.0.8" + }, + "devDependencies": { + "@types/node": "20.17.24", + "@vercel/ai-tsconfig": "workspace:*", + "tsup": "^8", + "typescript": "5.8.3", + "zod": "3.25.76" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4" + }, + "engines": { + "node": ">=18" + }, + "publishConfig": { + "access": "public" + }, + "homepage": "https://ai-sdk.dev/docs", + "repository": { + "type": "git", + "url": "git+https://github.com/vercel/ai.git" + }, + "bugs": { + "url": "https://github.com/vercel/ai/issues" + }, + "keywords": [ + "ai" + ] +} diff --git a/packages/baseten/src/baseten-chat-options.ts b/packages/baseten/src/baseten-chat-options.ts new file mode 100644 index 000000000000..7fd66c228bd7 --- /dev/null +++ b/packages/baseten/src/baseten-chat-options.ts @@ -0,0 +1,13 @@ +// https://docs.baseten.co/development/model-apis/overview#supported-models +// Below is the current list of models supported by Baseten model APIs. +// Ohter dedicated models are also supported, but not listed here. +export type BasetenChatModelId = + | 'deepseek-ai/DeepSeek-R1-0528' + | 'deepseek-ai/DeepSeek-V3-0324' + | 'meta-llama/Llama-4-Maverick-17B-128E-Instruct' + | 'meta-llama/Llama-4-Scout-17B-16E-Instruct' + | 'moonshotai/Kimi-K2-Instruct' + | 'Qwen/Qwen3-235B-A22B-Instruct-2507' + | 'Qwen/Qwen3-Coder-480B-A35B-Instruct' + | 'openai/gpt-oss-120b' + | (string & {}); diff --git a/packages/baseten/src/baseten-embedding-options.ts b/packages/baseten/src/baseten-embedding-options.ts new file mode 100644 index 000000000000..d88e036ce51c --- /dev/null +++ b/packages/baseten/src/baseten-embedding-options.ts @@ -0,0 +1,12 @@ +import { z } from 'zod/v4'; + +// https://www.baseten.co/library/tag/embedding/ +// Pass in the model URL directly, we won't be using the model ID + +export type BasetenEmbeddingModelId = string & {}; + +export const basetenEmbeddingProviderOptions = z.object({}); + +export type BasetenEmbeddingProviderOptions = z.infer< + typeof basetenEmbeddingProviderOptions +>; diff --git a/packages/baseten/src/baseten-provider.ts b/packages/baseten/src/baseten-provider.ts new file mode 100644 index 000000000000..6e9b34f8ba1a --- /dev/null +++ b/packages/baseten/src/baseten-provider.ts @@ -0,0 +1,240 @@ +import { + OpenAICompatibleChatLanguageModel, + OpenAICompatibleEmbeddingModel, + ProviderErrorStructure, +} from '@ai-sdk/openai-compatible'; +import { + EmbeddingModelV3, + LanguageModelV2, + NoSuchModelError, + ProviderV3, +} from '@ai-sdk/provider'; +import { + FetchFunction, + loadApiKey, + withoutTrailingSlash, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; +import { z } from 'zod/v4'; +import { BasetenChatModelId } from './baseten-chat-options'; +import { BasetenEmbeddingModelId } from './baseten-embedding-options'; +import { PerformanceClient } from '@basetenlabs/performance-client'; +import { VERSION } from './version'; + +export type BasetenErrorData = z.infer; + +const basetenErrorSchema = z.object({ + error: z.string(), +}); + +const basetenErrorStructure: ProviderErrorStructure = { + errorSchema: basetenErrorSchema, + errorToMessage: data => data.error, +}; + +export interface BasetenProviderSettings { + /** + * Baseten API key. Default value is taken from the `BASETEN_API_KEY` + * environment variable. + */ + apiKey?: string; + + /** + * Base URL for the Model APIs. Default: 'https://inference.baseten.co/v1' + */ + baseURL?: string; + + /** + * Model URL for custom models (chat or embeddings). + * If not supplied, the default Model APIs will be used. + */ + modelURL?: string; + /** + * Custom headers to include in the requests. + */ + headers?: Record; + + /** + * Custom fetch implementation. You can use it as a middleware to intercept requests, + * or to provide a custom fetch implementation for e.g. testing. + */ + fetch?: FetchFunction; +} + +export interface BasetenProvider extends ProviderV3 { + /** +Creates a chat model for text generation. +*/ + (modelId?: BasetenChatModelId): LanguageModelV2; + + /** +Creates a chat model for text generation. +*/ + chatModel(modelId?: BasetenChatModelId): LanguageModelV2; + + /** +Creates a language model for text generation. Alias for chatModel. +*/ + languageModel(modelId?: BasetenChatModelId): LanguageModelV2; + + /** +Creates a text embedding model for text generation. +*/ + textEmbeddingModel( + modelId?: BasetenEmbeddingModelId, + ): EmbeddingModelV3; +} + +// by default, we use the Model APIs +const defaultBaseURL = 'https://inference.baseten.co/v1'; + +export function createBaseten( + options: BasetenProviderSettings = {}, +): BasetenProvider { + const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'BASETEN_API_KEY', + description: 'Baseten API key', + })}`, + ...options.headers, + }, + `ai-sdk/baseten/${VERSION}`, + ); + + interface CommonModelConfig { + provider: string; + url: ({ path }: { path: string }) => string; + headers: () => Record; + fetch?: FetchFunction; + } + + const getCommonModelConfig = ( + modelType: string, + customURL?: string, + ): CommonModelConfig => ({ + provider: `baseten.${modelType}`, + url: ({ path }) => { + // For embeddings with /sync URLs (but not /sync/v1), we need to add /v1 + if ( + modelType === 'embedding' && + customURL?.includes('/sync') && + !customURL?.includes('/sync/v1') + ) { + return `${customURL}/v1${path}`; + } + return `${customURL || baseURL}${path}`; + }, + headers: getHeaders, + fetch: options.fetch, + }); + + const createChatModel = (modelId?: BasetenChatModelId) => { + // Use modelURL if provided, otherwise use default Model APIs + const customURL = options.modelURL; + + if (customURL) { + // Check if this is a /sync/v1 endpoint (OpenAI-compatible) or /predict endpoint (custom) + const isOpenAICompatible = customURL.includes('/sync/v1'); + + if (isOpenAICompatible) { + // For /sync/v1 endpoints, use standard OpenAI-compatible format + return new OpenAICompatibleChatLanguageModel(modelId ?? 'placeholder', { + ...getCommonModelConfig('chat', customURL), + errorStructure: basetenErrorStructure, + }); + } else if (customURL.includes('/predict')) { + throw new Error( + 'Not supported. You must use a /sync/v1 endpoint for chat models.', + ); + } + } + + // Use default OpenAI-compatible format for Model APIs + return new OpenAICompatibleChatLanguageModel(modelId ?? 'chat', { + ...getCommonModelConfig('chat'), + errorStructure: basetenErrorStructure, + }); + }; + + const createTextEmbeddingModel = (modelId?: BasetenEmbeddingModelId) => { + // Use modelURL if provided + const customURL = options.modelURL; + if (!customURL) { + throw new Error( + 'No model URL provided for embeddings. Please set modelURL option for embeddings.', + ); + } + + // Check if this is a /sync or /sync/v1 endpoint (OpenAI-compatible) + // We support both /sync and /sync/v1, stripping /v1 before passing to Performance Client, as Performance Client adds /v1 itself + const isOpenAICompatible = customURL.includes('/sync'); + + if (isOpenAICompatible) { + // Create the model using OpenAICompatibleEmbeddingModel and override doEmbed + const model = new OpenAICompatibleEmbeddingModel( + modelId ?? 'embeddings', + { + ...getCommonModelConfig('embedding', customURL), + errorStructure: basetenErrorStructure, + }, + ); + + // Strip /v1 from URL if present before passing to Performance Client to avoid double /v1 + const performanceClientURL = customURL.replace('/sync/v1', '/sync'); + + // Initialize the B10 Performance Client once for reuse + const performanceClient = new PerformanceClient( + performanceClientURL, + loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'BASETEN_API_KEY', + description: 'Baseten API key', + }), + ); + + // Override the doEmbed method to use the pre-created Performance Client + model.doEmbed = async params => { + if (!params.values || !Array.isArray(params.values)) { + throw new Error('params.values must be an array of strings'); + } + + // Performance Client handles batching internally, so we don't need to limit in 128 here + const response = await performanceClient.embed( + params.values, + modelId ?? 'embeddings', // model_id is for Model APIs, we don't use it here for dedicated + ); + // Transform the response to match the expected format + const embeddings = response.data.map((item: any) => item.embedding); + + return { + embeddings: embeddings, + usage: response.usage + ? { tokens: response.usage.total_tokens } + : undefined, + response: { headers: {}, body: response }, + }; + }; + + return model; + } else { + throw new Error( + 'Not supported. You must use a /sync or /sync/v1 endpoint for embeddings.', + ); + } + }; + + const provider = (modelId?: BasetenChatModelId) => createChatModel(modelId); + provider.chatModel = createChatModel; + provider.languageModel = createChatModel; + provider.imageModel = (modelId: string) => { + throw new NoSuchModelError({ modelId, modelType: 'imageModel' }); + }; + provider.textEmbeddingModel = createTextEmbeddingModel; + return provider; +} + +export const baseten = createBaseten(); diff --git a/packages/baseten/src/baseten-provider.unit.test.ts b/packages/baseten/src/baseten-provider.unit.test.ts new file mode 100644 index 000000000000..bd6b74d2d7db --- /dev/null +++ b/packages/baseten/src/baseten-provider.unit.test.ts @@ -0,0 +1,446 @@ +import { describe, it, expect, vi, beforeEach, Mock } from 'vitest'; +import { createBaseten } from './baseten-provider'; +import { + LanguageModelV2, + EmbeddingModelV3, + NoSuchModelError, +} from '@ai-sdk/provider'; +import { loadApiKey } from '@ai-sdk/provider-utils'; +import { + OpenAICompatibleChatLanguageModel, + OpenAICompatibleEmbeddingModel, +} from '@ai-sdk/openai-compatible'; + +// Mock the OpenAI-compatible classes +const OpenAICompatibleChatLanguageModelMock = + OpenAICompatibleChatLanguageModel as unknown as Mock; +const OpenAICompatibleEmbeddingModelMock = + OpenAICompatibleEmbeddingModel as unknown as Mock; + +vi.mock('@ai-sdk/openai-compatible', () => { + const createMockConstructor = (providerName: string) => { + const mockConstructor = vi.fn().mockImplementation(function ( + this: any, + modelId: string, + settings: any, + ) { + this.provider = providerName; + this.modelId = modelId; + this.settings = settings; + this.doGenerate = vi.fn(); + this.doEmbed = vi.fn(); + }); + return mockConstructor; + }; + + return { + OpenAICompatibleChatLanguageModel: createMockConstructor('baseten.chat'), + OpenAICompatibleEmbeddingModel: createMockConstructor('baseten.embedding'), + }; +}); + +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + loadApiKey: vi.fn().mockReturnValue('mock-api-key'), + withoutTrailingSlash: vi.fn(url => url), + }; +}); + +vi.mock('@basetenlabs/performance-client', () => ({ + PerformanceClient: vi.fn().mockImplementation(() => ({ + embed: vi.fn(), + embedBatch: vi.fn(), + })), +})); + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); + +describe('BasetenProvider', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('createBaseten', () => { + it('should create a BasetenProvider instance with default options', () => { + const provider = createBaseten(); + const model = provider.chatModel('deepseek-ai/DeepSeek-V3-0324'); + + const constructorCall = + OpenAICompatibleChatLanguageModelMock.mock.calls[0]; + const config = constructorCall[1]; + const headers = config.headers(); + + expect(loadApiKey).toHaveBeenCalledWith({ + apiKey: undefined, + environmentVariableName: 'BASETEN_API_KEY', + description: 'Baseten API key', + }); + expect(headers.authorization).toBe('Bearer mock-api-key'); + expect(config.provider).toBe('baseten.chat'); + }); + + it('should create a BasetenProvider instance with custom options', () => { + const options = { + apiKey: 'custom-key', + baseURL: 'https://custom.url', + headers: { 'Custom-Header': 'value' }, + }; + const provider = createBaseten(options); + const model = provider.chatModel('deepseek-ai/DeepSeek-V3-0324'); + + const constructorCall = + OpenAICompatibleChatLanguageModelMock.mock.calls[0]; + const config = constructorCall[1]; + const headers = config.headers(); + + expect(loadApiKey).toHaveBeenCalledWith({ + apiKey: 'custom-key', + environmentVariableName: 'BASETEN_API_KEY', + description: 'Baseten API key', + }); + expect(headers['custom-header']).toBe('value'); + }); + + it('should support optional modelId parameter', () => { + const provider = createBaseten(); + + // Should work without modelId + const model1 = provider(); + expect(model1).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + + // Should work with modelId + const model2 = provider('deepseek-ai/DeepSeek-V3-0324'); + expect(model2).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + }); + }); + + describe('chatModel', () => { + it('should construct a chat model with correct configuration for default Model APIs', () => { + const provider = createBaseten(); + const modelId = 'deepseek-ai/DeepSeek-V3-0324'; + + const model = provider.chatModel(modelId); + + expect(model).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + expect(OpenAICompatibleChatLanguageModelMock).toHaveBeenCalledWith( + modelId, + expect.objectContaining({ + provider: 'baseten.chat', + errorStructure: expect.any(Object), + }), + ); + }); + + it('should construct a chat model with optional modelId', () => { + const provider = createBaseten(); + + // Should work without modelId + const model1 = provider.chatModel(); + expect(model1).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + expect(OpenAICompatibleChatLanguageModelMock).toHaveBeenCalledWith( + 'chat', + expect.any(Object), + ); + + // Should work with modelId + const model2 = provider.chatModel('deepseek-ai/DeepSeek-V3-0324'); + expect(model2).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + }); + + it('should handle /sync/v1 endpoints correctly', () => { + const provider = createBaseten({ + modelURL: + 'https://model-123.api.baseten.co/environments/production/sync/v1', + }); + + const model = provider.chatModel(); + + expect(model).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + expect(OpenAICompatibleChatLanguageModelMock).toHaveBeenCalledWith( + 'placeholder', + expect.objectContaining({ + provider: 'baseten.chat', + url: expect.any(Function), + errorStructure: expect.any(Object), + }), + ); + + // Test URL construction + const constructorCall = + OpenAICompatibleChatLanguageModelMock.mock.calls[0]; + const config = constructorCall[1]; + const url = config.url({ path: '/chat/completions' }); + expect(url).toBe( + 'https://model-123.api.baseten.co/environments/production/sync/v1/chat/completions', + ); + }); + + it('should throw error for /predict endpoints with chat models', () => { + const provider = createBaseten({ + modelURL: + 'https://model-123.api.baseten.co/environments/production/predict', + }); + + expect(() => { + provider.chatModel(); + }).toThrow( + 'Not supported. You must use a /sync/v1 endpoint for chat models.', + ); + }); + }); + + describe('languageModel', () => { + it('should be an alias for chatModel', () => { + const provider = createBaseten(); + const modelId = 'deepseek-ai/DeepSeek-V3-0324'; + + const chatModel = provider.chatModel(modelId); + const languageModel = provider.languageModel(modelId); + + expect(chatModel).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + expect(languageModel).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + }); + + it('should support optional modelId parameter', () => { + const provider = createBaseten(); + + const model1 = provider.languageModel(); + expect(model1).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + + const model2 = provider.languageModel('deepseek-ai/DeepSeek-V3-0324'); + expect(model2).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + }); + }); + + describe('textEmbeddingModel', () => { + it('should throw error when no modelURL is provided', () => { + const provider = createBaseten(); + + expect(() => { + provider.textEmbeddingModel(); + }).toThrow( + 'No model URL provided for embeddings. Please set modelURL option for embeddings.', + ); + }); + + it('should construct embedding model for /sync endpoints', () => { + const provider = createBaseten({ + modelURL: + 'https://model-123.api.baseten.co/environments/production/sync', + }); + + const model = provider.textEmbeddingModel(); + + expect(model).toBeInstanceOf(OpenAICompatibleEmbeddingModel); + expect(OpenAICompatibleEmbeddingModelMock).toHaveBeenCalledWith( + 'embeddings', + expect.objectContaining({ + provider: 'baseten.embedding', + url: expect.any(Function), + errorStructure: expect.any(Object), + }), + ); + + // Test URL construction for embeddings (Performance Client adds /v1/embeddings) + const constructorCall = OpenAICompatibleEmbeddingModelMock.mock.calls[0]; + const config = constructorCall[1]; + const url = config.url({ path: '/embeddings' }); + expect(url).toBe( + 'https://model-123.api.baseten.co/environments/production/sync/v1/embeddings', + ); + }); + + it('should throw error for /predict endpoints (not supported with Performance Client)', () => { + const provider = createBaseten({ + modelURL: + 'https://model-123.api.baseten.co/environments/production/predict', + }); + + expect(() => { + provider.textEmbeddingModel(); + }).toThrow( + 'Not supported. You must use a /sync or /sync/v1 endpoint for embeddings.', + ); + }); + + it('should support /sync/v1 endpoints (strips /v1 before passing to Performance Client)', () => { + const provider = createBaseten({ + modelURL: + 'https://model-123.api.baseten.co/environments/production/sync/v1', + }); + + const model = provider.textEmbeddingModel(); + + expect(model).toBeInstanceOf(OpenAICompatibleEmbeddingModel); + expect(OpenAICompatibleEmbeddingModelMock).toHaveBeenCalledWith( + 'embeddings', + expect.any(Object), + ); + }); + + it('should support custom modelId for embeddings', () => { + const provider = createBaseten({ + modelURL: + 'https://model-123.api.baseten.co/environments/production/sync', + }); + + const model = provider.textEmbeddingModel(); + + expect(model).toBeInstanceOf(OpenAICompatibleEmbeddingModel); + expect(OpenAICompatibleEmbeddingModelMock).toHaveBeenCalledWith( + 'embeddings', + expect.any(Object), + ); + }); + }); + + describe('imageModel', () => { + it('should throw NoSuchModelError for unsupported image models', () => { + const provider = createBaseten(); + + expect(() => { + provider.imageModel('test-model'); + }).toThrow(NoSuchModelError); + }); + }); + + describe('URL construction', () => { + it('should use default baseURL when no modelURL is provided', () => { + const provider = createBaseten(); + const model = provider.chatModel('test-model'); + + const constructorCall = + OpenAICompatibleChatLanguageModelMock.mock.calls[0]; + const config = constructorCall[1]; + const url = config.url({ path: '/chat/completions' }); + expect(url).toBe('https://inference.baseten.co/v1/chat/completions'); + }); + + it('should use custom baseURL when provided', () => { + const provider = createBaseten({ + baseURL: 'https://custom.baseten.co/v1', + }); + const model = provider.chatModel('test-model'); + + const constructorCall = + OpenAICompatibleChatLanguageModelMock.mock.calls[0]; + const config = constructorCall[1]; + const url = config.url({ path: '/chat/completions' }); + expect(url).toBe('https://custom.baseten.co/v1/chat/completions'); + }); + + it('should use modelURL for custom endpoints', () => { + const provider = createBaseten({ + modelURL: + 'https://model-123.api.baseten.co/environments/production/sync/v1', + }); + const model = provider.chatModel(); + + const constructorCall = + OpenAICompatibleChatLanguageModelMock.mock.calls[0]; + const config = constructorCall[1]; + const url = config.url({ path: '/chat/completions' }); + expect(url).toBe( + 'https://model-123.api.baseten.co/environments/production/sync/v1/chat/completions', + ); + }); + }); + + describe('Headers', () => { + it('should include Authorization header with API key', () => { + const provider = createBaseten(); + const model = provider.chatModel('test-model'); + + const constructorCall = + OpenAICompatibleChatLanguageModelMock.mock.calls[0]; + const config = constructorCall[1]; + const headers = config.headers(); + + expect(headers.authorization).toBe('Bearer mock-api-key'); + }); + + it('should include custom headers when provided', () => { + const provider = createBaseten({ + headers: { 'Custom-Header': 'custom-value' }, + }); + const model = provider.chatModel('test-model'); + + const constructorCall = + OpenAICompatibleChatLanguageModelMock.mock.calls[0]; + const config = constructorCall[1]; + const headers = config.headers(); + + expect(headers.authorization).toBe('Bearer mock-api-key'); + expect(headers['custom-header']).toBe('custom-value'); + }); + + it('should include user-agent with version', async () => { + const fetchMock = vi + .fn() + .mockResolvedValue(new Response('{}', { status: 200 })); + + const provider = createBaseten({ fetch: fetchMock }); + const model = provider.chatModel('test-model'); + + const constructorCall = + OpenAICompatibleChatLanguageModelMock.mock.calls[0]; + const config = constructorCall[1]; + const headers = config.headers(); + + await fetchMock('https://example.com/test', { + method: 'POST', + headers, + }); + + expect(fetchMock.mock.calls[0][1].headers['user-agent']).toContain( + 'ai-sdk/baseten/0.0.0-test', + ); + }); + }); + + describe('Error handling', () => { + it('should handle missing modelURL for embeddings gracefully', () => { + const provider = createBaseten(); + + expect(() => { + provider.textEmbeddingModel(); + }).toThrow( + 'No model URL provided for embeddings. Please set modelURL option for embeddings.', + ); + }); + + it('should handle unsupported image models', () => { + const provider = createBaseten(); + + expect(() => { + provider.imageModel('unsupported-model'); + }).toThrow(NoSuchModelError); + }); + }); + + describe('Provider interface', () => { + it('should implement all required provider methods', () => { + const provider = createBaseten(); + + expect(typeof provider).toBe('function'); + expect(typeof provider.chatModel).toBe('function'); + expect(typeof provider.languageModel).toBe('function'); + expect(typeof provider.textEmbeddingModel).toBe('function'); + expect(typeof provider.imageModel).toBe('function'); + }); + + it('should allow calling provider as function', () => { + const provider = createBaseten(); + + const model1 = provider(); + expect(model1).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + + const model2 = provider('test-model'); + expect(model2).toBeInstanceOf(OpenAICompatibleChatLanguageModel); + }); + }); +}); diff --git a/packages/baseten/src/index.ts b/packages/baseten/src/index.ts new file mode 100644 index 000000000000..3bb8b2ead351 --- /dev/null +++ b/packages/baseten/src/index.ts @@ -0,0 +1,8 @@ +export type { BasetenChatModelId } from './baseten-chat-options'; +export { baseten, createBaseten } from './baseten-provider'; +export type { + BasetenProvider, + BasetenProviderSettings, + BasetenErrorData, +} from './baseten-provider'; +export { VERSION } from './version'; diff --git a/packages/baseten/src/version.ts b/packages/baseten/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/baseten/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/baseten/tsconfig.build.json b/packages/baseten/tsconfig.build.json new file mode 100644 index 000000000000..8181e407dd6d --- /dev/null +++ b/packages/baseten/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + // Disable project configuration for tsup builds + "composite": false + } +} diff --git a/packages/baseten/tsconfig.json b/packages/baseten/tsconfig.json new file mode 100644 index 000000000000..6c6ee8ebe46a --- /dev/null +++ b/packages/baseten/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "./node_modules/@vercel/ai-tsconfig/ts-library.json", + "compilerOptions": { + "composite": true, + "rootDir": "src", + "outDir": "dist" + }, + "exclude": ["dist", "build", "node_modules", "tsup.config.ts"], + "references": [ + { + "path": "../openai-compatible" + }, + { + "path": "../provider" + }, + { + "path": "../provider-utils" + }, + { + "path": "../ai" + } + ] +} diff --git a/packages/baseten/tsup.config.ts b/packages/baseten/tsup.config.ts new file mode 100644 index 000000000000..da74c084b2f1 --- /dev/null +++ b/packages/baseten/tsup.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'tsup'; +import packageJson from './package.json'; + +export default defineConfig([ + { + entry: ['src/index.ts'], + format: ['cjs', 'esm'], + dts: true, + sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, + }, +]); diff --git a/packages/baseten/turbo.json b/packages/baseten/turbo.json new file mode 100644 index 000000000000..3e50dc890ace --- /dev/null +++ b/packages/baseten/turbo.json @@ -0,0 +1,8 @@ +{ + "extends": ["//"], + "tasks": { + "build": { + "outputs": ["**/dist/**"] + } + } +} diff --git a/packages/baseten/vitest.edge.config.js b/packages/baseten/vitest.edge.config.js new file mode 100644 index 000000000000..838aa2f38c40 --- /dev/null +++ b/packages/baseten/vitest.edge.config.js @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; +import packageJson from './package.json'; + +// https://vitejs.dev/config/ +export default defineConfig({ + test: { + environment: 'edge-runtime', + globals: true, + include: ['**/*.test.ts', '**/*.test.tsx'], + }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, +}); diff --git a/packages/baseten/vitest.node.config.js b/packages/baseten/vitest.node.config.js new file mode 100644 index 000000000000..1c97a185facd --- /dev/null +++ b/packages/baseten/vitest.node.config.js @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; +import packageJson from './package.json'; + +// https://vitejs.dev/config/ +export default defineConfig({ + test: { + environment: 'node', + globals: true, + include: ['**/*.test.ts', '**/*.test.tsx'], + }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, +}); diff --git a/packages/cerebras/CHANGELOG.md b/packages/cerebras/CHANGELOG.md index a8801f10a302..8f18088cc9b5 100644 --- a/packages/cerebras/CHANGELOG.md +++ b/packages/cerebras/CHANGELOG.md @@ -1,5 +1,75 @@ # @ai-sdk/cerebras +## 1.1.0-beta.4 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/openai-compatible@1.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.3 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/openai-compatible@1.1.0-beta.2 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.2 + +### Patch Changes + +- 4d34a89: feat (provider/cerebras): enable structured outputs + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [cbb1d35] + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/openai-compatible@1.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/openai-compatible@1.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.18 + +### Patch Changes + +- Updated dependencies [28363da] + - @ai-sdk/openai-compatible@1.0.18 + +## 1.0.17 + +### Patch Changes + +- Updated dependencies [3aed04c] + - @ai-sdk/openai-compatible@1.0.17 + +## 1.0.16 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/openai-compatible@1.0.16 + ## 1.0.15 ### Patch Changes diff --git a/packages/cerebras/package.json b/packages/cerebras/package.json index 49ff6c819a62..be5a28325a4d 100644 --- a/packages/cerebras/package.json +++ b/packages/cerebras/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/cerebras", - "version": "1.0.15", + "version": "1.1.0-beta.4", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/cerebras/src/cerebras-provider.test.ts b/packages/cerebras/src/cerebras-provider.test.ts index 80480332a8df..8cbef81b58e6 100644 --- a/packages/cerebras/src/cerebras-provider.test.ts +++ b/packages/cerebras/src/cerebras-provider.test.ts @@ -11,11 +11,19 @@ vi.mock('@ai-sdk/openai-compatible', () => ({ OpenAICompatibleChatLanguageModel: vi.fn(), })); -vi.mock('@ai-sdk/provider-utils', () => ({ - loadApiKey: vi.fn().mockReturnValue('mock-api-key'), - withoutTrailingSlash: vi.fn(url => url), +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', })); +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + loadApiKey: vi.fn().mockReturnValue('mock-api-key'), + withoutTrailingSlash: vi.fn(url => url), + }; +}); + describe('CerebrasProvider', () => { beforeEach(() => { vi.clearAllMocks(); @@ -59,6 +67,29 @@ describe('CerebrasProvider', () => { }); }); + it('should pass header', async () => { + const fetchMock = vi + .fn() + .mockResolvedValue(new Response('{}', { status: 200 })); + + const provider = createCerebras({ fetch: fetchMock }); + provider('model-id'); + + const constructorCall = vi.mocked(OpenAICompatibleChatLanguageModel).mock + .calls[0]; + const config = constructorCall[1]; + const headers = config.headers(); + + await fetchMock('https://api.cerebras.ai/v1/test', { + method: 'POST', + headers, + }); + + expect(fetchMock.mock.calls[0][1].headers['user-agent']).toContain( + 'ai-sdk/cerebras/0.0.0-test', + ); + }); + it('should return a chat model when called as a function', () => { const provider = createCerebras(); const modelId = 'foo-model-id'; diff --git a/packages/cerebras/src/cerebras-provider.ts b/packages/cerebras/src/cerebras-provider.ts index 8bf15eb168a4..8bd906ba2c8f 100644 --- a/packages/cerebras/src/cerebras-provider.ts +++ b/packages/cerebras/src/cerebras-provider.ts @@ -2,16 +2,18 @@ import { OpenAICompatibleChatLanguageModel } from '@ai-sdk/openai-compatible'; import { LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { CerebrasChatModelId } from './cerebras-chat-options'; import { z } from 'zod/v4'; import { ProviderErrorStructure } from '@ai-sdk/openai-compatible'; +import { VERSION } from './version'; // Add error schema and structure const cerebrasErrorSchema = z.object({ @@ -48,7 +50,7 @@ or to provide a custom fetch implementation for e.g. testing. fetch?: FetchFunction; } -export interface CerebrasProvider extends ProviderV2 { +export interface CerebrasProvider extends ProviderV3 { /** Creates a Cerebras model for text generation. */ @@ -71,14 +73,18 @@ export function createCerebras( const baseURL = withoutTrailingSlash( options.baseURL ?? 'https://api.cerebras.ai/v1', ); - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'CEREBRAS_API_KEY', - description: 'Cerebras API key', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'CEREBRAS_API_KEY', + description: 'Cerebras API key', + })}`, + ...options.headers, + }, + `ai-sdk/cerebras/${VERSION}`, + ); const createLanguageModel = (modelId: CerebrasChatModelId) => { return new OpenAICompatibleChatLanguageModel(modelId, { @@ -87,6 +93,7 @@ export function createCerebras( headers: getHeaders, fetch: options.fetch, errorStructure: cerebrasErrorStructure, + supportsStructuredOutputs: true, }); }; diff --git a/packages/cerebras/src/index.ts b/packages/cerebras/src/index.ts index 1f047216e861..17c7be327c06 100644 --- a/packages/cerebras/src/index.ts +++ b/packages/cerebras/src/index.ts @@ -4,3 +4,4 @@ export type { CerebrasProviderSettings, } from './cerebras-provider'; export type { CerebrasErrorData } from './cerebras-provider'; +export { VERSION } from './version'; diff --git a/packages/cerebras/src/version.ts b/packages/cerebras/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/cerebras/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/cerebras/tsup.config.ts b/packages/cerebras/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/cerebras/tsup.config.ts +++ b/packages/cerebras/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/cerebras/vitest.edge.config.js b/packages/cerebras/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/cerebras/vitest.edge.config.js +++ b/packages/cerebras/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/cerebras/vitest.node.config.js b/packages/cerebras/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/cerebras/vitest.node.config.js +++ b/packages/cerebras/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/codemod/CHANGELOG.md b/packages/codemod/CHANGELOG.md index 8e0147060fcf..05dabda4013b 100644 --- a/packages/codemod/CHANGELOG.md +++ b/packages/codemod/CHANGELOG.md @@ -1,5 +1,11 @@ # @ai-sdk/codemod +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + ## 2.0.10 ### Patch Changes diff --git a/packages/codemod/package.json b/packages/codemod/package.json index 653ad92cd2df..363cc796ae09 100644 --- a/packages/codemod/package.json +++ b/packages/codemod/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/codemod", - "version": "2.0.10", + "version": "2.1.0-beta.0", "license": "Apache-2.0", "sideEffects": false, "files": [ diff --git a/packages/cohere/CHANGELOG.md b/packages/cohere/CHANGELOG.md index 52f70baf45d7..71aba960206c 100644 --- a/packages/cohere/CHANGELOG.md +++ b/packages/cohere/CHANGELOG.md @@ -1,5 +1,53 @@ # @ai-sdk/cohere +## 2.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.2 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.10 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 2.0.9 ### Patch Changes diff --git a/packages/cohere/package.json b/packages/cohere/package.json index 29546abcd843..da1b043eb67e 100644 --- a/packages/cohere/package.json +++ b/packages/cohere/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/cohere", - "version": "2.0.9", + "version": "2.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -33,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/cohere/src/cohere-chat-language-model.test.ts b/packages/cohere/src/cohere-chat-language-model.test.ts index 0f9ccebdca2d..90357371ea95 100644 --- a/packages/cohere/src/cohere-chat-language-model.test.ts +++ b/packages/cohere/src/cohere-chat-language-model.test.ts @@ -1,7 +1,7 @@ import { LanguageModelV2Prompt } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, isNodeVersion, } from '@ai-sdk/provider-utils/test'; import { createCohere } from './cohere-provider'; diff --git a/packages/cohere/src/cohere-embedding-model.test.ts b/packages/cohere/src/cohere-embedding-model.test.ts index 135e83b94494..c8fa45b8a338 100644 --- a/packages/cohere/src/cohere-embedding-model.test.ts +++ b/packages/cohere/src/cohere-embedding-model.test.ts @@ -1,7 +1,11 @@ -import { EmbeddingModelV2Embedding } from '@ai-sdk/provider'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { EmbeddingModelV3Embedding } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createCohere } from './cohere-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const dummyEmbeddings = [ [0.1, 0.2, 0.3, 0.4, 0.5], @@ -22,7 +26,7 @@ describe('doEmbed', () => { meta = { billed_units: { input_tokens: 8 } }, headers, }: { - embeddings?: EmbeddingModelV2Embedding[]; + embeddings?: EmbeddingModelV3Embedding[]; meta?: { billed_units: { input_tokens: number } }; headers?: Record; } = {}) { @@ -132,5 +136,8 @@ describe('doEmbed', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/cohere/0.0.0-test`, + ); }); }); diff --git a/packages/cohere/src/cohere-embedding-model.ts b/packages/cohere/src/cohere-embedding-model.ts index ce3db277cebc..f1b67a63b872 100644 --- a/packages/cohere/src/cohere-embedding-model.ts +++ b/packages/cohere/src/cohere-embedding-model.ts @@ -1,5 +1,5 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, TooManyEmbeddingValuesForCallError, } from '@ai-sdk/provider'; import { @@ -23,8 +23,8 @@ type CohereEmbeddingConfig = { fetch?: FetchFunction; }; -export class CohereEmbeddingModel implements EmbeddingModelV2 { - readonly specificationVersion = 'v2'; +export class CohereEmbeddingModel implements EmbeddingModelV3 { + readonly specificationVersion = 'v3'; readonly modelId: CohereEmbeddingModelId; readonly maxEmbeddingsPerCall = 96; @@ -46,8 +46,8 @@ export class CohereEmbeddingModel implements EmbeddingModelV2 { headers, abortSignal, providerOptions, - }: Parameters['doEmbed']>[0]): Promise< - Awaited['doEmbed']>> + }: Parameters['doEmbed']>[0]): Promise< + Awaited['doEmbed']>> > { const embeddingOptions = await parseProviderOptions({ provider: 'cohere', diff --git a/packages/cohere/src/cohere-provider.ts b/packages/cohere/src/cohere-provider.ts index bb9e98c05b21..4dd541475b68 100644 --- a/packages/cohere/src/cohere-provider.ts +++ b/packages/cohere/src/cohere-provider.ts @@ -1,21 +1,23 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, generateId, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { CohereChatLanguageModel } from './cohere-chat-language-model'; import { CohereChatModelId } from './cohere-chat-options'; import { CohereEmbeddingModel } from './cohere-embedding-model'; import { CohereEmbeddingModelId } from './cohere-embedding-options'; +import { VERSION } from './version'; -export interface CohereProvider extends ProviderV2 { +export interface CohereProvider extends ProviderV3 { (modelId: CohereChatModelId): LanguageModelV2; /** @@ -23,9 +25,9 @@ Creates a model for text generation. */ languageModel(modelId: CohereChatModelId): LanguageModelV2; - embedding(modelId: CohereEmbeddingModelId): EmbeddingModelV2; + embedding(modelId: CohereEmbeddingModelId): EmbeddingModelV3; - textEmbeddingModel(modelId: CohereEmbeddingModelId): EmbeddingModelV2; + textEmbeddingModel(modelId: CohereEmbeddingModelId): EmbeddingModelV3; } export interface CohereProviderSettings { @@ -67,14 +69,18 @@ export function createCohere( const baseURL = withoutTrailingSlash(options.baseURL) ?? 'https://api.cohere.com/v2'; - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'COHERE_API_KEY', - description: 'Cohere', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'COHERE_API_KEY', + description: 'Cohere', + })}`, + ...options.headers, + }, + `ai-sdk/cohere/${VERSION}`, + ); const createChatModel = (modelId: CohereChatModelId) => new CohereChatLanguageModel(modelId, { diff --git a/packages/cohere/src/index.ts b/packages/cohere/src/index.ts index d36326be7bce..164cab7dfe91 100644 --- a/packages/cohere/src/index.ts +++ b/packages/cohere/src/index.ts @@ -1,3 +1,4 @@ export { cohere, createCohere } from './cohere-provider'; export type { CohereProvider, CohereProviderSettings } from './cohere-provider'; export type { CohereChatModelOptions } from './cohere-chat-options'; +export { VERSION } from './version'; diff --git a/packages/cohere/src/version.ts b/packages/cohere/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/cohere/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/cohere/tsup.config.ts b/packages/cohere/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/cohere/tsup.config.ts +++ b/packages/cohere/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/cohere/vitest.edge.config.js b/packages/cohere/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/cohere/vitest.edge.config.js +++ b/packages/cohere/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/cohere/vitest.node.config.js b/packages/cohere/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/cohere/vitest.node.config.js +++ b/packages/cohere/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/deepgram/CHANGELOG.md b/packages/deepgram/CHANGELOG.md index abfcbe822479..e8e419cc3b76 100644 --- a/packages/deepgram/CHANGELOG.md +++ b/packages/deepgram/CHANGELOG.md @@ -1,5 +1,52 @@ # @ai-sdk/deepgram +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.8 ### Patch Changes diff --git a/packages/deepgram/package.json b/packages/deepgram/package.json index 86ad7196945d..cabd168bcb7a 100644 --- a/packages/deepgram/package.json +++ b/packages/deepgram/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/deepgram", - "version": "1.0.8", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -18,6 +18,7 @@ "type-check": "tsc --noEmit", "prettier-check": "prettier --check \"./**/*.ts*\"", "test": "pnpm test:node && pnpm test:edge", + "test:watch": "vitest --config vitest.node.config.js", "test:edge": "vitest --config vitest.edge.config.js --run", "test:node": "vitest --config vitest.node.config.js --run", "test:node:watch": "vitest --config vitest.node.config.js --watch" @@ -32,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/deepgram/src/deepgram-provider.ts b/packages/deepgram/src/deepgram-provider.ts index 6ff74c7ef77e..499261068069 100644 --- a/packages/deepgram/src/deepgram-provider.ts +++ b/packages/deepgram/src/deepgram-provider.ts @@ -1,13 +1,18 @@ import { TranscriptionModelV2, - ProviderV2, + ProviderV3, NoSuchModelError, } from '@ai-sdk/provider'; -import { FetchFunction, loadApiKey } from '@ai-sdk/provider-utils'; +import { + FetchFunction, + loadApiKey, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; import { DeepgramTranscriptionModel } from './deepgram-transcription-model'; import { DeepgramTranscriptionModelId } from './deepgram-transcription-options'; +import { VERSION } from './version'; -export interface DeepgramProvider extends ProviderV2 { +export interface DeepgramProvider extends ProviderV3 { ( modelId: 'nova-3', settings?: {}, @@ -45,14 +50,18 @@ Create an Deepgram provider instance. export function createDeepgram( options: DeepgramProviderSettings = {}, ): DeepgramProvider { - const getHeaders = () => ({ - authorization: `Token ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'DEEPGRAM_API_KEY', - description: 'Deepgram', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + authorization: `Token ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'DEEPGRAM_API_KEY', + description: 'Deepgram', + })}`, + ...options.headers, + }, + `ai-sdk/deepgram/${VERSION}`, + ); const createTranscriptionModel = (modelId: DeepgramTranscriptionModelId) => new DeepgramTranscriptionModel(modelId, { @@ -71,7 +80,7 @@ export function createDeepgram( provider.transcription = createTranscriptionModel; provider.transcriptionModel = createTranscriptionModel; - // Required ProviderV2 methods that are not supported + // Required ProviderV3 methods that are not supported provider.languageModel = () => { throw new NoSuchModelError({ modelId: 'unknown', diff --git a/packages/deepgram/src/deepgram-transcription-model.test.ts b/packages/deepgram/src/deepgram-transcription-model.test.ts index 83185a84fd1d..c73e4a3b1db5 100644 --- a/packages/deepgram/src/deepgram-transcription-model.test.ts +++ b/packages/deepgram/src/deepgram-transcription-model.test.ts @@ -1,9 +1,13 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { DeepgramTranscriptionModel } from './deepgram-transcription-model'; import { createDeepgram } from './deepgram-provider'; import { readFile } from 'node:fs/promises'; import path from 'node:path'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const audioData = await readFile(path.join(__dirname, 'transcript-test.mp3')); const provider = createDeepgram({ apiKey: 'test-api-key' }); @@ -124,6 +128,9 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/deepgram/0.0.0-test`, + ); }); it('should extract the transcription text', async () => { diff --git a/packages/deepgram/src/index.ts b/packages/deepgram/src/index.ts index 4abcf2461f66..e86cd82d4153 100644 --- a/packages/deepgram/src/index.ts +++ b/packages/deepgram/src/index.ts @@ -3,3 +3,4 @@ export type { DeepgramProvider, DeepgramProviderSettings, } from './deepgram-provider'; +export { VERSION } from './version'; diff --git a/packages/deepgram/src/version.ts b/packages/deepgram/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/deepgram/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/deepgram/tsup.config.ts b/packages/deepgram/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/deepgram/tsup.config.ts +++ b/packages/deepgram/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/deepgram/vitest.edge.config.js b/packages/deepgram/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/deepgram/vitest.edge.config.js +++ b/packages/deepgram/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/deepgram/vitest.node.config.js b/packages/deepgram/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/deepgram/vitest.node.config.js +++ b/packages/deepgram/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/deepinfra/CHANGELOG.md b/packages/deepinfra/CHANGELOG.md index c9110ed6f24c..458ae6b31eb1 100644 --- a/packages/deepinfra/CHANGELOG.md +++ b/packages/deepinfra/CHANGELOG.md @@ -1,5 +1,73 @@ # @ai-sdk/deepinfra +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/openai-compatible@1.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/openai-compatible@1.1.0-beta.2 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/openai-compatible@1.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/openai-compatible@1.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.18 + +### Patch Changes + +- Updated dependencies [28363da] + - @ai-sdk/openai-compatible@1.0.18 + +## 1.0.17 + +### Patch Changes + +- Updated dependencies [3aed04c] + - @ai-sdk/openai-compatible@1.0.17 + +## 1.0.16 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/openai-compatible@1.0.16 + ## 1.0.15 ### Patch Changes diff --git a/packages/deepinfra/package.json b/packages/deepinfra/package.json index b40b5f6dbbbc..3d951274c9c0 100644 --- a/packages/deepinfra/package.json +++ b/packages/deepinfra/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/deepinfra", - "version": "1.0.15", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -34,7 +34,8 @@ "dependencies": { "@ai-sdk/openai-compatible": "workspace:*", "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/deepinfra/src/deepinfra-image-model.test.ts b/packages/deepinfra/src/deepinfra-image-model.test.ts index bde06befad78..81e26f9c178e 100644 --- a/packages/deepinfra/src/deepinfra-image-model.test.ts +++ b/packages/deepinfra/src/deepinfra-image-model.test.ts @@ -1,4 +1,4 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { describe, expect, it } from 'vitest'; import { DeepInfraImageModel } from './deepinfra-image-model'; import { FetchFunction } from '@ai-sdk/provider-utils'; @@ -228,7 +228,7 @@ describe('DeepInfraImageModel', () => { expect(model.provider).toBe('deepinfra'); expect(model.modelId).toBe('stability-ai/sdxl'); - expect(model.specificationVersion).toBe('v2'); + expect(model.specificationVersion).toBe('v3'); expect(model.maxImagesPerCall).toBe(1); }); }); diff --git a/packages/deepinfra/src/deepinfra-image-model.ts b/packages/deepinfra/src/deepinfra-image-model.ts index 34790f9f218a..f339186cd610 100644 --- a/packages/deepinfra/src/deepinfra-image-model.ts +++ b/packages/deepinfra/src/deepinfra-image-model.ts @@ -1,4 +1,4 @@ -import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider'; +import { ImageModelV3, ImageModelV3CallWarning } from '@ai-sdk/provider'; import { FetchFunction, combineHeaders, @@ -19,8 +19,8 @@ interface DeepInfraImageModelConfig { }; } -export class DeepInfraImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class DeepInfraImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; readonly maxImagesPerCall = 1; get provider(): string { @@ -41,10 +41,10 @@ export class DeepInfraImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; // Some deepinfra models support size while others support aspect ratio. // Allow passing either and leave it up to the server to validate. diff --git a/packages/deepinfra/src/deepinfra-provider.test.ts b/packages/deepinfra/src/deepinfra-provider.test.ts index 53699538546f..cc59701048fd 100644 --- a/packages/deepinfra/src/deepinfra-provider.test.ts +++ b/packages/deepinfra/src/deepinfra-provider.test.ts @@ -5,7 +5,7 @@ import { OpenAICompatibleCompletionLanguageModel, OpenAICompatibleEmbeddingModel, } from '@ai-sdk/openai-compatible'; -import { LanguageModelV2, EmbeddingModelV2 } from '@ai-sdk/provider'; +import { LanguageModelV2, EmbeddingModelV3 } from '@ai-sdk/provider'; import { loadApiKey } from '@ai-sdk/provider-utils'; import { describe, it, expect, vi, beforeEach, Mock } from 'vitest'; @@ -19,10 +19,14 @@ vi.mock('@ai-sdk/openai-compatible', () => ({ OpenAICompatibleEmbeddingModel: vi.fn(), })); -vi.mock('@ai-sdk/provider-utils', () => ({ - loadApiKey: vi.fn().mockReturnValue('mock-api-key'), - withoutTrailingSlash: vi.fn(url => url), -})); +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + loadApiKey: vi.fn().mockReturnValue('mock-api-key'), + withoutTrailingSlash: vi.fn(url => url), + }; +}); vi.mock('./deepinfra-image-model', () => ({ DeepInfraImageModel: vi.fn(), @@ -30,7 +34,7 @@ vi.mock('./deepinfra-image-model', () => ({ describe('DeepInfraProvider', () => { let mockLanguageModel: LanguageModelV2; - let mockEmbeddingModel: EmbeddingModelV2; + let mockEmbeddingModel: EmbeddingModelV3; beforeEach(() => { // Mock implementations of models @@ -38,8 +42,8 @@ describe('DeepInfraProvider', () => { // Add any required methods for LanguageModelV2 } as LanguageModelV2; mockEmbeddingModel = { - // Add any required methods for EmbeddingModelV2 - } as EmbeddingModelV2; + // Add any required methods for EmbeddingModelV3 + } as EmbeddingModelV3; // Reset mocks vi.clearAllMocks(); diff --git a/packages/deepinfra/src/deepinfra-provider.ts b/packages/deepinfra/src/deepinfra-provider.ts index abd146bf2c8f..ac64cefa06a4 100644 --- a/packages/deepinfra/src/deepinfra-provider.ts +++ b/packages/deepinfra/src/deepinfra-provider.ts @@ -1,8 +1,8 @@ import { LanguageModelV2, - EmbeddingModelV2, - ProviderV2, - ImageModelV2, + EmbeddingModelV3, + ProviderV3, + ImageModelV3, } from '@ai-sdk/provider'; import { OpenAICompatibleChatLanguageModel, @@ -13,12 +13,14 @@ import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { DeepInfraChatModelId } from './deepinfra-chat-options'; import { DeepInfraEmbeddingModelId } from './deepinfra-embedding-options'; import { DeepInfraCompletionModelId } from './deepinfra-completion-options'; import { DeepInfraImageModelId } from './deepinfra-image-settings'; import { DeepInfraImageModel } from './deepinfra-image-model'; +import { VERSION } from './version'; export interface DeepInfraProviderSettings { /** @@ -40,7 +42,7 @@ or to provide a custom fetch implementation for e.g. testing. fetch?: FetchFunction; } -export interface DeepInfraProvider extends ProviderV2 { +export interface DeepInfraProvider extends ProviderV3 { /** Creates a model for text generation. */ @@ -54,12 +56,12 @@ Creates a chat model for text generation. /** Creates a model for image generation. */ - image(modelId: DeepInfraImageModelId): ImageModelV2; + image(modelId: DeepInfraImageModelId): ImageModelV3; /** Creates a model for image generation. */ - imageModel(modelId: DeepInfraImageModelId): ImageModelV2; + imageModel(modelId: DeepInfraImageModelId): ImageModelV3; /** Creates a chat model for text generation. @@ -76,7 +78,7 @@ Creates a text embedding model for text generation. */ textEmbeddingModel( modelId: DeepInfraEmbeddingModelId, - ): EmbeddingModelV2; + ): EmbeddingModelV3; } export function createDeepInfra( @@ -85,14 +87,18 @@ export function createDeepInfra( const baseURL = withoutTrailingSlash( options.baseURL ?? 'https://api.deepinfra.com/v1', ); - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'DEEPINFRA_API_KEY', - description: "DeepInfra's API key", - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'DEEPINFRA_API_KEY', + description: "DeepInfra's API key", + })}`, + ...options.headers, + }, + `ai-sdk/deepinfra/${VERSION}`, + ); interface CommonModelConfig { provider: string; diff --git a/packages/deepinfra/src/index.ts b/packages/deepinfra/src/index.ts index 0c5d1535d580..c10ddcf0618d 100644 --- a/packages/deepinfra/src/index.ts +++ b/packages/deepinfra/src/index.ts @@ -4,3 +4,4 @@ export type { DeepInfraProviderSettings, } from './deepinfra-provider'; export type { OpenAICompatibleErrorData as DeepInfraErrorData } from '@ai-sdk/openai-compatible'; +export { VERSION } from './version'; diff --git a/packages/deepinfra/src/version.ts b/packages/deepinfra/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/deepinfra/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/deepinfra/tsup.config.ts b/packages/deepinfra/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/deepinfra/tsup.config.ts +++ b/packages/deepinfra/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/deepinfra/vitest.edge.config.js b/packages/deepinfra/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/deepinfra/vitest.edge.config.js +++ b/packages/deepinfra/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/deepinfra/vitest.node.config.js b/packages/deepinfra/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/deepinfra/vitest.node.config.js +++ b/packages/deepinfra/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/deepseek/CHANGELOG.md b/packages/deepseek/CHANGELOG.md index 38c0f4f53b16..540585b644e1 100644 --- a/packages/deepseek/CHANGELOG.md +++ b/packages/deepseek/CHANGELOG.md @@ -1,5 +1,69 @@ # @ai-sdk/deepseek +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/openai-compatible@1.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/openai-compatible@1.1.0-beta.2 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [cbb1d35] + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/openai-compatible@1.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/openai-compatible@1.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.18 + +### Patch Changes + +- Updated dependencies [28363da] + - @ai-sdk/openai-compatible@1.0.18 + +## 1.0.17 + +### Patch Changes + +- Updated dependencies [3aed04c] + - @ai-sdk/openai-compatible@1.0.17 + +## 1.0.16 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/openai-compatible@1.0.16 + ## 1.0.15 ### Patch Changes diff --git a/packages/deepseek/package.json b/packages/deepseek/package.json index dd8b4f92d6a8..d3a6f5407074 100644 --- a/packages/deepseek/package.json +++ b/packages/deepseek/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/deepseek", - "version": "1.0.15", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/deepseek/src/deepseek-provider.test.ts b/packages/deepseek/src/deepseek-provider.test.ts index e9412214cc2c..95ee32ba45bc 100644 --- a/packages/deepseek/src/deepseek-provider.test.ts +++ b/packages/deepseek/src/deepseek-provider.test.ts @@ -11,9 +11,17 @@ vi.mock('@ai-sdk/openai-compatible', () => ({ OpenAICompatibleChatLanguageModel: vi.fn(), })); -vi.mock('@ai-sdk/provider-utils', () => ({ - loadApiKey: vi.fn().mockReturnValue('mock-api-key'), - withoutTrailingSlash: vi.fn(url => url), +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + loadApiKey: vi.fn().mockReturnValue('mock-api-key'), + withoutTrailingSlash: vi.fn(url => url), + }; +}); + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', })); describe('DeepSeekProvider', () => { @@ -66,6 +74,29 @@ describe('DeepSeekProvider', () => { const model = provider(modelId); expect(model).toBeInstanceOf(OpenAICompatibleChatLanguageModel); }); + + it('should include deepseek version in user-agent header', async () => { + const fetchMock = vi + .fn() + .mockResolvedValue(new Response('{}', { status: 200 })); + + const provider = createDeepSeek({ fetch: fetchMock }); + provider('model-id'); + + const constructorCall = vi.mocked(OpenAICompatibleChatLanguageModel).mock + .calls[0]; + const config = constructorCall[1]; + const headers = config.headers(); + + await fetchMock('https://api.deepseek.com/v1/test', { + method: 'POST', + headers, + }); + + expect(fetchMock.mock.calls[0][1].headers['user-agent']).toContain( + 'ai-sdk/deepseek/0.0.0-test', + ); + }); }); describe('chat', () => { diff --git a/packages/deepseek/src/deepseek-provider.ts b/packages/deepseek/src/deepseek-provider.ts index 7ff1b52b474e..7b613063d1be 100644 --- a/packages/deepseek/src/deepseek-provider.ts +++ b/packages/deepseek/src/deepseek-provider.ts @@ -2,15 +2,17 @@ import { OpenAICompatibleChatLanguageModel } from '@ai-sdk/openai-compatible'; import { LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { DeepSeekChatModelId } from './deepseek-chat-options'; import { deepSeekMetadataExtractor } from './deepseek-metadata-extractor'; +import { VERSION } from './version'; export interface DeepSeekProviderSettings { /** @@ -32,7 +34,7 @@ or to provide a custom fetch implementation for e.g. testing. fetch?: FetchFunction; } -export interface DeepSeekProvider extends ProviderV2 { +export interface DeepSeekProvider extends ProviderV3 { /** Creates a DeepSeek model for text generation. */ @@ -55,14 +57,18 @@ export function createDeepSeek( const baseURL = withoutTrailingSlash( options.baseURL ?? 'https://api.deepseek.com/v1', ); - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'DEEPSEEK_API_KEY', - description: 'DeepSeek API key', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'DEEPSEEK_API_KEY', + description: 'DeepSeek API key', + })}`, + ...options.headers, + }, + `ai-sdk/deepseek/${VERSION}`, + ); const createLanguageModel = (modelId: DeepSeekChatModelId) => { return new OpenAICompatibleChatLanguageModel(modelId, { diff --git a/packages/deepseek/src/index.ts b/packages/deepseek/src/index.ts index af1912beffb8..7a48f34171f1 100644 --- a/packages/deepseek/src/index.ts +++ b/packages/deepseek/src/index.ts @@ -4,3 +4,4 @@ export type { DeepSeekProviderSettings, } from './deepseek-provider'; export type { OpenAICompatibleErrorData as DeepSeekErrorData } from '@ai-sdk/openai-compatible'; +export { VERSION } from './version'; diff --git a/packages/deepseek/src/version.ts b/packages/deepseek/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/deepseek/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/deepseek/tsup.config.ts b/packages/deepseek/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/deepseek/tsup.config.ts +++ b/packages/deepseek/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/deepseek/vitest.edge.config.js b/packages/deepseek/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/deepseek/vitest.edge.config.js +++ b/packages/deepseek/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/deepseek/vitest.node.config.js b/packages/deepseek/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/deepseek/vitest.node.config.js +++ b/packages/deepseek/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/elevenlabs/CHANGELOG.md b/packages/elevenlabs/CHANGELOG.md index 9c788e700561..333d9820aabe 100644 --- a/packages/elevenlabs/CHANGELOG.md +++ b/packages/elevenlabs/CHANGELOG.md @@ -1,5 +1,52 @@ # @ai-sdk/elevenlabs +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.10 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.9 ### Patch Changes diff --git a/packages/elevenlabs/package.json b/packages/elevenlabs/package.json index e32de1126dd5..3fe71f3f9e36 100644 --- a/packages/elevenlabs/package.json +++ b/packages/elevenlabs/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/elevenlabs", - "version": "1.0.9", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -33,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/elevenlabs/src/elevenlabs-provider.ts b/packages/elevenlabs/src/elevenlabs-provider.ts index 22e0f016c89d..ce42395a4e24 100644 --- a/packages/elevenlabs/src/elevenlabs-provider.ts +++ b/packages/elevenlabs/src/elevenlabs-provider.ts @@ -1,16 +1,21 @@ import { TranscriptionModelV2, SpeechModelV2, - ProviderV2, + ProviderV3, NoSuchModelError, } from '@ai-sdk/provider'; -import { FetchFunction, loadApiKey } from '@ai-sdk/provider-utils'; +import { + FetchFunction, + loadApiKey, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; import { ElevenLabsTranscriptionModel } from './elevenlabs-transcription-model'; import { ElevenLabsTranscriptionModelId } from './elevenlabs-transcription-options'; import { ElevenLabsSpeechModel } from './elevenlabs-speech-model'; import { ElevenLabsSpeechModelId } from './elevenlabs-speech-options'; +import { VERSION } from './version'; -export interface ElevenLabsProvider extends ProviderV2 { +export interface ElevenLabsProvider extends ProviderV3 { ( modelId: 'scribe_v1', settings?: {}, @@ -53,14 +58,18 @@ Create an ElevenLabs provider instance. export function createElevenLabs( options: ElevenLabsProviderSettings = {}, ): ElevenLabsProvider { - const getHeaders = () => ({ - 'xi-api-key': loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'ELEVENLABS_API_KEY', - description: 'ElevenLabs', - }), - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + 'xi-api-key': loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'ELEVENLABS_API_KEY', + description: 'ElevenLabs', + }), + ...options.headers, + }, + `ai-sdk/elevenlabs/${VERSION}`, + ); const createTranscriptionModel = (modelId: ElevenLabsTranscriptionModelId) => new ElevenLabsTranscriptionModel(modelId, { diff --git a/packages/elevenlabs/src/elevenlabs-speech-model.test.ts b/packages/elevenlabs/src/elevenlabs-speech-model.test.ts index a9f54fe06a22..209e52e35c87 100644 --- a/packages/elevenlabs/src/elevenlabs-speech-model.test.ts +++ b/packages/elevenlabs/src/elevenlabs-speech-model.test.ts @@ -1,7 +1,11 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; -import { describe, expect, it } from 'vitest'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; +import { describe, expect, it, vi } from 'vitest'; import { createElevenLabs } from './elevenlabs-provider'; +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); + const provider = createElevenLabs({ apiKey: 'test-api-key' }); const model = provider.speech('eleven_multilingual_v2'); @@ -154,5 +158,18 @@ describe('ElevenLabsSpeechModel', () => { 'output_format=mp3_44100_128', ); }); + + it('should include user-agent header', async () => { + prepareAudioResponse(); + + await model.doGenerate({ + text: 'Hello, world!', + voice: 'test-voice-id', + }); + + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/elevenlabs/0.0.0-test`, + ); + }); }); }); diff --git a/packages/elevenlabs/src/elevenlabs-transcription-model.test.ts b/packages/elevenlabs/src/elevenlabs-transcription-model.test.ts index 9a00556dcba4..69725f936b33 100644 --- a/packages/elevenlabs/src/elevenlabs-transcription-model.test.ts +++ b/packages/elevenlabs/src/elevenlabs-transcription-model.test.ts @@ -1,9 +1,13 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { ElevenLabsTranscriptionModel } from './elevenlabs-transcription-model'; import { createElevenLabs } from './elevenlabs-provider'; import { readFile } from 'node:fs/promises'; import path from 'node:path'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const audioData = await readFile(path.join(__dirname, 'transcript-test.mp3')); const provider = createElevenLabs({ apiKey: 'test-api-key' }); @@ -122,6 +126,9 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/elevenlabs/0.0.0-test`, + ); }); it('should extract the transcription text', async () => { diff --git a/packages/elevenlabs/src/index.ts b/packages/elevenlabs/src/index.ts index 338220a09065..5054c77bc3ab 100644 --- a/packages/elevenlabs/src/index.ts +++ b/packages/elevenlabs/src/index.ts @@ -7,3 +7,4 @@ export type { ElevenLabsSpeechModelId, ElevenLabsSpeechVoiceId, } from './elevenlabs-speech-options'; +export { VERSION } from './version'; diff --git a/packages/elevenlabs/src/version.ts b/packages/elevenlabs/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/elevenlabs/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/elevenlabs/tsup.config.ts b/packages/elevenlabs/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/elevenlabs/tsup.config.ts +++ b/packages/elevenlabs/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/elevenlabs/vitest.edge.config.js b/packages/elevenlabs/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/elevenlabs/vitest.edge.config.js +++ b/packages/elevenlabs/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/elevenlabs/vitest.node.config.js b/packages/elevenlabs/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/elevenlabs/vitest.node.config.js +++ b/packages/elevenlabs/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/fal/CHANGELOG.md b/packages/fal/CHANGELOG.md index c6777622c82e..42a90972e3f5 100644 --- a/packages/fal/CHANGELOG.md +++ b/packages/fal/CHANGELOG.md @@ -1,5 +1,53 @@ # @ai-sdk/fal +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.13 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.12 ### Patch Changes diff --git a/packages/fal/package.json b/packages/fal/package.json index 16f68b575bc2..11cdc979f933 100644 --- a/packages/fal/package.json +++ b/packages/fal/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/fal", - "version": "1.0.12", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -33,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/fal/src/fal-image-model.test.ts b/packages/fal/src/fal-image-model.test.ts index de5543c6e630..67333918f2f6 100644 --- a/packages/fal/src/fal-image-model.test.ts +++ b/packages/fal/src/fal-image-model.test.ts @@ -1,5 +1,5 @@ import { FetchFunction } from '@ai-sdk/provider-utils'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { describe, expect, it } from 'vitest'; import { FalImageModel } from './fal-image-model'; @@ -305,7 +305,7 @@ describe('FalImageModel', () => { expect(model.provider).toBe('fal.image'); expect(model.modelId).toBe('fal-ai/qwen-image'); - expect(model.specificationVersion).toBe('v2'); + expect(model.specificationVersion).toBe('v3'); expect(model.maxImagesPerCall).toBe(1); }); }); diff --git a/packages/fal/src/fal-image-model.ts b/packages/fal/src/fal-image-model.ts index 4a6371fbbd02..fbdbad2cef23 100644 --- a/packages/fal/src/fal-image-model.ts +++ b/packages/fal/src/fal-image-model.ts @@ -1,6 +1,6 @@ import type { - ImageModelV2, - ImageModelV2CallWarning, + ImageModelV3, + ImageModelV3CallWarning, JSONObject, } from '@ai-sdk/provider'; import type { Resolvable } from '@ai-sdk/provider-utils'; @@ -28,8 +28,8 @@ interface FalImageModelConfig { }; } -export class FalImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class FalImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; readonly maxImagesPerCall = 1; get provider(): string { @@ -50,10 +50,10 @@ export class FalImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; let imageSize: FalImageSize | undefined; if (size) { diff --git a/packages/fal/src/fal-provider.ts b/packages/fal/src/fal-provider.ts index 9e9860726965..6c794db3b27f 100644 --- a/packages/fal/src/fal-provider.ts +++ b/packages/fal/src/fal-provider.ts @@ -1,18 +1,22 @@ import { - ImageModelV2, + ImageModelV3, NoSuchModelError, - ProviderV2, + ProviderV3, SpeechModelV2, TranscriptionModelV2, } from '@ai-sdk/provider'; import type { FetchFunction } from '@ai-sdk/provider-utils'; -import { withoutTrailingSlash } from '@ai-sdk/provider-utils'; +import { + withoutTrailingSlash, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; import { FalImageModel } from './fal-image-model'; import { FalImageModelId } from './fal-image-settings'; import { FalTranscriptionModelId } from './fal-transcription-options'; import { FalTranscriptionModel } from './fal-transcription-model'; import { FalSpeechModelId } from './fal-speech-settings'; import { FalSpeechModel } from './fal-speech-model'; +import { VERSION } from './version'; export interface FalProviderSettings { /** @@ -39,16 +43,16 @@ requests, or to provide a custom fetch implementation for e.g. testing. fetch?: FetchFunction; } -export interface FalProvider extends ProviderV2 { +export interface FalProvider extends ProviderV3 { /** Creates a model for image generation. */ - image(modelId: FalImageModelId): ImageModelV2; + image(modelId: FalImageModelId): ImageModelV3; /** Creates a model for image generation. */ - imageModel(modelId: FalImageModelId): ImageModelV2; + imageModel(modelId: FalImageModelId): ImageModelV3; /** Creates a model for transcription. @@ -109,12 +113,16 @@ Create a fal.ai provider instance. */ export function createFal(options: FalProviderSettings = {}): FalProvider { const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL); - const getHeaders = () => ({ - Authorization: `Key ${loadFalApiKey({ - apiKey: options.apiKey, - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Key ${loadFalApiKey({ + apiKey: options.apiKey, + })}`, + ...options.headers, + }, + `ai-sdk/fal/${VERSION}`, + ); const createImageModel = (modelId: FalImageModelId) => new FalImageModel(modelId, { diff --git a/packages/fal/src/fal-speech-model.test.ts b/packages/fal/src/fal-speech-model.test.ts index cc125d8e9c42..bd4f0be7e8f3 100644 --- a/packages/fal/src/fal-speech-model.test.ts +++ b/packages/fal/src/fal-speech-model.test.ts @@ -1,4 +1,4 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createFal } from './fal-provider'; import { FalSpeechModel } from './fal-speech-model'; import { describe, it, expect } from 'vitest'; diff --git a/packages/fal/src/fal-transcription-model.test.ts b/packages/fal/src/fal-transcription-model.test.ts index 93b03345de28..cb4471ecf4e7 100644 --- a/packages/fal/src/fal-transcription-model.test.ts +++ b/packages/fal/src/fal-transcription-model.test.ts @@ -1,4 +1,4 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createFal } from './fal-provider'; import { FalTranscriptionModel } from './fal-transcription-model'; import { readFile } from 'node:fs/promises'; diff --git a/packages/fal/src/index.ts b/packages/fal/src/index.ts index 969dda96f1ab..75c84221d5dc 100644 --- a/packages/fal/src/index.ts +++ b/packages/fal/src/index.ts @@ -1,2 +1,3 @@ export { createFal, fal } from './fal-provider'; export type { FalProvider, FalProviderSettings } from './fal-provider'; +export { VERSION } from './version'; diff --git a/packages/fal/src/version.ts b/packages/fal/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/fal/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/fal/tsup.config.ts b/packages/fal/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/fal/tsup.config.ts +++ b/packages/fal/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/fal/vitest.edge.config.js b/packages/fal/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/fal/vitest.edge.config.js +++ b/packages/fal/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/fal/vitest.node.config.js b/packages/fal/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/fal/vitest.node.config.js +++ b/packages/fal/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/fireworks/CHANGELOG.md b/packages/fireworks/CHANGELOG.md index 2e3416375373..0e5d1a62fe62 100644 --- a/packages/fireworks/CHANGELOG.md +++ b/packages/fireworks/CHANGELOG.md @@ -1,5 +1,73 @@ # @ai-sdk/fireworks +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/openai-compatible@1.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/openai-compatible@1.1.0-beta.2 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/openai-compatible@1.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/openai-compatible@1.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.18 + +### Patch Changes + +- Updated dependencies [28363da] + - @ai-sdk/openai-compatible@1.0.18 + +## 1.0.17 + +### Patch Changes + +- Updated dependencies [3aed04c] + - @ai-sdk/openai-compatible@1.0.17 + +## 1.0.16 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/openai-compatible@1.0.16 + ## 1.0.15 ### Patch Changes diff --git a/packages/fireworks/package.json b/packages/fireworks/package.json index d490c8baea91..1394a317386b 100644 --- a/packages/fireworks/package.json +++ b/packages/fireworks/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/fireworks", - "version": "1.0.15", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -34,7 +34,8 @@ "dependencies": { "@ai-sdk/openai-compatible": "workspace:*", "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/fireworks/src/fireworks-image-model.test.ts b/packages/fireworks/src/fireworks-image-model.test.ts index 183d6fcd2525..87e95bad9fc1 100644 --- a/packages/fireworks/src/fireworks-image-model.test.ts +++ b/packages/fireworks/src/fireworks-image-model.test.ts @@ -1,5 +1,5 @@ import { FetchFunction } from '@ai-sdk/provider-utils'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { describe, expect, it, vi } from 'vitest'; import { FireworksImageModel } from './fireworks-image-model'; @@ -353,7 +353,7 @@ describe('FireworksImageModel', () => { expect(model.provider).toBe('fireworks'); expect(model.modelId).toBe('accounts/fireworks/models/flux-1-dev-fp8'); - expect(model.specificationVersion).toBe('v2'); + expect(model.specificationVersion).toBe('v3'); expect(model.maxImagesPerCall).toBe(1); }); }); diff --git a/packages/fireworks/src/fireworks-image-model.ts b/packages/fireworks/src/fireworks-image-model.ts index 8a86cb34100f..de1463b5fdba 100644 --- a/packages/fireworks/src/fireworks-image-model.ts +++ b/packages/fireworks/src/fireworks-image-model.ts @@ -1,4 +1,4 @@ -import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider'; +import { ImageModelV3, ImageModelV3CallWarning } from '@ai-sdk/provider'; import { combineHeaders, createBinaryResponseHandler, @@ -67,8 +67,8 @@ interface FireworksImageModelConfig { }; } -export class FireworksImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class FireworksImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; readonly maxImagesPerCall = 1; get provider(): string { @@ -89,10 +89,10 @@ export class FireworksImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; const backendConfig = modelToBackendConfig[this.modelId]; if (!backendConfig?.supportsSize && size != null) { diff --git a/packages/fireworks/src/fireworks-provider.test.ts b/packages/fireworks/src/fireworks-provider.test.ts index 4ad9edc88835..c6a651f959f4 100644 --- a/packages/fireworks/src/fireworks-provider.test.ts +++ b/packages/fireworks/src/fireworks-provider.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach, Mock } from 'vitest'; import { createFireworks } from './fireworks-provider'; -import { LanguageModelV2, EmbeddingModelV2 } from '@ai-sdk/provider'; +import { LanguageModelV2, EmbeddingModelV3 } from '@ai-sdk/provider'; import { loadApiKey } from '@ai-sdk/provider-utils'; import { OpenAICompatibleChatLanguageModel, @@ -39,10 +39,14 @@ vi.mock('@ai-sdk/openai-compatible', () => { }; }); -vi.mock('@ai-sdk/provider-utils', () => ({ - loadApiKey: vi.fn().mockReturnValue('mock-api-key'), - withoutTrailingSlash: vi.fn(url => url), -})); +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + loadApiKey: vi.fn().mockReturnValue('mock-api-key'), + withoutTrailingSlash: vi.fn(url => url), + }; +}); vi.mock('./fireworks-image-model', () => ({ FireworksImageModel: vi.fn(), @@ -50,7 +54,7 @@ vi.mock('./fireworks-image-model', () => ({ describe('FireworksProvider', () => { let mockLanguageModel: LanguageModelV2; - let mockEmbeddingModel: EmbeddingModelV2; + let mockEmbeddingModel: EmbeddingModelV3; beforeEach(() => { // Mock implementations of models @@ -58,8 +62,8 @@ describe('FireworksProvider', () => { // Add any required methods for LanguageModelV2 } as LanguageModelV2; mockEmbeddingModel = { - // Add any required methods for EmbeddingModelV2 - } as EmbeddingModelV2; + // Add any required methods for EmbeddingModelV3 + } as EmbeddingModelV3; // Reset mocks vi.clearAllMocks(); diff --git a/packages/fireworks/src/fireworks-provider.ts b/packages/fireworks/src/fireworks-provider.ts index b13eb182b34d..25fd5510bb32 100644 --- a/packages/fireworks/src/fireworks-provider.ts +++ b/packages/fireworks/src/fireworks-provider.ts @@ -5,15 +5,16 @@ import { ProviderErrorStructure, } from '@ai-sdk/openai-compatible'; import { - EmbeddingModelV2, - ImageModelV2, + EmbeddingModelV3, + ImageModelV3, LanguageModelV2, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { z } from 'zod/v4'; import { FireworksChatModelId } from './fireworks-chat-options'; @@ -21,6 +22,7 @@ import { FireworksCompletionModelId } from './fireworks-completion-options'; import { FireworksEmbeddingModelId } from './fireworks-embedding-options'; import { FireworksImageModel } from './fireworks-image-model'; import { FireworksImageModelId } from './fireworks-image-options'; +import { VERSION } from './version'; export type FireworksErrorData = z.infer; @@ -54,7 +56,7 @@ or to provide a custom fetch implementation for e.g. testing. fetch?: FetchFunction; } -export interface FireworksProvider extends ProviderV2 { +export interface FireworksProvider extends ProviderV3 { /** Creates a model for text generation. */ @@ -80,17 +82,17 @@ Creates a text embedding model for text generation. */ textEmbeddingModel( modelId: FireworksEmbeddingModelId, - ): EmbeddingModelV2; + ): EmbeddingModelV3; /** Creates a model for image generation. */ - image(modelId: FireworksImageModelId): ImageModelV2; + image(modelId: FireworksImageModelId): ImageModelV3; /** Creates a model for image generation. */ - imageModel(modelId: FireworksImageModelId): ImageModelV2; + imageModel(modelId: FireworksImageModelId): ImageModelV3; } const defaultBaseURL = 'https://api.fireworks.ai/inference/v1'; @@ -99,14 +101,18 @@ export function createFireworks( options: FireworksProviderSettings = {}, ): FireworksProvider { const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL); - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'FIREWORKS_API_KEY', - description: 'Fireworks API key', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'FIREWORKS_API_KEY', + description: 'Fireworks API key', + })}`, + ...options.headers, + }, + `ai-sdk/fireworks/${VERSION}`, + ); interface CommonModelConfig { provider: string; diff --git a/packages/fireworks/src/index.ts b/packages/fireworks/src/index.ts index 48bec1c53551..4a5565e43127 100644 --- a/packages/fireworks/src/index.ts +++ b/packages/fireworks/src/index.ts @@ -10,3 +10,4 @@ export type { FireworksProviderSettings, FireworksErrorData, } from './fireworks-provider'; +export { VERSION } from './version'; diff --git a/packages/fireworks/src/version.ts b/packages/fireworks/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/fireworks/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/fireworks/tsup.config.ts b/packages/fireworks/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/fireworks/tsup.config.ts +++ b/packages/fireworks/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/fireworks/vitest.edge.config.js b/packages/fireworks/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/fireworks/vitest.edge.config.js +++ b/packages/fireworks/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/fireworks/vitest.node.config.js b/packages/fireworks/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/fireworks/vitest.node.config.js +++ b/packages/fireworks/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/gateway/CHANGELOG.md b/packages/gateway/CHANGELOG.md index e1aaba60072d..7f5aa53f3718 100644 --- a/packages/gateway/CHANGELOG.md +++ b/packages/gateway/CHANGELOG.md @@ -1,5 +1,85 @@ # @ai-sdk/gateway +## 1.1.0-beta.6 + +### Patch Changes + +- aaf5ebf: feat(provider/gateway): Add new Qwen models to Gateway model string autocomplete +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.5 + +### Patch Changes + +- 5d21222: feat(provider/gateway): Add gpt-5-codex to Gateway model string autocomplete +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.4 + +### Patch Changes + +- 7ccb36f: feat(provider/gateway): Add LongCat Thinking model to Gateway autocomplete +- 6c766ef: feat(provider/gateway): Add DeepSeek V3.1 Terminus to Gateway autocomplete + +## 1.1.0-beta.3 + +### Patch Changes + +- ea9ca31: feat(provider/gateway): Add new xAI models + +## 1.1.0-beta.2 + +### Patch Changes + +- 3e83633: add getCredits() gateway method +- f83903d: getCredits style improvements + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [cbb1d35] + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.23 + +### Patch Changes + +- f49f924: feat (provider/gateway): add qwen3 next model ids + +## 1.0.22 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + +## 1.0.21 + +### Patch Changes + +- 4ee3719: feat(provider/gateway): Add Meituan LongCat Flash Chat to autocomplete + ## 1.0.20 ### Patch Changes diff --git a/packages/gateway/package.json b/packages/gateway/package.json index bf917a184103..08859710a393 100644 --- a/packages/gateway/package.json +++ b/packages/gateway/package.json @@ -1,7 +1,7 @@ { "name": "@ai-sdk/gateway", "private": false, - "version": "1.0.20", + "version": "1.1.0-beta.6", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -37,6 +37,7 @@ "@ai-sdk/provider-utils": "workspace:*" }, "devDependencies": { + "@ai-sdk/test-server": "workspace:*", "@types/node": "18.15.11", "@vercel/ai-tsconfig": "workspace:*", "tsup": "^8", diff --git a/packages/gateway/src/gateway-embedding-model.test.ts b/packages/gateway/src/gateway-embedding-model.test.ts index 0259697a9327..f217a3ea4277 100644 --- a/packages/gateway/src/gateway-embedding-model.test.ts +++ b/packages/gateway/src/gateway-embedding-model.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { GatewayEmbeddingModel } from './gateway-embedding-model'; import type { GatewayConfig } from './gateway-config'; import { diff --git a/packages/gateway/src/gateway-embedding-model.ts b/packages/gateway/src/gateway-embedding-model.ts index b9249682bdde..0917500954a7 100644 --- a/packages/gateway/src/gateway-embedding-model.ts +++ b/packages/gateway/src/gateway-embedding-model.ts @@ -1,4 +1,4 @@ -import type { EmbeddingModelV2 } from '@ai-sdk/provider'; +import type { EmbeddingModelV3 } from '@ai-sdk/provider'; import { combineHeaders, createJsonResponseHandler, @@ -13,8 +13,8 @@ import { asGatewayError } from './errors'; import { parseAuthMethod } from './errors/parse-auth-method'; import type { SharedV2ProviderMetadata } from '@ai-sdk/provider'; -export class GatewayEmbeddingModel implements EmbeddingModelV2 { - readonly specificationVersion = 'v2'; +export class GatewayEmbeddingModel implements EmbeddingModelV3 { + readonly specificationVersion = 'v3'; readonly maxEmbeddingsPerCall = 2048; readonly supportsParallelCalls = true; @@ -35,8 +35,8 @@ export class GatewayEmbeddingModel implements EmbeddingModelV2 { headers, abortSignal, providerOptions, - }: Parameters['doEmbed']>[0]): Promise< - Awaited['doEmbed']>> + }: Parameters['doEmbed']>[0]): Promise< + Awaited['doEmbed']>> > { const resolvedHeaders = await resolve(this.config.headers()); try { diff --git a/packages/gateway/src/gateway-fetch-metadata.test.ts b/packages/gateway/src/gateway-fetch-metadata.test.ts index 8e7dcd7b383f..c64407ed63a8 100644 --- a/packages/gateway/src/gateway-fetch-metadata.test.ts +++ b/packages/gateway/src/gateway-fetch-metadata.test.ts @@ -1,4 +1,4 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { describe, expect, it, vi } from 'vitest'; import { GatewayFetchMetadata } from './gateway-fetch-metadata'; import type { FetchFunction } from '@ai-sdk/provider-utils'; @@ -504,4 +504,271 @@ describe('GatewayFetchMetadata', () => { }); }); }); + + describe('getCredits', () => { + it('should fetch credits from the correct endpoint', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'json-value', + body: { + balance: '150.50', + total_used: '75.25', + }, + }; + + const metadata = createBasicMetadataFetcher(); + const result = await metadata.getCredits(); + + expect(result).toEqual({ + balance: '150.50', + totalUsed: '75.25', + }); + }); + + it('should pass headers correctly to credits endpoint', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'json-value', + body: { + balance: '100.00', + total_used: '50.00', + }, + }; + + const metadata = createBasicMetadataFetcher({ + headers: () => ({ + Authorization: 'Bearer custom-token', + 'Custom-Header': 'custom-value', + }), + }); + + const result = await metadata.getCredits(); + + expect(server.calls[0].requestHeaders).toEqual({ + authorization: 'Bearer custom-token', + 'custom-header': 'custom-value', + }); + expect(result).toEqual({ + balance: '100.00', + totalUsed: '50.00', + }); + }); + + it('should handle API errors for credits endpoint', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'error', + status: 401, + body: JSON.stringify({ + error: { + type: 'authentication_error', + message: 'Invalid API key', + }, + }), + }; + + const metadata = createBasicMetadataFetcher(); + + await expect(metadata.getCredits()).rejects.toThrow( + GatewayAuthenticationError, + ); + }); + + it('should handle rate limit errors for credits endpoint', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'error', + status: 429, + body: JSON.stringify({ + error: { + type: 'rate_limit_exceeded', + message: 'Rate limit exceeded', + }, + }), + }; + + const metadata = createBasicMetadataFetcher(); + + await expect(metadata.getCredits()).rejects.toThrow( + GatewayRateLimitError, + ); + }); + + it('should handle internal server errors for credits endpoint', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'error', + status: 500, + body: JSON.stringify({ + error: { + type: 'internal_server_error', + message: 'Database unavailable', + }, + }), + }; + + const metadata = createBasicMetadataFetcher(); + + await expect(metadata.getCredits()).rejects.toThrow( + GatewayInternalServerError, + ); + }); + + it('should handle malformed credits response', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'json-value', + body: { + balance: 'not-a-number', + total_used: '75.25', + }, + }; + + const metadata = createBasicMetadataFetcher(); + const result = await metadata.getCredits(); + + expect(result).toEqual({ + balance: 'not-a-number', + totalUsed: '75.25', + }); + }); + + it('should use custom fetch function when provided', async () => { + const customFetch = vi.fn().mockResolvedValue( + new Response( + JSON.stringify({ + balance: '200.00', + total_used: '100.50', + }), + { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }, + ), + ); + + const metadata = createBasicMetadataFetcher({ + fetch: customFetch as unknown as FetchFunction, + }); + + const result = await metadata.getCredits(); + + expect(result).toEqual({ + balance: '200.00', + totalUsed: '100.50', + }); + + expect(customFetch).toHaveBeenCalledWith( + 'https://api.example.com/v1/credits', + expect.objectContaining({ + method: 'GET', + headers: expect.objectContaining({ + authorization: 'Bearer test-token', + }), + }), + ); + }); + + it('should convert API call errors to Gateway errors', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'error', + status: 403, + body: JSON.stringify({ + error: { + message: 'Forbidden access', + type: 'authentication_error', + }, + }), + }; + + const metadata = createBasicMetadataFetcher(); + + try { + await metadata.getCredits(); + expect.fail('Should have thrown an error'); + } catch (error) { + expect(GatewayAuthenticationError.isInstance(error)).toBe(true); + const authError = error as GatewayAuthenticationError; + expect(authError.message).toContain('No authentication provided'); + expect(authError.type).toBe('authentication_error'); + expect(authError.statusCode).toBe(403); + } + }); + + it('should handle malformed JSON error responses', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'error', + status: 500, + body: '{ invalid json', + }; + + const metadata = createBasicMetadataFetcher(); + + try { + await metadata.getCredits(); + expect.fail('Should have thrown an error'); + } catch (error) { + expect(GatewayResponseError.isInstance(error)).toBe(true); + const responseError = error as GatewayResponseError; + expect(responseError.statusCode).toBe(500); + expect(responseError.type).toBe('response_error'); + } + }); + + it('should not double-wrap existing Gateway errors', async () => { + const existingError = new GatewayAuthenticationError({ + message: 'Already wrapped', + statusCode: 401, + }); + + try { + throw existingError; + } catch (error: unknown) { + if (GatewayError.isInstance(error)) { + expect(error).toBe(existingError); + expect(error.message).toBe('Already wrapped'); + return; + } + throw new Error('Should not reach here'); + } + }); + + it('should preserve error cause chain', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'error', + status: 401, + body: JSON.stringify({ + error: { + message: 'Token expired', + type: 'authentication_error', + }, + }), + }; + + const metadata = createBasicMetadataFetcher(); + + try { + await metadata.getCredits(); + expect.fail('Should have thrown an error'); + } catch (error) { + expect(GatewayAuthenticationError.isInstance(error)).toBe(true); + const authError = error as GatewayAuthenticationError; + expect(authError.cause).toBeDefined(); + } + }); + + it('should handle empty response', async () => { + server.urls['https://api.example.com/*'].response = { + type: 'json-value', + body: { + balance: '0.00', + total_used: '0.00', + }, + }; + + const metadata = createBasicMetadataFetcher(); + const result = await metadata.getCredits(); + + expect(result).toEqual({ + balance: '0.00', + totalUsed: '0.00', + }); + }); + }); }); diff --git a/packages/gateway/src/gateway-fetch-metadata.ts b/packages/gateway/src/gateway-fetch-metadata.ts index 9b67a70cd581..a133cba73ae3 100644 --- a/packages/gateway/src/gateway-fetch-metadata.ts +++ b/packages/gateway/src/gateway-fetch-metadata.ts @@ -15,6 +15,13 @@ export interface GatewayFetchMetadataResponse { models: GatewayLanguageModelEntry[]; } +export interface GatewayCreditsResponse { + /** The remaining gateway credit balance available for API usage */ + balance: string; + /** The total amount of gateway credits that have been consumed */ + totalUsed: string; +} + export class GatewayFetchMetadata { constructor(private readonly config: GatewayFetchMetadataConfig) {} @@ -38,6 +45,28 @@ export class GatewayFetchMetadata { throw asGatewayError(error); } } + + async getCredits(): Promise { + try { + const baseUrl = new URL(this.config.baseURL); + + const { value } = await getFromApi({ + url: `${baseUrl.origin}/v1/credits`, + headers: await resolve(this.config.headers()), + successfulResponseHandler: + createJsonResponseHandler(gatewayCreditsSchema), + failedResponseHandler: createJsonErrorResponseHandler({ + errorSchema: z.any(), + errorToMessage: data => data, + }), + fetch: this.config.fetch, + }); + + return value; + } catch (error) { + throw asGatewayError(error); + } + } } const gatewayLanguageModelSpecificationSchema = z.object({ @@ -74,3 +103,13 @@ const gatewayLanguageModelEntrySchema = z.object({ const gatewayFetchMetadataSchema = z.object({ models: z.array(gatewayLanguageModelEntrySchema), }); + +const gatewayCreditsSchema = z + .object({ + balance: z.string(), + total_used: z.string(), + }) + .transform(({ balance, total_used }) => ({ + balance, + totalUsed: total_used, + })); diff --git a/packages/gateway/src/gateway-language-model-settings.ts b/packages/gateway/src/gateway-language-model-settings.ts index 230213e8d75c..2e3724681b52 100644 --- a/packages/gateway/src/gateway-language-model-settings.ts +++ b/packages/gateway/src/gateway-language-model-settings.ts @@ -4,7 +4,13 @@ export type GatewayModelId = | 'alibaba/qwen-3-30b' | 'alibaba/qwen-3-32b' | 'alibaba/qwen3-coder' + | 'alibaba/qwen3-coder-plus' | 'alibaba/qwen3-max' + | 'alibaba/qwen3-max-preview' + | 'alibaba/qwen3-next-80b-a3b-instruct' + | 'alibaba/qwen3-next-80b-a3b-thinking' + | 'alibaba/qwen3-vl-instruct' + | 'alibaba/qwen3-vl-thinking' | 'amazon/nova-lite' | 'amazon/nova-micro' | 'amazon/nova-pro' @@ -25,6 +31,7 @@ export type GatewayModelId = | 'deepseek/deepseek-v3.1' | 'deepseek/deepseek-v3.1-base' | 'deepseek/deepseek-v3.1-thinking' + | 'deepseek/deepseek-v3.1-terminus' | 'google/gemini-2.0-flash' | 'google/gemini-2.0-flash-lite' | 'google/gemini-2.5-flash' @@ -33,6 +40,8 @@ export type GatewayModelId = | 'google/gemini-2.5-pro' | 'google/gemma-2-9b' | 'inception/mercury-coder-small' + | 'meituan/longcat-flash-chat' + | 'meituan/longcat-flash-thinking' | 'meta/llama-3-70b' | 'meta/llama-3-8b' | 'meta/llama-3.1-70b' @@ -70,6 +79,7 @@ export type GatewayModelId = | 'openai/gpt-4o' | 'openai/gpt-4o-mini' | 'openai/gpt-5' + | 'openai/gpt-5-codex' | 'openai/gpt-5-mini' | 'openai/gpt-5-nano' | 'openai/gpt-oss-120b' @@ -94,6 +104,8 @@ export type GatewayModelId = | 'xai/grok-3-mini-fast' | 'xai/grok-4' | 'xai/grok-code-fast-1' + | 'xai/grok-4-fast-non-reasoning' + | 'xai/grok-4-fast-reasoning' | 'zai/glm-4.5' | 'zai/glm-4.5-air' | 'zai/glm-4.5v' diff --git a/packages/gateway/src/gateway-language-model.test.ts b/packages/gateway/src/gateway-language-model.test.ts index 5edf029655b4..9013e4fd97c2 100644 --- a/packages/gateway/src/gateway-language-model.test.ts +++ b/packages/gateway/src/gateway-language-model.test.ts @@ -2,10 +2,8 @@ import type { LanguageModelV2Prompt, LanguageModelV2FilePart, } from '@ai-sdk/provider'; -import { - convertReadableStreamToArray, - createTestServer, -} from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; +import { convertReadableStreamToArray } from '@ai-sdk/provider-utils/test'; import { GatewayLanguageModel } from './gateway-language-model'; import type { GatewayConfig } from './gateway-config'; import { diff --git a/packages/gateway/src/gateway-provider.test.ts b/packages/gateway/src/gateway-provider.test.ts index 5faa4b6c0c64..799cfee94575 100644 --- a/packages/gateway/src/gateway-provider.test.ts +++ b/packages/gateway/src/gateway-provider.test.ts @@ -23,6 +23,7 @@ vi.mock('./gateway-language-model', () => ({ // Mock the gateway fetch metadata to prevent actual network calls // We'll create a more flexible mock that can simulate auth failures const mockGetAvailableModels = vi.fn(); +const mockGetCredits = vi.fn(); vi.mock('./gateway-fetch-metadata', () => ({ GatewayFetchMetadata: vi.fn().mockImplementation((config: any) => ({ getAvailableModels: async () => { @@ -32,6 +33,13 @@ vi.mock('./gateway-fetch-metadata', () => ({ } return mockGetAvailableModels(); }, + getCredits: async () => { + // Call the headers function to trigger authentication logic + if (config.headers && typeof config.headers === 'function') { + await config.headers(); + } + return mockGetCredits(); + }, })), })); @@ -40,13 +48,18 @@ vi.mock('./vercel-environment', () => ({ getVercelRequestId: vi.fn(), })); +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); + describe('GatewayProvider', () => { beforeEach(() => { vi.clearAllMocks(); vi.mocked(getVercelOidcToken).mockResolvedValue('mock-oidc-token'); vi.mocked(getVercelRequestId).mockResolvedValue('mock-request-id'); - // Set up default mock behavior for getAvailableModels + // Set up default mock behavior for getAvailableModels and getCredits mockGetAvailableModels.mockReturnValue({ models: [] }); + mockGetCredits.mockReturnValue({ balance: '100.00', total_used: '50.00' }); if ('AI_GATEWAY_API_KEY' in process.env) { Reflect.deleteProperty(process.env, 'AI_GATEWAY_API_KEY'); } @@ -79,10 +92,11 @@ describe('GatewayProvider', () => { const headers = await config.headers(); expect(headers).toEqual({ - Authorization: 'Bearer test-api-key', - 'Custom-Header': 'value', + authorization: 'Bearer test-api-key', + 'custom-header': 'value', 'ai-gateway-protocol-version': expect.any(String), 'ai-gateway-auth-method': 'api-key', + 'user-agent': 'ai-sdk/gateway/0.0.0-test', }); }); @@ -100,10 +114,11 @@ describe('GatewayProvider', () => { const headers = await config.headers(); expect(headers).toEqual({ - Authorization: 'Bearer mock-oidc-token', - 'Custom-Header': 'value', + authorization: 'Bearer mock-oidc-token', + 'custom-header': 'value', 'ai-gateway-protocol-version': expect.any(String), 'ai-gateway-auth-method': 'oidc', + 'user-agent': 'ai-sdk/gateway/0.0.0-test', }); }); @@ -379,8 +394,9 @@ describe('GatewayProvider', () => { const headers = await resolve(config.headers()); // Verify that the API key was used in the Authorization header - expect(headers.Authorization).toBe(`Bearer ${testApiKey}`); + expect(headers['authorization']).toBe(`Bearer ${testApiKey}`); expect(headers['ai-gateway-auth-method']).toBe('api-key'); + expect(headers['user-agent']).toBe('ai-sdk/gateway/0.0.0-test'); // Verify getVercelOidcToken was never called expect(getVercelOidcToken).not.toHaveBeenCalled(); @@ -811,6 +827,100 @@ describe('GatewayProvider', () => { }); }); + describe('getCredits method', () => { + it('should fetch credits successfully', async () => { + const mockCredits = { balance: '150.50', total_used: '75.25' }; + mockGetCredits.mockReturnValue(mockCredits); + + const provider = createGatewayProvider({ + apiKey: 'test-key', + }); + + const credits = await provider.getCredits(); + + expect(credits).toEqual({ balance: '150.50', total_used: '75.25' }); + expect(GatewayFetchMetadata).toHaveBeenCalledWith( + expect.objectContaining({ + baseURL: 'https://ai-gateway.vercel.sh/v1/ai', + headers: expect.any(Function), + fetch: undefined, + }), + ); + }); + + it('should handle authentication errors in getCredits', async () => { + const provider = createGatewayProvider(); + + const result = await provider.getCredits(); + expect(result).toEqual({ balance: '100.00', total_used: '50.00' }); + }); + + it('should work with custom baseURL', async () => { + const customBaseURL = 'https://custom-gateway.example.com/v1/ai'; + const provider = createGatewayProvider({ + apiKey: 'test-key', + baseURL: customBaseURL, + }); + + await provider.getCredits(); + + expect(GatewayFetchMetadata).toHaveBeenCalledWith( + expect.objectContaining({ + baseURL: customBaseURL, + }), + ); + }); + + it('should work with OIDC authentication', async () => { + vi.mocked(getVercelOidcToken).mockResolvedValue('oidc-token'); + + const provider = createGatewayProvider(); + + const credits = await provider.getCredits(); + + expect(credits).toBeDefined(); + expect(getVercelOidcToken).toHaveBeenCalled(); + }); + + it('should handle errors from the credits endpoint', async () => { + const testError = new Error('Credits service unavailable'); + mockGetCredits.mockRejectedValue(testError); + + const provider = createGatewayProvider({ + apiKey: 'test-key', + }); + + await expect(provider.getCredits()).rejects.toThrow( + 'Credits service unavailable', + ); + }); + + it('should include proper headers for credits request', async () => { + const provider = createGatewayProvider({ + apiKey: 'test-key', + headers: { 'custom-header': 'custom-value' }, + }); + + await provider.getCredits(); + + const config = vi.mocked(GatewayFetchMetadata).mock.calls[0][0]; + const headers = await config.headers(); + + expect(headers).toEqual({ + authorization: 'Bearer test-key', + 'ai-gateway-protocol-version': '0.0.1', + 'ai-gateway-auth-method': 'api-key', + 'custom-header': 'custom-value', + 'user-agent': 'ai-sdk/gateway/0.0.0-test', + }); + }); + + it('should be available on the provider interface', () => { + const provider = createGatewayProvider({ apiKey: 'test-key' }); + expect(typeof provider.getCredits).toBe('function'); + }); + }); + describe('Error handling in metadata fetching', () => { it('should convert metadata fetch errors to Gateway errors', async () => { mockGetAvailableModels.mockImplementation(() => { diff --git a/packages/gateway/src/gateway-provider.ts b/packages/gateway/src/gateway-provider.ts index 1a76ba35acf1..9abbe4376914 100644 --- a/packages/gateway/src/gateway-provider.ts +++ b/packages/gateway/src/gateway-provider.ts @@ -12,6 +12,7 @@ import { import { GatewayFetchMetadata, type GatewayFetchMetadataResponse, + type GatewayCreditsResponse, } from './gateway-fetch-metadata'; import { GatewayLanguageModel } from './gateway-language-model'; import { GatewayEmbeddingModel } from './gateway-embedding-model'; @@ -20,11 +21,13 @@ import { getVercelOidcToken, getVercelRequestId } from './vercel-environment'; import type { GatewayModelId } from './gateway-language-model-settings'; import type { LanguageModelV2, - EmbeddingModelV2, - ProviderV2, + EmbeddingModelV3, + ProviderV3, } from '@ai-sdk/provider'; +import { withUserAgentSuffix } from '@ai-sdk/provider-utils'; +import { VERSION } from './version'; -export interface GatewayProvider extends ProviderV2 { +export interface GatewayProvider extends ProviderV3 { (modelId: GatewayModelId): LanguageModelV2; /** @@ -37,12 +40,17 @@ Returns available providers and models for use with the remote provider. */ getAvailableModels(): Promise; + /** +Returns credit information for the authenticated user. + */ + getCredits(): Promise; + /** Creates a model for generating text embeddings. */ textEmbeddingModel( modelId: GatewayEmbeddingModelId, - ): EmbeddingModelV2; + ): EmbeddingModelV3; } export interface GatewayProviderSettings { @@ -101,12 +109,15 @@ export function createGatewayProvider( const getHeaders = async () => { const auth = await getGatewayAuthToken(options); if (auth) { - return { - Authorization: `Bearer ${auth.token}`, - 'ai-gateway-protocol-version': AI_GATEWAY_PROTOCOL_VERSION, - [GATEWAY_AUTH_METHOD_HEADER]: auth.authMethod, - ...options.headers, - }; + return withUserAgentSuffix( + { + Authorization: `Bearer ${auth.token}`, + 'ai-gateway-protocol-version': AI_GATEWAY_PROTOCOL_VERSION, + [GATEWAY_AUTH_METHOD_HEADER]: auth.authMethod, + ...options.headers, + }, + `ai-sdk/gateway/${VERSION}`, + ); } throw GatewayAuthenticationError.createContextualError({ @@ -174,6 +185,18 @@ export function createGatewayProvider( return metadataCache ? Promise.resolve(metadataCache) : pendingMetadata; }; + const getCredits = async () => { + return new GatewayFetchMetadata({ + baseURL, + headers: getHeaders, + fetch: options.fetch, + }) + .getCredits() + .catch(async (error: unknown) => { + throw asGatewayError(error, parseAuthMethod(await getHeaders())); + }); + }; + const provider = function (modelId: GatewayModelId) { if (new.target) { throw new Error( @@ -185,6 +208,7 @@ export function createGatewayProvider( }; provider.getAvailableModels = getAvailableModels; + provider.getCredits = getCredits; provider.imageModel = (modelId: string) => { throw new NoSuchModelError({ modelId, modelType: 'imageModel' }); }; diff --git a/packages/gateway/src/index.ts b/packages/gateway/src/index.ts index 6a94e0fa315a..f9f929a74918 100644 --- a/packages/gateway/src/index.ts +++ b/packages/gateway/src/index.ts @@ -3,6 +3,7 @@ export type { GatewayLanguageModelEntry, GatewayLanguageModelSpecification, } from './gateway-model-entry'; +export type { GatewayCreditsResponse } from './gateway-fetch-metadata'; export type { GatewayLanguageModelEntry as GatewayModelEntry } from './gateway-model-entry'; export { createGatewayProvider, diff --git a/packages/gateway/src/version.ts b/packages/gateway/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/gateway/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/gateway/tsconfig.json b/packages/gateway/tsconfig.json index 6d7c00da20f6..e26d6c5085a9 100644 --- a/packages/gateway/tsconfig.json +++ b/packages/gateway/tsconfig.json @@ -3,7 +3,10 @@ "compilerOptions": { "composite": true, "rootDir": "src", - "outDir": "dist" + "outDir": "dist", + "paths": { + "@ai-sdk/test-server": ["../test-server/src"] + } }, "exclude": ["dist", "build", "node_modules", "tsup.config.ts"], "references": [ @@ -12,6 +15,9 @@ }, { "path": "../provider-utils" + }, + { + "path": "../test-server" } ] } diff --git a/packages/gateway/tsup.config.ts b/packages/gateway/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/gateway/tsup.config.ts +++ b/packages/gateway/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/gateway/vitest.edge.config.js b/packages/gateway/vitest.edge.config.js index 3dc49ba29774..02b9e8c6cf92 100644 --- a/packages/gateway/vitest.edge.config.js +++ b/packages/gateway/vitest.edge.config.js @@ -1,7 +1,15 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; + +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, test: { environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], diff --git a/packages/gateway/vitest.node.config.js b/packages/gateway/vitest.node.config.js index b7e4a9cabd48..5b86131f58c6 100644 --- a/packages/gateway/vitest.node.config.js +++ b/packages/gateway/vitest.node.config.js @@ -1,7 +1,15 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; + +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, test: { environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], diff --git a/packages/gladia/CHANGELOG.md b/packages/gladia/CHANGELOG.md index dc08ab72f672..fd60468de660 100644 --- a/packages/gladia/CHANGELOG.md +++ b/packages/gladia/CHANGELOG.md @@ -1,5 +1,52 @@ # @ai-sdk/gladia +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.8 ### Patch Changes diff --git a/packages/gladia/package.json b/packages/gladia/package.json index e268740a7cb9..c1617f5f2e17 100644 --- a/packages/gladia/package.json +++ b/packages/gladia/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/gladia", - "version": "1.0.8", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -18,6 +18,7 @@ "type-check": "tsc --noEmit", "prettier-check": "prettier --check \"./**/*.ts*\"", "test": "pnpm test:node && pnpm test:edge", + "test:watch": "vitest --config vitest.node.config.js", "test:edge": "vitest --config vitest.edge.config.js --run", "test:node": "vitest --config vitest.node.config.js --run", "test:node:watch": "vitest --config vitest.node.config.js --watch" @@ -32,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/gladia/src/gladia-provider.ts b/packages/gladia/src/gladia-provider.ts index 235dad00d0d9..471ff4b4c2f2 100644 --- a/packages/gladia/src/gladia-provider.ts +++ b/packages/gladia/src/gladia-provider.ts @@ -1,12 +1,17 @@ import { TranscriptionModelV2, - ProviderV2, + ProviderV3, NoSuchModelError, } from '@ai-sdk/provider'; -import { FetchFunction, loadApiKey } from '@ai-sdk/provider-utils'; +import { + FetchFunction, + loadApiKey, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; import { GladiaTranscriptionModel } from './gladia-transcription-model'; +import { VERSION } from './version'; -export interface GladiaProvider extends ProviderV2 { +export interface GladiaProvider extends ProviderV3 { (): { transcription: GladiaTranscriptionModel; }; @@ -41,14 +46,18 @@ Create a Gladia provider instance. export function createGladia( options: GladiaProviderSettings = {}, ): GladiaProvider { - const getHeaders = () => ({ - 'x-gladia-key': loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'GLADIA_API_KEY', - description: 'Gladia', - }), - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + 'x-gladia-key': loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'GLADIA_API_KEY', + description: 'Gladia', + }), + ...options.headers, + }, + `ai-sdk/gladia/${VERSION}`, + ); const createTranscriptionModel = () => new GladiaTranscriptionModel('default', { @@ -67,7 +76,7 @@ export function createGladia( provider.transcription = createTranscriptionModel; provider.transcriptionModel = createTranscriptionModel; - // Required ProviderV2 methods that are not supported + // Required ProviderV3 methods that are not supported provider.languageModel = () => { throw new NoSuchModelError({ modelId: 'unknown', diff --git a/packages/gladia/src/gladia-transcription-model.test.ts b/packages/gladia/src/gladia-transcription-model.test.ts index dafe1adc2104..c89a2184bd87 100644 --- a/packages/gladia/src/gladia-transcription-model.test.ts +++ b/packages/gladia/src/gladia-transcription-model.test.ts @@ -1,9 +1,13 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { GladiaTranscriptionModel } from './gladia-transcription-model'; import { createGladia } from './gladia-provider'; import { readFile } from 'node:fs/promises'; import path from 'node:path'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const audioData = await readFile(path.join(__dirname, 'transcript-test.mp3')); const provider = createGladia({ apiKey: 'test-api-key' }); @@ -152,6 +156,9 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/gladia/0.0.0-test`, + ); }); it('should extract the transcription text', async () => { diff --git a/packages/gladia/src/index.ts b/packages/gladia/src/index.ts index 4e5bf690e0d8..35561c23467e 100644 --- a/packages/gladia/src/index.ts +++ b/packages/gladia/src/index.ts @@ -1,2 +1,3 @@ export { createGladia, gladia } from './gladia-provider'; export type { GladiaProvider, GladiaProviderSettings } from './gladia-provider'; +export { VERSION } from './version'; diff --git a/packages/gladia/src/version.ts b/packages/gladia/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/gladia/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/gladia/tsup.config.ts b/packages/gladia/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/gladia/tsup.config.ts +++ b/packages/gladia/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/gladia/vitest.edge.config.js b/packages/gladia/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/gladia/vitest.edge.config.js +++ b/packages/gladia/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/gladia/vitest.node.config.js b/packages/gladia/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/gladia/vitest.node.config.js +++ b/packages/gladia/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/google-vertex/CHANGELOG.md b/packages/google-vertex/CHANGELOG.md index c6206a2320c7..2cb79c847dd2 100644 --- a/packages/google-vertex/CHANGELOG.md +++ b/packages/google-vertex/CHANGELOG.md @@ -1,5 +1,79 @@ # @ai-sdk/google-vertex +## 3.1.0-beta.4 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/anthropic@2.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/google@2.1.0-beta.4 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 3.1.0-beta.3 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] +- Updated dependencies [1cad0ab] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/google@2.1.0-beta.3 + - @ai-sdk/anthropic@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 3.1.0-beta.2 + +### Patch Changes + +- Updated dependencies [7dea60e] + - @ai-sdk/google@2.1.0-beta.2 + +## 3.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/anthropic@2.1.0-beta.1 + - @ai-sdk/google@2.1.0-beta.1 + +## 3.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/anthropic@2.1.0-beta.0 + - @ai-sdk/google@2.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 3.0.27 + +### Patch Changes + +- Updated dependencies [da92132] + - @ai-sdk/anthropic@2.0.17 + +## 3.0.26 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/anthropic@2.0.16 + - @ai-sdk/google@2.0.14 + ## 3.0.25 ### Patch Changes diff --git a/packages/google-vertex/package.json b/packages/google-vertex/package.json index cabdba33506a..2c84a1c0cf31 100644 --- a/packages/google-vertex/package.json +++ b/packages/google-vertex/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/google-vertex", - "version": "3.0.25", + "version": "3.1.0-beta.4", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -54,6 +54,7 @@ "@ai-sdk/google": "workspace:*", "@ai-sdk/provider": "workspace:*", "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*", "google-auth-library": "^9.15.0" }, "devDependencies": { diff --git a/packages/google-vertex/src/anthropic/google-vertex-anthropic-provider.ts b/packages/google-vertex/src/anthropic/google-vertex-anthropic-provider.ts index 6ce30e818edb..4749d80d36c6 100644 --- a/packages/google-vertex/src/anthropic/google-vertex-anthropic-provider.ts +++ b/packages/google-vertex/src/anthropic/google-vertex-anthropic-provider.ts @@ -1,7 +1,7 @@ import { LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, @@ -14,7 +14,7 @@ import { AnthropicMessagesLanguageModel, } from '@ai-sdk/anthropic/internal'; import { GoogleVertexAnthropicMessagesModelId } from './google-vertex-anthropic-messages-options'; -export interface GoogleVertexAnthropicProvider extends ProviderV2 { +export interface GoogleVertexAnthropicProvider extends ProviderV3 { /** Creates a model for text generation. */ diff --git a/packages/google-vertex/src/edge/google-vertex-auth-edge.test.ts b/packages/google-vertex/src/edge/google-vertex-auth-edge.test.ts index 13621ea9c71b..dd7ce347e8f8 100644 --- a/packages/google-vertex/src/edge/google-vertex-auth-edge.test.ts +++ b/packages/google-vertex/src/edge/google-vertex-auth-edge.test.ts @@ -4,6 +4,20 @@ import { } from './google-vertex-auth-edge'; import { beforeEach, afterEach, describe, expect, it, vi } from 'vitest'; +// Mock provider-utils to control runtime environment detection +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + getRuntimeEnvironmentUserAgent: vi.fn(() => 'runtime/testenv'), + withUserAgentSuffix: actual.withUserAgentSuffix, + }; +}); + +vi.mock('../version', () => ({ + VERSION: '0.0.0-test', +})); + describe('Google Vertex Edge Auth', () => { const mockCredentials: GoogleCredentials = { clientEmail: 'test@test.iam.gserviceaccount.com', @@ -272,4 +286,23 @@ describe('Google Vertex Edge Auth', () => { const header = JSON.parse(atob(parts[0])); expect(header).not.toHaveProperty('kid'); }); + + it('should include correct user-agent header', async () => { + const mockFetch = vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve({ access_token: 'mock.jwt.token' }), + }); + global.fetch = mockFetch; + + await generateAuthToken(mockCredentials); + + expect(mockFetch).toHaveBeenCalledWith( + 'https://oauth2.googleapis.com/token', + expect.objectContaining({ + headers: expect.objectContaining({ + 'user-agent': 'ai-sdk/google-vertex/0.0.0-test runtime/testenv', + }), + }), + ); + }); }); diff --git a/packages/google-vertex/src/edge/google-vertex-auth-edge.ts b/packages/google-vertex/src/edge/google-vertex-auth-edge.ts index 5e8814b3455b..378887713842 100644 --- a/packages/google-vertex/src/edge/google-vertex-auth-edge.ts +++ b/packages/google-vertex/src/edge/google-vertex-auth-edge.ts @@ -1,4 +1,10 @@ -import { loadOptionalSetting, loadSetting } from '@ai-sdk/provider-utils'; +import { + loadOptionalSetting, + loadSetting, + withUserAgentSuffix, + getRuntimeEnvironmentUserAgent, +} from '@ai-sdk/provider-utils'; +import { VERSION } from '../version'; export interface GoogleCredentials { /** @@ -132,7 +138,11 @@ export async function generateAuthToken(credentials?: GoogleCredentials) { const response = await fetch('https://oauth2.googleapis.com/token', { method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + headers: withUserAgentSuffix( + { 'Content-Type': 'application/x-www-form-urlencoded' }, + `ai-sdk/google-vertex/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ), body: new URLSearchParams({ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion: jwt, diff --git a/packages/google-vertex/src/google-vertex-embedding-model.test.ts b/packages/google-vertex/src/google-vertex-embedding-model.test.ts index 6ea63548fb97..570fe41f683f 100644 --- a/packages/google-vertex/src/google-vertex-embedding-model.test.ts +++ b/packages/google-vertex/src/google-vertex-embedding-model.test.ts @@ -1,10 +1,15 @@ import { - EmbeddingModelV2Embedding, + EmbeddingModelV3Embedding, TooManyEmbeddingValuesForCallError, } from '@ai-sdk/provider'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { GoogleVertexEmbeddingModel } from './google-vertex-embedding-model'; import { describe, it, expect, vi } from 'vitest'; +import { createVertex } from './google-vertex-provider'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const dummyEmbeddings = [ [0.1, 0.2, 0.3], @@ -48,7 +53,7 @@ describe('GoogleVertexEmbeddingModel', () => { tokenCounts = [1, 1], headers, }: { - embeddings?: EmbeddingModelV2Embedding[]; + embeddings?: EmbeddingModelV3Embedding[]; tokenCounts?: number[]; headers?: Record; } = {}) { @@ -167,21 +172,20 @@ describe('GoogleVertexEmbeddingModel', () => { }); }); + // changed test to go through the provider `createVertex` it('should pass headers correctly', async () => { prepareJsonResponse(); - const model = new GoogleVertexEmbeddingModel(mockModelId, { - ...mockConfig, - headers: () => ({ - 'X-Custom-Header': 'custom-value', - }), + const provider = createVertex({ + project: 'test-project', + location: 'us-central1', + headers: { 'X-Custom-Header': 'custom-value' }, }); - await model.doEmbed({ + await provider.textEmbeddingModel(mockModelId).doEmbed({ values: testValues, - headers: { - 'X-Request-Header': 'request-value', - }, + headers: { 'X-Request-Header': 'request-value' }, + providerOptions: { google: mockProviderOptions }, }); expect(server.calls[0].requestHeaders).toStrictEqual({ @@ -189,6 +193,9 @@ describe('GoogleVertexEmbeddingModel', () => { 'x-custom-header': 'custom-value', 'x-request-header': 'request-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/google-vertex/0.0.0-test`, + ); }); it('should throw TooManyEmbeddingValuesForCallError when too many values provided', async () => { diff --git a/packages/google-vertex/src/google-vertex-embedding-model.ts b/packages/google-vertex/src/google-vertex-embedding-model.ts index e226df34adb1..0f69d45a37bd 100644 --- a/packages/google-vertex/src/google-vertex-embedding-model.ts +++ b/packages/google-vertex/src/google-vertex-embedding-model.ts @@ -1,5 +1,5 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, TooManyEmbeddingValuesForCallError, } from '@ai-sdk/provider'; import { @@ -18,8 +18,8 @@ import { } from './google-vertex-embedding-options'; import { GoogleVertexConfig } from './google-vertex-config'; -export class GoogleVertexEmbeddingModel implements EmbeddingModelV2 { - readonly specificationVersion = 'v2'; +export class GoogleVertexEmbeddingModel implements EmbeddingModelV3 { + readonly specificationVersion = 'v3'; readonly modelId: GoogleVertexEmbeddingModelId; readonly maxEmbeddingsPerCall = 2048; readonly supportsParallelCalls = true; @@ -43,8 +43,8 @@ export class GoogleVertexEmbeddingModel implements EmbeddingModelV2 { headers, abortSignal, providerOptions, - }: Parameters['doEmbed']>[0]): Promise< - Awaited['doEmbed']>> + }: Parameters['doEmbed']>[0]): Promise< + Awaited['doEmbed']>> > { // Parse provider options const googleOptions = diff --git a/packages/google-vertex/src/google-vertex-image-model.test.ts b/packages/google-vertex/src/google-vertex-image-model.test.ts index d894fd752b13..ee7cf10e57c4 100644 --- a/packages/google-vertex/src/google-vertex-image-model.test.ts +++ b/packages/google-vertex/src/google-vertex-image-model.test.ts @@ -1,6 +1,11 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { GoogleVertexImageModel } from './google-vertex-image-model'; -import { describe, it, expect } from 'vitest'; +import { createVertex } from './google-vertex-provider'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const prompt = 'A cute baby sea otter'; @@ -50,30 +55,25 @@ describe('GoogleVertexImageModel', () => { }; } + // changed test to go through the provider `createVertex` it('should pass headers', async () => { prepareJsonResponse(); - const modelWithHeaders = new GoogleVertexImageModel( - 'imagen-3.0-generate-002', - { - provider: 'google-vertex', - baseURL: 'https://api.example.com', - headers: { - 'Custom-Provider-Header': 'provider-header-value', - }, - }, - ); + const provider = createVertex({ + project: 'test-project', + location: 'us-central1', + baseURL: 'https://api.example.com', + headers: { 'Custom-Provider-Header': 'provider-header-value' }, + }); - await modelWithHeaders.doGenerate({ + await provider.imageModel('imagen-3.0-generate-002').doGenerate({ prompt, n: 2, size: undefined, aspectRatio: undefined, seed: undefined, providerOptions: {}, - headers: { - 'Custom-Request-Header': 'request-header-value', - }, + headers: { 'Custom-Request-Header': 'request-header-value' }, }); expect(server.calls[0].requestHeaders).toStrictEqual({ @@ -81,6 +81,9 @@ describe('GoogleVertexImageModel', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/google-vertex/0.0.0-test`, + ); }); it('should use default maxImagesPerCall when not specified', () => { diff --git a/packages/google-vertex/src/google-vertex-image-model.ts b/packages/google-vertex/src/google-vertex-image-model.ts index 52133a9f04ae..f1de3f60a3f4 100644 --- a/packages/google-vertex/src/google-vertex-image-model.ts +++ b/packages/google-vertex/src/google-vertex-image-model.ts @@ -1,4 +1,4 @@ -import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider'; +import { ImageModelV3, ImageModelV3CallWarning } from '@ai-sdk/provider'; import { Resolvable, combineHeaders, @@ -22,8 +22,8 @@ interface GoogleVertexImageModelConfig { } // https://cloud.google.com/vertex-ai/generative-ai/docs/image/generate-images -export class GoogleVertexImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class GoogleVertexImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; // https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/imagen-api#parameter_list readonly maxImagesPerCall = 4; @@ -45,10 +45,10 @@ export class GoogleVertexImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; if (size != null) { warnings.push({ diff --git a/packages/google-vertex/src/google-vertex-provider.test.ts b/packages/google-vertex/src/google-vertex-provider.test.ts index 3da5e385a7cc..119ea2e10690 100644 --- a/packages/google-vertex/src/google-vertex-provider.test.ts +++ b/packages/google-vertex/src/google-vertex-provider.test.ts @@ -46,7 +46,7 @@ describe('google-vertex-provider', () => { provider: 'google.vertex.chat', baseURL: 'https://test-location-aiplatform.googleapis.com/v1/projects/test-project/locations/test-location/publishers/google', - headers: expect.any(Object), + headers: expect.any(Function), generateId: expect.any(Function), }), ); @@ -71,7 +71,7 @@ describe('google-vertex-provider', () => { 'test-embedding-model', expect.objectContaining({ provider: 'google.vertex.embedding', - headers: expect.any(Object), + headers: expect.any(Function), baseURL: 'https://test-location-aiplatform.googleapis.com/v1/projects/test-project/locations/test-location/publishers/google', }), @@ -90,7 +90,7 @@ describe('google-vertex-provider', () => { expect(GoogleGenerativeAILanguageModel).toHaveBeenCalledWith( expect.anything(), expect.objectContaining({ - headers: customHeaders, + headers: expect.any(Function), }), ); }); @@ -155,7 +155,7 @@ describe('google-vertex-provider', () => { provider: 'google.vertex.image', baseURL: 'https://test-location-aiplatform.googleapis.com/v1/projects/test-project/locations/test-location/publishers/google', - headers: expect.any(Object), + headers: expect.any(Function), }), ); }); @@ -173,7 +173,7 @@ describe('google-vertex-provider', () => { provider: 'google.vertex.chat', baseURL: 'https://aiplatform.googleapis.com/v1/projects/test-project/locations/global/publishers/google', - headers: expect.any(Object), + headers: expect.any(Function), generateId: expect.any(Function), }), ); @@ -190,7 +190,7 @@ describe('google-vertex-provider', () => { 'test-embedding-model', expect.objectContaining({ provider: 'google.vertex.embedding', - headers: expect.any(Object), + headers: expect.any(Function), baseURL: 'https://aiplatform.googleapis.com/v1/projects/test-project/locations/global/publishers/google', }), @@ -210,7 +210,7 @@ describe('google-vertex-provider', () => { provider: 'google.vertex.image', baseURL: 'https://aiplatform.googleapis.com/v1/projects/test-project/locations/global/publishers/google', - headers: expect.any(Object), + headers: expect.any(Function), }), ); }); @@ -240,7 +240,7 @@ describe('google-vertex-provider', () => { provider: 'google.vertex.chat', baseURL: 'https://us-central1-aiplatform.googleapis.com/v1/projects/test-project/locations/us-central1/publishers/google', - headers: expect.any(Object), + headers: expect.any(Function), generateId: expect.any(Function), }), ); diff --git a/packages/google-vertex/src/google-vertex-provider.ts b/packages/google-vertex/src/google-vertex-provider.ts index badcfa6e77e8..6fa9f788f424 100644 --- a/packages/google-vertex/src/google-vertex-provider.ts +++ b/packages/google-vertex/src/google-vertex-provider.ts @@ -1,12 +1,15 @@ import { GoogleGenerativeAILanguageModel } from '@ai-sdk/google/internal'; -import { ImageModelV2, LanguageModelV2, ProviderV2 } from '@ai-sdk/provider'; +import { ImageModelV3, LanguageModelV2, ProviderV3 } from '@ai-sdk/provider'; import { FetchFunction, generateId, loadSetting, + resolve, Resolvable, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; +import { VERSION } from './version'; import { GoogleVertexConfig } from './google-vertex-config'; import { GoogleVertexEmbeddingModel } from './google-vertex-embedding-model'; import { GoogleVertexEmbeddingModelId } from './google-vertex-embedding-options'; @@ -15,7 +18,7 @@ import { GoogleVertexImageModelId } from './google-vertex-image-settings'; import { GoogleVertexModelId } from './google-vertex-options'; import { googleVertexTools } from './google-vertex-tools'; -export interface GoogleVertexProvider extends ProviderV2 { +export interface GoogleVertexProvider extends ProviderV3 { /** Creates a model for text generation. */ @@ -26,12 +29,12 @@ Creates a model for text generation. /** * Creates a model for image generation. */ - image(modelId: GoogleVertexImageModelId): ImageModelV2; + image(modelId: GoogleVertexImageModelId): ImageModelV3; /** Creates a model for image generation. */ - imageModel(modelId: GoogleVertexImageModelId): ImageModelV2; + imageModel(modelId: GoogleVertexImageModelId): ImageModelV3; tools: typeof googleVertexTools; } @@ -108,9 +111,18 @@ export function createVertex( }; const createConfig = (name: string): GoogleVertexConfig => { + // Create a function that adds the user-agent suffix to headers + const getHeaders = async () => { + const originalHeaders = await resolve(options.headers ?? {}); + return withUserAgentSuffix( + originalHeaders, + `ai-sdk/google-vertex/${VERSION}`, + ); + }; + return { provider: `google.vertex.${name}`, - headers: options.headers ?? {}, + headers: getHeaders, fetch: options.fetch, baseURL: loadBaseURL(), }; diff --git a/packages/google-vertex/src/index.ts b/packages/google-vertex/src/index.ts index e84f8e06d72f..028275566864 100644 --- a/packages/google-vertex/src/index.ts +++ b/packages/google-vertex/src/index.ts @@ -4,3 +4,4 @@ export type { GoogleVertexProvider, GoogleVertexProviderSettings, } from './google-vertex-provider-node'; +export { VERSION } from './version'; diff --git a/packages/google-vertex/src/version.ts b/packages/google-vertex/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/google-vertex/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/google-vertex/tsup.config.ts b/packages/google-vertex/tsup.config.ts index 9842250fc08f..46ec8c78dd1c 100644 --- a/packages/google-vertex/tsup.config.ts +++ b/packages/google-vertex/tsup.config.ts @@ -6,6 +6,12 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, outDir: 'dist', }, { @@ -13,6 +19,12 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, outDir: 'dist/edge', }, { @@ -20,6 +32,12 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, outDir: 'dist/anthropic', }, { @@ -27,6 +45,12 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, outDir: 'dist/anthropic/edge', }, ]); diff --git a/packages/google-vertex/vitest.edge.config.js b/packages/google-vertex/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/google-vertex/vitest.edge.config.js +++ b/packages/google-vertex/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/google-vertex/vitest.node.config.js b/packages/google-vertex/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/google-vertex/vitest.node.config.js +++ b/packages/google-vertex/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/google/CHANGELOG.md b/packages/google/CHANGELOG.md index 74116f473935..dad06f11a114 100644 --- a/packages/google/CHANGELOG.md +++ b/packages/google/CHANGELOG.md @@ -1,5 +1,60 @@ # @ai-sdk/google +## 2.1.0-beta.4 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.3 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.2 + +### Patch Changes + +- 7dea60e: add promptFeedback outputs + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.14 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 2.0.13 ### Patch Changes diff --git a/packages/google/package.json b/packages/google/package.json index c608da9b602c..5ff40d318437 100644 --- a/packages/google/package.json +++ b/packages/google/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/google", - "version": "2.0.13", + "version": "2.1.0-beta.4", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -40,7 +40,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/google/src/google-generative-ai-embedding-model.test.ts b/packages/google/src/google-generative-ai-embedding-model.test.ts index b1da11a0f3a1..680f95da93d0 100644 --- a/packages/google/src/google-generative-ai-embedding-model.test.ts +++ b/packages/google/src/google-generative-ai-embedding-model.test.ts @@ -1,8 +1,12 @@ -import { EmbeddingModelV2Embedding } from '@ai-sdk/provider'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { EmbeddingModelV3Embedding } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { GoogleGenerativeAIEmbeddingModel } from './google-generative-ai-embedding-model'; import { createGoogleGenerativeAI } from './google-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const dummyEmbeddings = [ [0.1, 0.2, 0.3, 0.4, 0.5], @@ -25,7 +29,7 @@ describe('GoogleGenerativeAIEmbeddingModel', () => { embeddings = dummyEmbeddings, headers, }: { - embeddings?: EmbeddingModelV2Embedding[]; + embeddings?: EmbeddingModelV3Embedding[]; headers?: Record; } = {}) { server.urls[URL].response = { @@ -41,7 +45,7 @@ describe('GoogleGenerativeAIEmbeddingModel', () => { embeddings = dummyEmbeddings, headers, }: { - embeddings?: EmbeddingModelV2Embedding[]; + embeddings?: EmbeddingModelV3Embedding[]; headers?: Record; } = {}) { server.urls[URL].response = { @@ -153,6 +157,9 @@ describe('GoogleGenerativeAIEmbeddingModel', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/google/0.0.0-test`, + ); }); it('should throw an error if too many values are provided', async () => { diff --git a/packages/google/src/google-generative-ai-embedding-model.ts b/packages/google/src/google-generative-ai-embedding-model.ts index 61bdbf57dd0a..f893bbea7802 100644 --- a/packages/google/src/google-generative-ai-embedding-model.ts +++ b/packages/google/src/google-generative-ai-embedding-model.ts @@ -1,5 +1,5 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, TooManyEmbeddingValuesForCallError, } from '@ai-sdk/provider'; import { @@ -25,9 +25,9 @@ type GoogleGenerativeAIEmbeddingConfig = { }; export class GoogleGenerativeAIEmbeddingModel - implements EmbeddingModelV2 + implements EmbeddingModelV3 { - readonly specificationVersion = 'v2'; + readonly specificationVersion = 'v3'; readonly modelId: GoogleGenerativeAIEmbeddingModelId; readonly maxEmbeddingsPerCall = 2048; readonly supportsParallelCalls = true; @@ -50,8 +50,8 @@ export class GoogleGenerativeAIEmbeddingModel headers, abortSignal, providerOptions, - }: Parameters['doEmbed']>[0]): Promise< - Awaited['doEmbed']>> + }: Parameters['doEmbed']>[0]): Promise< + Awaited['doEmbed']>> > { // Parse provider options const googleOptions = await parseProviderOptions({ diff --git a/packages/google/src/google-generative-ai-image-model.test.ts b/packages/google/src/google-generative-ai-image-model.test.ts index 4f875ca6d2f7..f273a1e9f3da 100644 --- a/packages/google/src/google-generative-ai-image-model.test.ts +++ b/packages/google/src/google-generative-ai-image-model.test.ts @@ -1,4 +1,4 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { GoogleGenerativeAIImageModel } from './google-generative-ai-image-model'; import { describe, it, expect } from 'vitest'; diff --git a/packages/google/src/google-generative-ai-image-model.ts b/packages/google/src/google-generative-ai-image-model.ts index 98b6cc6729f7..7dea4f9c0943 100644 --- a/packages/google/src/google-generative-ai-image-model.ts +++ b/packages/google/src/google-generative-ai-image-model.ts @@ -1,4 +1,4 @@ -import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider'; +import { ImageModelV3, ImageModelV3CallWarning } from '@ai-sdk/provider'; import { combineHeaders, createJsonResponseHandler, @@ -25,8 +25,8 @@ interface GoogleGenerativeAIImageModelConfig { }; } -export class GoogleGenerativeAIImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class GoogleGenerativeAIImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; get maxImagesPerCall(): number { // https://ai.google.dev/gemini-api/docs/imagen#imagen-model @@ -44,8 +44,8 @@ export class GoogleGenerativeAIImageModel implements ImageModelV2 { ) {} async doGenerate( - options: Parameters[0], - ): Promise>> { + options: Parameters[0], + ): Promise>> { const { prompt, n = 1, @@ -56,7 +56,7 @@ export class GoogleGenerativeAIImageModel implements ImageModelV2 { headers, abortSignal, } = options; - const warnings: Array = []; + const warnings: Array = []; if (size != null) { warnings.push({ diff --git a/packages/google/src/google-generative-ai-language-model.test.ts b/packages/google/src/google-generative-ai-language-model.test.ts index 1f63c10ece64..edab0b770357 100644 --- a/packages/google/src/google-generative-ai-language-model.test.ts +++ b/packages/google/src/google-generative-ai-language-model.test.ts @@ -2,10 +2,8 @@ import { LanguageModelV2Prompt, LanguageModelV2ProviderDefinedTool, } from '@ai-sdk/provider'; -import { - convertReadableStreamToArray, - createTestServer, -} from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; +import { convertReadableStreamToArray } from '@ai-sdk/provider-utils/test'; import { GoogleGenerativeAILanguageModel } from './google-generative-ai-language-model'; import { @@ -15,7 +13,11 @@ import { import { createGoogleGenerativeAI } from './google-provider'; import { groundingMetadataSchema } from './tool/google-search'; import { urlContextMetadataSchema } from './tool/url-context'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const TEST_PROMPT: LanguageModelV2Prompt = [ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, @@ -675,6 +677,9 @@ describe('doGenerate', () => { 'custom-request-header': 'request-header-value', 'x-goog-api-key': 'test-api-key', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/google/0.0.0-test`, + ); }); it('should pass response format', async () => { @@ -925,6 +930,35 @@ describe('doGenerate', () => { ]); }); + it('should expose PromptFeedback in provider metadata', async () => { + server.urls[TEST_URL_GEMINI_PRO].response = { + type: 'json-value', + body: { + candidates: [ + { + content: { parts: [{ text: 'No' }], role: 'model' }, + finishReason: 'SAFETY', + index: 0, + safetyRatings: SAFETY_RATINGS, + }, + ], + promptFeedback: { + blockReason: 'SAFETY', + safetyRatings: SAFETY_RATINGS, + }, + }, + }; + + const { providerMetadata } = await model.doGenerate({ + prompt: TEST_PROMPT, + }); + + expect(providerMetadata?.google.promptFeedback).toStrictEqual({ + blockReason: 'SAFETY', + safetyRatings: SAFETY_RATINGS, + }); + }); + it('should expose grounding metadata in provider metadata', async () => { prepareJsonResponse({ content: 'test response', @@ -1900,6 +1934,7 @@ describe('doStream', () => { "providerMetadata": { "google": { "groundingMetadata": null, + "promptFeedback": null, "safetyRatings": [ { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", @@ -1973,6 +2008,36 @@ describe('doStream', () => { ]); }); + it('should expose PromptFeedback in provider metadata on finish', async () => { + server.urls[TEST_URL_GEMINI_PRO].response = { + type: 'stream-chunks', + chunks: [ + `data: {"candidates": [{"content": {"parts": [{"text": "No"}],"role": "model"},` + + `"finishReason": "PROHIBITED_CONTENT","index": 0}],` + + `"promptFeedback": {"blockReason": "PROHIBITED_CONTENT","safetyRatings": [` + + `{"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT","probability": "NEGLIGIBLE"},` + + `{"category": "HARM_CATEGORY_HATE_SPEECH","probability": "NEGLIGIBLE"},` + + `{"category": "HARM_CATEGORY_HARASSMENT","probability": "NEGLIGIBLE"},` + + `{"category": "HARM_CATEGORY_DANGEROUS_CONTENT","probability": "NEGLIGIBLE"}]}}\n\n`, + ], + }; + + const { stream } = await model.doStream({ + prompt: TEST_PROMPT, + }); + + const events = await convertReadableStreamToArray(stream); + const finishEvent = events.find(event => event.type === 'finish'); + + expect( + finishEvent?.type === 'finish' && + finishEvent.providerMetadata?.google.promptFeedback, + ).toStrictEqual({ + blockReason: 'PROHIBITED_CONTENT', + safetyRatings: SAFETY_RATINGS, + }); + }); + it('should stream code execution tool calls and results', async () => { server.urls[TEST_URL_GEMINI_2_0_PRO].response = { type: 'stream-chunks', @@ -2387,6 +2452,7 @@ describe('doStream', () => { "providerMetadata": { "google": { "groundingMetadata": null, + "promptFeedback": null, "safetyRatings": [ { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", @@ -2666,6 +2732,7 @@ describe('doStream', () => { "providerMetadata": { "google": { "groundingMetadata": null, + "promptFeedback": null, "safetyRatings": null, "urlContextMetadata": null, "usageMetadata": { @@ -2794,6 +2861,7 @@ describe('doStream', () => { "providerMetadata": { "google": { "groundingMetadata": null, + "promptFeedback": null, "safetyRatings": [ { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", diff --git a/packages/google/src/google-generative-ai-language-model.ts b/packages/google/src/google-generative-ai-language-model.ts index 4ed0996b08ba..d0aea7454f6a 100644 --- a/packages/google/src/google-generative-ai-language-model.ts +++ b/packages/google/src/google-generative-ai-language-model.ts @@ -292,6 +292,7 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV2 { warnings, providerMetadata: { google: { + promptFeedback: response.promptFeedback ?? null, groundingMetadata: candidate.groundingMetadata ?? null, urlContextMetadata: candidate.urlContextMetadata ?? null, safetyRatings: candidate.safetyRatings ?? null, @@ -590,6 +591,7 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV2 { providerMetadata = { google: { + promptFeedback: value.promptFeedback ?? null, groundingMetadata: candidate.groundingMetadata ?? null, urlContextMetadata: candidate.urlContextMetadata ?? null, safetyRatings: candidate.safetyRatings ?? null, @@ -763,6 +765,12 @@ const responseSchema = z.object({ }), ), usageMetadata: usageSchema.nullish(), + promptFeedback: z + .object({ + blockReason: z.string().nullish(), + safetyRatings: z.array(safetyRatingSchema).nullish(), + }) + .nullish(), }); // limited version of the schema, focussed on what is needed for the implementation @@ -780,4 +788,10 @@ const chunkSchema = z.object({ ) .nullish(), usageMetadata: usageSchema.nullish(), + promptFeedback: z + .object({ + blockReason: z.string().nullish(), + safetyRatings: z.array(safetyRatingSchema).nullish(), + }) + .nullish(), }); diff --git a/packages/google/src/google-provider.test.ts b/packages/google/src/google-provider.test.ts index ca5a1772c65a..baef649c254f 100644 --- a/packages/google/src/google-provider.test.ts +++ b/packages/google/src/google-provider.test.ts @@ -25,7 +25,9 @@ vi.mock('./google-generative-ai-embedding-model', () => ({ vi.mock('./google-generative-ai-image-model', () => ({ GoogleGenerativeAIImageModel: vi.fn(), })); - +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); describe('google-provider', () => { beforeEach(() => { vi.clearAllMocks(); @@ -92,7 +94,8 @@ describe('google-provider', () => { const headers = options.headers(); expect(headers).toEqual({ 'x-goog-api-key': 'test-api-key', - 'Custom-Header': 'custom-value', + 'custom-header': 'custom-value', + 'user-agent': 'ai-sdk/google/0.0.0-test', }); }); diff --git a/packages/google/src/google-provider.ts b/packages/google/src/google-provider.ts index df81d9cdce2a..baedc3134cc8 100644 --- a/packages/google/src/google-provider.ts +++ b/packages/google/src/google-provider.ts @@ -1,15 +1,17 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, LanguageModelV2, - ProviderV2, - ImageModelV2, + ProviderV3, + ImageModelV3, } from '@ai-sdk/provider'; import { FetchFunction, generateId, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; +import { VERSION } from './version'; import { GoogleGenerativeAIEmbeddingModel } from './google-generative-ai-embedding-model'; import { GoogleGenerativeAIEmbeddingModelId } from './google-generative-ai-embedding-options'; import { GoogleGenerativeAILanguageModel } from './google-generative-ai-language-model'; @@ -22,7 +24,7 @@ import { } from './google-generative-ai-image-settings'; import { GoogleGenerativeAIImageModel } from './google-generative-ai-image-model'; -export interface GoogleGenerativeAIProvider extends ProviderV2 { +export interface GoogleGenerativeAIProvider extends ProviderV3 { (modelId: GoogleGenerativeAIModelId): LanguageModelV2; languageModel(modelId: GoogleGenerativeAIModelId): LanguageModelV2; @@ -35,7 +37,7 @@ Creates a model for image generation. image( modelId: GoogleGenerativeAIImageModelId, settings?: GoogleGenerativeAIImageSettings, - ): ImageModelV2; + ): ImageModelV3; /** * @deprecated Use `chat()` instead. @@ -47,15 +49,15 @@ Creates a model for image generation. */ embedding( modelId: GoogleGenerativeAIEmbeddingModelId, - ): EmbeddingModelV2; + ): EmbeddingModelV3; textEmbedding( modelId: GoogleGenerativeAIEmbeddingModelId, - ): EmbeddingModelV2; + ): EmbeddingModelV3; textEmbeddingModel( modelId: GoogleGenerativeAIEmbeddingModelId, - ): EmbeddingModelV2; + ): EmbeddingModelV3; tools: typeof googleTools; } @@ -100,14 +102,18 @@ export function createGoogleGenerativeAI( withoutTrailingSlash(options.baseURL) ?? 'https://generativelanguage.googleapis.com/v1beta'; - const getHeaders = () => ({ - 'x-goog-api-key': loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'GOOGLE_GENERATIVE_AI_API_KEY', - description: 'Google Generative AI', - }), - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + 'x-goog-api-key': loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'GOOGLE_GENERATIVE_AI_API_KEY', + description: 'Google Generative AI', + }), + ...options.headers, + }, + `ai-sdk/google/${VERSION}`, + ); const createChatModel = (modelId: GoogleGenerativeAIModelId) => new GoogleGenerativeAILanguageModel(modelId, { diff --git a/packages/google/src/index.ts b/packages/google/src/index.ts index 498e6105cc82..983c4f2df1ef 100644 --- a/packages/google/src/index.ts +++ b/packages/google/src/index.ts @@ -8,3 +8,4 @@ export type { GoogleGenerativeAIProvider, GoogleGenerativeAIProviderSettings, } from './google-provider'; +export { VERSION } from './version'; diff --git a/packages/google/src/version.ts b/packages/google/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/google/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/google/tsup.config.ts b/packages/google/tsup.config.ts index 87efcf0d5720..d0b56a7122cd 100644 --- a/packages/google/tsup.config.ts +++ b/packages/google/tsup.config.ts @@ -6,6 +6,12 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, { entry: ['src/internal/index.ts'], @@ -13,5 +19,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/google/vitest.edge.config.js b/packages/google/vitest.edge.config.js index 3dc49ba29774..265b201c0a28 100644 --- a/packages/google/vitest.edge.config.js +++ b/packages/google/vitest.edge.config.js @@ -1,7 +1,14 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, test: { environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], diff --git a/packages/google/vitest.node.config.js b/packages/google/vitest.node.config.js index b7e4a9cabd48..28e23c82c433 100644 --- a/packages/google/vitest.node.config.js +++ b/packages/google/vitest.node.config.js @@ -1,4 +1,8 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +10,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, }); diff --git a/packages/groq/CHANGELOG.md b/packages/groq/CHANGELOG.md index ff7a4dfe28e2..4cfe93119fa5 100644 --- a/packages/groq/CHANGELOG.md +++ b/packages/groq/CHANGELOG.md @@ -1,5 +1,53 @@ # @ai-sdk/groq +## 2.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.1 + +### Patch Changes + +- 3f464f4: fix(provider/groq): track cached tokens usage +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.19 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 2.0.18 ### Patch Changes diff --git a/packages/groq/package.json b/packages/groq/package.json index 2bf2ff32a594..ab081a84a2a3 100644 --- a/packages/groq/package.json +++ b/packages/groq/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/groq", - "version": "2.0.18", + "version": "2.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -33,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/groq/src/groq-chat-language-model.test.ts b/packages/groq/src/groq-chat-language-model.test.ts index 92d0a2f46f8d..00365a94d351 100644 --- a/packages/groq/src/groq-chat-language-model.test.ts +++ b/packages/groq/src/groq-chat-language-model.test.ts @@ -1,11 +1,15 @@ import { LanguageModelV2Prompt } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, isNodeVersion, } from '@ai-sdk/provider-utils/test'; import { createGroq } from './groq-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const TEST_PROMPT: LanguageModelV2Prompt = [ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, @@ -53,6 +57,9 @@ describe('doGenerate', () => { prompt_tokens?: number; total_tokens?: number; completion_tokens?: number; + prompt_tokens_details?: { + cached_tokens?: number; + }; }; finish_reason?: string; created?: number; @@ -134,6 +141,7 @@ describe('doGenerate', () => { expect(usage).toMatchInlineSnapshot(` { + "cachedInputTokens": undefined, "inputTokens": 20, "outputTokens": 5, "totalTokens": 25, @@ -173,12 +181,40 @@ describe('doGenerate', () => { expect(usage).toMatchInlineSnapshot(` { + "cachedInputTokens": undefined, "inputTokens": 20, "outputTokens": undefined, "totalTokens": 20, } `); }); + + it('should extract cached input tokens', async () => { + prepareJsonResponse({ + usage: { + prompt_tokens: 20, + total_tokens: 25, + completion_tokens: 5, + prompt_tokens_details: { + cached_tokens: 15, + }, + }, + }); + + const { usage } = await model.doGenerate({ + prompt: TEST_PROMPT, + }); + + expect(usage).toMatchInlineSnapshot(` + { + "cachedInputTokens": 15, + "inputTokens": 20, + "outputTokens": 5, + "totalTokens": 25, + } + `); + }); + it('should extract finish reason', async () => { prepareJsonResponse({ finish_reason: 'stop', @@ -351,6 +387,9 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/groq/0.0.0-test`, + ); }); it('should parse tool results', async () => { @@ -812,6 +851,7 @@ describe('doStream', () => { "finishReason": "stop", "type": "finish", "usage": { + "cachedInputTokens": undefined, "inputTokens": 18, "outputTokens": 439, "totalTokens": 457, @@ -895,6 +935,7 @@ describe('doStream', () => { "finishReason": "stop", "type": "finish", "usage": { + "cachedInputTokens": undefined, "inputTokens": 18, "outputTokens": 439, "totalTokens": 457, @@ -1025,6 +1066,7 @@ describe('doStream', () => { "finishReason": "tool-calls", "type": "finish", "usage": { + "cachedInputTokens": undefined, "inputTokens": 18, "outputTokens": 439, "totalTokens": 457, @@ -1160,6 +1202,7 @@ describe('doStream', () => { "finishReason": "tool-calls", "type": "finish", "usage": { + "cachedInputTokens": undefined, "inputTokens": 18, "outputTokens": 439, "totalTokens": 457, @@ -1286,6 +1329,7 @@ describe('doStream', () => { "finishReason": "tool-calls", "type": "finish", "usage": { + "cachedInputTokens": undefined, "inputTokens": undefined, "outputTokens": undefined, "totalTokens": undefined, @@ -1365,6 +1409,7 @@ describe('doStream', () => { "finishReason": "tool-calls", "type": "finish", "usage": { + "cachedInputTokens": undefined, "inputTokens": 18, "outputTokens": 439, "totalTokens": 457, @@ -1405,6 +1450,7 @@ describe('doStream', () => { "finishReason": "error", "type": "finish", "usage": { + "cachedInputTokens": undefined, "inputTokens": undefined, "outputTokens": undefined, "totalTokens": undefined, @@ -1443,6 +1489,7 @@ describe('doStream', () => { "finishReason": "error", "type": "finish", "usage": { + "cachedInputTokens": undefined, "inputTokens": undefined, "outputTokens": undefined, "totalTokens": undefined, @@ -1643,6 +1690,7 @@ describe('doStream with raw chunks', () => { "finishReason": "stop", "type": "finish", "usage": { + "cachedInputTokens": undefined, "inputTokens": 10, "outputTokens": 5, "totalTokens": 15, diff --git a/packages/groq/src/groq-chat-language-model.ts b/packages/groq/src/groq-chat-language-model.ts index c3cd0fe73958..a6811c3aadcf 100644 --- a/packages/groq/src/groq-chat-language-model.ts +++ b/packages/groq/src/groq-chat-language-model.ts @@ -224,6 +224,8 @@ export class GroqChatLanguageModel implements LanguageModelV2 { inputTokens: response.usage?.prompt_tokens ?? undefined, outputTokens: response.usage?.completion_tokens ?? undefined, totalTokens: response.usage?.total_tokens ?? undefined, + cachedInputTokens: + response.usage?.prompt_tokens_details?.cached_tokens ?? undefined, }, response: { ...getResponseMetadata(response), @@ -274,6 +276,7 @@ export class GroqChatLanguageModel implements LanguageModelV2 { inputTokens: undefined, outputTokens: undefined, totalTokens: undefined, + cachedInputTokens: undefined, }; let isFirstChunk = true; let isActiveText = false; @@ -326,6 +329,9 @@ export class GroqChatLanguageModel implements LanguageModelV2 { usage.outputTokens = value.x_groq.usage.completion_tokens ?? undefined; usage.totalTokens = value.x_groq.usage.total_tokens ?? undefined; + usage.cachedInputTokens = + value.x_groq.usage.prompt_tokens_details?.cached_tokens ?? + undefined; } const choice = value.choices[0]; @@ -546,6 +552,11 @@ const groqChatResponseSchema = z.object({ prompt_tokens: z.number().nullish(), completion_tokens: z.number().nullish(), total_tokens: z.number().nullish(), + prompt_tokens_details: z + .object({ + cached_tokens: z.number().nullish(), + }) + .nullish(), }) .nullish(), }); @@ -589,6 +600,11 @@ const groqChatChunkSchema = z.union([ prompt_tokens: z.number().nullish(), completion_tokens: z.number().nullish(), total_tokens: z.number().nullish(), + prompt_tokens_details: z + .object({ + cached_tokens: z.number().nullish(), + }) + .nullish(), }) .nullish(), }) diff --git a/packages/groq/src/groq-provider.ts b/packages/groq/src/groq-provider.ts index 8cc8cc6520e2..7deadbd9b2a7 100644 --- a/packages/groq/src/groq-provider.ts +++ b/packages/groq/src/groq-provider.ts @@ -1,13 +1,14 @@ import { LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, TranscriptionModelV2, } from '@ai-sdk/provider'; import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { GroqChatLanguageModel } from './groq-chat-language-model'; import { GroqChatModelId } from './groq-chat-options'; @@ -15,7 +16,8 @@ import { GroqTranscriptionModelId } from './groq-transcription-options'; import { GroqTranscriptionModel } from './groq-transcription-model'; import { groqTools } from './groq-tools'; -export interface GroqProvider extends ProviderV2 { +import { VERSION } from './version'; +export interface GroqProvider extends ProviderV3 { /** Creates a model for text generation. */ @@ -67,14 +69,18 @@ export function createGroq(options: GroqProviderSettings = {}): GroqProvider { const baseURL = withoutTrailingSlash(options.baseURL) ?? 'https://api.groq.com/openai/v1'; - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'GROQ_API_KEY', - description: 'Groq', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'GROQ_API_KEY', + description: 'Groq', + })}`, + ...options.headers, + }, + `ai-sdk/groq/${VERSION}`, + ); const createChatModel = (modelId: GroqChatModelId) => new GroqChatLanguageModel(modelId, { diff --git a/packages/groq/src/groq-transcription-model.test.ts b/packages/groq/src/groq-transcription-model.test.ts index 0907cdd08d25..a766bd3346a5 100644 --- a/packages/groq/src/groq-transcription-model.test.ts +++ b/packages/groq/src/groq-transcription-model.test.ts @@ -1,9 +1,13 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { GroqTranscriptionModel } from './groq-transcription-model'; import { createGroq } from './groq-provider'; import { readFile } from 'node:fs/promises'; import path from 'node:path'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const audioData = await readFile(path.join(__dirname, 'transcript-test.mp3')); const provider = createGroq({ apiKey: 'test-api-key' }); @@ -87,6 +91,9 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/groq/0.0.0-test`, + ); }); it('should extract the transcription text', async () => { diff --git a/packages/groq/src/index.ts b/packages/groq/src/index.ts index c1a8b38656e7..e5d472087502 100644 --- a/packages/groq/src/index.ts +++ b/packages/groq/src/index.ts @@ -2,3 +2,4 @@ export { createGroq, groq } from './groq-provider'; export type { GroqProvider, GroqProviderSettings } from './groq-provider'; export type { GroqProviderOptions } from './groq-chat-options'; export { browserSearch } from './tool/browser-search'; +export { VERSION } from './version'; diff --git a/packages/groq/src/version.ts b/packages/groq/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/groq/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/groq/tsup.config.ts b/packages/groq/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/groq/tsup.config.ts +++ b/packages/groq/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/groq/vitest.edge.config.js b/packages/groq/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/groq/vitest.edge.config.js +++ b/packages/groq/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/groq/vitest.node.config.js b/packages/groq/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/groq/vitest.node.config.js +++ b/packages/groq/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/hume/CHANGELOG.md b/packages/hume/CHANGELOG.md index efdb1086900f..6f7e90b5fa34 100644 --- a/packages/hume/CHANGELOG.md +++ b/packages/hume/CHANGELOG.md @@ -1,5 +1,52 @@ # @ai-sdk/hume +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.8 ### Patch Changes diff --git a/packages/hume/package.json b/packages/hume/package.json index c7d01d8d7512..f1aff8b9a87b 100644 --- a/packages/hume/package.json +++ b/packages/hume/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/hume", - "version": "1.0.8", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -18,6 +18,7 @@ "type-check": "tsc --noEmit", "prettier-check": "prettier --check \"./**/*.ts*\"", "test": "pnpm test:node && pnpm test:edge", + "test:watch": "vitest --config vitest.node.config.js --watch", "test:edge": "vitest --config vitest.edge.config.js --run", "test:node": "vitest --config vitest.node.config.js --run", "test:node:watch": "vitest --config vitest.node.config.js --watch" @@ -32,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/hume/src/hume-provider.ts b/packages/hume/src/hume-provider.ts index 4d6849adb2e0..a776494a22ca 100644 --- a/packages/hume/src/hume-provider.ts +++ b/packages/hume/src/hume-provider.ts @@ -1,8 +1,13 @@ -import { SpeechModelV2, ProviderV2 } from '@ai-sdk/provider'; -import { FetchFunction, loadApiKey } from '@ai-sdk/provider-utils'; +import { SpeechModelV2, ProviderV3 } from '@ai-sdk/provider'; +import { + FetchFunction, + loadApiKey, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; import { HumeSpeechModel } from './hume-speech-model'; +import { VERSION } from './version'; -export interface HumeProvider extends Pick { +export interface HumeProvider extends Pick { (settings?: {}): { speech: HumeSpeechModel; }; @@ -35,14 +40,18 @@ or to provide a custom fetch implementation for e.g. testing. Create an Hume provider instance. */ export function createHume(options: HumeProviderSettings = {}): HumeProvider { - const getHeaders = () => ({ - 'X-Hume-Api-Key': loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'HUME_API_KEY', - description: 'Hume', - }), - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + 'X-Hume-Api-Key': loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'HUME_API_KEY', + description: 'Hume', + }), + ...options.headers, + }, + `ai-sdk/hume/${VERSION}`, + ); const createSpeechModel = () => new HumeSpeechModel('', { diff --git a/packages/hume/src/hume-speech-model.test.ts b/packages/hume/src/hume-speech-model.test.ts index 937cb507999a..2f8b187856f5 100644 --- a/packages/hume/src/hume-speech-model.test.ts +++ b/packages/hume/src/hume-speech-model.test.ts @@ -1,7 +1,11 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { HumeSpeechModel } from './hume-speech-model'; import { createHume } from './hume-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const provider = createHume({ apiKey: 'test-api-key' }); const model = provider.speech(); @@ -76,6 +80,9 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/hume/0.0.0-test`, + ); }); it('should pass options', async () => { diff --git a/packages/hume/src/index.ts b/packages/hume/src/index.ts index 2fd4e0d07b2c..7911ef9ffa11 100644 --- a/packages/hume/src/index.ts +++ b/packages/hume/src/index.ts @@ -1,2 +1,3 @@ export { createHume, hume } from './hume-provider'; export type { HumeProvider, HumeProviderSettings } from './hume-provider'; +export { VERSION } from './version'; diff --git a/packages/hume/src/version.ts b/packages/hume/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/hume/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/hume/tsup.config.ts b/packages/hume/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/hume/tsup.config.ts +++ b/packages/hume/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/hume/vitest.edge.config.js b/packages/hume/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/hume/vitest.edge.config.js +++ b/packages/hume/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/hume/vitest.node.config.js b/packages/hume/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/hume/vitest.node.config.js +++ b/packages/hume/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/langchain/CHANGELOG.md b/packages/langchain/CHANGELOG.md index a0d0bd844189..bec3189c17da 100644 --- a/packages/langchain/CHANGELOG.md +++ b/packages/langchain/CHANGELOG.md @@ -1,5 +1,119 @@ # @ai-sdk/langchain +## 1.1.0-beta.9 + +### Patch Changes + +- Updated dependencies [ed329cb] +- Updated dependencies [177b475] +- Updated dependencies [522f6b8] + - ai@5.1.0-beta.9 + +## 1.1.0-beta.8 + +### Patch Changes + +- Updated dependencies [7eca093] + - ai@5.1.0-beta.8 + +## 1.1.0-beta.7 + +### Patch Changes + +- Updated dependencies [5a4e732] + - ai@5.1.0-beta.7 + +## 1.1.0-beta.6 + +### Patch Changes + +- Updated dependencies [0c4822d] + - ai@5.1.0-beta.6 + +## 1.1.0-beta.5 + +### Patch Changes + +- ai@5.1.0-beta.5 + +## 1.1.0-beta.4 + +### Patch Changes + +- ai@5.1.0-beta.4 + +## 1.1.0-beta.3 + +### Patch Changes + +- ai@5.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- ai@5.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [a7f6f81] + - ai@5.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - ai@5.1.0-beta.0 + +## 1.0.45 + +### Patch Changes + +- Updated dependencies [76024fc] +- Updated dependencies [93d8b60] +- Updated dependencies [d8eb31f] + - ai@5.0.45 + +## 1.0.44 + +### Patch Changes + +- ai@5.0.44 + +## 1.0.43 + +### Patch Changes + +- Updated dependencies [0294b58] + - ai@5.0.43 + +## 1.0.42 + +### Patch Changes + +- Updated dependencies [de5c066] + - ai@5.0.42 + +## 1.0.41 + +### Patch Changes + +- Updated dependencies [cd91e4b] + - ai@5.0.41 + +## 1.0.40 + +### Patch Changes + +- ai@5.0.40 + ## 1.0.39 ### Patch Changes diff --git a/packages/langchain/package.json b/packages/langchain/package.json index 44b0138bd357..35c1d79783fc 100644 --- a/packages/langchain/package.json +++ b/packages/langchain/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/langchain", - "version": "1.0.39", + "version": "1.1.0-beta.9", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/llamaindex/CHANGELOG.md b/packages/llamaindex/CHANGELOG.md index 66a22184c952..7b7a130e0c3e 100644 --- a/packages/llamaindex/CHANGELOG.md +++ b/packages/llamaindex/CHANGELOG.md @@ -1,5 +1,119 @@ # @ai-sdk/llamaindex +## 1.1.0-beta.9 + +### Patch Changes + +- Updated dependencies [ed329cb] +- Updated dependencies [177b475] +- Updated dependencies [522f6b8] + - ai@5.1.0-beta.9 + +## 1.1.0-beta.8 + +### Patch Changes + +- Updated dependencies [7eca093] + - ai@5.1.0-beta.8 + +## 1.1.0-beta.7 + +### Patch Changes + +- Updated dependencies [5a4e732] + - ai@5.1.0-beta.7 + +## 1.1.0-beta.6 + +### Patch Changes + +- Updated dependencies [0c4822d] + - ai@5.1.0-beta.6 + +## 1.1.0-beta.5 + +### Patch Changes + +- ai@5.1.0-beta.5 + +## 1.1.0-beta.4 + +### Patch Changes + +- ai@5.1.0-beta.4 + +## 1.1.0-beta.3 + +### Patch Changes + +- ai@5.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- ai@5.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [a7f6f81] + - ai@5.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - ai@5.1.0-beta.0 + +## 1.0.45 + +### Patch Changes + +- Updated dependencies [76024fc] +- Updated dependencies [93d8b60] +- Updated dependencies [d8eb31f] + - ai@5.0.45 + +## 1.0.44 + +### Patch Changes + +- ai@5.0.44 + +## 1.0.43 + +### Patch Changes + +- Updated dependencies [0294b58] + - ai@5.0.43 + +## 1.0.42 + +### Patch Changes + +- Updated dependencies [de5c066] + - ai@5.0.42 + +## 1.0.41 + +### Patch Changes + +- Updated dependencies [cd91e4b] + - ai@5.0.41 + +## 1.0.40 + +### Patch Changes + +- ai@5.0.40 + ## 1.0.39 ### Patch Changes diff --git a/packages/llamaindex/package.json b/packages/llamaindex/package.json index e12f9bd8d2bb..1c254718a524 100644 --- a/packages/llamaindex/package.json +++ b/packages/llamaindex/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/llamaindex", - "version": "1.0.39", + "version": "1.1.0-beta.9", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/lmnt/CHANGELOG.md b/packages/lmnt/CHANGELOG.md index bfcd1ab3f5c5..a3fac3a26a23 100644 --- a/packages/lmnt/CHANGELOG.md +++ b/packages/lmnt/CHANGELOG.md @@ -1,5 +1,52 @@ # @ai-sdk/lmnt +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.8 ### Patch Changes diff --git a/packages/lmnt/package.json b/packages/lmnt/package.json index f3d0455a8a3e..c4cf3845b50a 100644 --- a/packages/lmnt/package.json +++ b/packages/lmnt/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/lmnt", - "version": "1.0.8", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -18,6 +18,7 @@ "type-check": "tsc --noEmit", "prettier-check": "prettier --check \"./**/*.ts*\"", "test": "pnpm test:node && pnpm test:edge", + "test:watch": "vitest --config vitest.node.config.js --watch", "test:edge": "vitest --config vitest.edge.config.js --run", "test:node": "vitest --config vitest.node.config.js --run", "test:node:watch": "vitest --config vitest.node.config.js --watch" @@ -32,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/lmnt/src/index.ts b/packages/lmnt/src/index.ts index 879f4bf9eb70..675cb881c797 100644 --- a/packages/lmnt/src/index.ts +++ b/packages/lmnt/src/index.ts @@ -1,2 +1,3 @@ export { createLMNT, lmnt } from './lmnt-provider'; export type { LMNTProvider, LMNTProviderSettings } from './lmnt-provider'; +export { VERSION } from './version'; diff --git a/packages/lmnt/src/lmnt-provider.ts b/packages/lmnt/src/lmnt-provider.ts index 649c88eb6971..63fe556475f3 100644 --- a/packages/lmnt/src/lmnt-provider.ts +++ b/packages/lmnt/src/lmnt-provider.ts @@ -1,9 +1,14 @@ -import { SpeechModelV2, ProviderV2 } from '@ai-sdk/provider'; -import { FetchFunction, loadApiKey } from '@ai-sdk/provider-utils'; +import { SpeechModelV2, ProviderV3 } from '@ai-sdk/provider'; +import { + FetchFunction, + loadApiKey, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; import { LMNTSpeechModel } from './lmnt-speech-model'; import { LMNTSpeechModelId } from './lmnt-speech-options'; +import { VERSION } from './version'; -export interface LMNTProvider extends Pick { +export interface LMNTProvider extends Pick { ( modelId: 'aurora', settings?: {}, @@ -39,14 +44,18 @@ or to provide a custom fetch implementation for e.g. testing. Create an LMNT provider instance. */ export function createLMNT(options: LMNTProviderSettings = {}): LMNTProvider { - const getHeaders = () => ({ - 'x-api-key': loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'LMNT_API_KEY', - description: 'LMNT', - }), - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + 'x-api-key': loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'LMNT_API_KEY', + description: 'LMNT', + }), + ...options.headers, + }, + `ai-sdk/lmnt/${VERSION}`, + ); const createSpeechModel = (modelId: LMNTSpeechModelId) => new LMNTSpeechModel(modelId, { diff --git a/packages/lmnt/src/lmnt-speech-model.test.ts b/packages/lmnt/src/lmnt-speech-model.test.ts index 07624446cb15..c63d46afdd2e 100644 --- a/packages/lmnt/src/lmnt-speech-model.test.ts +++ b/packages/lmnt/src/lmnt-speech-model.test.ts @@ -1,7 +1,11 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { LMNTSpeechModel } from './lmnt-speech-model'; import { createLMNT } from './lmnt-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const provider = createLMNT({ apiKey: 'test-api-key' }); const model = provider.speech('aurora'); @@ -66,6 +70,9 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/lmnt/0.0.0-test`, + ); }); it('should pass options', async () => { diff --git a/packages/lmnt/src/version.ts b/packages/lmnt/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/lmnt/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/lmnt/tsup.config.ts b/packages/lmnt/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/lmnt/tsup.config.ts +++ b/packages/lmnt/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/lmnt/vitest.edge.config.js b/packages/lmnt/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/lmnt/vitest.edge.config.js +++ b/packages/lmnt/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/lmnt/vitest.node.config.js b/packages/lmnt/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/lmnt/vitest.node.config.js +++ b/packages/lmnt/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/luma/CHANGELOG.md b/packages/luma/CHANGELOG.md index f770d14dfeb8..ad412ef813e1 100644 --- a/packages/luma/CHANGELOG.md +++ b/packages/luma/CHANGELOG.md @@ -1,5 +1,53 @@ # @ai-sdk/luma +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.8 ### Patch Changes diff --git a/packages/luma/package.json b/packages/luma/package.json index 07796f488366..46f5ea3bf843 100644 --- a/packages/luma/package.json +++ b/packages/luma/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/luma", - "version": "1.0.8", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -33,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/luma/src/index.ts b/packages/luma/src/index.ts index 57e5f4561e47..b811aa9f5029 100644 --- a/packages/luma/src/index.ts +++ b/packages/luma/src/index.ts @@ -1,3 +1,4 @@ export { createLuma, luma } from './luma-provider'; export type { LumaProvider, LumaProviderSettings } from './luma-provider'; export type { LumaErrorData } from './luma-image-model'; +export { VERSION } from './version'; diff --git a/packages/luma/src/luma-image-model.test.ts b/packages/luma/src/luma-image-model.test.ts index 3e95aa0eb6df..5c8cabef679f 100644 --- a/packages/luma/src/luma-image-model.test.ts +++ b/packages/luma/src/luma-image-model.test.ts @@ -1,5 +1,5 @@ import { FetchFunction } from '@ai-sdk/provider-utils'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { describe, expect, it } from 'vitest'; import { LumaImageModel } from './luma-image-model'; import { InvalidResponseDataError } from '@ai-sdk/provider'; @@ -294,7 +294,7 @@ describe('LumaImageModel', () => { expect(model.provider).toBe('luma'); expect(model.modelId).toBe('test-model'); - expect(model.specificationVersion).toBe('v2'); + expect(model.specificationVersion).toBe('v3'); expect(model.maxImagesPerCall).toBe(1); }); }); diff --git a/packages/luma/src/luma-image-model.ts b/packages/luma/src/luma-image-model.ts index 19dabfcddafd..8a3567a17f6c 100644 --- a/packages/luma/src/luma-image-model.ts +++ b/packages/luma/src/luma-image-model.ts @@ -1,6 +1,6 @@ import { - ImageModelV2, - ImageModelV2CallWarning, + ImageModelV3, + ImageModelV3CallWarning, InvalidResponseDataError, } from '@ai-sdk/provider'; import { @@ -30,8 +30,8 @@ interface LumaImageModelConfig { }; } -export class LumaImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class LumaImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; readonly maxImagesPerCall = 1; readonly pollIntervalMillis = DEFAULT_POLL_INTERVAL_MILLIS; readonly maxPollAttempts = DEFAULT_MAX_POLL_ATTEMPTS; @@ -54,10 +54,10 @@ export class LumaImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; if (seed != null) { warnings.push({ diff --git a/packages/luma/src/luma-provider.ts b/packages/luma/src/luma-provider.ts index d2c9f16b6311..c72c947c4c76 100644 --- a/packages/luma/src/luma-provider.ts +++ b/packages/luma/src/luma-provider.ts @@ -1,11 +1,13 @@ -import { ImageModelV2, NoSuchModelError, ProviderV2 } from '@ai-sdk/provider'; +import { ImageModelV3, NoSuchModelError, ProviderV3 } from '@ai-sdk/provider'; import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { LumaImageModel } from './luma-image-model'; import { LumaImageModelId } from './luma-image-settings'; +import { VERSION } from './version'; export interface LumaProviderSettings { /** @@ -28,30 +30,34 @@ or to provide a custom fetch implementation for e.g. testing. fetch?: FetchFunction; } -export interface LumaProvider extends ProviderV2 { +export interface LumaProvider extends ProviderV3 { /** Creates a model for image generation. */ - image(modelId: LumaImageModelId): ImageModelV2; + image(modelId: LumaImageModelId): ImageModelV3; /** Creates a model for image generation. */ - imageModel(modelId: LumaImageModelId): ImageModelV2; + imageModel(modelId: LumaImageModelId): ImageModelV3; } const defaultBaseURL = 'https://api.lumalabs.ai'; export function createLuma(options: LumaProviderSettings = {}): LumaProvider { const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL); - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'LUMA_API_KEY', - description: 'Luma', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'LUMA_API_KEY', + description: 'Luma', + })}`, + ...options.headers, + }, + `ai-sdk/luma/${VERSION}`, + ); const createImageModel = (modelId: LumaImageModelId) => new LumaImageModel(modelId, { diff --git a/packages/luma/src/version.ts b/packages/luma/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/luma/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/luma/tsup.config.ts b/packages/luma/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/luma/tsup.config.ts +++ b/packages/luma/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/luma/vitest.edge.config.js b/packages/luma/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/luma/vitest.edge.config.js +++ b/packages/luma/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/luma/vitest.node.config.js b/packages/luma/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/luma/vitest.node.config.js +++ b/packages/luma/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/mistral/CHANGELOG.md b/packages/mistral/CHANGELOG.md index 219db001b48a..222b6c42cc3c 100644 --- a/packages/mistral/CHANGELOG.md +++ b/packages/mistral/CHANGELOG.md @@ -1,5 +1,59 @@ # @ai-sdk/mistral +## 2.1.0-beta.4 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.3 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.2 + +### Patch Changes + +- 62731a8: Add option for disabling parallel tool call in mistral + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.14 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 2.0.13 ### Patch Changes diff --git a/packages/mistral/package.json b/packages/mistral/package.json index 113e614a9fe9..a322b796afbb 100644 --- a/packages/mistral/package.json +++ b/packages/mistral/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/mistral", - "version": "2.0.13", + "version": "2.1.0-beta.4", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -33,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/mistral/src/index.ts b/packages/mistral/src/index.ts index 1a634dc3b650..d8acf2e24933 100644 --- a/packages/mistral/src/index.ts +++ b/packages/mistral/src/index.ts @@ -4,3 +4,4 @@ export type { MistralProviderSettings, } from './mistral-provider'; export type { MistralLanguageModelOptions } from './mistral-chat-options'; +export { VERSION } from './version'; diff --git a/packages/mistral/src/mistral-chat-language-model.test.ts b/packages/mistral/src/mistral-chat-language-model.test.ts index 533e56fb8ff2..38efac6f6670 100644 --- a/packages/mistral/src/mistral-chat-language-model.test.ts +++ b/packages/mistral/src/mistral-chat-language-model.test.ts @@ -1,11 +1,15 @@ import { LanguageModelV2Prompt } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, mockId, } from '@ai-sdk/provider-utils/test'; import { createMistral } from './mistral-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const TEST_PROMPT: LanguageModelV2Prompt = [ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, @@ -464,6 +468,9 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/mistral/0.0.0-test`, + ); }); it('should send request body', async () => { @@ -680,6 +687,53 @@ describe('doGenerate', () => { ] `); }); + + it('should pass parallelToolCalls option', async () => { + prepareJsonResponse({ content: '' }); + + await model.doGenerate({ + tools: [ + { + type: 'function', + name: 'test-tool', + inputSchema: { + type: 'object', + properties: { value: { type: 'string' } }, + required: ['value'], + additionalProperties: false, + $schema: 'http://json-schema.org/draft-07/schema#', + }, + }, + ], + prompt: TEST_PROMPT, + providerOptions: { + mistral: { + parallelToolCalls: false, + }, + }, + }); + + expect(await server.calls[0].requestBodyJson).toMatchObject({ + model: 'mistral-small-latest', + messages: [{ role: 'user', content: [{ type: 'text', text: 'Hello' }] }], + tools: [ + { + type: 'function', + function: { + name: 'test-tool', + parameters: { + type: 'object', + properties: { value: { type: 'string' } }, + required: ['value'], + additionalProperties: false, + $schema: 'http://json-schema.org/draft-07/schema#', + }, + }, + }, + ], + parallel_tool_calls: false, + }); + }); }); describe('doStream', () => { @@ -973,6 +1027,9 @@ describe('doStream', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/mistral/0.0.0-test`, + ); }); it('should send request body', async () => { diff --git a/packages/mistral/src/mistral-chat-language-model.ts b/packages/mistral/src/mistral-chat-language-model.ts index 5e50b6e8d357..1acf029db294 100644 --- a/packages/mistral/src/mistral-chat-language-model.ts +++ b/packages/mistral/src/mistral-chat-language-model.ts @@ -173,6 +173,9 @@ export class MistralChatLanguageModel implements LanguageModelV2 { ...baseArgs, tools: mistralTools, tool_choice: mistralToolChoice, + ...(mistralTools != null && options.parallelToolCalls !== undefined + ? { parallel_tool_calls: options.parallelToolCalls } + : {}), }, warnings: [...warnings, ...toolWarnings], }; diff --git a/packages/mistral/src/mistral-chat-options.ts b/packages/mistral/src/mistral-chat-options.ts index 0433f7695851..5cd15a543e7a 100644 --- a/packages/mistral/src/mistral-chat-options.ts +++ b/packages/mistral/src/mistral-chat-options.ts @@ -48,6 +48,14 @@ Defaults to `false`. * @default false */ strictJsonSchema: z.boolean().optional(), + + /** + * Whether to enable parallel function calling during tool use. + * When set to false, the model will use at most one tool per response. + * + * @default true + */ + parallelToolCalls: z.boolean().optional(), }); export type MistralLanguageModelOptions = z.infer< diff --git a/packages/mistral/src/mistral-embedding-model.test.ts b/packages/mistral/src/mistral-embedding-model.test.ts index abacf43b04b8..17cf1c5a8859 100644 --- a/packages/mistral/src/mistral-embedding-model.test.ts +++ b/packages/mistral/src/mistral-embedding-model.test.ts @@ -1,7 +1,11 @@ -import { EmbeddingModelV2Embedding } from '@ai-sdk/provider'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { EmbeddingModelV3Embedding } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createMistral } from './mistral-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const dummyEmbeddings = [ [0.1, 0.2, 0.3, 0.4, 0.5], @@ -22,7 +26,7 @@ describe('doEmbed', () => { usage = { prompt_tokens: 8, total_tokens: 8 }, headers, }: { - embeddings?: EmbeddingModelV2Embedding[]; + embeddings?: EmbeddingModelV3Embedding[]; usage?: { prompt_tokens: number; total_tokens: number }; headers?: Record; } = {}) { @@ -116,5 +120,8 @@ describe('doEmbed', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/mistral/0.0.0-test`, + ); }); }); diff --git a/packages/mistral/src/mistral-embedding-model.ts b/packages/mistral/src/mistral-embedding-model.ts index beee67cddeb4..7b91134f1cb4 100644 --- a/packages/mistral/src/mistral-embedding-model.ts +++ b/packages/mistral/src/mistral-embedding-model.ts @@ -1,5 +1,5 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, TooManyEmbeddingValuesForCallError, } from '@ai-sdk/provider'; import { @@ -19,8 +19,8 @@ type MistralEmbeddingConfig = { fetch?: FetchFunction; }; -export class MistralEmbeddingModel implements EmbeddingModelV2 { - readonly specificationVersion = 'v2'; +export class MistralEmbeddingModel implements EmbeddingModelV3 { + readonly specificationVersion = 'v3'; readonly modelId: MistralEmbeddingModelId; readonly maxEmbeddingsPerCall = 32; readonly supportsParallelCalls = false; @@ -43,8 +43,8 @@ export class MistralEmbeddingModel implements EmbeddingModelV2 { values, abortSignal, headers, - }: Parameters['doEmbed']>[0]): Promise< - Awaited['doEmbed']>> + }: Parameters['doEmbed']>[0]): Promise< + Awaited['doEmbed']>> > { if (values.length > this.maxEmbeddingsPerCall) { throw new TooManyEmbeddingValuesForCallError({ diff --git a/packages/mistral/src/mistral-provider.ts b/packages/mistral/src/mistral-provider.ts index aa18abad6177..73a9008e4ca3 100644 --- a/packages/mistral/src/mistral-provider.ts +++ b/packages/mistral/src/mistral-provider.ts @@ -1,20 +1,22 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { MistralChatLanguageModel } from './mistral-chat-language-model'; import { MistralChatModelId } from './mistral-chat-options'; import { MistralEmbeddingModel } from './mistral-embedding-model'; import { MistralEmbeddingModelId } from './mistral-embedding-options'; +import { VERSION } from './version'; -export interface MistralProvider extends ProviderV2 { +export interface MistralProvider extends ProviderV3 { (modelId: MistralChatModelId): LanguageModelV2; /** @@ -30,13 +32,13 @@ Creates a model for text generation. /** @deprecated Use `textEmbedding()` instead. */ - embedding(modelId: MistralEmbeddingModelId): EmbeddingModelV2; + embedding(modelId: MistralEmbeddingModelId): EmbeddingModelV3; - textEmbedding(modelId: MistralEmbeddingModelId): EmbeddingModelV2; + textEmbedding(modelId: MistralEmbeddingModelId): EmbeddingModelV3; textEmbeddingModel: ( modelId: MistralEmbeddingModelId, - ) => EmbeddingModelV2; + ) => EmbeddingModelV3; } export interface MistralProviderSettings { @@ -75,14 +77,18 @@ export function createMistral( const baseURL = withoutTrailingSlash(options.baseURL) ?? 'https://api.mistral.ai/v1'; - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'MISTRAL_API_KEY', - description: 'Mistral', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'MISTRAL_API_KEY', + description: 'Mistral', + })}`, + ...options.headers, + }, + `ai-sdk/mistral/${VERSION}`, + ); const createChatModel = (modelId: MistralChatModelId) => new MistralChatLanguageModel(modelId, { diff --git a/packages/mistral/src/version.ts b/packages/mistral/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/mistral/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/mistral/tsup.config.ts b/packages/mistral/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/mistral/tsup.config.ts +++ b/packages/mistral/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/mistral/vitest.edge.config.js b/packages/mistral/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/mistral/vitest.edge.config.js +++ b/packages/mistral/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/mistral/vitest.node.config.js b/packages/mistral/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/mistral/vitest.node.config.js +++ b/packages/mistral/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/openai-compatible/CHANGELOG.md b/packages/openai-compatible/CHANGELOG.md index 3bc2e3586aa7..7cc7a5c9d74d 100644 --- a/packages/openai-compatible/CHANGELOG.md +++ b/packages/openai-compatible/CHANGELOG.md @@ -1,5 +1,65 @@ # @ai-sdk/openai-compatible +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.18 + +### Patch Changes + +- 28363da: feat(openai-compatible): add `supportsStructuredOutputs` to provider settings + +## 1.0.17 + +### Patch Changes + +- 3aed04c: feat(provider/openai-compatible): set `user-agent` header for `createOpenAICompatible` + +## 1.0.16 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.15 ### Patch Changes diff --git a/packages/openai-compatible/package.json b/packages/openai-compatible/package.json index 360ba8f2d097..f23cc85a62e4 100644 --- a/packages/openai-compatible/package.json +++ b/packages/openai-compatible/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/openai-compatible", - "version": "1.0.15", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -40,7 +40,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/openai-compatible/src/chat/openai-compatible-chat-language-model.test.ts b/packages/openai-compatible/src/chat/openai-compatible-chat-language-model.test.ts index 85f00150946a..0584a85da78e 100644 --- a/packages/openai-compatible/src/chat/openai-compatible-chat-language-model.test.ts +++ b/packages/openai-compatible/src/chat/openai-compatible-chat-language-model.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; import { LanguageModelV2Prompt } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, isNodeVersion, } from '@ai-sdk/provider-utils/test'; import { createOpenAICompatible } from '../openai-compatible-provider'; diff --git a/packages/openai-compatible/src/completion/openai-compatible-completion-language-model.test.ts b/packages/openai-compatible/src/completion/openai-compatible-completion-language-model.test.ts index 2ded48833d2f..372178feefc1 100644 --- a/packages/openai-compatible/src/completion/openai-compatible-completion-language-model.test.ts +++ b/packages/openai-compatible/src/completion/openai-compatible-completion-language-model.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; import { LanguageModelV2Prompt } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, isNodeVersion, } from '@ai-sdk/provider-utils/test'; import { createOpenAICompatible } from '../openai-compatible-provider'; diff --git a/packages/openai-compatible/src/embedding/openai-compatible-embedding-model.test.ts b/packages/openai-compatible/src/embedding/openai-compatible-embedding-model.test.ts index 9e0f6e2308d6..b723f419061c 100644 --- a/packages/openai-compatible/src/embedding/openai-compatible-embedding-model.test.ts +++ b/packages/openai-compatible/src/embedding/openai-compatible-embedding-model.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from 'vitest'; -import { EmbeddingModelV2Embedding } from '@ai-sdk/provider'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { EmbeddingModelV3Embedding } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createOpenAICompatible } from '../openai-compatible-provider'; const dummyEmbeddings = [ @@ -28,7 +28,7 @@ describe('doEmbed', () => { usage = { prompt_tokens: 8, total_tokens: 8 }, headers, }: { - embeddings?: EmbeddingModelV2Embedding[]; + embeddings?: EmbeddingModelV3Embedding[]; usage?: { prompt_tokens: number; total_tokens: number }; headers?: Record; } = {}) { diff --git a/packages/openai-compatible/src/embedding/openai-compatible-embedding-model.ts b/packages/openai-compatible/src/embedding/openai-compatible-embedding-model.ts index 65251eb1525a..770b7eba147a 100644 --- a/packages/openai-compatible/src/embedding/openai-compatible-embedding-model.ts +++ b/packages/openai-compatible/src/embedding/openai-compatible-embedding-model.ts @@ -1,5 +1,5 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, TooManyEmbeddingValuesForCallError, } from '@ai-sdk/provider'; import { @@ -39,9 +39,9 @@ Override the parallelism of embedding calls. }; export class OpenAICompatibleEmbeddingModel - implements EmbeddingModelV2 + implements EmbeddingModelV3 { - readonly specificationVersion = 'v2'; + readonly specificationVersion = 'v3'; readonly modelId: OpenAICompatibleEmbeddingModelId; private readonly config: OpenAICompatibleEmbeddingConfig; @@ -75,8 +75,8 @@ export class OpenAICompatibleEmbeddingModel headers, abortSignal, providerOptions, - }: Parameters['doEmbed']>[0]): Promise< - Awaited['doEmbed']>> + }: Parameters['doEmbed']>[0]): Promise< + Awaited['doEmbed']>> > { const compatibleOptions = Object.assign( (await parseProviderOptions({ diff --git a/packages/openai-compatible/src/image/openai-compatible-image-model.test.ts b/packages/openai-compatible/src/image/openai-compatible-image-model.test.ts index bc5f86e4c21e..54089975f7a6 100644 --- a/packages/openai-compatible/src/image/openai-compatible-image-model.test.ts +++ b/packages/openai-compatible/src/image/openai-compatible-image-model.test.ts @@ -1,10 +1,10 @@ import { describe, it, expect } from 'vitest'; import { FetchFunction } from '@ai-sdk/provider-utils'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { OpenAICompatibleImageModel } from './openai-compatible-image-model'; import { z } from 'zod/v4'; import { ProviderErrorStructure } from '../openai-compatible-error'; -import { ImageModelV2CallOptions } from '@ai-sdk/provider'; +import { ImageModelV3CallOptions } from '@ai-sdk/provider'; const prompt = 'A photorealistic astronaut riding a horse'; @@ -31,7 +31,7 @@ function createBasicModel({ }); } -function createDefaultGenerateParams(overrides = {}): ImageModelV2CallOptions { +function createDefaultGenerateParams(overrides = {}): ImageModelV3CallOptions { return { prompt: 'A photorealistic astronaut riding a horse', n: 1, @@ -70,7 +70,7 @@ describe('OpenAICompatibleImageModel', () => { expect(model.provider).toBe('openai-compatible'); expect(model.modelId).toBe('dall-e-3'); - expect(model.specificationVersion).toBe('v2'); + expect(model.specificationVersion).toBe('v3'); expect(model.maxImagesPerCall).toBe(10); }); }); diff --git a/packages/openai-compatible/src/image/openai-compatible-image-model.ts b/packages/openai-compatible/src/image/openai-compatible-image-model.ts index ea1ff8ba69f6..5c5c2c93bb49 100644 --- a/packages/openai-compatible/src/image/openai-compatible-image-model.ts +++ b/packages/openai-compatible/src/image/openai-compatible-image-model.ts @@ -1,4 +1,4 @@ -import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider'; +import { ImageModelV3, ImageModelV3CallWarning } from '@ai-sdk/provider'; import { combineHeaders, createJsonErrorResponseHandler, @@ -24,8 +24,8 @@ export type OpenAICompatibleImageModelConfig = { }; }; -export class OpenAICompatibleImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class OpenAICompatibleImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; readonly maxImagesPerCall = 10; get provider(): string { @@ -46,10 +46,10 @@ export class OpenAICompatibleImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; if (aspectRatio != null) { warnings.push({ diff --git a/packages/openai-compatible/src/index.ts b/packages/openai-compatible/src/index.ts index f781eddba2d2..75da5c767ba1 100644 --- a/packages/openai-compatible/src/index.ts +++ b/packages/openai-compatible/src/index.ts @@ -24,3 +24,4 @@ export type { OpenAICompatibleProvider, OpenAICompatibleProviderSettings, } from './openai-compatible-provider'; +export { VERSION } from './version'; diff --git a/packages/openai-compatible/src/openai-compatible-provider.test.ts b/packages/openai-compatible/src/openai-compatible-provider.test.ts index 261adb542a75..3fbeb3e0ca77 100644 --- a/packages/openai-compatible/src/openai-compatible-provider.test.ts +++ b/packages/openai-compatible/src/openai-compatible-provider.test.ts @@ -2,8 +2,14 @@ import { createOpenAICompatible } from './openai-compatible-provider'; import { OpenAICompatibleChatLanguageModel } from './chat/openai-compatible-chat-language-model'; import { OpenAICompatibleCompletionLanguageModel } from './completion/openai-compatible-completion-language-model'; import { OpenAICompatibleEmbeddingModel } from './embedding/openai-compatible-embedding-model'; +import { OpenAICompatibleImageModel } from './image/openai-compatible-image-model'; import { vi, describe, beforeEach, it, expect } from 'vitest'; +// Mock version +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); + const OpenAICompatibleChatLanguageModelMock = vi.mocked( OpenAICompatibleChatLanguageModel, ); @@ -14,10 +20,16 @@ const OpenAICompatibleEmbeddingModelMock = vi.mocked( OpenAICompatibleEmbeddingModel, ); +const OpenAICompatibleImageModelMock = vi.mocked(OpenAICompatibleImageModel); + vi.mock('./chat/openai-compatible-chat-language-model', () => ({ OpenAICompatibleChatLanguageModel: vi.fn(), })); +vi.mock('./image/openai-compatible-image-model', () => ({ + OpenAICompatibleImageModel: vi.fn(), +})); + vi.mock('./completion/openai-compatible-completion-language-model', () => ({ OpenAICompatibleCompletionLanguageModel: vi.fn(), })); @@ -37,7 +49,7 @@ describe('OpenAICompatibleProvider', () => { baseURL: 'https://api.example.com', name: 'test-provider', apiKey: 'test-api-key', - headers: { 'Custom-Header': 'value' }, + headers: { 'custom-header': 'value' }, queryParams: { 'Custom-Param': 'value' }, }; @@ -50,8 +62,9 @@ describe('OpenAICompatibleProvider', () => { const headers = config.headers(); expect(headers).toEqual({ - Authorization: 'Bearer test-api-key', - 'Custom-Header': 'value', + authorization: 'Bearer test-api-key', + 'custom-header': 'value', + 'user-agent': 'ai-sdk/openai-compatible/0.0.0-test', }); expect(config.provider).toBe('test-provider.chat'); expect(config.url({ modelId: 'model-id', path: '/v1/chat' })).toBe( @@ -59,11 +72,11 @@ describe('OpenAICompatibleProvider', () => { ); }); - it('should create headers without Authorization when no apiKey provided', () => { + it('should create headers without authorization when no apiKey provided', () => { const options = { baseURL: 'https://api.example.com', name: 'test-provider', - headers: { 'Custom-Header': 'value' }, + headers: { 'custom-header': 'value' }, }; const provider = createOpenAICompatible(options); @@ -75,7 +88,8 @@ describe('OpenAICompatibleProvider', () => { const headers = config.headers(); expect(headers).toEqual({ - 'Custom-Header': 'value', + 'custom-header': 'value', + 'user-agent': 'ai-sdk/openai-compatible/0.0.0-test', }); }); }); @@ -85,7 +99,7 @@ describe('OpenAICompatibleProvider', () => { baseURL: 'https://api.example.com', name: 'test-provider', apiKey: 'test-api-key', - headers: { 'Custom-Header': 'value' }, + headers: { 'custom-header': 'value' }, queryParams: { 'Custom-Param': 'value' }, }; @@ -100,8 +114,9 @@ describe('OpenAICompatibleProvider', () => { const headers = config.headers(); expect(headers).toEqual({ - Authorization: 'Bearer test-api-key', - 'Custom-Header': 'value', + authorization: 'Bearer test-api-key', + 'custom-header': 'value', + 'user-agent': 'ai-sdk/openai-compatible/0.0.0-test', }); expect(config.provider).toBe('test-provider.chat'); expect(config.url({ modelId: 'model-id', path: '/v1/chat' })).toBe( @@ -120,8 +135,9 @@ describe('OpenAICompatibleProvider', () => { const headers = config.headers(); expect(headers).toEqual({ - Authorization: 'Bearer test-api-key', - 'Custom-Header': 'value', + authorization: 'Bearer test-api-key', + 'custom-header': 'value', + 'user-agent': 'ai-sdk/openai-compatible/0.0.0-test', }); expect(config.provider).toBe('test-provider.completion'); expect( @@ -139,8 +155,9 @@ describe('OpenAICompatibleProvider', () => { const headers = config.headers(); expect(headers).toEqual({ - Authorization: 'Bearer test-api-key', - 'Custom-Header': 'value', + authorization: 'Bearer test-api-key', + 'custom-header': 'value', + 'user-agent': 'ai-sdk/openai-compatible/0.0.0-test', }); expect(config.provider).toBe('test-provider.embedding'); expect( @@ -256,4 +273,57 @@ describe('OpenAICompatibleProvider', () => { ).toBeUndefined(); }); }); + + describe('supportsStructuredOutputs setting', () => { + it('should pass supportsStructuredOutputs to to .chatModel() and .languageModel() only', () => { + const options = { + baseURL: 'https://api.example.com', + name: 'test-provider', + supportsStructuredOutputs: true, + }; + const provider = createOpenAICompatible(options); + + provider('model-id'); + expect( + OpenAICompatibleChatLanguageModelMock.mock.calls[0][1] + .supportsStructuredOutputs, + ).toBe(true); + + provider.chatModel('chat-model'); + expect( + OpenAICompatibleChatLanguageModelMock.mock.calls[1][1] + .supportsStructuredOutputs, + ).toBe(true); + + provider.languageModel('completion-model'); + expect( + OpenAICompatibleChatLanguageModelMock.mock.calls[2][1] + .supportsStructuredOutputs, + ).toBe(true); + + provider.completionModel('completion-model'); + const completionModelConfigArg = + OpenAICompatibleCompletionLanguageModelMock.mock.calls[0][1]; + expect( + // @ts-expect-error - testing + completionModelConfigArg.supportsStructuredOutputs, + ).toBe(undefined); + + provider.textEmbeddingModel('embedding-model'); + const embeddingModelConfigArg = + OpenAICompatibleEmbeddingModelMock.mock.calls[0][1]; + expect( + // @ts-expect-error - testing + embeddingModelConfigArg.supportsStructuredOutputs, + ).toBe(undefined); + + provider.imageModel('image-model'); + const imageModelConfigArg = + OpenAICompatibleImageModelMock.mock.calls[0][1]; + expect( + // @ts-expect-error - testing + imageModelConfigArg.supportsStructuredOutputs, + ).toBe(undefined); + }); + }); }); diff --git a/packages/openai-compatible/src/openai-compatible-provider.ts b/packages/openai-compatible/src/openai-compatible-provider.ts index d222283327c3..3c1687655f3d 100644 --- a/packages/openai-compatible/src/openai-compatible-provider.ts +++ b/packages/openai-compatible/src/openai-compatible-provider.ts @@ -1,32 +1,44 @@ import { - EmbeddingModelV2, - ImageModelV2, + EmbeddingModelV3, + ImageModelV3, LanguageModelV2, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; -import { FetchFunction, withoutTrailingSlash } from '@ai-sdk/provider-utils'; -import { OpenAICompatibleChatLanguageModel } from './chat/openai-compatible-chat-language-model'; +import { + FetchFunction, + withoutTrailingSlash, + withUserAgentSuffix, + getRuntimeEnvironmentUserAgent, +} from '@ai-sdk/provider-utils'; +import { + OpenAICompatibleChatConfig, + OpenAICompatibleChatLanguageModel, +} from './chat/openai-compatible-chat-language-model'; import { OpenAICompatibleCompletionLanguageModel } from './completion/openai-compatible-completion-language-model'; import { OpenAICompatibleEmbeddingModel } from './embedding/openai-compatible-embedding-model'; import { OpenAICompatibleImageModel } from './image/openai-compatible-image-model'; +import { VERSION } from './version'; export interface OpenAICompatibleProvider< CHAT_MODEL_IDS extends string = string, COMPLETION_MODEL_IDS extends string = string, EMBEDDING_MODEL_IDS extends string = string, IMAGE_MODEL_IDS extends string = string, -> extends Omit { +> extends Omit { (modelId: CHAT_MODEL_IDS): LanguageModelV2; - languageModel(modelId: CHAT_MODEL_IDS): LanguageModelV2; + languageModel( + modelId: CHAT_MODEL_IDS, + config?: Partial, + ): LanguageModelV2; chatModel(modelId: CHAT_MODEL_IDS): LanguageModelV2; completionModel(modelId: COMPLETION_MODEL_IDS): LanguageModelV2; - textEmbeddingModel(modelId: EMBEDDING_MODEL_IDS): EmbeddingModelV2; + textEmbeddingModel(modelId: EMBEDDING_MODEL_IDS): EmbeddingModelV3; - imageModel(modelId: IMAGE_MODEL_IDS): ImageModelV2; + imageModel(modelId: IMAGE_MODEL_IDS): ImageModelV3; } export interface OpenAICompatibleProviderSettings { @@ -68,6 +80,11 @@ or to provide a custom fetch implementation for e.g. testing. Include usage information in streaming responses. */ includeUsage?: boolean; + + /** + * Whether the provider supports structured outputs in chat models. + */ + supportsStructuredOutputs?: boolean; } /** @@ -96,10 +113,13 @@ export function createOpenAICompatible< fetch?: FetchFunction; } - const getHeaders = () => ({ + const headers = { ...(options.apiKey && { Authorization: `Bearer ${options.apiKey}` }), ...options.headers, - }); + }; + + const getHeaders = () => + withUserAgentSuffix(headers, `ai-sdk/openai-compatible/${VERSION}`); const getCommonModelConfig = (modelType: string): CommonModelConfig => ({ provider: `${providerName}.${modelType}`, @@ -121,6 +141,7 @@ export function createOpenAICompatible< new OpenAICompatibleChatLanguageModel(modelId, { ...getCommonModelConfig('chat'), includeUsage: options.includeUsage, + supportsStructuredOutputs: options.supportsStructuredOutputs, }); const createCompletionModel = (modelId: COMPLETION_MODEL_IDS) => diff --git a/packages/openai-compatible/src/version.ts b/packages/openai-compatible/src/version.ts new file mode 100644 index 000000000000..8fda877d6d33 --- /dev/null +++ b/packages/openai-compatible/src/version.ts @@ -0,0 +1,5 @@ +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/openai-compatible/tsup.config.ts b/packages/openai-compatible/tsup.config.ts index 87efcf0d5720..d0b56a7122cd 100644 --- a/packages/openai-compatible/tsup.config.ts +++ b/packages/openai-compatible/tsup.config.ts @@ -6,6 +6,12 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, { entry: ['src/internal/index.ts'], @@ -13,5 +19,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/openai-compatible/vitest.edge.config.js b/packages/openai-compatible/vitest.edge.config.js index 3dc49ba29774..02b9e8c6cf92 100644 --- a/packages/openai-compatible/vitest.edge.config.js +++ b/packages/openai-compatible/vitest.edge.config.js @@ -1,7 +1,15 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; + +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, test: { environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], diff --git a/packages/openai-compatible/vitest.node.config.js b/packages/openai-compatible/vitest.node.config.js index b7e4a9cabd48..5b86131f58c6 100644 --- a/packages/openai-compatible/vitest.node.config.js +++ b/packages/openai-compatible/vitest.node.config.js @@ -1,7 +1,15 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; + +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, test: { environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], diff --git a/packages/openai/CHANGELOG.md b/packages/openai/CHANGELOG.md index d0f6a8711451..da447b3d983f 100644 --- a/packages/openai/CHANGELOG.md +++ b/packages/openai/CHANGELOG.md @@ -1,5 +1,104 @@ # @ai-sdk/openai +## 2.1.0-beta.4 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.3 + +### Patch Changes + +- 2e86082: feat(provider/openai): `OpenAIChatLanguageModelOptions` type + + ```ts + import { openai, type OpenAIChatLanguageModelOptions } from '@ai-sdk/openai'; + import { generateText } from 'ai'; + + await generateText({ + model: openai.chat('gpt-4o'), + prompt: 'Invent a new holiday and describe its traditions.', + providerOptions: { + openai: { + user: 'user-123', + } satisfies OpenAIChatLanguageModelOptions, + }, + }); + ``` + +## 2.1.0-beta.2 + +### Patch Changes + +- 4920119: fix the "incomplete_details" key from nullable to nullish for openai compatibility +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.32 + +### Patch Changes + +- 1cf857d: fix(provider/openai): remove provider-executed tools from chat completions model +- 01de47f: feat(provider/openai): rework file search tool + +## 2.0.31 + +### Patch Changes + +- bb94467: feat(provider/openai): add maxToolCalls provider option +- 4a2b70e: feat(provider/openai): send item references for provider-executed tool results +- 643711d: feat (provider/openai): provider defined image generation tool support + +## 2.0.30 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + +## 2.0.29 + +### Patch Changes + +- 4235eb3: feat(provider/openai): code interpreter tool calls and results + +## 2.0.28 + +### Patch Changes + +- 4c2bb77: fix (provider/openai): send sources action as include +- 561e8b0: fix (provider/openai): fix code interpreter tool in doGenerate + ## 2.0.27 ### Patch Changes diff --git a/packages/openai/package.json b/packages/openai/package.json index b4e8ca1dcd0d..d4ad796b0b96 100644 --- a/packages/openai/package.json +++ b/packages/openai/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/openai", - "version": "2.0.27", + "version": "2.1.0-beta.4", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -40,7 +40,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/openai/src/chat/openai-chat-language-model.test.ts b/packages/openai/src/chat/openai-chat-language-model.test.ts index a7e19b5d6842..c5e109340b80 100644 --- a/packages/openai/src/chat/openai-chat-language-model.test.ts +++ b/packages/openai/src/chat/openai-chat-language-model.test.ts @@ -1,11 +1,15 @@ import { LanguageModelV2Prompt } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, isNodeVersion, } from '@ai-sdk/provider-utils/test'; import { createOpenAI } from '../openai-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('../version', () => ({ + VERSION: '0.0.0-test', +})); const TEST_PROMPT: LanguageModelV2Prompt = [ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, @@ -613,6 +617,9 @@ describe('doGenerate', () => { 'openai-organization': 'test-organization', 'openai-project': 'test-project', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/openai/0.0.0-test`, + ); }); it('should parse tool results', async () => { diff --git a/packages/openai/src/chat/openai-chat-language-model.ts b/packages/openai/src/chat/openai-chat-language-model.ts index 41c16c2a9bd1..c2795cf359fe 100644 --- a/packages/openai/src/chat/openai-chat-language-model.ts +++ b/packages/openai/src/chat/openai-chat-language-model.ts @@ -30,7 +30,7 @@ import { getResponseMetadata } from './get-response-metadata'; import { mapOpenAIFinishReason } from './map-openai-finish-reason'; import { OpenAIChatModelId, - openaiProviderOptions, + openaiChatLanguageModelOptions, } from './openai-chat-options'; import { prepareChatTools } from './openai-chat-prepare-tools'; @@ -83,7 +83,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV2 { (await parseProviderOptions({ provider: 'openai', providerOptions, - schema: openaiProviderOptions, + schema: openaiChatLanguageModelOptions, })) ?? {}; const structuredOutputs = openaiOptions.structuredOutputs ?? true; diff --git a/packages/openai/src/chat/openai-chat-options.ts b/packages/openai/src/chat/openai-chat-options.ts index cd1bad7d288a..0ac9b5d3582e 100644 --- a/packages/openai/src/chat/openai-chat-options.ts +++ b/packages/openai/src/chat/openai-chat-options.ts @@ -39,7 +39,7 @@ export type OpenAIChatModelId = | 'gpt-5-chat-latest' | (string & {}); -export const openaiProviderOptions = z.object({ +export const openaiChatLanguageModelOptions = z.object({ /** * Modify the likelihood of specified tokens appearing in the completion. * @@ -141,4 +141,6 @@ export const openaiProviderOptions = z.object({ safetyIdentifier: z.string().optional(), }); -export type OpenAIProviderOptions = z.infer; +export type OpenAIChatLanguageModelOptions = z.infer< + typeof openaiChatLanguageModelOptions +>; diff --git a/packages/openai/src/chat/openai-chat-prepare-tools.test.ts b/packages/openai/src/chat/openai-chat-prepare-tools.test.ts index ac2b02f6ea38..7ba4d1262890 100644 --- a/packages/openai/src/chat/openai-chat-prepare-tools.test.ts +++ b/packages/openai/src/chat/openai-chat-prepare-tools.test.ts @@ -58,103 +58,6 @@ it('should correctly prepare function tools', () => { expect(result.toolWarnings).toEqual([]); }); -it('should correctly prepare provider-defined-server tools', () => { - const result = prepareChatTools({ - tools: [ - { - type: 'provider-defined', - id: 'openai.file_search', - name: 'file_search', - args: { - vectorStoreIds: ['vs_123'], - maxNumResults: 10, - ranking: { - ranker: 'auto', - }, - }, - }, - { - type: 'provider-defined', - id: 'openai.web_search_preview', - name: 'web_search_preview', - args: { - searchContextSize: 'high', - userLocation: { - type: 'approximate', - city: 'San Francisco', - region: 'CA', - }, - }, - }, - ], - structuredOutputs: false, - strictJsonSchema: false, - }); - - expect(result.tools).toEqual([ - { - type: 'file_search', - vector_store_ids: ['vs_123'], - max_num_results: 10, - ranking_options: { - ranker: 'auto', - }, - }, - { - type: 'web_search_preview', - search_context_size: 'high', - user_location: { - type: 'approximate', - city: 'San Francisco', - region: 'CA', - }, - }, - ]); - expect(result.toolChoice).toBeUndefined(); - expect(result.toolWarnings).toEqual([]); -}); - -it('should correctly prepare file_search with filters', () => { - const result = prepareChatTools({ - tools: [ - { - type: 'provider-defined', - id: 'openai.file_search', - name: 'file_search', - args: { - vectorStoreIds: ['vs_123'], - maxNumResults: 5, - filters: { - type: 'and', - filters: [ - { key: 'author', type: 'eq', value: 'John Doe' }, - { key: 'date', type: 'gte', value: '2023-01-01' }, - ], - }, - }, - }, - ], - structuredOutputs: false, - strictJsonSchema: false, - }); - - expect(result.tools).toEqual([ - { - type: 'file_search', - vector_store_ids: ['vs_123'], - max_num_results: 5, - ranking_options: undefined, - filters: { - type: 'and', - filters: [ - { key: 'author', type: 'eq', value: 'John Doe' }, - { key: 'date', type: 'gte', value: '2023-01-01' }, - ], - }, - }, - ]); -}); - it('should add warnings for unsupported tools', () => { const result = prepareChatTools({ tools: [ @@ -186,35 +89,6 @@ it('should add warnings for unsupported tools', () => { `); }); -it('should add warnings for unsupported provider-defined tools', () => { - const result = prepareChatTools({ - tools: [ - { - type: 'provider-defined', - id: 'some.client_tool', - name: 'clientTool', - args: {}, - } as any, - ], - structuredOutputs: false, - strictJsonSchema: false, - }); - - expect(result.tools).toEqual([]); - expect(result.toolChoice).toBeUndefined(); - expect(result.toolWarnings).toEqual([ - { - type: 'unsupported-tool', - tool: { - type: 'provider-defined', - id: 'some.client_tool', - name: 'clientTool', - args: {}, - }, - }, - ]); -}); - it('should handle tool choice "auto"', () => { const result = prepareChatTools({ tools: [ diff --git a/packages/openai/src/chat/openai-chat-prepare-tools.ts b/packages/openai/src/chat/openai-chat-prepare-tools.ts index 38c630da46c5..e7bd2be7fe95 100644 --- a/packages/openai/src/chat/openai-chat-prepare-tools.ts +++ b/packages/openai/src/chat/openai-chat-prepare-tools.ts @@ -3,9 +3,10 @@ import { LanguageModelV2CallWarning, UnsupportedFunctionalityError, } from '@ai-sdk/provider'; -import { fileSearchArgsSchema } from '../tool/file-search'; -import { webSearchPreviewArgsSchema } from '../tool/web-search-preview'; -import { OpenAIChatToolChoice, OpenAIChatTools } from './openai-chat-types'; +import { + OpenAIChatToolChoice, + OpenAIChatFunctionTool, +} from './openai-chat-types'; export function prepareChatTools({ tools, @@ -18,7 +19,7 @@ export function prepareChatTools({ structuredOutputs: boolean; strictJsonSchema: boolean; }): { - tools?: OpenAIChatTools; + tools?: OpenAIChatFunctionTool[]; toolChoice?: OpenAIChatToolChoice; toolWarnings: Array; } { @@ -31,7 +32,7 @@ export function prepareChatTools({ return { tools: undefined, toolChoice: undefined, toolWarnings }; } - const openaiTools: OpenAIChatTools = []; + const openaiTools: OpenAIChatFunctionTool[] = []; for (const tool of tools) { switch (tool.type) { @@ -46,35 +47,6 @@ export function prepareChatTools({ }, }); break; - case 'provider-defined': - switch (tool.id) { - case 'openai.file_search': { - const args = fileSearchArgsSchema.parse(tool.args); - openaiTools.push({ - type: 'file_search', - vector_store_ids: args.vectorStoreIds, - max_num_results: args.maxNumResults, - ranking_options: args.ranking - ? { ranker: args.ranking.ranker } - : undefined, - filters: args.filters, - }); - break; - } - case 'openai.web_search_preview': { - const args = webSearchPreviewArgsSchema.parse(tool.args); - openaiTools.push({ - type: 'web_search_preview', - search_context_size: args.searchContextSize, - user_location: args.userLocation, - }); - break; - } - default: - toolWarnings.push({ type: 'unsupported-tool', tool }); - break; - } - break; default: toolWarnings.push({ type: 'unsupported-tool', tool }); break; diff --git a/packages/openai/src/chat/openai-chat-types.ts b/packages/openai/src/chat/openai-chat-types.ts index 42c235d4b2bd..896dbda8709a 100644 --- a/packages/openai/src/chat/openai-chat-types.ts +++ b/packages/openai/src/chat/openai-chat-types.ts @@ -1,9 +1,6 @@ import { JSONSchema7 } from '@ai-sdk/provider'; -/** - * OpenAI function tool definition - */ -interface OpenAIChatFunctionTool { +export interface OpenAIChatFunctionTool { type: 'function'; function: { name: string; @@ -13,78 +10,8 @@ interface OpenAIChatFunctionTool { }; } -/** - * OpenAI file search tool definition - */ -interface OpenAIChatFileSearchTool { - type: 'file_search'; - vector_store_ids?: string[]; - max_num_results?: number; - ranking_options?: { - ranker?: 'auto' | 'default-2024-08-21'; - }; - filters?: - | { - key: string; - type: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte'; - value: string | number | boolean; - } - | { - type: 'and' | 'or'; - filters: any[]; - }; -} - -/** - * User location for web search - */ -interface OpenAIChatWebSearchUserLocation { - type?: 'approximate'; - city?: string; - region?: string; - country?: string; - timezone?: string; -} - -/** - * OpenAI web search preview tool definition - */ -interface OpenAIChatWebSearchPreviewTool { - type: 'web_search_preview'; - search_context_size?: 'low' | 'medium' | 'high'; - user_location?: OpenAIChatWebSearchUserLocation; -} - -/** - * OpenAI code interpreter tool definition - */ -interface OpenAIChatCodeInterpreterTool { - type: 'code_interpreter'; - container: { - type: 'auto'; - file_ids: string[]; - }; -} - -/** - * Union type for all OpenAI tools - */ -export type OpenAIChatTool = - | OpenAIChatFunctionTool - | OpenAIChatFileSearchTool - | OpenAIChatWebSearchPreviewTool - | OpenAIChatCodeInterpreterTool; - -/** - * OpenAI tool choice options - */ export type OpenAIChatToolChoice = | 'auto' | 'none' | 'required' | { type: 'function'; function: { name: string } }; - -/** - * OpenAI tools array type - */ -export type OpenAIChatTools = Array; diff --git a/packages/openai/src/completion/openai-completion-language-model.test.ts b/packages/openai/src/completion/openai-completion-language-model.test.ts index 6306f86a3a7b..fe6426e73c71 100644 --- a/packages/openai/src/completion/openai-completion-language-model.test.ts +++ b/packages/openai/src/completion/openai-completion-language-model.test.ts @@ -1,11 +1,15 @@ import { LanguageModelV2Prompt } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, isNodeVersion, } from '@ai-sdk/provider-utils/test'; import { createOpenAI } from '../openai-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('../version', () => ({ + VERSION: '0.0.0-test', +})); const TEST_PROMPT: LanguageModelV2Prompt = [ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, @@ -678,5 +682,8 @@ describe('doStream', () => { 'openai-organization': 'test-organization', 'openai-project': 'test-project', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/openai/0.0.0-test`, + ); }); }); diff --git a/packages/openai/src/embedding/openai-embedding-model.test.ts b/packages/openai/src/embedding/openai-embedding-model.test.ts index 83542550a827..bcad76aa48d2 100644 --- a/packages/openai/src/embedding/openai-embedding-model.test.ts +++ b/packages/openai/src/embedding/openai-embedding-model.test.ts @@ -1,7 +1,11 @@ -import { EmbeddingModelV2Embedding } from '@ai-sdk/provider'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { EmbeddingModelV3Embedding } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createOpenAI } from '../openai-provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('../version', () => ({ + VERSION: '0.0.0-test', +})); const dummyEmbeddings = [ [0.1, 0.2, 0.3, 0.4, 0.5], @@ -22,7 +26,7 @@ describe('doEmbed', () => { usage = { prompt_tokens: 8, total_tokens: 8 }, headers, }: { - embeddings?: EmbeddingModelV2Embedding[]; + embeddings?: EmbeddingModelV3Embedding[]; usage?: { prompt_tokens: number; total_tokens: number }; headers?: Record; } = {}) { @@ -135,5 +139,8 @@ describe('doEmbed', () => { 'openai-organization': 'test-organization', 'openai-project': 'test-project', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/openai/0.0.0-test`, + ); }); }); diff --git a/packages/openai/src/embedding/openai-embedding-model.ts b/packages/openai/src/embedding/openai-embedding-model.ts index 93795b6603a2..4e39fdd1b3b6 100644 --- a/packages/openai/src/embedding/openai-embedding-model.ts +++ b/packages/openai/src/embedding/openai-embedding-model.ts @@ -1,5 +1,5 @@ import { - EmbeddingModelV2, + EmbeddingModelV3, TooManyEmbeddingValuesForCallError, } from '@ai-sdk/provider'; import { @@ -16,8 +16,8 @@ import { openaiEmbeddingProviderOptions, } from './openai-embedding-options'; -export class OpenAIEmbeddingModel implements EmbeddingModelV2 { - readonly specificationVersion = 'v2'; +export class OpenAIEmbeddingModel implements EmbeddingModelV3 { + readonly specificationVersion = 'v3'; readonly modelId: OpenAIEmbeddingModelId; readonly maxEmbeddingsPerCall = 2048; readonly supportsParallelCalls = true; @@ -38,8 +38,8 @@ export class OpenAIEmbeddingModel implements EmbeddingModelV2 { headers, abortSignal, providerOptions, - }: Parameters['doEmbed']>[0]): Promise< - Awaited['doEmbed']>> + }: Parameters['doEmbed']>[0]): Promise< + Awaited['doEmbed']>> > { if (values.length > this.maxEmbeddingsPerCall) { throw new TooManyEmbeddingValuesForCallError({ diff --git a/packages/openai/src/image/openai-image-model.test.ts b/packages/openai/src/image/openai-image-model.test.ts index c6a293e41f33..0f9780895936 100644 --- a/packages/openai/src/image/openai-image-model.test.ts +++ b/packages/openai/src/image/openai-image-model.test.ts @@ -1,7 +1,11 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createOpenAI } from '../openai-provider'; import { OpenAIImageModel } from './openai-image-model'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('../version', () => ({ + VERSION: '0.0.0-test', +})); const prompt = 'A cute baby sea otter'; @@ -91,6 +95,9 @@ describe('doGenerate', () => { 'openai-organization': 'test-organization', 'openai-project': 'test-project', }); + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/openai/0.0.0-test`, + ); }); it('should extract the generated images', async () => { diff --git a/packages/openai/src/image/openai-image-model.ts b/packages/openai/src/image/openai-image-model.ts index 7f9ac2f204d0..9e750a7cdae9 100644 --- a/packages/openai/src/image/openai-image-model.ts +++ b/packages/openai/src/image/openai-image-model.ts @@ -1,4 +1,4 @@ -import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider'; +import { ImageModelV3, ImageModelV3CallWarning } from '@ai-sdk/provider'; import { combineHeaders, createJsonResponseHandler, @@ -19,8 +19,8 @@ interface OpenAIImageModelConfig extends OpenAIConfig { }; } -export class OpenAIImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class OpenAIImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; get maxImagesPerCall(): number { return modelMaxImagesPerCall[this.modelId] ?? 1; @@ -44,10 +44,10 @@ export class OpenAIImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; if (aspectRatio != null) { warnings.push({ diff --git a/packages/openai/src/index.ts b/packages/openai/src/index.ts index f590b8e2aec9..59747996375a 100644 --- a/packages/openai/src/index.ts +++ b/packages/openai/src/index.ts @@ -1,3 +1,5 @@ export { createOpenAI, openai } from './openai-provider'; export type { OpenAIProvider, OpenAIProviderSettings } from './openai-provider'; export type { OpenAIResponsesProviderOptions } from './responses/openai-responses-language-model'; +export type { OpenAIChatLanguageModelOptions } from './chat/openai-chat-options'; +export { VERSION } from './version'; diff --git a/packages/openai/src/openai-provider.ts b/packages/openai/src/openai-provider.ts index 755b48bd3736..dc64e82b0241 100644 --- a/packages/openai/src/openai-provider.ts +++ b/packages/openai/src/openai-provider.ts @@ -1,8 +1,8 @@ import { - EmbeddingModelV2, - ImageModelV2, + EmbeddingModelV3, + ImageModelV3, LanguageModelV2, - ProviderV2, + ProviderV3, SpeechModelV2, TranscriptionModelV2, } from '@ai-sdk/provider'; @@ -10,6 +10,7 @@ import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { OpenAIChatLanguageModel } from './chat/openai-chat-language-model'; import { OpenAIChatModelId } from './chat/openai-chat-options'; @@ -26,8 +27,9 @@ import { OpenAISpeechModel } from './speech/openai-speech-model'; import { OpenAISpeechModelId } from './speech/openai-speech-options'; import { OpenAITranscriptionModel } from './transcription/openai-transcription-model'; import { OpenAITranscriptionModelId } from './transcription/openai-transcription-options'; +import { VERSION } from './version'; -export interface OpenAIProvider extends ProviderV2 { +export interface OpenAIProvider extends ProviderV3 { (modelId: OpenAIResponsesModelId): LanguageModelV2; /** @@ -53,27 +55,27 @@ Creates an OpenAI completion model for text generation. /** Creates a model for text embeddings. */ - embedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV2; + embedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3; /** Creates a model for text embeddings. */ - textEmbedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV2; + textEmbedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3; /** Creates a model for text embeddings. */ - textEmbeddingModel(modelId: OpenAIEmbeddingModelId): EmbeddingModelV2; + textEmbeddingModel(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3; /** Creates a model for image generation. */ - image(modelId: OpenAIImageModelId): ImageModelV2; + image(modelId: OpenAIImageModelId): ImageModelV3; /** Creates a model for image generation. */ - imageModel(modelId: OpenAIImageModelId): ImageModelV2; + imageModel(modelId: OpenAIImageModelId): ImageModelV3; /** Creates a model for transcription. @@ -140,16 +142,20 @@ export function createOpenAI( const providerName = options.name ?? 'openai'; - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'OPENAI_API_KEY', - description: 'OpenAI', - })}`, - 'OpenAI-Organization': options.organization, - 'OpenAI-Project': options.project, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'OPENAI_API_KEY', + description: 'OpenAI', + })}`, + 'OpenAI-Organization': options.organization, + 'OpenAI-Project': options.project, + ...options.headers, + }, + `ai-sdk/openai/${VERSION}`, + ); const createChatModel = (modelId: OpenAIChatModelId) => new OpenAIChatLanguageModel(modelId, { diff --git a/packages/openai/src/openai-tools.ts b/packages/openai/src/openai-tools.ts index c3a9ff92d89e..b3c4e4390be1 100644 --- a/packages/openai/src/openai-tools.ts +++ b/packages/openai/src/openai-tools.ts @@ -1,5 +1,6 @@ import { codeInterpreter } from './tool/code-interpreter'; import { fileSearch } from './tool/file-search'; +import { imageGeneration } from './tool/image-generation'; import { webSearch } from './tool/web-search'; import { webSearchPreview } from './tool/web-search-preview'; @@ -29,6 +30,21 @@ export const openaiTools = { */ fileSearch, + /** + * The image generation tool allows you to generate images using a text prompt, + * and optionally image inputs. It leverages the GPT Image model, + * and automatically optimizes text inputs for improved performance. + * + * Must have name `image_generation`. + * + * @param size - Image dimensions (e.g., 1024x1024, 1024x1536) + * @param quality - Rendering quality (e.g. low, medium, high) + * @param format - File output format + * @param compression - Compression level (0-100%) for JPEG and WebP formats + * @param background - Transparent or opaque + */ + imageGeneration, + /** * Web search allows models to access up-to-date information from the internet * and provide answers with sourced citations. diff --git a/packages/openai/src/responses/__fixtures__/openai-code-interpreter-tool.1.chunks.txt b/packages/openai/src/responses/__fixtures__/openai-code-interpreter-tool.1.chunks.txt new file mode 100644 index 000000000000..526e654d1d84 --- /dev/null +++ b/packages/openai/src/responses/__fixtures__/openai-code-interpreter-tool.1.chunks.txt @@ -0,0 +1,393 @@ +{"type":"response.created","sequence_number":0,"response":{"id":"resp_68c2e6efa238819383d5f52a2c2a3baa02d3a5742c7ddae9","object":"response","created_at":1757603567,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-nano-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"code_interpreter","container":{"type":"auto"}}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_68c2e6efa238819383d5f52a2c2a3baa02d3a5742c7ddae9","object":"response","created_at":1757603567,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-nano-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"code_interpreter","container":{"type":"auto"}}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"rs_68c2e6f40ba48193a1c27abf31130e7e02d3a5742c7ddae9","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":3,"output_index":0,"item":{"id":"rs_68c2e6f40ba48193a1c27abf31130e7e02d3a5742c7ddae9","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":4,"output_index":1,"item":{"id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","type":"code_interpreter_call","status":"in_progress","code":"","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","outputs":[]}} +{"type":"response.code_interpreter_call.in_progress","sequence_number":5,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":6,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"import","obfuscation":"OIvaVX38kd"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":7,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" random","obfuscation":"BehxQZQ2d"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":8,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":",","obfuscation":"9CZBTAhqNL39rvm"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":9,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" math","obfuscation":"gJGstQCbmBz"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":10,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"\n","obfuscation":"NDJnE8FanAc30He"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":11,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"N","obfuscation":"EzKVUcA2jjv2vlZ"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":12,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"=","obfuscation":"7ZY0446GwpTQvtm"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":13,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"100","obfuscation":"NsI6sDvcnIzse"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":14,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"00","obfuscation":"9X1Ho4jfEV0RS9"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":15,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"\n","obfuscation":"H8Y1P6g9UEtJwk2"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":16,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"s","obfuscation":"9QCH6CJ1iI6n2qX"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":17,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"ums","obfuscation":"TUy2OEScLJqyu"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":18,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"=[]\n","obfuscation":"mY5A7Xd6WQaB"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":19,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"s","obfuscation":"jd0bnnJ6KLIOb0Z"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":20,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"=","obfuscation":"QxbN5tWnCnhiujx"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":21,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"0","obfuscation":"ybsZK3KxG5hAA62"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":22,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"\n","obfuscation":"pGerylB9mkV7M9y"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":23,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"for","obfuscation":"bugXXbayxnyEn"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":24,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" _","obfuscation":"swCViNFMEreQOE"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":25,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" in","obfuscation":"aOzFRkHvGQaOf"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":26,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" range","obfuscation":"rOq4cK4Xkb"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":27,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"(N","obfuscation":"kQC1XGCTtAyXut"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":28,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"):\n","obfuscation":"UBYG2mZnN0Kn6"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":29,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" ","obfuscation":"cwVPkTduQyDRH"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":30,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" a","obfuscation":"jkL2ggSaHCoQZE"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":31,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"=random","obfuscation":"CeILD3TgG"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":32,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":".randint","obfuscation":"H6ej8bzj"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":33,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"(","obfuscation":"A6wLj2RbRElPaYh"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":34,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"1","obfuscation":"20oH9KzqbEgwf2E"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":35,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":",","obfuscation":"VQovrtpRVURakU4"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":36,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"6","obfuscation":"OaLX7hoG9MVNB78"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":37,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":")\n","obfuscation":"b5t7NMWofCIeb4"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":38,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" ","obfuscation":"mUnVcQCuBKrRb"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":39,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" b","obfuscation":"ou8Xxmmv5u59HZ"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":40,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"=random","obfuscation":"IkxH8gSk3"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":41,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":".randint","obfuscation":"ZFMdoKnr"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":42,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"(","obfuscation":"matJkyirCs8fEkT"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":43,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"1","obfuscation":"6392sm7p643sNwQ"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":44,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":",","obfuscation":"CylXXp45gG2YpfU"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":45,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"6","obfuscation":"jR4lmAu43NGVN5w"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":46,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":")\n","obfuscation":"d551m56KVrZvkP"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":47,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" ","obfuscation":"E4jdWpuII0V6Q"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":48,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" sm","obfuscation":"9PCqkf9B9HQ03"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":49,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"=a","obfuscation":"VX03wzsXAo9Gj8"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":50,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"+b","obfuscation":"aQz4e6tOKSv5Xv"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":51,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"\n","obfuscation":"MgxWQt0jjfjoh40"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":52,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" ","obfuscation":"AxB3ZJpztCNHO"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":53,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" sums","obfuscation":"ZT4QjPPzgfa"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":54,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":".append","obfuscation":"jIgGSr7nx"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":55,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"(sm","obfuscation":"6lOALP9UAcwli"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":56,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":")\n","obfuscation":"FDmptnYJsF06tf"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":57,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" ","obfuscation":"VTrrsRPIFwGLr"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":58,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" s","obfuscation":"C7Ld7ZOT0NIfH4"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":59,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"+=","obfuscation":"h0QkRsiSMS3ST5"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":60,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"sm","obfuscation":"w67YRJSYiImgMw"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":61,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"\n","obfuscation":"nyadeNRxjzKhah9"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":62,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"min","obfuscation":"L1FOw2uMN41wr"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":63,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"(s","obfuscation":"x9G1pMe4HPtWRc"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":64,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"ums","obfuscation":"bRhDo2uoDbzDU"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":65,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"),","obfuscation":"7ir1OOQ8PRXepf"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":66,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" max","obfuscation":"MY4uXjzfiJYC"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":67,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"(s","obfuscation":"KUMVY4a2EuTlUB"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":68,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"ums","obfuscation":"HabMLvTvv9Xpb"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":69,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"),","obfuscation":"k5Z4QViGpCalFV"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":70,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" sum","obfuscation":"gHPfwElMRQ7X"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":71,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"(s","obfuscation":"OQqKGcI6yD3hCv"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":72,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"ums","obfuscation":"eleO2Cy8G36IN"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":73,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"),","obfuscation":"KH87OaX6qL9EoE"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":74,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":" sum","obfuscation":"6jtxAwH8MlID"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":75,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"(s","obfuscation":"BQMUi7ayzyAobI"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":76,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"ums","obfuscation":"jfYB6TdANxirQ"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":77,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":")/","obfuscation":"82XAQdKQv3ocdA"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":78,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"N","obfuscation":"1BmZgJs1MxSt7BP"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":79,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","delta":"\n","obfuscation":"paA5Kh4ppB56TM7"} +{"type":"response.code_interpreter_call_code.done","sequence_number":80,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","code":"import random, math\nN=10000\nsums=[]\ns=0\nfor _ in range(N):\n a=random.randint(1,6)\n b=random.randint(1,6)\n sm=a+b\n sums.append(sm)\n s+=sm\nmin(sums), max(sums), sum(sums), sum(sums)/N\n"} +{"type":"response.code_interpreter_call.interpreting","sequence_number":81,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9"} +{"type":"response.code_interpreter_call.completed","sequence_number":82,"output_index":1,"item_id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9"} +{"type":"response.output_item.done","sequence_number":83,"output_index":1,"item":{"id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","type":"code_interpreter_call","status":"completed","code":"import random, math\nN=10000\nsums=[]\ns=0\nfor _ in range(N):\n a=random.randint(1,6)\n b=random.randint(1,6)\n sm=a+b\n sums.append(sm)\n s+=sm\nmin(sums), max(sums), sum(sums), sum(sums)/N\n","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","outputs":[{"type":"logs","logs":"(2, 12, 69868, 6.9868)"}]}} +{"type":"response.output_item.added","sequence_number":84,"output_index":2,"item":{"id":"rs_68c2e6fcb52881938f21c45741216ac002d3a5742c7ddae9","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":85,"output_index":2,"item":{"id":"rs_68c2e6fcb52881938f21c45741216ac002d3a5742c7ddae9","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":86,"output_index":3,"item":{"id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","type":"code_interpreter_call","status":"in_progress","code":"","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","outputs":[]}} +{"type":"response.code_interpreter_call.in_progress","sequence_number":87,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":88,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"import","obfuscation":"Q5Vt5nbYav"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":89,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" csv","obfuscation":"kWZINj0xnmCN"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":90,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":",","obfuscation":"yuD5SWIiH0mZy9p"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":91,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" pathlib","obfuscation":"LVw3IcA3"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":92,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"\n","obfuscation":"Nr92hIGSaSrOCop"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":93,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"path","obfuscation":"tYmBas4T1VlZ"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":94,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" =","obfuscation":"Y4MuYj1jZHCwlU"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":95,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" pathlib","obfuscation":"zmW7YzNY"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":96,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":".Path","obfuscation":"YW0SRfsvBPX"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":97,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"('/","obfuscation":"cDwpVqOjfQdMz"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":98,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"mnt","obfuscation":"vzMBtn7n4vmqu"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":99,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"/data","obfuscation":"BDpBczqzb03"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":100,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"/","obfuscation":"iMOcC2sfCeqvPWt"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":101,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"roll","obfuscation":"e06sua0vHSZI"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":102,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"2","obfuscation":"EkQb6y3vxcY8akF"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":103,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"dice","obfuscation":"rIrGtWmbqnaL"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":104,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"_s","obfuscation":"5V89xn1ccGFLCX"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":105,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"ums","obfuscation":"dJtfaB4Z1mjbp"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":106,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"_","obfuscation":"2JOwD91dVMndxUt"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":107,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"100","obfuscation":"gYu9oFkUcX2U0"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":108,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"00","obfuscation":"LSMwodFP8vB6Vk"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":109,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":".csv","obfuscation":"lBH2cU2HiAJl"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":110,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"')\n","obfuscation":"VLuOi5ItXC12s"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":111,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"with","obfuscation":"HGPo22WbgQQx"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":112,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" open","obfuscation":"Y63mv40IMcX"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":113,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"(path","obfuscation":"99cn0n4KKeC"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":114,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":",","obfuscation":"GrmejhFdMKkcnfo"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":115,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" '","obfuscation":"az3yVeZK1rhy3s"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":116,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"w","obfuscation":"uu8LMJNvzUSz9U9"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":117,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"',","obfuscation":"AiYFdBpnV7hzDd"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":118,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" newline","obfuscation":"O3nB1Q3L"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":119,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"='","obfuscation":"yFJ3FwOeIEShoN"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":120,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"')","obfuscation":"ZoSctx5RbMFuvv"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":121,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" as","obfuscation":"YxkRPQDKS0rcn"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":122,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" f","obfuscation":"0X8tGkLUnAsHHq"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":123,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":":\n","obfuscation":"2ZiXc6z84Fx7n2"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":124,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" ","obfuscation":"XL7r4TwA1JNmn"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":125,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" writer","obfuscation":"wam8ZK8pj"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":126,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" =","obfuscation":"fURGlZd9iB14Ta"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":127,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" csv","obfuscation":"DFciDuEyx2iM"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":128,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":".writer","obfuscation":"oHAcHpp7k"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":129,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"(f","obfuscation":"c7FyIJS5Tz6UyO"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":130,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":")\n","obfuscation":"d2bqVnyYwlHKC7"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":131,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" ","obfuscation":"RVJgqZtsODA6K"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":132,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" writer","obfuscation":"FIDF831k1"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":133,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":".writerow","obfuscation":"Lcn10d9"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":134,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"(['","obfuscation":"RxqMcQOqjouZ8"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":135,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"sum","obfuscation":"3ltJUghFzhYrR"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":136,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"'])\n","obfuscation":"qdEyqJq5J6Ju"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":137,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" ","obfuscation":"kqIZFGi458Szj"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":138,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" for","obfuscation":"qvWBlahiKoTK"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":139,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" val","obfuscation":"QMq3J5caChq3"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":140,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" in","obfuscation":"v2nA64jkmmBeN"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":141,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" sums","obfuscation":"Q5iqkWm1jol"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":142,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":":\n","obfuscation":"CK3ULGAJcvFAJe"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":143,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" ","obfuscation":"GMvgyT2Rv"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":144,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" writer","obfuscation":"ihT43CIeC"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":145,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":".writerow","obfuscation":"AY0Mmyl"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":146,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"([","obfuscation":"FQGJsMr18gcWuK"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":147,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"val","obfuscation":"TtXREk8S4EdYL"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":148,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"])\n","obfuscation":"uYp4Eex0ELRfK"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":149,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"path","obfuscation":"4dybh126gQHx"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":150,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":",","obfuscation":"t8OFnbdkUrs6Uno"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":151,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" path","obfuscation":"jzkGOtvXcB7"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":152,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":".exists","obfuscation":"OTPZHwIxr"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":153,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"(),","obfuscation":"vR0eajccRRVMX"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":154,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":" len","obfuscation":"EXhzSHusL3cL"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":155,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"(s","obfuscation":"XsAd0nPHtCaIST"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":156,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":"ums","obfuscation":"SlF1CGCVNiTj3"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":157,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","delta":")\n","obfuscation":"rMHq84Q57a55mS"} +{"type":"response.code_interpreter_call_code.done","sequence_number":158,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","code":"import csv, pathlib\npath = pathlib.Path('/mnt/data/roll2dice_sums_10000.csv')\nwith open(path, 'w', newline='') as f:\n writer = csv.writer(f)\n writer.writerow(['sum'])\n for val in sums:\n writer.writerow([val])\npath, path.exists(), len(sums)\n"} +{"type":"response.code_interpreter_call.interpreting","sequence_number":159,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9"} +{"type":"response.code_interpreter_call.completed","sequence_number":160,"output_index":3,"item_id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9"} +{"type":"response.output_item.done","sequence_number":161,"output_index":3,"item":{"id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","type":"code_interpreter_call","status":"completed","code":"import csv, pathlib\npath = pathlib.Path('/mnt/data/roll2dice_sums_10000.csv')\nwith open(path, 'w', newline='') as f:\n writer = csv.writer(f)\n writer.writerow(['sum'])\n for val in sums:\n writer.writerow([val])\npath, path.exists(), len(sums)\n","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","outputs":[{"type":"logs","logs":"(PosixPath('/mnt/data/roll2dice_sums_10000.csv'), True, 10000)"}]}} +{"type":"response.output_item.added","sequence_number":162,"output_index":4,"item":{"id":"rs_68c2e6fff1808193a78d43410a1feb4802d3a5742c7ddae9","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":163,"output_index":4,"item":{"id":"rs_68c2e6fff1808193a78d43410a1feb4802d3a5742c7ddae9","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":164,"output_index":5,"item":{"id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9","type":"code_interpreter_call","status":"in_progress","code":"","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","outputs":[]}} +{"type":"response.code_interpreter_call.in_progress","sequence_number":165,"output_index":5,"item_id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":166,"output_index":5,"item_id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9","delta":"s","obfuscation":"K7FMMOT7d8kYYva"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":167,"output_index":5,"item_id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9","delta":"ums","obfuscation":"wfKSZgnAloo8W"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":168,"output_index":5,"item_id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9","delta":"[:","obfuscation":"G5XMdLaW2r0wBo"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":169,"output_index":5,"item_id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9","delta":"20","obfuscation":"VnqDLZheFrqn5b"} +{"type":"response.code_interpreter_call_code.delta","sequence_number":170,"output_index":5,"item_id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9","delta":"]\n","obfuscation":"5BBjQbjI1SbB5q"} +{"type":"response.code_interpreter_call_code.done","sequence_number":171,"output_index":5,"item_id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9","code":"sums[:20]\n"} +{"type":"response.code_interpreter_call.interpreting","sequence_number":172,"output_index":5,"item_id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9"} +{"type":"response.code_interpreter_call.completed","sequence_number":173,"output_index":5,"item_id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9"} +{"type":"response.output_item.done","sequence_number":174,"output_index":5,"item":{"id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9","type":"code_interpreter_call","status":"completed","code":"sums[:20]\n","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","outputs":[{"type":"logs","logs":"[6, 7, 2, 5, 5, 11, 4, 8, 10, 7, 5, 8, 8, 7, 10, 8, 9, 5, 4, 7]"}]}} +{"type":"response.output_item.added","sequence_number":175,"output_index":6,"item":{"id":"rs_68c2e703d114819383c5da260649c7ce02d3a5742c7ddae9","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":176,"output_index":6,"item":{"id":"rs_68c2e703d114819383c5da260649c7ce02d3a5742c7ddae9","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":177,"output_index":7,"item":{"id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","type":"message","status":"in_progress","content":[],"role":"assistant"}} +{"type":"response.content_part.added","sequence_number":178,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}} +{"type":"response.output_text.delta","sequence_number":179,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"Here","logprobs":[],"obfuscation":"cWtiKXaGjem2"} +{"type":"response.output_text.delta","sequence_number":180,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"’s","logprobs":[],"obfuscation":"tCu4gPjumNTFmD"} +{"type":"response.output_text.delta","sequence_number":181,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"JnPxZem2fRHtAY"} +{"type":"response.output_text.delta","sequence_number":182,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" simulation","logprobs":[],"obfuscation":"wwKNf"} +{"type":"response.output_text.delta","sequence_number":183,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"iaryaBgPsdz34"} +{"type":"response.output_text.delta","sequence_number":184,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" rolling","logprobs":[],"obfuscation":"oyUpOVUY"} +{"type":"response.output_text.delta","sequence_number":185,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" two","logprobs":[],"obfuscation":"uUEDqEO4Zw33"} +{"type":"response.output_text.delta","sequence_number":186,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" fair","logprobs":[],"obfuscation":"0BdgPF0tVha"} +{"type":"response.output_text.delta","sequence_number":187,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" six","logprobs":[],"obfuscation":"RJNXKa4QfiPn"} +{"type":"response.output_text.delta","sequence_number":188,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"-sided","logprobs":[],"obfuscation":"J2wIUlUlDK"} +{"type":"response.output_text.delta","sequence_number":189,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" dice","logprobs":[],"obfuscation":"uQ01CzXfntg"} +{"type":"response.output_text.delta","sequence_number":190,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"kaSJw7hDfrziOu0"} +{"type":"response.output_text.delta","sequence_number":191,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"10","logprobs":[],"obfuscation":"eOVSUlhAVZKn91"} +{"type":"response.output_text.delta","sequence_number":192,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"7N197ClBTCK1JOQ"} +{"type":"response.output_text.delta","sequence_number":193,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"000","logprobs":[],"obfuscation":"VjnhfcA30nIGG"} +{"type":"response.output_text.delta","sequence_number":194,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" times","logprobs":[],"obfuscation":"Z8Q7sWHzsq"} +{"type":"response.output_text.delta","sequence_number":195,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":".","logprobs":[],"obfuscation":"IN62T6mCu6fYl7Z"} +{"type":"response.output_text.delta","sequence_number":196,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" Each","logprobs":[],"obfuscation":"2MZMAmlsfNc"} +{"type":"response.output_text.delta","sequence_number":197,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" trial","logprobs":[],"obfuscation":"oizOX5EXr5"} +{"type":"response.output_text.delta","sequence_number":198,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" sums","logprobs":[],"obfuscation":"5ObkKIGcTkQ"} +{"type":"response.output_text.delta","sequence_number":199,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"asb6TrkUh1Cm"} +{"type":"response.output_text.delta","sequence_number":200,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" two","logprobs":[],"obfuscation":"DiIKkiBtzYOB"} +{"type":"response.output_text.delta","sequence_number":201,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" dice","logprobs":[],"obfuscation":"dSmCBiYzgkA"} +{"type":"response.output_text.delta","sequence_number":202,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":".\n\n","logprobs":[],"obfuscation":"B4RRfgIWurZhM"} +{"type":"response.output_text.delta","sequence_number":203,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"Results","logprobs":[],"obfuscation":"I8hspPPYn"} +{"type":"response.output_text.delta","sequence_number":204,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"\n","logprobs":[],"obfuscation":"k9ZUdNPKl9MokYL"} +{"type":"response.output_text.delta","sequence_number":205,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"-","logprobs":[],"obfuscation":"f6MR2xtEU5uYHlp"} +{"type":"response.output_text.delta","sequence_number":206,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" Total","logprobs":[],"obfuscation":"3ISIUjGjnU"} +{"type":"response.output_text.delta","sequence_number":207,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" sum","logprobs":[],"obfuscation":"ODYO2Simfox4"} +{"type":"response.output_text.delta","sequence_number":208,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"3Y3Ptvu0BqapM"} +{"type":"response.output_text.delta","sequence_number":209,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" all","logprobs":[],"obfuscation":"AszqcOsVr72y"} +{"type":"response.output_text.delta","sequence_number":210,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"Jy7ALXZ6mlpMekP"} +{"type":"response.output_text.delta","sequence_number":211,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"10","logprobs":[],"obfuscation":"kc4mRtEUhUdtSX"} +{"type":"response.output_text.delta","sequence_number":212,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"cDQGVbxXjI7yLV9"} +{"type":"response.output_text.delta","sequence_number":213,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"000","logprobs":[],"obfuscation":"PQ9Rbi6B1pDGv"} +{"type":"response.output_text.delta","sequence_number":214,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" trials","logprobs":[],"obfuscation":"3Hy0lSObp"} +{"type":"response.output_text.delta","sequence_number":215,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":":","logprobs":[],"obfuscation":"gl1nkwnjIeRW0uj"} +{"type":"response.output_text.delta","sequence_number":216,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"MIDLjmmIoCEi9em"} +{"type":"response.output_text.delta","sequence_number":217,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"69","logprobs":[],"obfuscation":"PbzKsAbJaBcHJC"} +{"type":"response.output_text.delta","sequence_number":218,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"vZ7xqtdD8EJTicP"} +{"type":"response.output_text.delta","sequence_number":219,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"868","logprobs":[],"obfuscation":"bJpXgNh7BsJcq"} +{"type":"response.output_text.delta","sequence_number":220,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"\n","logprobs":[],"obfuscation":"JNDFGdujdYg21ES"} +{"type":"response.output_text.delta","sequence_number":221,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"-","logprobs":[],"obfuscation":"QXSorNvhTzeaXh8"} +{"type":"response.output_text.delta","sequence_number":222,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" Average","logprobs":[],"obfuscation":"D0CVJd3J"} +{"type":"response.output_text.delta","sequence_number":223,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" sum","logprobs":[],"obfuscation":"k4SZuQjxkPG2"} +{"type":"response.output_text.delta","sequence_number":224,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" per","logprobs":[],"obfuscation":"NNFtPpEGRDaq"} +{"type":"response.output_text.delta","sequence_number":225,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" trial","logprobs":[],"obfuscation":"p1OMEEEgdy"} +{"type":"response.output_text.delta","sequence_number":226,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":":","logprobs":[],"obfuscation":"dzqJ1rG9L8JlybS"} +{"type":"response.output_text.delta","sequence_number":227,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"S3pApfeofpkiGR2"} +{"type":"response.output_text.delta","sequence_number":228,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"6","logprobs":[],"obfuscation":"vamf1TIG5wk7vR7"} +{"type":"response.output_text.delta","sequence_number":229,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":".","logprobs":[],"obfuscation":"hi8WfRh2huRV2av"} +{"type":"response.output_text.delta","sequence_number":230,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"986","logprobs":[],"obfuscation":"eQl8O30dpxC1D"} +{"type":"response.output_text.delta","sequence_number":231,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"8","logprobs":[],"obfuscation":"pWiLsTRf53gtR5k"} +{"type":"response.output_text.delta","sequence_number":232,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"\n","logprobs":[],"obfuscation":"iJJ0EbjegjFMJIU"} +{"type":"response.output_text.delta","sequence_number":233,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"-","logprobs":[],"obfuscation":"N0bGXFvSI8S79P9"} +{"type":"response.output_text.delta","sequence_number":234,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" Minimum","logprobs":[],"obfuscation":"Dw0jHUib"} +{"type":"response.output_text.delta","sequence_number":235,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" sum","logprobs":[],"obfuscation":"vEVnMQIaSbKv"} +{"type":"response.output_text.delta","sequence_number":236,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" observed","logprobs":[],"obfuscation":"NtvpKxj"} +{"type":"response.output_text.delta","sequence_number":237,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":":","logprobs":[],"obfuscation":"aCDwp3IWLjpZYXN"} +{"type":"response.output_text.delta","sequence_number":238,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"LMKMpUEYzeSLVzM"} +{"type":"response.output_text.delta","sequence_number":239,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"2","logprobs":[],"obfuscation":"ClYZjsEoHgeyyx5"} +{"type":"response.output_text.delta","sequence_number":240,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"\n","logprobs":[],"obfuscation":"eWgBfrp3etb1PXW"} +{"type":"response.output_text.delta","sequence_number":241,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"-","logprobs":[],"obfuscation":"quVcOZuR0EQJRLU"} +{"type":"response.output_text.delta","sequence_number":242,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" Maximum","logprobs":[],"obfuscation":"MSYZTyax"} +{"type":"response.output_text.delta","sequence_number":243,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" sum","logprobs":[],"obfuscation":"skeWftDXCy0f"} +{"type":"response.output_text.delta","sequence_number":244,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" observed","logprobs":[],"obfuscation":"Es7GIxV"} +{"type":"response.output_text.delta","sequence_number":245,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":":","logprobs":[],"obfuscation":"L1yobSjDDHdJj2Q"} +{"type":"response.output_text.delta","sequence_number":246,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"rKximwRLUxT1oE8"} +{"type":"response.output_text.delta","sequence_number":247,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"12","logprobs":[],"obfuscation":"vxCOZriMlGIBr5"} +{"type":"response.output_text.delta","sequence_number":248,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"\n","logprobs":[],"obfuscation":"93iYynmGyvaDROv"} +{"type":"response.output_text.delta","sequence_number":249,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"-","logprobs":[],"obfuscation":"vYWCVytchr887ft"} +{"type":"response.output_text.delta","sequence_number":250,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" Sample","logprobs":[],"obfuscation":"oTY4DvhLU"} +{"type":"response.output_text.delta","sequence_number":251,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"uab8JVOfMHCBy"} +{"type":"response.output_text.delta","sequence_number":252,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"Px636omVZ9eT"} +{"type":"response.output_text.delta","sequence_number":253,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" first","logprobs":[],"obfuscation":"8kXFpfluR6"} +{"type":"response.output_text.delta","sequence_number":254,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"2P4bZfiZns17SjY"} +{"type":"response.output_text.delta","sequence_number":255,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"20","logprobs":[],"obfuscation":"juXtPm1WNuxXsu"} +{"type":"response.output_text.delta","sequence_number":256,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" trial","logprobs":[],"obfuscation":"s3rXjHd8HT"} +{"type":"response.output_text.delta","sequence_number":257,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" sums","logprobs":[],"obfuscation":"Z8LVrQHamR5"} +{"type":"response.output_text.delta","sequence_number":258,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":":","logprobs":[],"obfuscation":"nncCGQgd7S6dugK"} +{"type":"response.output_text.delta","sequence_number":259,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"jwxRD0GfBSMl3n3"} +{"type":"response.output_text.delta","sequence_number":260,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"6","logprobs":[],"obfuscation":"e2LguwC6eWkDYJL"} +{"type":"response.output_text.delta","sequence_number":261,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"GWh6hS60wuKC5vg"} +{"type":"response.output_text.delta","sequence_number":262,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"HRjkZOGFA6ABf7e"} +{"type":"response.output_text.delta","sequence_number":263,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"7","logprobs":[],"obfuscation":"NV7T3fVKnZjaoh7"} +{"type":"response.output_text.delta","sequence_number":264,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"0hQqXftC4Hm1DZU"} +{"type":"response.output_text.delta","sequence_number":265,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"myz0bO87K5wuzKx"} +{"type":"response.output_text.delta","sequence_number":266,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"2","logprobs":[],"obfuscation":"3UQjA7MPiSu4wft"} +{"type":"response.output_text.delta","sequence_number":267,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"e2DmWcn2QSCqO8T"} +{"type":"response.output_text.delta","sequence_number":268,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"4PgVLhowFQInu8j"} +{"type":"response.output_text.delta","sequence_number":269,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"5","logprobs":[],"obfuscation":"Je43jmILGxAHVLX"} +{"type":"response.output_text.delta","sequence_number":270,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"xLRCC2wPENo8kjM"} +{"type":"response.output_text.delta","sequence_number":271,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"aHJ31Fc1Q4Wkhtf"} +{"type":"response.output_text.delta","sequence_number":272,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"5","logprobs":[],"obfuscation":"qIUWrJBtGqzfUYv"} +{"type":"response.output_text.delta","sequence_number":273,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"iUjdWK214dw3gyE"} +{"type":"response.output_text.delta","sequence_number":274,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"XELnI6FE9VyDspQ"} +{"type":"response.output_text.delta","sequence_number":275,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"11","logprobs":[],"obfuscation":"S0yhClyBH6fxe0"} +{"type":"response.output_text.delta","sequence_number":276,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"5QncHOPIDC6HBOh"} +{"type":"response.output_text.delta","sequence_number":277,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"0ZJ4iQpb5FXwlV5"} +{"type":"response.output_text.delta","sequence_number":278,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"4","logprobs":[],"obfuscation":"e1ky3dAFjWbfdiJ"} +{"type":"response.output_text.delta","sequence_number":279,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"DOKodHuxCEFe2DP"} +{"type":"response.output_text.delta","sequence_number":280,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"9OrQn0kuad7Lz6a"} +{"type":"response.output_text.delta","sequence_number":281,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"8","logprobs":[],"obfuscation":"vPhqvXeSkulQg2a"} +{"type":"response.output_text.delta","sequence_number":282,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"ALNYVvL8vMucMLT"} +{"type":"response.output_text.delta","sequence_number":283,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"MndsWcUDU3nHNNz"} +{"type":"response.output_text.delta","sequence_number":284,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"10","logprobs":[],"obfuscation":"TgTAh8ufRUWzNE"} +{"type":"response.output_text.delta","sequence_number":285,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"dnnmqq7hIOEC4JZ"} +{"type":"response.output_text.delta","sequence_number":286,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"nRUxu3QaMtgNmWT"} +{"type":"response.output_text.delta","sequence_number":287,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"7","logprobs":[],"obfuscation":"8tbbRihVBi306eS"} +{"type":"response.output_text.delta","sequence_number":288,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"gZhLtTYHoldGVWK"} +{"type":"response.output_text.delta","sequence_number":289,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"iVBTTaAfcxERh2P"} +{"type":"response.output_text.delta","sequence_number":290,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"5","logprobs":[],"obfuscation":"QIIR6BkPzw6APPl"} +{"type":"response.output_text.delta","sequence_number":291,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"ebTTUkU9r9HVszz"} +{"type":"response.output_text.delta","sequence_number":292,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"9XK2wBq8udw3eFr"} +{"type":"response.output_text.delta","sequence_number":293,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"8","logprobs":[],"obfuscation":"rMSAFNcC5g9p9DN"} +{"type":"response.output_text.delta","sequence_number":294,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"QLqJqJkFAjXPI2Y"} +{"type":"response.output_text.delta","sequence_number":295,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"5KCGtHjEH61OZhc"} +{"type":"response.output_text.delta","sequence_number":296,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"8","logprobs":[],"obfuscation":"IUJJnpfdkyLeccq"} +{"type":"response.output_text.delta","sequence_number":297,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"OpfU3QYrayPiMOm"} +{"type":"response.output_text.delta","sequence_number":298,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"AliFIu1VX7Dz74r"} +{"type":"response.output_text.delta","sequence_number":299,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"7","logprobs":[],"obfuscation":"mPJ8kR8OSPDzPQl"} +{"type":"response.output_text.delta","sequence_number":300,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"b7M6KuSQYsnFVZg"} +{"type":"response.output_text.delta","sequence_number":301,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"JTgFDVXH3kWQcYx"} +{"type":"response.output_text.delta","sequence_number":302,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"10","logprobs":[],"obfuscation":"KxVELZQq9yCVUQ"} +{"type":"response.output_text.delta","sequence_number":303,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"1gA2ZtMvi7G8mFZ"} +{"type":"response.output_text.delta","sequence_number":304,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"CuStWf7xXL0G00v"} +{"type":"response.output_text.delta","sequence_number":305,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"8","logprobs":[],"obfuscation":"OAHgvv8Cngs8xFn"} +{"type":"response.output_text.delta","sequence_number":306,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"alKHq8tUmAFUrZu"} +{"type":"response.output_text.delta","sequence_number":307,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"5vAFerkS24LZAOD"} +{"type":"response.output_text.delta","sequence_number":308,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"9","logprobs":[],"obfuscation":"u6pAUP1AFWosM0l"} +{"type":"response.output_text.delta","sequence_number":309,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"ruCFwr6QtNzHgWh"} +{"type":"response.output_text.delta","sequence_number":310,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"B8uJnFA5fqLzMUn"} +{"type":"response.output_text.delta","sequence_number":311,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"5","logprobs":[],"obfuscation":"IemN0l0cJ3M7p7W"} +{"type":"response.output_text.delta","sequence_number":312,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"cM8qo7LcbhjVnLP"} +{"type":"response.output_text.delta","sequence_number":313,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"I4U0eaDMax4NFVx"} +{"type":"response.output_text.delta","sequence_number":314,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"4","logprobs":[],"obfuscation":"0jDd1xIFZGsym4c"} +{"type":"response.output_text.delta","sequence_number":315,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"SIairBPzlvUVHnV"} +{"type":"response.output_text.delta","sequence_number":316,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"gfD5s5fdJA7jdNa"} +{"type":"response.output_text.delta","sequence_number":317,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"7","logprobs":[],"obfuscation":"6Uehs9yaaYLxqgk"} +{"type":"response.output_text.delta","sequence_number":318,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"\n\n","logprobs":[],"obfuscation":"7T2NHwJTG86sNN"} +{"type":"response.output_text.delta","sequence_number":319,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"Full","logprobs":[],"obfuscation":"5y4T5HBe50r7"} +{"type":"response.output_text.delta","sequence_number":320,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" data","logprobs":[],"obfuscation":"vXpsCx5y3Sp"} +{"type":"response.output_text.delta","sequence_number":321,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"\n","logprobs":[],"obfuscation":"PrQvID5NzVyCJcC"} +{"type":"response.output_text.delta","sequence_number":322,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"-","logprobs":[],"obfuscation":"2GE1CtejTAi96YO"} +{"type":"response.output_text.delta","sequence_number":323,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" You","logprobs":[],"obfuscation":"r3foZ9yVkATc"} +{"type":"response.output_text.delta","sequence_number":324,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" can","logprobs":[],"obfuscation":"fh1PiubrLQeS"} +{"type":"response.output_text.delta","sequence_number":325,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" download","logprobs":[],"obfuscation":"pBopd1w"} +{"type":"response.output_text.delta","sequence_number":326,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" all","logprobs":[],"obfuscation":"aPdfZwfpQuEl"} +{"type":"response.output_text.delta","sequence_number":327,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"xG3frwmAq5zanxi"} +{"type":"response.output_text.delta","sequence_number":328,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"10","logprobs":[],"obfuscation":"85Zhu6ZApSSv49"} +{"type":"response.output_text.delta","sequence_number":329,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"90KtoHbick8dVbm"} +{"type":"response.output_text.delta","sequence_number":330,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"000","logprobs":[],"obfuscation":"MPVfxNDAGjNTL"} +{"type":"response.output_text.delta","sequence_number":331,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" sums","logprobs":[],"obfuscation":"TLHgl1UKQ7G"} +{"type":"response.output_text.delta","sequence_number":332,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" as","logprobs":[],"obfuscation":"pkzFVYXfopfRb"} +{"type":"response.output_text.delta","sequence_number":333,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"kX0QfcY8nY4FQg"} +{"type":"response.output_text.delta","sequence_number":334,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" CSV","logprobs":[],"obfuscation":"1yyQP1VWHMmh"} +{"type":"response.output_text.delta","sequence_number":335,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" file","logprobs":[],"obfuscation":"XVH1wugfb3W"} +{"type":"response.output_text.delta","sequence_number":336,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" here","logprobs":[],"obfuscation":"LYk6z7SShk3"} +{"type":"response.output_text.delta","sequence_number":337,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":":","logprobs":[],"obfuscation":"EHznVM6qV3dUz5q"} +{"type":"response.output_text.delta","sequence_number":338,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" [","logprobs":[],"obfuscation":"yC0E2HbfZJfr58"} +{"type":"response.output_text.delta","sequence_number":339,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"Download","logprobs":[],"obfuscation":"zBVk2U1X"} +{"type":"response.output_text.delta","sequence_number":340,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"YukWgk3NVFTf"} +{"type":"response.output_text.delta","sequence_number":341,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" sums","logprobs":[],"obfuscation":"Ff4UB1pYLEw"} +{"type":"response.output_text.delta","sequence_number":342,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" CSV","logprobs":[],"obfuscation":"7qg90SXOrR64"} +{"type":"response.output_text.delta","sequence_number":343,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"](","logprobs":[],"obfuscation":"uad1fLm2LyJFXp"} +{"type":"response.output_text.delta","sequence_number":344,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"sandbox","logprobs":[],"obfuscation":"Gzvqa3eWs"} +{"type":"response.output_text.delta","sequence_number":345,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":":/","logprobs":[],"obfuscation":"3G1JcCwqSZ3E07"} +{"type":"response.output_text.delta","sequence_number":346,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"mnt","logprobs":[],"obfuscation":"qNM4XBDC5E47U"} +{"type":"response.output_text.delta","sequence_number":347,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"/data","logprobs":[],"obfuscation":"eQPcHBXTp1O"} +{"type":"response.output_text.delta","sequence_number":348,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"/","logprobs":[],"obfuscation":"PRXarZXoQfBHUYr"} +{"type":"response.output_text.delta","sequence_number":349,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"roll","logprobs":[],"obfuscation":"8gyrwnLDVb1u"} +{"type":"response.output_text.delta","sequence_number":350,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"2","logprobs":[],"obfuscation":"AnANPoowjy7CFPM"} +{"type":"response.output_text.delta","sequence_number":351,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"dice","logprobs":[],"obfuscation":"a2J0djksVmXT"} +{"type":"response.output_text.delta","sequence_number":352,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"_s","logprobs":[],"obfuscation":"SNdtEN2TqFvJwn"} +{"type":"response.output_text.delta","sequence_number":353,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"ums","logprobs":[],"obfuscation":"cC7vj3HQvDsKT"} +{"type":"response.output_text.delta","sequence_number":354,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"_","logprobs":[],"obfuscation":"aqwtHC8bIEmSlaH"} +{"type":"response.output_text.delta","sequence_number":355,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"100","logprobs":[],"obfuscation":"Zl5mTHeqBQC7f"} +{"type":"response.output_text.delta","sequence_number":356,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"00","logprobs":[],"obfuscation":"wzcbOFqdd6Bq6l"} +{"type":"response.output_text.delta","sequence_number":357,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":".csv","logprobs":[],"obfuscation":"nFiPj3YSH1wI"} +{"type":"response.output_text.delta","sequence_number":358,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":")\n\n","logprobs":[],"obfuscation":"c63JCElW1sxgE"} +{"type":"response.output_text.delta","sequence_number":359,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"If","logprobs":[],"obfuscation":"hmuiqROMBAtN3v"} +{"type":"response.output_text.delta","sequence_number":360,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" you","logprobs":[],"obfuscation":"LGTlBp5C2814"} +{"type":"response.output_text.delta","sequence_number":361,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"’d","logprobs":[],"obfuscation":"MWryEKNYHOb89i"} +{"type":"response.output_text.delta","sequence_number":362,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" like","logprobs":[],"obfuscation":"6MF1XQrHKG4"} +{"type":"response.output_text.delta","sequence_number":363,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"a9wF93x9t4wgffs"} +{"type":"response.output_text.delta","sequence_number":364,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" I","logprobs":[],"obfuscation":"0z50QafGlya07v"} +{"type":"response.output_text.delta","sequence_number":365,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" can","logprobs":[],"obfuscation":"1PLHvN4if6gl"} +{"type":"response.output_text.delta","sequence_number":366,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" also","logprobs":[],"obfuscation":"acmi80RliNw"} +{"type":"response.output_text.delta","sequence_number":367,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" provide","logprobs":[],"obfuscation":"L8up9l6A"} +{"type":"response.output_text.delta","sequence_number":368,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"rGTbPB0pm5uufW"} +{"type":"response.output_text.delta","sequence_number":369,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" frequency","logprobs":[],"obfuscation":"K8fKda"} +{"type":"response.output_text.delta","sequence_number":370,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" distribution","logprobs":[],"obfuscation":"aqu"} +{"type":"response.output_text.delta","sequence_number":371,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"QRmWuvGSe0XSma2"} +{"type":"response.output_text.delta","sequence_number":372,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" histogram","logprobs":[],"obfuscation":"y17GhG"} +{"type":"response.output_text.delta","sequence_number":373,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"N5afzRDEPIOge85"} +{"type":"response.output_text.delta","sequence_number":374,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" or","logprobs":[],"obfuscation":"4o1w6HFm362pQ"} +{"type":"response.output_text.delta","sequence_number":375,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" export","logprobs":[],"obfuscation":"X4Puseb6P"} +{"type":"response.output_text.delta","sequence_number":376,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"zdlHqrMrs2x2"} +{"type":"response.output_text.delta","sequence_number":377,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" data","logprobs":[],"obfuscation":"Do99yawuoct"} +{"type":"response.output_text.delta","sequence_number":378,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" in","logprobs":[],"obfuscation":"HWSZIK8AMkR9k"} +{"type":"response.output_text.delta","sequence_number":379,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" another","logprobs":[],"obfuscation":"eOrsXpaC"} +{"type":"response.output_text.delta","sequence_number":380,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" format","logprobs":[],"obfuscation":"KcsARIA8Q"} +{"type":"response.output_text.delta","sequence_number":381,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" (","logprobs":[],"obfuscation":"JDIAi2tJwZYfxH"} +{"type":"response.output_text.delta","sequence_number":382,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":"JSON","logprobs":[],"obfuscation":"FiK1wrEbetDq"} +{"type":"response.output_text.delta","sequence_number":383,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"Fdy5HG1UlwZ7vrh"} +{"type":"response.output_text.delta","sequence_number":384,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" Excel","logprobs":[],"obfuscation":"DZltKnNygj"} +{"type":"response.output_text.delta","sequence_number":385,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":",","logprobs":[],"obfuscation":"YYKStBfj7zeBNm6"} +{"type":"response.output_text.delta","sequence_number":386,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":" etc","logprobs":[],"obfuscation":"4NZz1Y5LYAJx"} +{"type":"response.output_text.delta","sequence_number":387,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"delta":".).","logprobs":[],"obfuscation":"9cCnvOYtIf9pW"} +{"type":"response.output_text.annotation.added","sequence_number":388,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"annotation_index":0,"annotation":{"type":"container_file_citation","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","end_index":465,"file_id":"cfile_68c2e7084ab48191a67824aa1f4c90f1","filename":"roll2dice_sums_10000.csv","start_index":423}} +{"type":"response.output_text.done","sequence_number":389,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"text":"Here’s a simulation of rolling two fair six-sided dice 10,000 times. Each trial sums the two dice.\n\nResults\n- Total sum of all 10,000 trials: 69,868\n- Average sum per trial: 6.9868\n- Minimum sum observed: 2\n- Maximum sum observed: 12\n- Sample of the first 20 trial sums: 6, 7, 2, 5, 5, 11, 4, 8, 10, 7, 5, 8, 8, 7, 10, 8, 9, 5, 4, 7\n\nFull data\n- You can download all 10,000 sums as a CSV file here: [Download the sums CSV](sandbox:/mnt/data/roll2dice_sums_10000.csv)\n\nIf you’d like, I can also provide a frequency distribution, histogram, or export the data in another format (JSON, Excel, etc.).","logprobs":[]} +{"type":"response.content_part.done","sequence_number":390,"item_id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","output_index":7,"content_index":0,"part":{"type":"output_text","annotations":[{"type":"container_file_citation","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","end_index":465,"file_id":"cfile_68c2e7084ab48191a67824aa1f4c90f1","filename":"roll2dice_sums_10000.csv","start_index":423}],"logprobs":[],"text":"Here’s a simulation of rolling two fair six-sided dice 10,000 times. Each trial sums the two dice.\n\nResults\n- Total sum of all 10,000 trials: 69,868\n- Average sum per trial: 6.9868\n- Minimum sum observed: 2\n- Maximum sum observed: 12\n- Sample of the first 20 trial sums: 6, 7, 2, 5, 5, 11, 4, 8, 10, 7, 5, 8, 8, 7, 10, 8, 9, 5, 4, 7\n\nFull data\n- You can download all 10,000 sums as a CSV file here: [Download the sums CSV](sandbox:/mnt/data/roll2dice_sums_10000.csv)\n\nIf you’d like, I can also provide a frequency distribution, histogram, or export the data in another format (JSON, Excel, etc.)."}} +{"type":"response.output_item.done","sequence_number":391,"output_index":7,"item":{"id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","type":"message","status":"completed","content":[{"type":"output_text","annotations":[{"type":"container_file_citation","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","end_index":465,"file_id":"cfile_68c2e7084ab48191a67824aa1f4c90f1","filename":"roll2dice_sums_10000.csv","start_index":423}],"logprobs":[],"text":"Here’s a simulation of rolling two fair six-sided dice 10,000 times. Each trial sums the two dice.\n\nResults\n- Total sum of all 10,000 trials: 69,868\n- Average sum per trial: 6.9868\n- Minimum sum observed: 2\n- Maximum sum observed: 12\n- Sample of the first 20 trial sums: 6, 7, 2, 5, 5, 11, 4, 8, 10, 7, 5, 8, 8, 7, 10, 8, 9, 5, 4, 7\n\nFull data\n- You can download all 10,000 sums as a CSV file here: [Download the sums CSV](sandbox:/mnt/data/roll2dice_sums_10000.csv)\n\nIf you’d like, I can also provide a frequency distribution, histogram, or export the data in another format (JSON, Excel, etc.)."}],"role":"assistant"}} +{"type":"response.completed","sequence_number":392,"response":{"id":"resp_68c2e6efa238819383d5f52a2c2a3baa02d3a5742c7ddae9","object":"response","created_at":1757603567,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-nano-2025-08-07","output":[{"id":"rs_68c2e6f40ba48193a1c27abf31130e7e02d3a5742c7ddae9","type":"reasoning","summary":[]},{"id":"ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9","type":"code_interpreter_call","status":"completed","code":"import random, math\nN=10000\nsums=[]\ns=0\nfor _ in range(N):\n a=random.randint(1,6)\n b=random.randint(1,6)\n sm=a+b\n sums.append(sm)\n s+=sm\nmin(sums), max(sums), sum(sums), sum(sums)/N\n","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","outputs":[{"type":"logs","logs":"(2, 12, 69868, 6.9868)"}]},{"id":"rs_68c2e6fcb52881938f21c45741216ac002d3a5742c7ddae9","type":"reasoning","summary":[]},{"id":"ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9","type":"code_interpreter_call","status":"completed","code":"import csv, pathlib\npath = pathlib.Path('/mnt/data/roll2dice_sums_10000.csv')\nwith open(path, 'w', newline='') as f:\n writer = csv.writer(f)\n writer.writerow(['sum'])\n for val in sums:\n writer.writerow([val])\npath, path.exists(), len(sums)\n","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","outputs":[{"type":"logs","logs":"(PosixPath('/mnt/data/roll2dice_sums_10000.csv'), True, 10000)"}]},{"id":"rs_68c2e6fff1808193a78d43410a1feb4802d3a5742c7ddae9","type":"reasoning","summary":[]},{"id":"ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9","type":"code_interpreter_call","status":"completed","code":"sums[:20]\n","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","outputs":[{"type":"logs","logs":"[6, 7, 2, 5, 5, 11, 4, 8, 10, 7, 5, 8, 8, 7, 10, 8, 9, 5, 4, 7]"}]},{"id":"rs_68c2e703d114819383c5da260649c7ce02d3a5742c7ddae9","type":"reasoning","summary":[]},{"id":"msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9","type":"message","status":"completed","content":[{"type":"output_text","annotations":[{"type":"container_file_citation","container_id":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9","end_index":465,"file_id":"cfile_68c2e7084ab48191a67824aa1f4c90f1","filename":"roll2dice_sums_10000.csv","start_index":423}],"logprobs":[],"text":"Here’s a simulation of rolling two fair six-sided dice 10,000 times. Each trial sums the two dice.\n\nResults\n- Total sum of all 10,000 trials: 69,868\n- Average sum per trial: 6.9868\n- Minimum sum observed: 2\n- Maximum sum observed: 12\n- Sample of the first 20 trial sums: 6, 7, 2, 5, 5, 11, 4, 8, 10, 7, 5, 8, 8, 7, 10, 8, 9, 5, 4, 7\n\nFull data\n- You can download all 10,000 sums as a CSV file here: [Download the sums CSV](sandbox:/mnt/data/roll2dice_sums_10000.csv)\n\nIf you’d like, I can also provide a frequency distribution, histogram, or export the data in another format (JSON, Excel, etc.)."}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"code_interpreter","container":{"type":"auto"}}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":{"input_tokens":6047,"input_tokens_details":{"cached_tokens":2944},"output_tokens":1623,"output_tokens_details":{"reasoning_tokens":1408},"total_tokens":7670},"user":null,"metadata":{}}} \ No newline at end of file diff --git a/packages/openai/src/responses/__fixtures__/openai-code-interpreter-tool.1.json b/packages/openai/src/responses/__fixtures__/openai-code-interpreter-tool.1.json new file mode 100644 index 000000000000..b495cfb5e14e --- /dev/null +++ b/packages/openai/src/responses/__fixtures__/openai-code-interpreter-tool.1.json @@ -0,0 +1,112 @@ +{ + "id": "resp_68c2e2c6f7208190b9a439ac98147eb40b24aae9c6c01e4f", + "object": "response", + "created_at": 1757602503, + "status": "completed", + "background": false, + "error": null, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5-nano-2025-08-07", + "output": [ + { + "id": "rs_68c2e2cbc0a08190bc754d734af0940f0b24aae9c6c01e4f", + "type": "reasoning", + "summary": [] + }, + { + "id": "ci_68c2e2cf522c81908f3e2c1bccd1493b0b24aae9c6c01e4f", + "type": "code_interpreter_call", + "status": "completed", + "code": "import random\nrandom.seed() # system time\nn=10000\nsums=[(random.randint(1,6)+random.randint(1,6)) for _ in range(n)]\ntotal=sum(sums)\nmean=total/n\nfrom collections import Counter\ncounts=Counter(sums)\ncounts_sorted=[(sum_val, counts[sum_val]) for sum_val in range(2,13)]\ntotal, mean, counts_sorted[:5], counts_sorted[-5:]", + "container_id": "cntr_68c2e2caf50c8193b4069276f4c75ef301e63bd5fd6a4d4d", + "outputs": [ + { + "type": "logs", + "logs": "(70141,\n 7.0141,\n [(2, 269), (3, 511), (4, 865), (5, 1130), (6, 1353)],\n [(8, 1387), (9, 1110), (10, 828), (11, 538), (12, 299)])" + } + ] + }, + { + "id": "rs_68c2e2d67f60819097167827b0e29b4f0b24aae9c6c01e4f", + "type": "reasoning", + "summary": [] + }, + { + "id": "ci_68c2e2d75fe08190b27c6e44213143010b24aae9c6c01e4f", + "type": "code_interpreter_call", + "status": "completed", + "code": "counts_sorted_full = [(s,c) for s,c in sorted(counts.items())]\ncounts_sorted_full", + "container_id": "cntr_68c2e2caf50c8193b4069276f4c75ef301e63bd5fd6a4d4d", + "outputs": [ + { + "type": "logs", + "logs": "[(2, 269),\n (3, 511),\n (4, 865),\n (5, 1130),\n (6, 1353),\n (7, 1710),\n (8, 1387),\n (9, 1110),\n (10, 828),\n (11, 538),\n (12, 299)]" + } + ] + }, + { + "id": "rs_68c2e2dab6508190987f0d3db143b0580b24aae9c6c01e4f", + "type": "reasoning", + "summary": [] + }, + { + "id": "msg_68c2e2e513c88190a72cefb37140d19a0b24aae9c6c01e4f", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "Here’s a quick result from simulating 10,000 rolls of two fair six-sided dice (sum per trial, then total across all trials):\n\n- Total sum of all 10,000 trial sums: 70141\n- Average sum per trial: 7.0141\n\nDistribution of the per-trial sums (2–12):\n- 2: 269 (2.69%)\n- 3: 511 (5.11%)\n- 4: 865 (8.65%)\n- 5: 1130 (11.30%)\n- 6: 1353 (13.53%)\n- 7: 1710 (17.10%)\n- 8: 1387 (13.87%)\n- 9: 1110 (11.10%)\n- 10: 828 (8.28%)\n- 11: 538 (5.38%)\n- 12: 299 (2.99%)\n\nNotes:\n- The total is around 7,0000 since the expected sum per trial is 7, so 10,000 trials ≈ 70000. Your exact total will vary with each run unless you fix a random seed.\n- If you’d like, I can provide the per-trial sums as a CSV file or share a reproducible run with a fixed seed." + } + ], + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "previous_response_id": null, + "prompt_cache_key": null, + "reasoning": { + "effort": "medium", + "summary": null + }, + "safety_identifier": null, + "service_tier": "default", + "store": true, + "temperature": 1, + "text": { + "format": { + "type": "text" + }, + "verbosity": "medium" + }, + "tool_choice": "auto", + "tools": [ + { + "type": "code_interpreter", + "container": { + "type": "auto" + } + } + ], + "top_logprobs": 0, + "top_p": 1, + "truncation": "disabled", + "usage": { + "input_tokens": 4071, + "input_tokens_details": { + "cached_tokens": 0 + }, + "output_tokens": 2456, + "output_tokens_details": { + "reasoning_tokens": 2176 + }, + "total_tokens": 6527 + }, + "user": null, + "metadata": {} +} diff --git a/packages/openai/src/responses/__fixtures__/openai-file-search-tool.1.chunks.txt b/packages/openai/src/responses/__fixtures__/openai-file-search-tool.1.chunks.txt new file mode 100644 index 000000000000..914a434eb071 --- /dev/null +++ b/packages/openai/src/responses/__fixtures__/openai-file-search-tool.1.chunks.txt @@ -0,0 +1,94 @@ +{"type":"response.created","sequence_number":0,"response":{"id":"resp_0459517ad68504ad0068cabfba22b88192836339640e9a765a","object":"response","created_at":1758117818,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-mini-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"file_search","filters":null,"max_num_results":20,"ranking_options":{"ranker":"auto","score_threshold":0},"vector_store_ids":["vs_68caad8bd5d88191ab766cf043d89a18"]}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_0459517ad68504ad0068cabfba22b88192836339640e9a765a","object":"response","created_at":1758117818,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-mini-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"file_search","filters":null,"max_num_results":20,"ranking_options":{"ranker":"auto","score_threshold":0},"vector_store_ids":["vs_68caad8bd5d88191ab766cf043d89a18"]}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"rs_0459517ad68504ad0068cabfba951881929654a05214361b35","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":3,"output_index":0,"item":{"id":"rs_0459517ad68504ad0068cabfba951881929654a05214361b35","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":4,"output_index":1,"item":{"id":"fs_0459517ad68504ad0068cabfbd76888192a5dc4475fadabf8a","type":"file_search_call","status":"in_progress","queries":[],"results":null}} +{"type":"response.file_search_call.in_progress","sequence_number":5,"output_index":1,"item_id":"fs_0459517ad68504ad0068cabfbd76888192a5dc4475fadabf8a"} +{"type":"response.file_search_call.searching","sequence_number":6,"output_index":1,"item_id":"fs_0459517ad68504ad0068cabfbd76888192a5dc4475fadabf8a"} +{"type":"response.file_search_call.completed","sequence_number":7,"output_index":1,"item_id":"fs_0459517ad68504ad0068cabfbd76888192a5dc4475fadabf8a"} +{"type":"response.output_item.done","sequence_number":8,"output_index":1,"item":{"id":"fs_0459517ad68504ad0068cabfbd76888192a5dc4475fadabf8a","type":"file_search_call","status":"completed","queries":["What is an embedding model according to this document?","What is an embedding model defined as in the document?","definition of embedding model"],"results":null}} +{"type":"response.output_item.added","sequence_number":9,"output_index":2,"item":{"id":"rs_0459517ad68504ad0068cabfbf337881929cf5266be7a008a9","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":10,"output_index":2,"item":{"id":"rs_0459517ad68504ad0068cabfbf337881929cf5266be7a008a9","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":11,"output_index":3,"item":{"id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","type":"message","status":"in_progress","content":[],"role":"assistant"}} +{"type":"response.content_part.added","sequence_number":12,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}} +{"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":"According","logprobs":[],"obfuscation":"liJu2gE"} +{"type":"response.output_text.delta","sequence_number":14,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"5HNu0x2oBP4DS"} +{"type":"response.output_text.delta","sequence_number":15,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"oMCnjSTGpdPE"} +{"type":"response.output_text.delta","sequence_number":16,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" document","logprobs":[],"obfuscation":"NiZmPdD"} +{"type":"response.output_text.delta","sequence_number":17,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":",","logprobs":[],"obfuscation":"vlgD14WDda5lNTa"} +{"type":"response.output_text.delta","sequence_number":18,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" an","logprobs":[],"obfuscation":"ubOMhz6bqdOfs"} +{"type":"response.output_text.delta","sequence_number":19,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" embedding","logprobs":[],"obfuscation":"6OHQBe"} +{"type":"response.output_text.delta","sequence_number":20,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" model","logprobs":[],"obfuscation":"wE2FfjpXAl"} +{"type":"response.output_text.delta","sequence_number":21,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" converts","logprobs":[],"obfuscation":"cdIHT2o"} +{"type":"response.output_text.delta","sequence_number":22,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" complex","logprobs":[],"obfuscation":"0LIh8ijL"} +{"type":"response.output_text.delta","sequence_number":23,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" data","logprobs":[],"obfuscation":"XDDB8MMj7dQ"} +{"type":"response.output_text.delta","sequence_number":24,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" (","logprobs":[],"obfuscation":"xrOoDo1pxe8Sih"} +{"type":"response.output_text.delta","sequence_number":25,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":"e","logprobs":[],"obfuscation":"YrjNY3GNWvBvvtA"} +{"type":"response.output_text.delta","sequence_number":26,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":".g","logprobs":[],"obfuscation":"FfWwJ3WQRyPMOI"} +{"type":"response.output_text.delta","sequence_number":27,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":".,","logprobs":[],"obfuscation":"52FV9X2Y5LfzVW"} +{"type":"response.output_text.delta","sequence_number":28,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" words","logprobs":[],"obfuscation":"Qu3QkUBEwy"} +{"type":"response.output_text.delta","sequence_number":29,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" or","logprobs":[],"obfuscation":"Lb2zYunjo6tJp"} +{"type":"response.output_text.delta","sequence_number":30,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" images","logprobs":[],"obfuscation":"T0I6C2Ji0"} +{"type":"response.output_text.delta","sequence_number":31,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":")","logprobs":[],"obfuscation":"hLXFmqQJOpK7lmV"} +{"type":"response.output_text.delta","sequence_number":32,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" into","logprobs":[],"obfuscation":"shSSEWk9ZhS"} +{"type":"response.output_text.delta","sequence_number":33,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"aBFr0xTdklDdiA"} +{"type":"response.output_text.delta","sequence_number":34,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" dense","logprobs":[],"obfuscation":"YfRRLmWPET"} +{"type":"response.output_text.delta","sequence_number":35,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" vector","logprobs":[],"obfuscation":"FvaquGcUw"} +{"type":"response.output_text.delta","sequence_number":36,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" —","logprobs":[],"obfuscation":"8PuGQrs29oeDLj"} +{"type":"response.output_text.delta","sequence_number":37,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"gJpFvi1LcxcOtE"} +{"type":"response.output_text.delta","sequence_number":38,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" list","logprobs":[],"obfuscation":"xwPT69uDxS2"} +{"type":"response.output_text.delta","sequence_number":39,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"vEKNu3upEN6T6"} +{"type":"response.output_text.delta","sequence_number":40,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" numbers","logprobs":[],"obfuscation":"YY7mOFEn"} +{"type":"response.output_text.delta","sequence_number":41,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" —","logprobs":[],"obfuscation":"4UBtB3i3LbiWrJ"} +{"type":"response.output_text.delta","sequence_number":42,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" called","logprobs":[],"obfuscation":"cnjAeV2A0"} +{"type":"response.output_text.delta","sequence_number":43,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" an","logprobs":[],"obfuscation":"COksnLu2vES9P"} +{"type":"response.output_text.delta","sequence_number":44,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" embedding","logprobs":[],"obfuscation":"w96Cn5"} +{"type":"response.output_text.delta","sequence_number":45,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"1UseJlZiemBSPAg"} +{"type":"response.output_text.annotation.added","sequence_number":46,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"annotation_index":0,"annotation":{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":154}} +{"type":"response.output_text.delta","sequence_number":47,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":".","logprobs":[],"obfuscation":"8aFRlmffIqtlfCt"} +{"type":"response.output_text.delta","sequence_number":48,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" Unlike","logprobs":[],"obfuscation":"xUqTw4yKa"} +{"type":"response.output_text.delta","sequence_number":49,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" gener","logprobs":[],"obfuscation":"NsFTmfGbff"} +{"type":"response.output_text.delta","sequence_number":50,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":"ative","logprobs":[],"obfuscation":"qBiTdJa2gyP"} +{"type":"response.output_text.delta","sequence_number":51,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" models","logprobs":[],"obfuscation":"PSKt3fxkM"} +{"type":"response.output_text.delta","sequence_number":52,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":",","logprobs":[],"obfuscation":"8e8Za1VVyteB4ds"} +{"type":"response.output_text.delta","sequence_number":53,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" embedding","logprobs":[],"obfuscation":"Gs3cTl"} +{"type":"response.output_text.delta","sequence_number":54,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" models","logprobs":[],"obfuscation":"xrC7jkFgt"} +{"type":"response.output_text.delta","sequence_number":55,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" do","logprobs":[],"obfuscation":"R7RQOJ17j1cpc"} +{"type":"response.output_text.delta","sequence_number":56,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" not","logprobs":[],"obfuscation":"HLUy8me4lqhJ"} +{"type":"response.output_text.delta","sequence_number":57,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" generate","logprobs":[],"obfuscation":"nVQusCL"} +{"type":"response.output_text.delta","sequence_number":58,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" new","logprobs":[],"obfuscation":"8p6C49tSUygH"} +{"type":"response.output_text.delta","sequence_number":59,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" text","logprobs":[],"obfuscation":"NAiFjEoDpi3"} +{"type":"response.output_text.delta","sequence_number":60,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" or","logprobs":[],"obfuscation":"exp5SVQ1bWj35"} +{"type":"response.output_text.delta","sequence_number":61,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" data","logprobs":[],"obfuscation":"mpWYgcEeCJG"} +{"type":"response.output_text.delta","sequence_number":62,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":";","logprobs":[],"obfuscation":"ugjrVmPsBQ0sBVM"} +{"type":"response.output_text.delta","sequence_number":63,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" instead","logprobs":[],"obfuscation":"5TuCbJBY"} +{"type":"response.output_text.delta","sequence_number":64,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" they","logprobs":[],"obfuscation":"7GfAc92ZRM0"} +{"type":"response.output_text.delta","sequence_number":65,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" produce","logprobs":[],"obfuscation":"LW1cSi08"} +{"type":"response.output_text.delta","sequence_number":66,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" vector","logprobs":[],"obfuscation":"vQvkU1Q0g"} +{"type":"response.output_text.delta","sequence_number":67,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" representations","logprobs":[],"obfuscation":""} +{"type":"response.output_text.delta","sequence_number":68,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" that","logprobs":[],"obfuscation":"H6ufQbaSbhr"} +{"type":"response.output_text.delta","sequence_number":69,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" capture","logprobs":[],"obfuscation":"G9rJM2Kb"} +{"type":"response.output_text.delta","sequence_number":70,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" semantic","logprobs":[],"obfuscation":"0C6xQkm"} +{"type":"response.output_text.delta","sequence_number":71,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"gob8I5gbSO5U"} +{"type":"response.output_text.delta","sequence_number":72,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" synt","logprobs":[],"obfuscation":"U3SbSG7fMxc"} +{"type":"response.output_text.delta","sequence_number":73,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":"actic","logprobs":[],"obfuscation":"W4sXaF0Eyf7"} +{"type":"response.output_text.delta","sequence_number":74,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" relationships","logprobs":[],"obfuscation":"1g"} +{"type":"response.output_text.delta","sequence_number":75,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"T8VvgtUNIhwm"} +{"type":"response.output_text.delta","sequence_number":76,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" can","logprobs":[],"obfuscation":"YlEDrBvI3rGk"} +{"type":"response.output_text.delta","sequence_number":77,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" be","logprobs":[],"obfuscation":"d2YAlk8o41VBn"} +{"type":"response.output_text.delta","sequence_number":78,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" used","logprobs":[],"obfuscation":"h4uUBaMut0Y"} +{"type":"response.output_text.delta","sequence_number":79,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" as","logprobs":[],"obfuscation":"Cu4PJZ54whk2T"} +{"type":"response.output_text.delta","sequence_number":80,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" input","logprobs":[],"obfuscation":"D2Py3Lykxm"} +{"type":"response.output_text.delta","sequence_number":81,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" for","logprobs":[],"obfuscation":"db4mrk4WThq1"} +{"type":"response.output_text.delta","sequence_number":82,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" other","logprobs":[],"obfuscation":"Yq7VkDPJKu"} +{"type":"response.output_text.delta","sequence_number":83,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" models","logprobs":[],"obfuscation":"yhKaHEHFm"} +{"type":"response.output_text.delta","sequence_number":84,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" or","logprobs":[],"obfuscation":"JXNpZ1gnAGSeJ"} +{"type":"response.output_text.delta","sequence_number":85,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" NLP","logprobs":[],"obfuscation":"XH6YlZrmr3mA"} +{"type":"response.output_text.delta","sequence_number":86,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" tasks","logprobs":[],"obfuscation":"Jotz6jyyyq"} +{"type":"response.output_text.delta","sequence_number":87,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"PbwW8c892lezp7M"} +{"type":"response.output_text.annotation.added","sequence_number":88,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"annotation_index":1,"annotation":{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":382}} +{"type":"response.output_text.delta","sequence_number":89,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"delta":".","logprobs":[],"obfuscation":"brJFUhKp1ov7xs6"} +{"type":"response.output_text.done","sequence_number":90,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"text":"According to the document, an embedding model converts complex data (e.g., words or images) into a dense vector — a list of numbers — called an embedding . Unlike generative models, embedding models do not generate new text or data; instead they produce vector representations that capture semantic and syntactic relationships and can be used as input for other models or NLP tasks .","logprobs":[]} +{"type":"response.content_part.done","sequence_number":91,"item_id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","output_index":3,"content_index":0,"part":{"type":"output_text","annotations":[{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":154},{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":382}],"logprobs":[],"text":"According to the document, an embedding model converts complex data (e.g., words or images) into a dense vector — a list of numbers — called an embedding . Unlike generative models, embedding models do not generate new text or data; instead they produce vector representations that capture semantic and syntactic relationships and can be used as input for other models or NLP tasks ."}} +{"type":"response.output_item.done","sequence_number":92,"output_index":3,"item":{"id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","type":"message","status":"completed","content":[{"type":"output_text","annotations":[{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":154},{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":382}],"logprobs":[],"text":"According to the document, an embedding model converts complex data (e.g., words or images) into a dense vector — a list of numbers — called an embedding . Unlike generative models, embedding models do not generate new text or data; instead they produce vector representations that capture semantic and syntactic relationships and can be used as input for other models or NLP tasks ."}],"role":"assistant"}} +{"type":"response.completed","sequence_number":93,"response":{"id":"resp_0459517ad68504ad0068cabfba22b88192836339640e9a765a","object":"response","created_at":1758117818,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-mini-2025-08-07","output":[{"id":"rs_0459517ad68504ad0068cabfba951881929654a05214361b35","type":"reasoning","summary":[]},{"id":"fs_0459517ad68504ad0068cabfbd76888192a5dc4475fadabf8a","type":"file_search_call","status":"completed","queries":["What is an embedding model according to this document?","What is an embedding model defined as in the document?","definition of embedding model"],"results":null},{"id":"rs_0459517ad68504ad0068cabfbf337881929cf5266be7a008a9","type":"reasoning","summary":[]},{"id":"msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1","type":"message","status":"completed","content":[{"type":"output_text","annotations":[{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":154},{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":382}],"logprobs":[],"text":"According to the document, an embedding model converts complex data (e.g., words or images) into a dense vector — a list of numbers — called an embedding . Unlike generative models, embedding models do not generate new text or data; instead they produce vector representations that capture semantic and syntactic relationships and can be used as input for other models or NLP tasks ."}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"file_search","filters":null,"max_num_results":20,"ranking_options":{"ranker":"auto","score_threshold":0},"vector_store_ids":["vs_68caad8bd5d88191ab766cf043d89a18"]}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":{"input_tokens":3737,"input_tokens_details":{"cached_tokens":2304},"output_tokens":621,"output_tokens_details":{"reasoning_tokens":512},"total_tokens":4358},"user":null,"metadata":{}}} \ No newline at end of file diff --git a/packages/openai/src/responses/__fixtures__/openai-file-search-tool.1.json b/packages/openai/src/responses/__fixtures__/openai-file-search-tool.1.json new file mode 100644 index 000000000000..26d4b7addb1e --- /dev/null +++ b/packages/openai/src/responses/__fixtures__/openai-file-search-tool.1.json @@ -0,0 +1,89 @@ +{ + "id": "resp_0a098396a8feca410068caae39e7648196b346e99fa8ec494c", + "object": "response", + "created_at": 1758113338, + "status": "completed", + "background": false, + "error": null, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5-mini-2025-08-07", + "output": [ + { + "id": "rs_0a098396a8feca410068caae3b47208196957fe59419daad70", + "type": "reasoning", + "summary": [] + }, + { + "id": "fs_0a098396a8feca410068caae3cab5c8196a54fd00498464e62", + "type": "file_search_call", + "status": "completed", + "queries": [ + "What is an embedding model according to this document?", + "What is an embedding model?", + "definition of embedding model in the document", + "embedding model description" + ], + "results": null + }, + { + "id": "rs_0a098396a8feca410068caae3e21a081968e7ac588401c4a6a", + "type": "reasoning", + "summary": [] + }, + { + "id": "msg_0a098396a8feca410068caae457c508196b2fcd079d1d3ec74", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [ + { + "type": "file_citation", + "file_id": "file-Ebzhf8H4DPGPr9pUhr7n7v", + "filename": "ai.pdf", + "index": 438 + } + ], + "logprobs": [], + "text": "According to the document, an embedding model is used to convert complex data (like words or images) into a dense vector (a list of numbers) representation called an embedding, which captures semantic and syntactic relationships. Unlike generative models, embedding models do not generate new text or data; instead, they provide these vector representations to be used as input for other models or other natural language processing tasks ." + } + ], + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "previous_response_id": null, + "prompt_cache_key": null, + "reasoning": { "effort": "medium", "summary": null }, + "safety_identifier": null, + "service_tier": "default", + "store": true, + "temperature": 1, + "text": { "format": { "type": "text" }, "verbosity": "medium" }, + "tool_choice": "auto", + "tools": [ + { + "type": "file_search", + "filters": null, + "max_num_results": 20, + "ranking_options": { "ranker": "auto", "score_threshold": 0 }, + "vector_store_ids": ["vs_68caad8bd5d88191ab766cf043d89a18"] + } + ], + "top_logprobs": 0, + "top_p": 1, + "truncation": "disabled", + "usage": { + "input_tokens": 3700, + "input_tokens_details": { "cached_tokens": 2560 }, + "output_tokens": 741, + "output_tokens_details": { "reasoning_tokens": 640 }, + "total_tokens": 4441 + }, + "user": null, + "metadata": {} +} diff --git a/packages/openai/src/responses/__fixtures__/openai-file-search-tool.2.chunks.txt b/packages/openai/src/responses/__fixtures__/openai-file-search-tool.2.chunks.txt new file mode 100644 index 000000000000..0d5c1ab4f3c4 --- /dev/null +++ b/packages/openai/src/responses/__fixtures__/openai-file-search-tool.2.chunks.txt @@ -0,0 +1,93 @@ +{"type":"response.created","sequence_number":0,"response":{"id":"resp_06456cb9918b63780068cacd710b0881a1b00b5fca56e7100b","object":"response","created_at":1758121329,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-mini-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"file_search","filters":null,"max_num_results":20,"ranking_options":{"ranker":"auto","score_threshold":0},"vector_store_ids":["vs_68caad8bd5d88191ab766cf043d89a18"]}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_06456cb9918b63780068cacd710b0881a1b00b5fca56e7100b","object":"response","created_at":1758121329,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-mini-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"file_search","filters":null,"max_num_results":20,"ranking_options":{"ranker":"auto","score_threshold":0},"vector_store_ids":["vs_68caad8bd5d88191ab766cf043d89a18"]}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"rs_06456cb9918b63780068cacd717c3481a1b8c7094da5770b41","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":3,"output_index":0,"item":{"id":"rs_06456cb9918b63780068cacd717c3481a1b8c7094da5770b41","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":4,"output_index":1,"item":{"id":"fs_06456cb9918b63780068cacd74a1dc81a1bf68dd57f140b4b6","type":"file_search_call","status":"in_progress","queries":[],"results":null}} +{"type":"response.file_search_call.in_progress","sequence_number":5,"output_index":1,"item_id":"fs_06456cb9918b63780068cacd74a1dc81a1bf68dd57f140b4b6"} +{"type":"response.file_search_call.searching","sequence_number":6,"output_index":1,"item_id":"fs_06456cb9918b63780068cacd74a1dc81a1bf68dd57f140b4b6"} +{"type":"response.file_search_call.completed","sequence_number":7,"output_index":1,"item_id":"fs_06456cb9918b63780068cacd74a1dc81a1bf68dd57f140b4b6"} +{"type":"response.output_item.done","sequence_number":8,"output_index":1,"item":{"id":"fs_06456cb9918b63780068cacd74a1dc81a1bf68dd57f140b4b6","type":"file_search_call","status":"completed","queries":["What is an embedding model according to this document?","What is an embedding model definition in this document?","How does the document define an embedding model?"],"results":[{"attributes":{},"file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","score":0.9312,"text":"AI 1\n\nAI\nGenerative artificial intelligence refers to models that predict and generate \nvarious types of outputs (such as text, images, or audio) based on whatʼs \nstatistically likely, pulling from patterns theyʼve learned from their training data. \nFor example:\n\nGiven a photo, a generative model can generate a caption.\n\nGiven an audio file, a generative model can generate a transcription.\n\nGiven a text description, a generative model can generate an image.\n\nA large language model LLM is a subset of generative models focused \nprimarily on text. An LLM takes a sequence of words as input and aims to \npredict the most likely sequence to follow. It assigns probabilities to potential \nnext sequences and then selects one. The model continues to generate \nsequences until it meets a specified stopping criterion.\n\nLLMs learn by training on massive collections of written text, which means they \nwill be better suited to some use cases than others. For example, a model \ntrained on GitHub data would understand the probabilities of sequences in \nsource code particularly well.\n\nHowever, it's crucial to understand LLMs' limitations. When asked about less \nknown or absent information, like the birthday of a personal relative, LLMs \nmight \"hallucinate\" or make up information. It's essential to consider how well-\nrepresented the information you need is in the model.\n\nAn embedding model is used to convert complex data (like words or images) \ninto a dense vector (a list of numbers) representation, known as an embedding. \nUnlike generative models, embedding models do not generate new text or data. \nInstead, they provide representations of semantic and synactic relationships \nbetween entities that can be used as input for other models or other natural \nlanguage processing tasks.\n\nIn the next section, you will learn about the difference between models \nproviders and models, and which ones are available in the AI SDK."}]}} +{"type":"response.output_item.added","sequence_number":9,"output_index":2,"item":{"id":"rs_06456cb9918b63780068cacd7663c481a191dd84333d842728","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":10,"output_index":2,"item":{"id":"rs_06456cb9918b63780068cacd7663c481a191dd84333d842728","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":11,"output_index":3,"item":{"id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","type":"message","status":"in_progress","content":[],"role":"assistant"}} +{"type":"response.content_part.added","sequence_number":12,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}} +{"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":"The","logprobs":[],"obfuscation":"yXJ7d69Qa0Xhg"} +{"type":"response.output_text.delta","sequence_number":14,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" document","logprobs":[],"obfuscation":"uRM0Xte"} +{"type":"response.output_text.delta","sequence_number":15,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" defines","logprobs":[],"obfuscation":"gqfYU8Gk"} +{"type":"response.output_text.delta","sequence_number":16,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" an","logprobs":[],"obfuscation":"sIOtpEg2ePgh9"} +{"type":"response.output_text.delta","sequence_number":17,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" embedding","logprobs":[],"obfuscation":"BL6ayz"} +{"type":"response.output_text.delta","sequence_number":18,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" model","logprobs":[],"obfuscation":"cOZxeAdcof"} +{"type":"response.output_text.delta","sequence_number":19,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" as","logprobs":[],"obfuscation":"33u4lzP2RCmBA"} +{"type":"response.output_text.delta","sequence_number":20,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"tAdbvxKxU9Jt34"} +{"type":"response.output_text.delta","sequence_number":21,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" tool","logprobs":[],"obfuscation":"ToTXHZ3M1lZ"} +{"type":"response.output_text.delta","sequence_number":22,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" that","logprobs":[],"obfuscation":"yO9zzzFiEnB"} +{"type":"response.output_text.delta","sequence_number":23,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" converts","logprobs":[],"obfuscation":"NIS0KqN"} +{"type":"response.output_text.delta","sequence_number":24,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" complex","logprobs":[],"obfuscation":"8eyFBFah"} +{"type":"response.output_text.delta","sequence_number":25,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" data","logprobs":[],"obfuscation":"MXLSAE7Hciw"} +{"type":"response.output_text.delta","sequence_number":26,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" (","logprobs":[],"obfuscation":"KujSuxv3mVdafv"} +{"type":"response.output_text.delta","sequence_number":27,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":"e","logprobs":[],"obfuscation":"WQiFog0AB5WgHEX"} +{"type":"response.output_text.delta","sequence_number":28,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":".g","logprobs":[],"obfuscation":"EcWbFs0sP9xTCK"} +{"type":"response.output_text.delta","sequence_number":29,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":".,","logprobs":[],"obfuscation":"hyYzGk2OvxhNnC"} +{"type":"response.output_text.delta","sequence_number":30,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" words","logprobs":[],"obfuscation":"wMKwLlAkhz"} +{"type":"response.output_text.delta","sequence_number":31,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" or","logprobs":[],"obfuscation":"YCetLlQLYpljF"} +{"type":"response.output_text.delta","sequence_number":32,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" images","logprobs":[],"obfuscation":"iGIypDuiQ"} +{"type":"response.output_text.delta","sequence_number":33,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":")","logprobs":[],"obfuscation":"rlDCo94jSRrQ0Ku"} +{"type":"response.output_text.delta","sequence_number":34,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" into","logprobs":[],"obfuscation":"hqKnAHBodav"} +{"type":"response.output_text.delta","sequence_number":35,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"l7Se5SpBVh2BpH"} +{"type":"response.output_text.delta","sequence_number":36,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" dense","logprobs":[],"obfuscation":"xfttmfQBKD"} +{"type":"response.output_text.delta","sequence_number":37,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" vector","logprobs":[],"obfuscation":"wPnUfyNXf"} +{"type":"response.output_text.delta","sequence_number":38,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" (","logprobs":[],"obfuscation":"5qP6M3c0mgjVkN"} +{"type":"response.output_text.delta","sequence_number":39,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":"a","logprobs":[],"obfuscation":"QaUxc9fnyinuNQ6"} +{"type":"response.output_text.delta","sequence_number":40,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" list","logprobs":[],"obfuscation":"DeEdqnfe944"} +{"type":"response.output_text.delta","sequence_number":41,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"Bm7EpLyUCn2AN"} +{"type":"response.output_text.delta","sequence_number":42,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" numbers","logprobs":[],"obfuscation":"IKqcNUbi"} +{"type":"response.output_text.delta","sequence_number":43,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":")","logprobs":[],"obfuscation":"UQTvFE7bChKyFp5"} +{"type":"response.output_text.delta","sequence_number":44,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" called","logprobs":[],"obfuscation":"WTwiUhbHS"} +{"type":"response.output_text.delta","sequence_number":45,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" an","logprobs":[],"obfuscation":"kttPbHSNqmX0y"} +{"type":"response.output_text.delta","sequence_number":46,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" embedding","logprobs":[],"obfuscation":"Moo0yX"} +{"type":"response.output_text.delta","sequence_number":47,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":".","logprobs":[],"obfuscation":"EmvnJ4uA6NZ5ceE"} +{"type":"response.output_text.delta","sequence_number":48,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" Unlike","logprobs":[],"obfuscation":"TIMqttB6l"} +{"type":"response.output_text.delta","sequence_number":49,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" gener","logprobs":[],"obfuscation":"CWGu8UmkPE"} +{"type":"response.output_text.delta","sequence_number":50,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":"ative","logprobs":[],"obfuscation":"fZYGNftnexv"} +{"type":"response.output_text.delta","sequence_number":51,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" models","logprobs":[],"obfuscation":"NhiGZhiO1"} +{"type":"response.output_text.delta","sequence_number":52,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":",","logprobs":[],"obfuscation":"oct7t3SuU2oyXa8"} +{"type":"response.output_text.delta","sequence_number":53,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" embedding","logprobs":[],"obfuscation":"fhrQQu"} +{"type":"response.output_text.delta","sequence_number":54,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" models","logprobs":[],"obfuscation":"newAISHsy"} +{"type":"response.output_text.delta","sequence_number":55,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" don","logprobs":[],"obfuscation":"wgLqz59u8sBH"} +{"type":"response.output_text.delta","sequence_number":56,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":"’t","logprobs":[],"obfuscation":"3apfijLo4kchSy"} +{"type":"response.output_text.delta","sequence_number":57,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" generate","logprobs":[],"obfuscation":"NOB6Rt5"} +{"type":"response.output_text.delta","sequence_number":58,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" new","logprobs":[],"obfuscation":"7PhHJxzKxHAh"} +{"type":"response.output_text.delta","sequence_number":59,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" text","logprobs":[],"obfuscation":"XHE9N4Pci7r"} +{"type":"response.output_text.delta","sequence_number":60,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" or","logprobs":[],"obfuscation":"EdN3SzRu0FHE1"} +{"type":"response.output_text.delta","sequence_number":61,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" data","logprobs":[],"obfuscation":"F8WJ5dJC1le"} +{"type":"response.output_text.delta","sequence_number":62,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":";","logprobs":[],"obfuscation":"VO2swkknSS59gpy"} +{"type":"response.output_text.delta","sequence_number":63,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" they","logprobs":[],"obfuscation":"0dS8z4W1nya"} +{"type":"response.output_text.delta","sequence_number":64,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" provide","logprobs":[],"obfuscation":"zvMkHWTz"} +{"type":"response.output_text.delta","sequence_number":65,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" vector","logprobs":[],"obfuscation":"eLO2EBfHb"} +{"type":"response.output_text.delta","sequence_number":66,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" representations","logprobs":[],"obfuscation":""} +{"type":"response.output_text.delta","sequence_number":67,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" that","logprobs":[],"obfuscation":"U1OjtYxSGzH"} +{"type":"response.output_text.delta","sequence_number":68,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" capture","logprobs":[],"obfuscation":"1WNFLSPy"} +{"type":"response.output_text.delta","sequence_number":69,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" semantic","logprobs":[],"obfuscation":"W94qMwH"} +{"type":"response.output_text.delta","sequence_number":70,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"yHXnkXLRkRiJ"} +{"type":"response.output_text.delta","sequence_number":71,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" synt","logprobs":[],"obfuscation":"yba7aRbW35i"} +{"type":"response.output_text.delta","sequence_number":72,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":"actic","logprobs":[],"obfuscation":"fBctDzgyXwp"} +{"type":"response.output_text.delta","sequence_number":73,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" relationships","logprobs":[],"obfuscation":"ij"} +{"type":"response.output_text.delta","sequence_number":74,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"IkjQHX8UZAqw"} +{"type":"response.output_text.delta","sequence_number":75,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" can","logprobs":[],"obfuscation":"KeWSf6GIB255"} +{"type":"response.output_text.delta","sequence_number":76,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" be","logprobs":[],"obfuscation":"S9FqWtZQIVLyk"} +{"type":"response.output_text.delta","sequence_number":77,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" used","logprobs":[],"obfuscation":"LCbNtpBZ0e9"} +{"type":"response.output_text.delta","sequence_number":78,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" as","logprobs":[],"obfuscation":"wuOZSH4cQ3noT"} +{"type":"response.output_text.delta","sequence_number":79,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" input","logprobs":[],"obfuscation":"1T7tFOMhrM"} +{"type":"response.output_text.delta","sequence_number":80,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" for","logprobs":[],"obfuscation":"BdCcok8fktXY"} +{"type":"response.output_text.delta","sequence_number":81,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" other","logprobs":[],"obfuscation":"0wdxG2uVZP"} +{"type":"response.output_text.delta","sequence_number":82,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" models","logprobs":[],"obfuscation":"RAUycCDJu"} +{"type":"response.output_text.delta","sequence_number":83,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" or","logprobs":[],"obfuscation":"6iPHFYBL95P3E"} +{"type":"response.output_text.delta","sequence_number":84,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" NLP","logprobs":[],"obfuscation":"GBY2kZCP5O8j"} +{"type":"response.output_text.delta","sequence_number":85,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" tasks","logprobs":[],"obfuscation":"gf7oRS9CDZ"} +{"type":"response.output_text.delta","sequence_number":86,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"TojvmgJPmRBgDD4"} +{"type":"response.output_text.annotation.added","sequence_number":87,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"annotation_index":0,"annotation":{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":379}} +{"type":"response.output_text.delta","sequence_number":88,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"delta":".","logprobs":[],"obfuscation":"UccCBPjfZeqM25q"} +{"type":"response.output_text.done","sequence_number":89,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"text":"The document defines an embedding model as a tool that converts complex data (e.g., words or images) into a dense vector (a list of numbers) called an embedding. Unlike generative models, embedding models don’t generate new text or data; they provide vector representations that capture semantic and syntactic relationships and can be used as input for other models or NLP tasks .","logprobs":[]} +{"type":"response.content_part.done","sequence_number":90,"item_id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","output_index":3,"content_index":0,"part":{"type":"output_text","annotations":[{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":379}],"logprobs":[],"text":"The document defines an embedding model as a tool that converts complex data (e.g., words or images) into a dense vector (a list of numbers) called an embedding. Unlike generative models, embedding models don’t generate new text or data; they provide vector representations that capture semantic and syntactic relationships and can be used as input for other models or NLP tasks ."}} +{"type":"response.output_item.done","sequence_number":91,"output_index":3,"item":{"id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","type":"message","status":"completed","content":[{"type":"output_text","annotations":[{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":379}],"logprobs":[],"text":"The document defines an embedding model as a tool that converts complex data (e.g., words or images) into a dense vector (a list of numbers) called an embedding. Unlike generative models, embedding models don’t generate new text or data; they provide vector representations that capture semantic and syntactic relationships and can be used as input for other models or NLP tasks ."}],"role":"assistant"}} +{"type":"response.completed","sequence_number":92,"response":{"id":"resp_06456cb9918b63780068cacd710b0881a1b00b5fca56e7100b","object":"response","created_at":1758121329,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-mini-2025-08-07","output":[{"id":"rs_06456cb9918b63780068cacd717c3481a1b8c7094da5770b41","type":"reasoning","summary":[]},{"id":"fs_06456cb9918b63780068cacd74a1dc81a1bf68dd57f140b4b6","type":"file_search_call","status":"completed","queries":["What is an embedding model according to this document?","What is an embedding model definition in this document?","How does the document define an embedding model?"],"results":[{"attributes":{},"file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","score":0.9312,"text":"AI 1\n\nAI\nGenerative artificial intelligence refers to models that predict and generate \nvarious types of outputs (such as text, images, or audio) based on whatʼs \nstatistically likely, pulling from patterns theyʼve learned from their training data. \nFor example:\n\nGiven a photo, a generative model can generate a caption.\n\nGiven an audio file, a generative model can generate a transcription.\n\nGiven a text description, a generative model can generate an image.\n\nA large language model LLM is a subset of generative models focused \nprimarily on text. An LLM takes a sequence of words as input and aims to \npredict the most likely sequence to follow. It assigns probabilities to potential \nnext sequences and then selects one. The model continues to generate \nsequences until it meets a specified stopping criterion.\n\nLLMs learn by training on massive collections of written text, which means they \nwill be better suited to some use cases than others. For example, a model \ntrained on GitHub data would understand the probabilities of sequences in \nsource code particularly well.\n\nHowever, it's crucial to understand LLMs' limitations. When asked about less \nknown or absent information, like the birthday of a personal relative, LLMs \nmight \"hallucinate\" or make up information. It's essential to consider how well-\nrepresented the information you need is in the model.\n\nAn embedding model is used to convert complex data (like words or images) \ninto a dense vector (a list of numbers) representation, known as an embedding. \nUnlike generative models, embedding models do not generate new text or data. \nInstead, they provide representations of semantic and synactic relationships \nbetween entities that can be used as input for other models or other natural \nlanguage processing tasks.\n\nIn the next section, you will learn about the difference between models \nproviders and models, and which ones are available in the AI SDK."}]},{"id":"rs_06456cb9918b63780068cacd7663c481a191dd84333d842728","type":"reasoning","summary":[]},{"id":"msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f","type":"message","status":"completed","content":[{"type":"output_text","annotations":[{"type":"file_citation","file_id":"file-Ebzhf8H4DPGPr9pUhr7n7v","filename":"ai.pdf","index":379}],"logprobs":[],"text":"The document defines an embedding model as a tool that converts complex data (e.g., words or images) into a dense vector (a list of numbers) called an embedding. Unlike generative models, embedding models don’t generate new text or data; they provide vector representations that capture semantic and syntactic relationships and can be used as input for other models or NLP tasks ."}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"file_search","filters":null,"max_num_results":20,"ranking_options":{"ranker":"auto","score_threshold":0},"vector_store_ids":["vs_68caad8bd5d88191ab766cf043d89a18"]}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":{"input_tokens":3748,"input_tokens_details":{"cached_tokens":2304},"output_tokens":543,"output_tokens_details":{"reasoning_tokens":448},"total_tokens":4291},"user":null,"metadata":{}}} \ No newline at end of file diff --git a/packages/openai/src/responses/__fixtures__/openai-file-search-tool.2.json b/packages/openai/src/responses/__fixtures__/openai-file-search-tool.2.json new file mode 100644 index 000000000000..3a28b1fc87be --- /dev/null +++ b/packages/openai/src/responses/__fixtures__/openai-file-search-tool.2.json @@ -0,0 +1,112 @@ +{ + "id": "resp_0365d26c32c64c650068cabb02fea4819495862c2bc58440ad", + "object": "response", + "created_at": 1758116611, + "status": "completed", + "background": false, + "error": null, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5-mini-2025-08-07", + "output": [ + { + "id": "rs_0365d26c32c64c650068cabb03bcc48194bfbd973152bca8f6", + "type": "reasoning", + "summary": [] + }, + { + "id": "fs_0365d26c32c64c650068cabb04aa388194b53c59de50a3951e", + "type": "file_search_call", + "status": "completed", + "queries": [ + "What is an embedding model according to this document?", + "What is an embedding model in the document?", + "definition of embedding model", + "embedding model explanation 'embedding model'" + ], + "results": [ + { + "attributes": {}, + "file_id": "file-Ebzhf8H4DPGPr9pUhr7n7v", + "filename": "ai.pdf", + "score": 0.9311, + "text": "AI 1\n\nAI\nGenerative artificial intelligence refers to models that predict and generate \nvarious types of outputs (such as text, images, or audio) based on whatʼs \nstatistically likely, pulling from patterns theyʼve learned from their training data. \nFor example:\n\nGiven a photo, a generative model can generate a caption.\n\nGiven an audio file, a generative model can generate a transcription.\n\nGiven a text description, a generative model can generate an image.\n\nA large language model LLM is a subset of generative models focused \nprimarily on text. An LLM takes a sequence of words as input and aims to \npredict the most likely sequence to follow. It assigns probabilities to potential \nnext sequences and then selects one. The model continues to generate \nsequences until it meets a specified stopping criterion.\n\nLLMs learn by training on massive collections of written text, which means they \nwill be better suited to some use cases than others. For example, a model \ntrained on GitHub data would understand the probabilities of sequences in \nsource code particularly well.\n\nHowever, it's crucial to understand LLMs' limitations. When asked about less \nknown or absent information, like the birthday of a personal relative, LLMs \nmight \"hallucinate\" or make up information. It's essential to consider how well-\nrepresented the information you need is in the model.\n\nAn embedding model is used to convert complex data (like words or images) \ninto a dense vector (a list of numbers) representation, known as an embedding. \nUnlike generative models, embedding models do not generate new text or data. \nInstead, they provide representations of semantic and synactic relationships \nbetween entities that can be used as input for other models or other natural \nlanguage processing tasks.\n\nIn the next section, you will learn about the difference between models \nproviders and models, and which ones are available in the AI SDK." + } + ] + }, + { + "id": "rs_0365d26c32c64c650068cabb061740819491324d349d0f07ca", + "type": "reasoning", + "summary": [] + }, + { + "id": "msg_0365d26c32c64c650068cabb0e66b081949f66f61dacef39f3", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [ + { + "type": "file_citation", + "file_id": "file-Ebzhf8H4DPGPr9pUhr7n7v", + "filename": "ai.pdf", + "index": 350 + } + ], + "logprobs": [], + "text": "According to the document, an embedding model converts complex data (like words or images) into a dense vector — a list of numbers — called an embedding. It does not generate new text or data; instead it encodes semantic and syntactic relationships between entities so those vector representations can be used as inputs for other models or NLP tasks ." + } + ], + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "previous_response_id": null, + "prompt_cache_key": null, + "reasoning": { + "effort": "medium", + "summary": null + }, + "safety_identifier": null, + "service_tier": "default", + "store": true, + "temperature": 1, + "text": { + "format": { + "type": "text" + }, + "verbosity": "medium" + }, + "tool_choice": "auto", + "tools": [ + { + "type": "file_search", + "filters": null, + "max_num_results": 20, + "ranking_options": { + "ranker": "auto", + "score_threshold": 0 + }, + "vector_store_ids": ["vs_68caad8bd5d88191ab766cf043d89a18"] + } + ], + "top_logprobs": 0, + "top_p": 1, + "truncation": "disabled", + "usage": { + "input_tokens": 3678, + "input_tokens_details": { + "cached_tokens": 2304 + }, + "output_tokens": 536, + "output_tokens_details": { + "reasoning_tokens": 448 + }, + "total_tokens": 4214 + }, + "user": null, + "metadata": {} +} diff --git a/packages/openai/src/responses/__fixtures__/openai-image-generation-tool.1.chunks.txt b/packages/openai/src/responses/__fixtures__/openai-image-generation-tool.1.chunks.txt new file mode 100644 index 000000000000..0d587cf50a19 --- /dev/null +++ b/packages/openai/src/responses/__fixtures__/openai-image-generation-tool.1.chunks.txt @@ -0,0 +1,16 @@ +{"type":"response.created","sequence_number":0,"response":{"id":"resp_0df93c0bb83a72f20068c979db26ac819e8b5a444fad3f0d7f","object":"response","created_at":1758034395,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"image_generation","background":"auto","moderation":"auto","n":1,"output_compression":100,"output_format":"webp","quality":"low","size":"auto"}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_0df93c0bb83a72f20068c979db26ac819e8b5a444fad3f0d7f","object":"response","created_at":1758034395,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"image_generation","background":"auto","moderation":"auto","n":1,"output_compression":100,"output_format":"webp","quality":"low","size":"auto"}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"rs_0df93c0bb83a72f20068c979db90b4819e94cedbfda2d49af6","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":3,"output_index":0,"item":{"id":"rs_0df93c0bb83a72f20068c979db90b4819e94cedbfda2d49af6","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":4,"output_index":1,"item":{"id":"ig_0df93c0bb83a72f20068c979f589c0819e9f0fc2d1a27aa1b8","type":"image_generation_call","status":"in_progress"}} +{"type":"response.image_generation_call.in_progress","sequence_number":5,"output_index":1,"item_id":"ig_0df93c0bb83a72f20068c979f589c0819e9f0fc2d1a27aa1b8"} +{"type":"response.image_generation_call.generating","sequence_number":6,"output_index":1,"item_id":"ig_0df93c0bb83a72f20068c979f589c0819e9f0fc2d1a27aa1b8"} +{"type":"response.image_generation_call.partial_image","sequence_number":7,"output_index":1,"item_id":"ig_0df93c0bb83a72f20068c979f589c0819e9f0fc2d1a27aa1b8","partial_image_index":0,"partial_image_b64":"UklGRuIWGQBXRUJQVlA4TKAwGAAv/8X/ABlJbiNJkgRDwkID67D/P9gjl9nuEf2fgPyZzj1Jyu97SlIDX5iPbDv2F3U/+UU+JIlr+wVtEwKO7xiJ7dh26zu3NgZIasDGMcSYOIltx8MpJGFWJAaDE8g4AzhJzCAkCedAeJ17KsRCTxd5r4c1SfLsHwzwZ/2/f67rukb7R1yzavfWH3mdtqpvK4HU00+v2a1qb/...AAAPZYQFuWuM6Be+taQrxy8eMnvFntuAhnHLJbzoq1L9GGMdWs/9hArxYpBl4GS+zJ3eoEsBEkmxChF9k+m5HNgnA2uzI=","size":"1536x1024","quality":"low","background":"opaque","output_format":"webp"} +{"type":"response.image_generation_call.completed","sequence_number":8,"output_index":1,"item_id":"ig_0df93c0bb83a72f20068c979f589c0819e9f0fc2d1a27aa1b8"} +{"type":"response.output_item.done","sequence_number":9,"output_index":1,"item":{"id":"ig_0df93c0bb83a72f20068c979f589c0819e9f0fc2d1a27aa1b8","type":"image_generation_call","status":"completed","background":"opaque","output_format":"webp","quality":"low","result":"UklGRuIWGQBXRUJQVlA4TKAwGAAv/8X/ABlJbiNJkgRDwkID67D/P9gjl9nuEf2fgPyZzj1Jyu97SlIDX5iPbDv2F3U/+UU+JIlr+wVtEwKO7xiJ7dh26zu3NgZIasDGMcSYOIltx8MpJGFWJAaDE8g4AzhJzCAkCedAeJ17KsRCTxd5r4c1SfLsHwzwZ/2/f67rukb7R1yzavfWH3mdtqpvK4HU00+v2a1qb/...AAAPZYQFuWuM6Be+taQrxy8eMnvFntuAhnHLJbzoq1L9GGMdWs/9hArxYpBl4GS+zJ3eoEsBEkmxChF9k+m5HNgnA2uzI=","revised_prompt":"Create a high-resolution, hyperrealistic illustration of an echidna swimming across the Mozambique Channel. Composition: wide, cinematic aerial perspective over the Indian Ocean with Mozambique’s coastline faintly visible to the left and Madagascar’s coastline faintly visible to the right, both softened by atmospheric haze and no text labels. In the midground, feature a short-beaked echidna partially submerged: spines slick and glistening with seawater, small snout just above the surface, front limbs paddling and creating delicate ripples and a subtle V-shaped wake. Water: deep cobalt transitioning to turquoise, with gentle swells, current lines, and sparkling sun reflections. Lighting: warm golden-hour late afternoon, long highlights on wave crests and soft shadows. Add a few distant seabirds and soft cumulus clouds for scale and atmosphere. Style: richly detailed, natural colors, crisp yet painterly rendering, shallow depth of field emphasizing the echidna, 16:9 aspect ratio, 4K resolution.","size":"1536x1024"}} +{"type":"response.output_item.added","sequence_number":10,"output_index":2,"item":{"id":"msg_0df93c0bb83a72f20068c97a0b36f4819ea5906451007f95e2","type":"message","status":"in_progress","content":[],"role":"assistant"}} +{"type":"response.content_part.added","sequence_number":11,"item_id":"msg_0df93c0bb83a72f20068c97a0b36f4819ea5906451007f95e2","output_index":2,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}} +{"type":"response.output_text.done","sequence_number":12,"item_id":"msg_0df93c0bb83a72f20068c97a0b36f4819ea5906451007f95e2","output_index":2,"content_index":0,"text":"","logprobs":[]} +{"type":"response.content_part.done","sequence_number":13,"item_id":"msg_0df93c0bb83a72f20068c97a0b36f4819ea5906451007f95e2","output_index":2,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}} +{"type":"response.output_item.done","sequence_number":14,"output_index":2,"item":{"id":"msg_0df93c0bb83a72f20068c97a0b36f4819ea5906451007f95e2","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":""}],"role":"assistant"}} +{"type":"response.completed","sequence_number":15,"response":{"id":"resp_0df93c0bb83a72f20068c979db26ac819e8b5a444fad3f0d7f","object":"response","created_at":1758034395,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-2025-08-07","output":[{"id":"rs_0df93c0bb83a72f20068c979db90b4819e94cedbfda2d49af6","type":"reasoning","summary":[]},{"id":"ig_0df93c0bb83a72f20068c979f589c0819e9f0fc2d1a27aa1b8","type":"image_generation_call","status":"completed","background":"opaque","output_format":"webp","quality":"low","result":"UklGRuIWGQBXRUJQVlA4TKAwGAAv/8X/ABlJbiNJkgRDwkID67D/P9gjl9nuEf2fgPyZzj1Jyu97SlIDX5iPbDv2F3U/+UU+JIlr+wVtEwKO7xiJ7dh26zu3NgZIasDGMcSYOIltx8MpJGFWJAaDE8g4AzhJzCAkCedAeJ17KsRCTxd5r4c1SfLsHwzwZ/2/f67rukb7R1yzavfWH3mdtqpvK4HU00+v2a1qb/...AAAPZYQFuWuM6Be+taQrxy8eMnvFntuAhnHLJbzoq1L9GGMdWs/9hArxYpBl4GS+zJ3eoEsBEkmxChF9k+m5HNgnA2uzI=","revised_prompt":"Create a high-resolution, hyperrealistic illustration of an echidna swimming across the Mozambique Channel. Composition: wide, cinematic aerial perspective over the Indian Ocean with Mozambique’s coastline faintly visible to the left and Madagascar’s coastline faintly visible to the right, both softened by atmospheric haze and no text labels. In the midground, feature a short-beaked echidna partially submerged: spines slick and glistening with seawater, small snout just above the surface, front limbs paddling and creating delicate ripples and a subtle V-shaped wake. Water: deep cobalt transitioning to turquoise, with gentle swells, current lines, and sparkling sun reflections. Lighting: warm golden-hour late afternoon, long highlights on wave crests and soft shadows. Add a few distant seabirds and soft cumulus clouds for scale and atmosphere. Style: richly detailed, natural colors, crisp yet painterly rendering, shallow depth of field emphasizing the echidna, 16:9 aspect ratio, 4K resolution.","size":"1536x1024"},{"id":"msg_0df93c0bb83a72f20068c97a0b36f4819ea5906451007f95e2","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":""}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"image_generation","background":"auto","moderation":"auto","n":1,"output_compression":100,"output_format":"webp","quality":"low","size":"auto"}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":{"input_tokens":2941,"input_tokens_details":{"cached_tokens":1920},"output_tokens":1249,"output_tokens_details":{"reasoning_tokens":1024},"total_tokens":4190},"user":null,"metadata":{}}} \ No newline at end of file diff --git a/packages/openai/src/responses/__fixtures__/openai-image-generation-tool.1.json b/packages/openai/src/responses/__fixtures__/openai-image-generation-tool.1.json new file mode 100644 index 000000000000..52e9ff9f7a90 --- /dev/null +++ b/packages/openai/src/responses/__fixtures__/openai-image-generation-tool.1.json @@ -0,0 +1,96 @@ +{ + "id": "resp_0a33d15155cb126d0068c96c54970481958484dea31f07926d", + "object": "response", + "created_at": 1758030932, + "status": "completed", + "background": false, + "error": null, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5-nano-2025-08-07", + "output": [ + { + "id": "rs_0a33d15155cb126d0068c96c5527808195a933b468ccb5dfd9", + "type": "reasoning", + "summary": [] + }, + { + "id": "ig_0a33d15155cb126d0068c96c59bc14819599154c9988b82996", + "type": "image_generation_call", + "status": "completed", + "background": "opaque", + "output_format": "webp", + "quality": "low", + "result": "UklGRoitEQBXRUJQVlA4TEGzEAAv/8P/AM1AbNtGkITZhU4fH9J/wTOT+xIi+j8BuT4kABkCibNAZrlwIPyQ7W/bH5L2RHMzMBKgXmfZeYi9tLtrrQkZvN1yXHLLgG71gPkpDxmI/gc03YFulQR...AA9lhA0Y9rVdqQs/W4w/MOxeRW5+R1/UXmmNVi9yQ7x/vG0q2VRk01seZIuj5OmRYhD+yY82dZqMH1BCueTeOcNfGKxQ==", + "revised_prompt": "A cute fluffy cat sitting on a sunlit windowsill, warm sunlight, soft fur, expressive eyes, photorealistic style.", + "size": "1024x1024" + }, + { + "id": "rs_0a33d15155cb126d0068c96c6c0ef48195bc73e30faf832ba3", + "type": "reasoning", + "summary": [] + }, + { + "id": "msg_0a33d15155cb126d0068c96c723ed88195b1405bc370bb8a65", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "" + } + ], + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "previous_response_id": null, + "prompt_cache_key": null, + "reasoning": { + "effort": "medium", + "summary": null + }, + "safety_identifier": null, + "service_tier": "default", + "store": true, + "temperature": 1, + "text": { + "format": { + "type": "text" + }, + "verbosity": "medium" + }, + "tool_choice": "auto", + "tools": [ + { + "type": "image_generation", + "background": "auto", + "moderation": "auto", + "n": 1, + "output_compression": 100, + "output_format": "webp", + "quality": "low", + "size": "1024x1024" + } + ], + "top_logprobs": 0, + "top_p": 1, + "truncation": "disabled", + "usage": { + "input_tokens": 3151, + "input_tokens_details": { + "cached_tokens": 0 + }, + "output_tokens": 1970, + "output_tokens_details": { + "reasoning_tokens": 1920 + }, + "total_tokens": 5121 + }, + "user": null, + "metadata": {} +} diff --git a/packages/openai/src/responses/__fixtures__/openai-web-search-tool.chunks.txt b/packages/openai/src/responses/__fixtures__/openai-web-search-tool.chunks.txt new file mode 100644 index 000000000000..5c7868d99060 --- /dev/null +++ b/packages/openai/src/responses/__fixtures__/openai-web-search-tool.chunks.txt @@ -0,0 +1,56 @@ +{"type":"response.created","sequence_number":0,"response":{"id":"resp_68c187cc09508192aa225af9734e2ed905ca09a4773fcd25","object":"response","created_at":1757513676,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-nano-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"web_search","filters":null,"search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_68c187cc09508192aa225af9734e2ed905ca09a4773fcd25","object":"response","created_at":1757513676,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-nano-2025-08-07","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"web_search","filters":null,"search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} +{"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"rs_68c187cc87a88192b58352081364836c05ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":3,"output_index":0,"item":{"id":"rs_68c187cc87a88192b58352081364836c05ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":4,"output_index":1,"item":{"id":"ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25","type":"web_search_call","status":"in_progress"}} +{"type":"response.web_search_call.in_progress","sequence_number":5,"output_index":1,"item_id":"ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25"} +{"type":"response.web_search_call.searching","sequence_number":6,"output_index":1,"item_id":"ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25"} +{"type":"response.web_search_call.completed","sequence_number":7,"output_index":1,"item_id":"ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25"} +{"type":"response.output_item.done","sequence_number":8,"output_index":1,"item":{"id":"ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25","type":"web_search_call","status":"completed","action":{"type":"search","query":"Berlin news today","sources":[{"type":"url","url":"https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/"},{"type":"url","url":"https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025"},{"type":"url","url":"https://en.wikipedia.org/wiki/75th_Berlin_International_Film_Festival"},{"type":"url","url":"https://apnews.com/article/ecf774eea5cdc7cbf88adf3887102d9b"},{"type":"url","url":"https://apnews.com/article/1710be90a0e733d016e32db4d8353e1c"},{"type":"url","url":"https://en.wikipedia.org/wiki/Rave_The_Planet_Parade"},{"type":"url","url":"https://en.wikipedia.org/wiki/2025_DFB-Pokal_final"},{"type":"url","url":"https://en.wikipedia.org/wiki/2025_Berlin_Tennis_Open"},{"type":"url","url":"https://en.wikipedia.org/wiki/Parkb%C3%BChne_Wuhlheide"},{"type":"url","url":"https://en.wikipedia.org/wiki/2025_Berlin_Tennis_Open_%E2%80%93_Singles"},{"type":"url","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url","url":"https://helloberl.in/berlin-events-feb-27-march-2nd-2025/"}]}}} +{"type":"response.output_item.added","sequence_number":9,"output_index":2,"item":{"id":"rs_68c187d2484881929a3908a9ad4e745f05ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":10,"output_index":2,"item":{"id":"rs_68c187d2484881929a3908a9ad4e745f05ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":11,"output_index":3,"item":{"id":"ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25","type":"web_search_call","status":"in_progress"}} +{"type":"response.web_search_call.in_progress","sequence_number":12,"output_index":3,"item_id":"ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25"} +{"type":"response.web_search_call.searching","sequence_number":13,"output_index":3,"item_id":"ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25"} +{"type":"response.web_search_call.completed","sequence_number":14,"output_index":3,"item_id":"ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25"} +{"type":"response.output_item.done","sequence_number":15,"output_index":3,"item":{"id":"ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25","type":"web_search_call","status":"completed","action":{"type":"search","sources":[{"type":"url","url":"https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/"}]}}} +{"type":"response.output_item.added","sequence_number":16,"output_index":4,"item":{"id":"rs_68c187d42c0481929f8e156e064bd0a105ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":17,"output_index":4,"item":{"id":"rs_68c187d42c0481929f8e156e064bd0a105ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":18,"output_index":5,"item":{"id":"ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25","type":"web_search_call","status":"in_progress"}} +{"type":"response.web_search_call.in_progress","sequence_number":19,"output_index":5,"item_id":"ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25"} +{"type":"response.web_search_call.searching","sequence_number":20,"output_index":5,"item_id":"ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25"} +{"type":"response.web_search_call.completed","sequence_number":21,"output_index":5,"item_id":"ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25"} +{"type":"response.output_item.done","sequence_number":22,"output_index":5,"item":{"id":"ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25","type":"web_search_call","status":"completed","action":{"type":"search","sources":[{"type":"url","url":"https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025"}]}}} +{"type":"response.output_item.added","sequence_number":23,"output_index":6,"item":{"id":"rs_68c187d592f481929b10ff6121241b1d05ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":24,"output_index":6,"item":{"id":"rs_68c187d592f481929b10ff6121241b1d05ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":25,"output_index":7,"item":{"id":"ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25","type":"web_search_call","status":"in_progress"}} +{"type":"response.web_search_call.in_progress","sequence_number":26,"output_index":7,"item_id":"ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25"} +{"type":"response.web_search_call.searching","sequence_number":27,"output_index":7,"item_id":"ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25"} +{"type":"response.web_search_call.completed","sequence_number":28,"output_index":7,"item_id":"ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25"} +{"type":"response.output_item.done","sequence_number":29,"output_index":7,"item":{"id":"ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25","type":"web_search_call","status":"completed","action":{"type":"search","sources":[{"type":"url","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"}]}}} +{"type":"response.output_item.added","sequence_number":30,"output_index":8,"item":{"id":"rs_68c187d87fb481929fc9d6593d88c3dd05ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.done","sequence_number":31,"output_index":8,"item":{"id":"rs_68c187d87fb481929fc9d6593d88c3dd05ca09a4773fcd25","type":"reasoning","summary":[]}} +{"type":"response.output_item.added","sequence_number":32,"output_index":9,"item":{"id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","type":"message","status":"in_progress","content":[],"role":"assistant"}} +{"type":"response.content_part.added","sequence_number":33,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}} +{"type":"response.output_text.delta","sequence_number":34,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":"Here’s what’s notable in Berlin today (September 10, 2025), based on three quick web searches:\n\n- Berlin Art Week 2025 kicks off today and runs through September 14. The city’s autumn art season opens with more than 100 venues, featuring exhibitions from Patti Smith, Mark Leckey, Katharina Grosse, Carrie Mae Weems, and more. ([wallpaper.com](https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025))\n\n- The city is highlighting its 200-year Museum Island anniversary this year, with ongoing events and exhibitions around Berlin’s historic center. This is part of Berlin’s big year of cultural highlights. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- 49h ICC: Open House is scheduled for September 11–14, offering guided tours and design talks at the former ICC Berlin. It’s one of the major architecture/design events associated with Berlin 2025. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- Open Monument Day is coming up on September 13–14, when many","logprobs":[],"obfuscation":"Y"} +{"type":"response.output_text.annotation.added","sequence_number":35,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"annotation_index":0,"annotation":{"type":"url_citation","end_index":414,"start_index":327,"title":"What to see at Berlin Art Week 2025 | Wallpaper*","url":"https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025"}} +{"type":"response.output_text.annotation.added","sequence_number":36,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"annotation_index":1,"annotation":{"type":"url_citation","end_index":697,"start_index":620,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"}} +{"type":"response.output_text.annotation.added","sequence_number":37,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"annotation_index":2,"annotation":{"type":"url_citation","end_index":975,"start_index":898,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"}} +{"type":"response.output_text.delta","sequence_number":38,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":" historic sites around Berlin open to the public with special programs. If you’re in town this weekend, it’s a good chance to explore landmarks that aren’t usually accessible.","logprobs":[],"obfuscation":"M"} +{"type":"response.output_text.delta","sequence_number":39,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":" ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- If you’re a sports fan, Berlin will host NFL games","logprobs":[],"obfuscation":"IGQbTBYQU3o5"} +{"type":"response.output_text.annotation.added","sequence_number":40,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"annotation_index":3,"annotation":{"type":"url_citation","end_index":1292,"start_index":1215,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"}} +{"type":"response.output_text.delta","sequence_number":41,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":" in November 2025 (three regular-season games in the Olympic Stadium, with the Indianapolis Colts among","logprobs":[],"obfuscation":"obbirOyig"} +{"type":"response.output_text.delta","sequence_number":42,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":" the teams). It’s part of Berlin’s ongoing slate of major events this year","logprobs":[],"obfuscation":"y4HnJl"} +{"type":"response.output_text.delta","sequence_number":43,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":". ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- For some broader","logprobs":[],"obfuscation":"TmpmuVqo23O5Q"} +{"type":"response.output_text.annotation.added","sequence_number":44,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"annotation_index":4,"annotation":{"type":"url_citation","end_index":1602,"start_index":1525,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"}} +{"type":"response.output_text.delta","sequence_number":45,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":" context, Berlin has been discussing its role in postwar security arrangements for Ukraine, with","logprobs":[],"obfuscation":""} +{"type":"response.output_text.delta","sequence_number":46,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":" German officials signaling readiness to increase support but delaying a formal deployment decision until broader conditions are","logprobs":[],"obfuscation":""} +{"type":"response.output_text.delta","sequence_number":47,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":" clearer. This","logprobs":[],"obfuscation":"k6"} +{"type":"response.output_text.delta","sequence_number":48,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":" was reported for early September 2025. ([reuters.com](https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/))","logprobs":[],"obfuscation":"sFsCwiO"} +{"type":"response.output_text.annotation.added","sequence_number":49,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"annotation_index":5,"annotation":{"type":"url_citation","end_index":2029,"start_index":1900,"title":"Berlin holds off decision on participation in postwar Ukraine force | Reuters","url":"https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/"}} +{"type":"response.output_text.delta","sequence_number":50,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":"\n\nWould you like me to pull live updates or focus on a specific topic (arts,","logprobs":[],"obfuscation":"0Jl6"} +{"type":"response.output_text.delta","sequence_number":51,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"delta":" politics, sports) from today?","logprobs":[],"obfuscation":"67"} +{"type":"response.output_text.done","sequence_number":52,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"text":"Here’s what’s notable in Berlin today (September 10, 2025), based on three quick web searches:\n\n- Berlin Art Week 2025 kicks off today and runs through September 14. The city’s autumn art season opens with more than 100 venues, featuring exhibitions from Patti Smith, Mark Leckey, Katharina Grosse, Carrie Mae Weems, and more. ([wallpaper.com](https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025))\n\n- The city is highlighting its 200-year Museum Island anniversary this year, with ongoing events and exhibitions around Berlin’s historic center. This is part of Berlin’s big year of cultural highlights. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- 49h ICC: Open House is scheduled for September 11–14, offering guided tours and design talks at the former ICC Berlin. It’s one of the major architecture/design events associated with Berlin 2025. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- Open Monument Day is coming up on September 13–14, when many historic sites around Berlin open to the public with special programs. If you’re in town this weekend, it’s a good chance to explore landmarks that aren’t usually accessible. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- If you’re a sports fan, Berlin will host NFL games in November 2025 (three regular-season games in the Olympic Stadium, with the Indianapolis Colts among the teams). It’s part of Berlin’s ongoing slate of major events this year. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- For some broader context, Berlin has been discussing its role in postwar security arrangements for Ukraine, with German officials signaling readiness to increase support but delaying a formal deployment decision until broader conditions are clearer. This was reported for early September 2025. ([reuters.com](https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/))\n\nWould you like me to pull live updates or focus on a specific topic (arts, politics, sports) from today?","logprobs":[]} +{"type":"response.content_part.done","sequence_number":53,"item_id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","output_index":9,"content_index":0,"part":{"type":"output_text","annotations":[{"type":"url_citation","end_index":414,"start_index":327,"title":"What to see at Berlin Art Week 2025 | Wallpaper*","url":"https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025"},{"type":"url_citation","end_index":697,"start_index":620,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":975,"start_index":898,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":1292,"start_index":1215,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":1602,"start_index":1525,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":2029,"start_index":1900,"title":"Berlin holds off decision on participation in postwar Ukraine force | Reuters","url":"https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/"}],"logprobs":[],"text":"Here’s what’s notable in Berlin today (September 10, 2025), based on three quick web searches:\n\n- Berlin Art Week 2025 kicks off today and runs through September 14. The city’s autumn art season opens with more than 100 venues, featuring exhibitions from Patti Smith, Mark Leckey, Katharina Grosse, Carrie Mae Weems, and more. ([wallpaper.com](https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025))\n\n- The city is highlighting its 200-year Museum Island anniversary this year, with ongoing events and exhibitions around Berlin’s historic center. This is part of Berlin’s big year of cultural highlights. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- 49h ICC: Open House is scheduled for September 11–14, offering guided tours and design talks at the former ICC Berlin. It’s one of the major architecture/design events associated with Berlin 2025. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- Open Monument Day is coming up on September 13–14, when many historic sites around Berlin open to the public with special programs. If you’re in town this weekend, it’s a good chance to explore landmarks that aren’t usually accessible. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- If you’re a sports fan, Berlin will host NFL games in November 2025 (three regular-season games in the Olympic Stadium, with the Indianapolis Colts among the teams). It’s part of Berlin’s ongoing slate of major events this year. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- For some broader context, Berlin has been discussing its role in postwar security arrangements for Ukraine, with German officials signaling readiness to increase support but delaying a formal deployment decision until broader conditions are clearer. This was reported for early September 2025. ([reuters.com](https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/))\n\nWould you like me to pull live updates or focus on a specific topic (arts, politics, sports) from today?"}} +{"type":"response.output_item.done","sequence_number":54,"output_index":9,"item":{"id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","type":"message","status":"completed","content":[{"type":"output_text","annotations":[{"type":"url_citation","end_index":414,"start_index":327,"title":"What to see at Berlin Art Week 2025 | Wallpaper*","url":"https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025"},{"type":"url_citation","end_index":697,"start_index":620,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":975,"start_index":898,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":1292,"start_index":1215,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":1602,"start_index":1525,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":2029,"start_index":1900,"title":"Berlin holds off decision on participation in postwar Ukraine force | Reuters","url":"https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/"}],"logprobs":[],"text":"Here’s what’s notable in Berlin today (September 10, 2025), based on three quick web searches:\n\n- Berlin Art Week 2025 kicks off today and runs through September 14. The city’s autumn art season opens with more than 100 venues, featuring exhibitions from Patti Smith, Mark Leckey, Katharina Grosse, Carrie Mae Weems, and more. ([wallpaper.com](https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025))\n\n- The city is highlighting its 200-year Museum Island anniversary this year, with ongoing events and exhibitions around Berlin’s historic center. This is part of Berlin’s big year of cultural highlights. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- 49h ICC: Open House is scheduled for September 11–14, offering guided tours and design talks at the former ICC Berlin. It’s one of the major architecture/design events associated with Berlin 2025. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- Open Monument Day is coming up on September 13–14, when many historic sites around Berlin open to the public with special programs. If you’re in town this weekend, it’s a good chance to explore landmarks that aren’t usually accessible. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- If you’re a sports fan, Berlin will host NFL games in November 2025 (three regular-season games in the Olympic Stadium, with the Indianapolis Colts among the teams). It’s part of Berlin’s ongoing slate of major events this year. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- For some broader context, Berlin has been discussing its role in postwar security arrangements for Ukraine, with German officials signaling readiness to increase support but delaying a formal deployment decision until broader conditions are clearer. This was reported for early September 2025. ([reuters.com](https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/))\n\nWould you like me to pull live updates or focus on a specific topic (arts, politics, sports) from today?"}],"role":"assistant"}} +{"type":"response.completed","sequence_number":55,"response":{"id":"resp_68c187cc09508192aa225af9734e2ed905ca09a4773fcd25","object":"response","created_at":1757513676,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5-nano-2025-08-07","output":[{"id":"rs_68c187cc87a88192b58352081364836c05ca09a4773fcd25","type":"reasoning","summary":[]},{"id":"ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25","type":"web_search_call","status":"completed","action":{"type":"search","query":"Berlin news today","sources":[{"type":"url","url":"https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/"},{"type":"url","url":"https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025"},{"type":"url","url":"https://en.wikipedia.org/wiki/75th_Berlin_International_Film_Festival"},{"type":"url","url":"https://apnews.com/article/ecf774eea5cdc7cbf88adf3887102d9b"},{"type":"url","url":"https://apnews.com/article/1710be90a0e733d016e32db4d8353e1c"},{"type":"url","url":"https://en.wikipedia.org/wiki/Rave_The_Planet_Parade"},{"type":"url","url":"https://en.wikipedia.org/wiki/2025_DFB-Pokal_final"},{"type":"url","url":"https://en.wikipedia.org/wiki/2025_Berlin_Tennis_Open"},{"type":"url","url":"https://en.wikipedia.org/wiki/Parkb%C3%BChne_Wuhlheide"},{"type":"url","url":"https://en.wikipedia.org/wiki/2025_Berlin_Tennis_Open_%E2%80%93_Singles"},{"type":"url","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url","url":"https://helloberl.in/berlin-events-feb-27-march-2nd-2025/"}]}},{"id":"rs_68c187d2484881929a3908a9ad4e745f05ca09a4773fcd25","type":"reasoning","summary":[]},{"id":"ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25","type":"web_search_call","status":"completed","action":{"type":"search","sources":[{"type":"url","url":"https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/"}]}},{"id":"rs_68c187d42c0481929f8e156e064bd0a105ca09a4773fcd25","type":"reasoning","summary":[]},{"id":"ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25","type":"web_search_call","status":"completed","action":{"type":"search","sources":[{"type":"url","url":"https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025"}]}},{"id":"rs_68c187d592f481929b10ff6121241b1d05ca09a4773fcd25","type":"reasoning","summary":[]},{"id":"ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25","type":"web_search_call","status":"completed","action":{"type":"search","sources":[{"type":"url","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"}]}},{"id":"rs_68c187d87fb481929fc9d6593d88c3dd05ca09a4773fcd25","type":"reasoning","summary":[]},{"id":"msg_68c187e279048192be3775da689aa25105ca09a4773fcd25","type":"message","status":"completed","content":[{"type":"output_text","annotations":[{"type":"url_citation","end_index":414,"start_index":327,"title":"What to see at Berlin Art Week 2025 | Wallpaper*","url":"https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025"},{"type":"url_citation","end_index":697,"start_index":620,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":975,"start_index":898,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":1292,"start_index":1215,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":1602,"start_index":1525,"title":"Berlin 2025 – the main events | visitBerlin.de","url":"https://www.visitberlin.de/en/berlin-2025-the-main-events"},{"type":"url_citation","end_index":2029,"start_index":1900,"title":"Berlin holds off decision on participation in postwar Ukraine force | Reuters","url":"https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/"}],"logprobs":[],"text":"Here’s what’s notable in Berlin today (September 10, 2025), based on three quick web searches:\n\n- Berlin Art Week 2025 kicks off today and runs through September 14. The city’s autumn art season opens with more than 100 venues, featuring exhibitions from Patti Smith, Mark Leckey, Katharina Grosse, Carrie Mae Weems, and more. ([wallpaper.com](https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025))\n\n- The city is highlighting its 200-year Museum Island anniversary this year, with ongoing events and exhibitions around Berlin’s historic center. This is part of Berlin’s big year of cultural highlights. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- 49h ICC: Open House is scheduled for September 11–14, offering guided tours and design talks at the former ICC Berlin. It’s one of the major architecture/design events associated with Berlin 2025. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- Open Monument Day is coming up on September 13–14, when many historic sites around Berlin open to the public with special programs. If you’re in town this weekend, it’s a good chance to explore landmarks that aren’t usually accessible. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- If you’re a sports fan, Berlin will host NFL games in November 2025 (three regular-season games in the Olympic Stadium, with the Indianapolis Colts among the teams). It’s part of Berlin’s ongoing slate of major events this year. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events))\n\n- For some broader context, Berlin has been discussing its role in postwar security arrangements for Ukraine, with German officials signaling readiness to increase support but delaying a formal deployment decision until broader conditions are clearer. This was reported for early September 2025. ([reuters.com](https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/))\n\nWould you like me to pull live updates or focus on a specific topic (arts, politics, sports) from today?"}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"web_search","filters":null,"search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_logprobs":0,"top_p":1,"truncation":"disabled","usage":{"input_tokens":60093,"input_tokens_details":{"cached_tokens":34560},"output_tokens":4080,"output_tokens_details":{"reasoning_tokens":3648},"total_tokens":64173},"user":null,"metadata":{}}} \ No newline at end of file diff --git a/packages/openai/src/responses/__snapshots__/openai-responses-language-model.test.ts.snap b/packages/openai/src/responses/__snapshots__/openai-responses-language-model.test.ts.snap new file mode 100644 index 000000000000..3e0ffa0df6b1 --- /dev/null +++ b/packages/openai/src/responses/__snapshots__/openai-responses-language-model.test.ts.snap @@ -0,0 +1,2702 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`OpenAIResponsesLanguageModel > doGenerate > code interpreter tool > should include code interpreter tool call and result in content 1`] = ` +[ + { + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e2cbc0a08190bc754d734af0940f0b24aae9c6c01e4f", + "reasoningEncryptedContent": null, + }, + }, + "text": "", + "type": "reasoning", + }, + { + "input": "{"code":"import random\\nrandom.seed() # system time\\nn=10000\\nsums=[(random.randint(1,6)+random.randint(1,6)) for _ in range(n)]\\ntotal=sum(sums)\\nmean=total/n\\nfrom collections import Counter\\ncounts=Counter(sums)\\ncounts_sorted=[(sum_val, counts[sum_val]) for sum_val in range(2,13)]\\ntotal, mean, counts_sorted[:5], counts_sorted[-5:]","containerId":"cntr_68c2e2caf50c8193b4069276f4c75ef301e63bd5fd6a4d4d"}", + "providerExecuted": true, + "toolCallId": "ci_68c2e2cf522c81908f3e2c1bccd1493b0b24aae9c6c01e4f", + "toolName": "code_interpreter", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "outputs": [ + { + "logs": "(70141, + 7.0141, + [(2, 269), (3, 511), (4, 865), (5, 1130), (6, 1353)], + [(8, 1387), (9, 1110), (10, 828), (11, 538), (12, 299)])", + "type": "logs", + }, + ], + }, + "toolCallId": "ci_68c2e2cf522c81908f3e2c1bccd1493b0b24aae9c6c01e4f", + "toolName": "code_interpreter", + "type": "tool-result", + }, + { + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e2d67f60819097167827b0e29b4f0b24aae9c6c01e4f", + "reasoningEncryptedContent": null, + }, + }, + "text": "", + "type": "reasoning", + }, + { + "input": "{"code":"counts_sorted_full = [(s,c) for s,c in sorted(counts.items())]\\ncounts_sorted_full","containerId":"cntr_68c2e2caf50c8193b4069276f4c75ef301e63bd5fd6a4d4d"}", + "providerExecuted": true, + "toolCallId": "ci_68c2e2d75fe08190b27c6e44213143010b24aae9c6c01e4f", + "toolName": "code_interpreter", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "outputs": [ + { + "logs": "[(2, 269), + (3, 511), + (4, 865), + (5, 1130), + (6, 1353), + (7, 1710), + (8, 1387), + (9, 1110), + (10, 828), + (11, 538), + (12, 299)]", + "type": "logs", + }, + ], + }, + "toolCallId": "ci_68c2e2d75fe08190b27c6e44213143010b24aae9c6c01e4f", + "toolName": "code_interpreter", + "type": "tool-result", + }, + { + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e2dab6508190987f0d3db143b0580b24aae9c6c01e4f", + "reasoningEncryptedContent": null, + }, + }, + "text": "", + "type": "reasoning", + }, + { + "providerMetadata": { + "openai": { + "itemId": "msg_68c2e2e513c88190a72cefb37140d19a0b24aae9c6c01e4f", + }, + }, + "text": "Here’s a quick result from simulating 10,000 rolls of two fair six-sided dice (sum per trial, then total across all trials): + +- Total sum of all 10,000 trial sums: 70141 +- Average sum per trial: 7.0141 + +Distribution of the per-trial sums (2–12): +- 2: 269 (2.69%) +- 3: 511 (5.11%) +- 4: 865 (8.65%) +- 5: 1130 (11.30%) +- 6: 1353 (13.53%) +- 7: 1710 (17.10%) +- 8: 1387 (13.87%) +- 9: 1110 (11.10%) +- 10: 828 (8.28%) +- 11: 538 (5.38%) +- 12: 299 (2.99%) + +Notes: +- The total is around 7,0000 since the expected sum per trial is 7, so 10,000 trials ≈ 70000. Your exact total will vary with each run unless you fix a random seed. +- If you’d like, I can provide the per-trial sums as a CSV file or share a reproducible run with a fixed seed.", + "type": "text", + }, +] +`; + +exports[`OpenAIResponsesLanguageModel > doGenerate > file search tool > with results include > should include file search tool call and result in content 1`] = ` +[ + { + "providerMetadata": { + "openai": { + "itemId": "rs_0365d26c32c64c650068cabb03bcc48194bfbd973152bca8f6", + "reasoningEncryptedContent": null, + }, + }, + "text": "", + "type": "reasoning", + }, + { + "input": "{}", + "providerExecuted": true, + "toolCallId": "fs_0365d26c32c64c650068cabb04aa388194b53c59de50a3951e", + "toolName": "file_search", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "queries": [ + "What is an embedding model according to this document?", + "What is an embedding model in the document?", + "definition of embedding model", + "embedding model explanation 'embedding model'", + ], + "results": [ + { + "attributes": {}, + "fileId": "file-Ebzhf8H4DPGPr9pUhr7n7v", + "filename": "ai.pdf", + "score": 0.9311, + "text": "AI 1 + +AI +Generative artificial intelligence refers to models that predict and generate +various types of outputs (such as text, images, or audio) based on whatʼs +statistically likely, pulling from patterns theyʼve learned from their training data. +For example: + +Given a photo, a generative model can generate a caption. + +Given an audio file, a generative model can generate a transcription. + +Given a text description, a generative model can generate an image. + +A large language model LLM is a subset of generative models focused +primarily on text. An LLM takes a sequence of words as input and aims to +predict the most likely sequence to follow. It assigns probabilities to potential +next sequences and then selects one. The model continues to generate +sequences until it meets a specified stopping criterion. + +LLMs learn by training on massive collections of written text, which means they +will be better suited to some use cases than others. For example, a model +trained on GitHub data would understand the probabilities of sequences in +source code particularly well. + +However, it's crucial to understand LLMs' limitations. When asked about less +known or absent information, like the birthday of a personal relative, LLMs +might "hallucinate" or make up information. It's essential to consider how well- +represented the information you need is in the model. + +An embedding model is used to convert complex data (like words or images) +into a dense vector (a list of numbers) representation, known as an embedding. +Unlike generative models, embedding models do not generate new text or data. +Instead, they provide representations of semantic and synactic relationships +between entities that can be used as input for other models or other natural +language processing tasks. + +In the next section, you will learn about the difference between models +providers and models, and which ones are available in the AI SDK.", + }, + ], + }, + "toolCallId": "fs_0365d26c32c64c650068cabb04aa388194b53c59de50a3951e", + "toolName": "file_search", + "type": "tool-result", + }, + { + "providerMetadata": { + "openai": { + "itemId": "rs_0365d26c32c64c650068cabb061740819491324d349d0f07ca", + "reasoningEncryptedContent": null, + }, + }, + "text": "", + "type": "reasoning", + }, + { + "providerMetadata": { + "openai": { + "itemId": "msg_0365d26c32c64c650068cabb0e66b081949f66f61dacef39f3", + }, + }, + "text": "According to the document, an embedding model converts complex data (like words or images) into a dense vector — a list of numbers — called an embedding. It does not generate new text or data; instead it encodes semantic and syntactic relationships between entities so those vector representations can be used as inputs for other models or NLP tasks .", + "type": "text", + }, + { + "filename": "ai.pdf", + "id": "id-0", + "mediaType": "text/plain", + "sourceType": "document", + "title": "ai.pdf", + "type": "source", + }, +] +`; + +exports[`OpenAIResponsesLanguageModel > doGenerate > file search tool > without results include > should include file search tool call and result in content 1`] = ` +[ + { + "providerMetadata": { + "openai": { + "itemId": "rs_0a098396a8feca410068caae3b47208196957fe59419daad70", + "reasoningEncryptedContent": null, + }, + }, + "text": "", + "type": "reasoning", + }, + { + "input": "{}", + "providerExecuted": true, + "toolCallId": "fs_0a098396a8feca410068caae3cab5c8196a54fd00498464e62", + "toolName": "file_search", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "queries": [ + "What is an embedding model according to this document?", + "What is an embedding model?", + "definition of embedding model in the document", + "embedding model description", + ], + "results": null, + }, + "toolCallId": "fs_0a098396a8feca410068caae3cab5c8196a54fd00498464e62", + "toolName": "file_search", + "type": "tool-result", + }, + { + "providerMetadata": { + "openai": { + "itemId": "rs_0a098396a8feca410068caae3e21a081968e7ac588401c4a6a", + "reasoningEncryptedContent": null, + }, + }, + "text": "", + "type": "reasoning", + }, + { + "providerMetadata": { + "openai": { + "itemId": "msg_0a098396a8feca410068caae457c508196b2fcd079d1d3ec74", + }, + }, + "text": "According to the document, an embedding model is used to convert complex data (like words or images) into a dense vector (a list of numbers) representation called an embedding, which captures semantic and syntactic relationships. Unlike generative models, embedding models do not generate new text or data; instead, they provide these vector representations to be used as input for other models or other natural language processing tasks .", + "type": "text", + }, + { + "filename": "ai.pdf", + "id": "id-0", + "mediaType": "text/plain", + "sourceType": "document", + "title": "ai.pdf", + "type": "source", + }, +] +`; + +exports[`OpenAIResponsesLanguageModel > doGenerate > image generation tool > should include generate image tool call and result in content 1`] = ` +[ + { + "providerMetadata": { + "openai": { + "itemId": "rs_0a33d15155cb126d0068c96c5527808195a933b468ccb5dfd9", + "reasoningEncryptedContent": null, + }, + }, + "text": "", + "type": "reasoning", + }, + { + "input": "{}", + "providerExecuted": true, + "toolCallId": "ig_0a33d15155cb126d0068c96c59bc14819599154c9988b82996", + "toolName": "image_generation", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "result": "UklGRoitEQBXRUJQVlA4TEGzEAAv/8P/AM1AbNtGkITZhU4fH9J/wTOT+xIi+j8BuT4kABkCibNAZrlwIPyQ7W/bH5L2RHMzMBKgXmfZeYi9tLtrrQkZvN1yXHLLgG71gPkpDxmI/gc03YFulQR...AA9lhA0Y9rVdqQs/W4w/MOxeRW5+R1/UXmmNVi9yQ7x/vG0q2VRk01seZIuj5OmRYhD+yY82dZqMH1BCueTeOcNfGKxQ==", + }, + "toolCallId": "ig_0a33d15155cb126d0068c96c59bc14819599154c9988b82996", + "toolName": "image_generation", + "type": "tool-result", + }, + { + "providerMetadata": { + "openai": { + "itemId": "rs_0a33d15155cb126d0068c96c6c0ef48195bc73e30faf832ba3", + "reasoningEncryptedContent": null, + }, + }, + "text": "", + "type": "reasoning", + }, + { + "providerMetadata": { + "openai": { + "itemId": "msg_0a33d15155cb126d0068c96c723ed88195b1405bc370bb8a65", + }, + }, + "text": "", + "type": "text", + }, +] +`; + +exports[`OpenAIResponsesLanguageModel > doStream > code interpreter tool > should stream code interpreter results 1`] = ` +[ + { + "type": "stream-start", + "warnings": [], + }, + { + "id": "resp_68c2e6efa238819383d5f52a2c2a3baa02d3a5742c7ddae9", + "modelId": "gpt-5-nano-2025-08-07", + "timestamp": 2025-09-11T15:12:47.000Z, + "type": "response-metadata", + }, + { + "id": "rs_68c2e6f40ba48193a1c27abf31130e7e02d3a5742c7ddae9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e6f40ba48193a1c27abf31130e7e02d3a5742c7ddae9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_68c2e6f40ba48193a1c27abf31130e7e02d3a5742c7ddae9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e6f40ba48193a1c27abf31130e7e02d3a5742c7ddae9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "input": "{"code":"import random, math\\nN=10000\\nsums=[]\\ns=0\\nfor _ in range(N):\\n a=random.randint(1,6)\\n b=random.randint(1,6)\\n sm=a+b\\n sums.append(sm)\\n s+=sm\\nmin(sums), max(sums), sum(sums), sum(sums)/N\\n","containerId":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9"}", + "providerExecuted": true, + "toolCallId": "ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9", + "toolName": "code_interpreter", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "outputs": [ + { + "logs": "(2, 12, 69868, 6.9868)", + "type": "logs", + }, + ], + }, + "toolCallId": "ci_68c2e6f7b72c8193ba1f552552c8dc9202d3a5742c7ddae9", + "toolName": "code_interpreter", + "type": "tool-result", + }, + { + "id": "rs_68c2e6fcb52881938f21c45741216ac002d3a5742c7ddae9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e6fcb52881938f21c45741216ac002d3a5742c7ddae9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_68c2e6fcb52881938f21c45741216ac002d3a5742c7ddae9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e6fcb52881938f21c45741216ac002d3a5742c7ddae9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "input": "{"code":"import csv, pathlib\\npath = pathlib.Path('/mnt/data/roll2dice_sums_10000.csv')\\nwith open(path, 'w', newline='') as f:\\n writer = csv.writer(f)\\n writer.writerow(['sum'])\\n for val in sums:\\n writer.writerow([val])\\npath, path.exists(), len(sums)\\n","containerId":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9"}", + "providerExecuted": true, + "toolCallId": "ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9", + "toolName": "code_interpreter", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "outputs": [ + { + "logs": "(PosixPath('/mnt/data/roll2dice_sums_10000.csv'), True, 10000)", + "type": "logs", + }, + ], + }, + "toolCallId": "ci_68c2e6fd57948193aa93df6bdb00a86d02d3a5742c7ddae9", + "toolName": "code_interpreter", + "type": "tool-result", + }, + { + "id": "rs_68c2e6fff1808193a78d43410a1feb4802d3a5742c7ddae9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e6fff1808193a78d43410a1feb4802d3a5742c7ddae9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_68c2e6fff1808193a78d43410a1feb4802d3a5742c7ddae9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e6fff1808193a78d43410a1feb4802d3a5742c7ddae9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "input": "{"code":"sums[:20]\\n","containerId":"cntr_68c2e6f380d881908a57a82d394434ff02f484f5344062e9"}", + "providerExecuted": true, + "toolCallId": "ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9", + "toolName": "code_interpreter", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "outputs": [ + { + "logs": "[6, 7, 2, 5, 5, 11, 4, 8, 10, 7, 5, 8, 8, 7, 10, 8, 9, 5, 4, 7]", + "type": "logs", + }, + ], + }, + "toolCallId": "ci_68c2e701a23081939c93b6fb5bb952d302d3a5742c7ddae9", + "toolName": "code_interpreter", + "type": "tool-result", + }, + { + "id": "rs_68c2e703d114819383c5da260649c7ce02d3a5742c7ddae9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e703d114819383c5da260649c7ce02d3a5742c7ddae9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_68c2e703d114819383c5da260649c7ce02d3a5742c7ddae9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c2e703d114819383c5da260649c7ce02d3a5742c7ddae9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "providerMetadata": { + "openai": { + "itemId": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + }, + }, + "type": "text-start", + }, + { + "delta": "Here", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "’s", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " a", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " simulation", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " of", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " rolling", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " two", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " fair", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " six", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "-sided", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " dice", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "10", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "000", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " times", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ".", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " Each", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " trial", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " sums", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " the", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " two", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " dice", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ". + +", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "Results", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " +", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "-", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " Total", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " sum", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " of", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " all", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "10", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "000", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " trials", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ":", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "69", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "868", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " +", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "-", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " Average", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " sum", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " per", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " trial", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ":", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "6", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ".", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "986", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "8", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " +", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "-", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " Minimum", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " sum", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " observed", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ":", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "2", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " +", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "-", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " Maximum", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " sum", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " observed", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ":", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "12", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " +", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "-", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " Sample", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " of", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " the", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " first", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "20", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " trial", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " sums", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ":", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "6", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "7", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "2", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "5", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "5", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "11", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "4", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "8", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "10", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "7", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "5", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "8", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "8", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "7", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "10", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "8", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "9", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "5", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "4", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "7", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " + +", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "Full", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " data", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " +", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "-", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " You", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " can", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " download", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " all", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "10", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "000", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " sums", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " as", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " a", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " CSV", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " file", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " here", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ":", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " [", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "Download", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " the", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " sums", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " CSV", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "](", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "sandbox", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ":/", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "mnt", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "/data", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "/", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "roll", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "2", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "dice", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "_s", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "ums", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "_", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "100", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "00", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ".csv", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ") + +", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "If", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " you", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "’d", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " like", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " I", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " can", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " also", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " provide", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " a", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " frequency", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " distribution", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " histogram", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " or", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " export", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " the", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " data", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " in", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " another", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " format", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " (", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": "JSON", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " Excel", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": " etc", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "delta": ".).", + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-delta", + }, + { + "id": "msg_68c2e7054ae481938354ab3e4e77abad02d3a5742c7ddae9", + "type": "text-end", + }, + { + "finishReason": "stop", + "providerMetadata": { + "openai": { + "responseId": "resp_68c2e6efa238819383d5f52a2c2a3baa02d3a5742c7ddae9", + "serviceTier": "default", + }, + }, + "type": "finish", + "usage": { + "cachedInputTokens": 2944, + "inputTokens": 6047, + "outputTokens": 1623, + "reasoningTokens": 1408, + "totalTokens": 7670, + }, + }, +] +`; + +exports[`OpenAIResponsesLanguageModel > doStream > file search tool > with results include > should stream file search results 1`] = ` +[ + { + "type": "stream-start", + "warnings": [], + }, + { + "id": "resp_06456cb9918b63780068cacd710b0881a1b00b5fca56e7100b", + "modelId": "gpt-5-mini-2025-08-07", + "timestamp": 2025-09-17T15:02:09.000Z, + "type": "response-metadata", + }, + { + "id": "rs_06456cb9918b63780068cacd717c3481a1b8c7094da5770b41:0", + "providerMetadata": { + "openai": { + "itemId": "rs_06456cb9918b63780068cacd717c3481a1b8c7094da5770b41", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_06456cb9918b63780068cacd717c3481a1b8c7094da5770b41:0", + "providerMetadata": { + "openai": { + "itemId": "rs_06456cb9918b63780068cacd717c3481a1b8c7094da5770b41", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "input": "{}", + "providerExecuted": true, + "toolCallId": "fs_06456cb9918b63780068cacd74a1dc81a1bf68dd57f140b4b6", + "toolName": "file_search", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "queries": [ + "What is an embedding model according to this document?", + "What is an embedding model definition in this document?", + "How does the document define an embedding model?", + ], + "results": [ + { + "attributes": {}, + "fileId": "file-Ebzhf8H4DPGPr9pUhr7n7v", + "filename": "ai.pdf", + "score": 0.9312, + "text": "AI 1 + +AI +Generative artificial intelligence refers to models that predict and generate +various types of outputs (such as text, images, or audio) based on whatʼs +statistically likely, pulling from patterns theyʼve learned from their training data. +For example: + +Given a photo, a generative model can generate a caption. + +Given an audio file, a generative model can generate a transcription. + +Given a text description, a generative model can generate an image. + +A large language model LLM is a subset of generative models focused +primarily on text. An LLM takes a sequence of words as input and aims to +predict the most likely sequence to follow. It assigns probabilities to potential +next sequences and then selects one. The model continues to generate +sequences until it meets a specified stopping criterion. + +LLMs learn by training on massive collections of written text, which means they +will be better suited to some use cases than others. For example, a model +trained on GitHub data would understand the probabilities of sequences in +source code particularly well. + +However, it's crucial to understand LLMs' limitations. When asked about less +known or absent information, like the birthday of a personal relative, LLMs +might "hallucinate" or make up information. It's essential to consider how well- +represented the information you need is in the model. + +An embedding model is used to convert complex data (like words or images) +into a dense vector (a list of numbers) representation, known as an embedding. +Unlike generative models, embedding models do not generate new text or data. +Instead, they provide representations of semantic and synactic relationships +between entities that can be used as input for other models or other natural +language processing tasks. + +In the next section, you will learn about the difference between models +providers and models, and which ones are available in the AI SDK.", + }, + ], + }, + "toolCallId": "fs_06456cb9918b63780068cacd74a1dc81a1bf68dd57f140b4b6", + "toolName": "file_search", + "type": "tool-result", + }, + { + "id": "rs_06456cb9918b63780068cacd7663c481a191dd84333d842728:0", + "providerMetadata": { + "openai": { + "itemId": "rs_06456cb9918b63780068cacd7663c481a191dd84333d842728", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_06456cb9918b63780068cacd7663c481a191dd84333d842728:0", + "providerMetadata": { + "openai": { + "itemId": "rs_06456cb9918b63780068cacd7663c481a191dd84333d842728", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "providerMetadata": { + "openai": { + "itemId": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + }, + }, + "type": "text-start", + }, + { + "delta": "The", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " document", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " defines", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " an", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " embedding", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " model", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " as", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " a", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " tool", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " that", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " converts", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " complex", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " data", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " (", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": "e", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": ".g", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": ".,", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " words", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " or", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " images", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": ")", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " into", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " a", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " dense", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " vector", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " (", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": "a", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " list", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " of", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " numbers", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": ")", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " called", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " an", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " embedding", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": ".", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " Unlike", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " gener", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": "ative", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " models", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " embedding", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " models", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " don", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": "’t", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " generate", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " new", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " text", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " or", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " data", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": ";", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " they", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " provide", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " vector", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " representations", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " that", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " capture", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " semantic", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " and", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " synt", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": "actic", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " relationships", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " and", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " can", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " be", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " used", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " as", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " input", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " for", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " other", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " models", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " or", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " NLP", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " tasks", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "filename": "ai.pdf", + "id": "id-0", + "mediaType": "text/plain", + "sourceType": "document", + "title": "ai.pdf", + "type": "source", + }, + { + "delta": ".", + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-delta", + }, + { + "id": "msg_06456cb9918b63780068cacd7c922081a1ae15f2672a51980f", + "type": "text-end", + }, + { + "finishReason": "stop", + "providerMetadata": { + "openai": { + "responseId": "resp_06456cb9918b63780068cacd710b0881a1b00b5fca56e7100b", + "serviceTier": "default", + }, + }, + "type": "finish", + "usage": { + "cachedInputTokens": 2304, + "inputTokens": 3748, + "outputTokens": 543, + "reasoningTokens": 448, + "totalTokens": 4291, + }, + }, +] +`; + +exports[`OpenAIResponsesLanguageModel > doStream > file search tool > without results include > should stream file search results 1`] = ` +[ + { + "type": "stream-start", + "warnings": [], + }, + { + "id": "resp_0459517ad68504ad0068cabfba22b88192836339640e9a765a", + "modelId": "gpt-5-mini-2025-08-07", + "timestamp": 2025-09-17T14:03:38.000Z, + "type": "response-metadata", + }, + { + "id": "rs_0459517ad68504ad0068cabfba951881929654a05214361b35:0", + "providerMetadata": { + "openai": { + "itemId": "rs_0459517ad68504ad0068cabfba951881929654a05214361b35", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_0459517ad68504ad0068cabfba951881929654a05214361b35:0", + "providerMetadata": { + "openai": { + "itemId": "rs_0459517ad68504ad0068cabfba951881929654a05214361b35", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "input": "{}", + "providerExecuted": true, + "toolCallId": "fs_0459517ad68504ad0068cabfbd76888192a5dc4475fadabf8a", + "toolName": "file_search", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "queries": [ + "What is an embedding model according to this document?", + "What is an embedding model defined as in the document?", + "definition of embedding model", + ], + "results": null, + }, + "toolCallId": "fs_0459517ad68504ad0068cabfbd76888192a5dc4475fadabf8a", + "toolName": "file_search", + "type": "tool-result", + }, + { + "id": "rs_0459517ad68504ad0068cabfbf337881929cf5266be7a008a9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_0459517ad68504ad0068cabfbf337881929cf5266be7a008a9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_0459517ad68504ad0068cabfbf337881929cf5266be7a008a9:0", + "providerMetadata": { + "openai": { + "itemId": "rs_0459517ad68504ad0068cabfbf337881929cf5266be7a008a9", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "providerMetadata": { + "openai": { + "itemId": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + }, + }, + "type": "text-start", + }, + { + "delta": "According", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " to", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " the", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " document", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " an", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " embedding", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " model", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " converts", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " complex", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " data", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " (", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": "e", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": ".g", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": ".,", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " words", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " or", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " images", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": ")", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " into", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " a", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " dense", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " vector", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " —", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " a", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " list", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " of", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " numbers", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " —", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " called", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " an", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " embedding", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "filename": "ai.pdf", + "id": "id-0", + "mediaType": "text/plain", + "sourceType": "document", + "title": "ai.pdf", + "type": "source", + }, + { + "delta": ".", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " Unlike", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " gener", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": "ative", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " models", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": ",", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " embedding", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " models", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " do", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " not", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " generate", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " new", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " text", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " or", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " data", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": ";", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " instead", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " they", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " produce", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " vector", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " representations", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " that", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " capture", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " semantic", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " and", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " synt", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": "actic", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " relationships", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " and", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " can", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " be", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " used", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " as", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " input", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " for", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " other", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " models", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " or", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " NLP", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " tasks", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "delta": " ", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "filename": "ai.pdf", + "id": "id-1", + "mediaType": "text/plain", + "sourceType": "document", + "title": "ai.pdf", + "type": "source", + }, + { + "delta": ".", + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-delta", + }, + { + "id": "msg_0459517ad68504ad0068cabfc6b5c48192a15ac773668537f1", + "type": "text-end", + }, + { + "finishReason": "stop", + "providerMetadata": { + "openai": { + "responseId": "resp_0459517ad68504ad0068cabfba22b88192836339640e9a765a", + "serviceTier": "default", + }, + }, + "type": "finish", + "usage": { + "cachedInputTokens": 2304, + "inputTokens": 3737, + "outputTokens": 621, + "reasoningTokens": 512, + "totalTokens": 4358, + }, + }, +] +`; + +exports[`OpenAIResponsesLanguageModel > doStream > image generation tool > should stream code image generation results 1`] = ` +[ + { + "type": "stream-start", + "warnings": [], + }, + { + "id": "resp_0df93c0bb83a72f20068c979db26ac819e8b5a444fad3f0d7f", + "modelId": "gpt-5-2025-08-07", + "timestamp": 2025-09-16T14:53:15.000Z, + "type": "response-metadata", + }, + { + "id": "rs_0df93c0bb83a72f20068c979db90b4819e94cedbfda2d49af6:0", + "providerMetadata": { + "openai": { + "itemId": "rs_0df93c0bb83a72f20068c979db90b4819e94cedbfda2d49af6", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_0df93c0bb83a72f20068c979db90b4819e94cedbfda2d49af6:0", + "providerMetadata": { + "openai": { + "itemId": "rs_0df93c0bb83a72f20068c979db90b4819e94cedbfda2d49af6", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "input": "{}", + "providerExecuted": true, + "toolCallId": "ig_0df93c0bb83a72f20068c979f589c0819e9f0fc2d1a27aa1b8", + "toolName": "image_generation", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "result": "UklGRuIWGQBXRUJQVlA4TKAwGAAv/8X/ABlJbiNJkgRDwkID67D/P9gjl9nuEf2fgPyZzj1Jyu97SlIDX5iPbDv2F3U/+UU+JIlr+wVtEwKO7xiJ7dh26zu3NgZIasDGMcSYOIltx8MpJGFWJAaDE8g4AzhJzCAkCedAeJ17KsRCTxd5r4c1SfLsHwzwZ/2/f67rukb7R1yzavfWH3mdtqpvK4HU00+v2a1qb/...AAAPZYQFuWuM6Be+taQrxy8eMnvFntuAhnHLJbzoq1L9GGMdWs/9hArxYpBl4GS+zJ3eoEsBEkmxChF9k+m5HNgnA2uzI=", + }, + "toolCallId": "ig_0df93c0bb83a72f20068c979f589c0819e9f0fc2d1a27aa1b8", + "toolName": "image_generation", + "type": "tool-result", + }, + { + "id": "msg_0df93c0bb83a72f20068c97a0b36f4819ea5906451007f95e2", + "providerMetadata": { + "openai": { + "itemId": "msg_0df93c0bb83a72f20068c97a0b36f4819ea5906451007f95e2", + }, + }, + "type": "text-start", + }, + { + "id": "msg_0df93c0bb83a72f20068c97a0b36f4819ea5906451007f95e2", + "type": "text-end", + }, + { + "finishReason": "stop", + "providerMetadata": { + "openai": { + "responseId": "resp_0df93c0bb83a72f20068c979db26ac819e8b5a444fad3f0d7f", + "serviceTier": "default", + }, + }, + "type": "finish", + "usage": { + "cachedInputTokens": 1920, + "inputTokens": 2941, + "outputTokens": 1249, + "reasoningTokens": 1024, + "totalTokens": 4190, + }, + }, +] +`; diff --git a/packages/openai/src/responses/convert-to-openai-responses-messages.test.ts b/packages/openai/src/responses/convert-to-openai-responses-input.test.ts similarity index 86% rename from packages/openai/src/responses/convert-to-openai-responses-messages.test.ts rename to packages/openai/src/responses/convert-to-openai-responses-input.test.ts index 65133229f32f..442fedf420a3 100644 --- a/packages/openai/src/responses/convert-to-openai-responses-messages.test.ts +++ b/packages/openai/src/responses/convert-to-openai-responses-input.test.ts @@ -1,41 +1,42 @@ -import { convertToOpenAIResponsesMessages } from './convert-to-openai-responses-messages'; +import { convertToOpenAIResponsesInput } from './convert-to-openai-responses-input'; import { describe, it, expect } from 'vitest'; -describe('convertToOpenAIResponsesMessages', () => { +describe('convertToOpenAIResponsesInput', () => { describe('system messages', () => { it('should convert system messages to system role', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [{ role: 'system', content: 'Hello' }], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([{ role: 'system', content: 'Hello' }]); + expect(result.input).toEqual([{ role: 'system', content: 'Hello' }]); }); it('should convert system messages to developer role', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [{ role: 'system', content: 'Hello' }], systemMessageMode: 'developer', + store: true, }); - expect(result.messages).toEqual([ - { role: 'developer', content: 'Hello' }, - ]); + expect(result.input).toEqual([{ role: 'developer', content: 'Hello' }]); }); it('should remove system messages', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [{ role: 'system', content: 'Hello' }], systemMessageMode: 'remove', + store: true, }); - expect(result.messages).toEqual([]); + expect(result.input).toEqual([]); }); }); describe('user messages', () => { it('should convert messages with only a text part to a string content', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -43,15 +44,16 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [{ type: 'input_text', text: 'Hello' }] }, ]); }); it('should convert messages with image parts using URL', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -66,9 +68,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -83,7 +86,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert messages with image parts using binary data', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -97,9 +100,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -113,7 +117,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert messages with image parts using Uint8Array', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -127,9 +131,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -143,7 +148,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert messages with image parts using file_id', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -158,9 +163,10 @@ describe('convertToOpenAIResponsesMessages', () => { ], systemMessageMode: 'system', fileIdPrefixes: ['file-'], + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -174,7 +180,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should use default mime type for binary images', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -188,9 +194,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -204,7 +211,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should add image detail when specified through extension', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -223,9 +230,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -242,7 +250,7 @@ describe('convertToOpenAIResponsesMessages', () => { it('should convert messages with PDF file parts', async () => { const base64Data = 'AQIDBAU='; // Base64 encoding of pdfData - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -257,9 +265,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -274,7 +283,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert messages with PDF file parts using file_id', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -289,9 +298,10 @@ describe('convertToOpenAIResponsesMessages', () => { ], systemMessageMode: 'system', fileIdPrefixes: ['file-'], + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -307,7 +317,7 @@ describe('convertToOpenAIResponsesMessages', () => { it('should use default filename for PDF file parts when not provided', async () => { const base64Data = 'AQIDBAU='; - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -321,9 +331,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -341,7 +352,7 @@ describe('convertToOpenAIResponsesMessages', () => { const base64Data = 'AQIDBAU='; await expect( - convertToOpenAIResponsesMessages({ + convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -355,12 +366,13 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }), ).rejects.toThrow('file part media type text/plain'); }); it('should convert PDF file parts with URL to input_file with file_url', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -374,9 +386,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -391,7 +404,7 @@ describe('convertToOpenAIResponsesMessages', () => { describe('Azure OpenAI file ID support', () => { it('should convert image parts with assistant- prefix', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -406,9 +419,10 @@ describe('convertToOpenAIResponsesMessages', () => { ], systemMessageMode: 'system', fileIdPrefixes: ['assistant-'], + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -422,7 +436,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert PDF parts with assistant- prefix', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -437,9 +451,10 @@ describe('convertToOpenAIResponsesMessages', () => { ], systemMessageMode: 'system', fileIdPrefixes: ['assistant-'], + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -453,7 +468,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should support multiple file ID prefixes', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -473,9 +488,10 @@ describe('convertToOpenAIResponsesMessages', () => { ], systemMessageMode: 'system', fileIdPrefixes: ['assistant-', 'file-'], + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -495,7 +511,7 @@ describe('convertToOpenAIResponsesMessages', () => { describe('fileIdPrefixes undefined behavior', () => { it('should treat all file data as base64 when fileIdPrefixes is undefined', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -516,9 +532,10 @@ describe('convertToOpenAIResponsesMessages', () => { ], systemMessageMode: 'system', // fileIdPrefixes intentionally omitted + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -537,7 +554,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should handle empty fileIdPrefixes array', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -552,9 +569,10 @@ describe('convertToOpenAIResponsesMessages', () => { ], systemMessageMode: 'system', fileIdPrefixes: [], // Empty array should disable file ID detection + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [ @@ -571,14 +589,15 @@ describe('convertToOpenAIResponsesMessages', () => { describe('assistant messages', () => { it('should convert messages with only a text part to a string content', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', content: [{ type: 'text', text: 'Hello' }] }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'assistant', content: [{ type: 'output_text', text: 'Hello' }], @@ -587,7 +606,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert messages with tool call parts', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -603,9 +622,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'assistant', content: [ @@ -625,7 +645,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert messages with tool call parts that have ids', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -654,9 +674,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toMatchInlineSnapshot(` + expect(result.input).toMatchInlineSnapshot(` [ { "content": [ @@ -680,7 +701,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert multiple tool call parts in a single message', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -701,9 +722,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'function_call', call_id: 'call_123', @@ -722,7 +744,7 @@ describe('convertToOpenAIResponsesMessages', () => { describe('reasoning messages', () => { describe('basic conversion', () => { it('should convert single reasoning part with text', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -740,9 +762,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'reasoning', id: 'reasoning_001', @@ -760,7 +783,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert single reasoning part with encrypted content', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -779,9 +802,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'reasoning', id: 'reasoning_001', @@ -799,7 +823,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert single reasoning part with null encrypted content', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -818,9 +842,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'reasoning', id: 'reasoning_001', @@ -840,7 +865,7 @@ describe('convertToOpenAIResponsesMessages', () => { describe('empty text handling', () => { it('should create empty summary for initial empty text', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -858,9 +883,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'reasoning', id: 'reasoning_001', @@ -873,7 +899,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should create empty summary for initial empty text with encrypted content', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -892,9 +918,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'reasoning', id: 'reasoning_001', @@ -907,7 +934,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should warn when appending empty text to existing sequence', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -934,9 +961,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'reasoning', id: 'reasoning_001', @@ -963,7 +991,7 @@ describe('convertToOpenAIResponsesMessages', () => { describe('merging and sequencing', () => { it('should merge consecutive parts with same reasoning ID', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -990,9 +1018,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'reasoning', id: 'reasoning_001', @@ -1014,7 +1043,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should create separate messages for different reasoning IDs', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -1041,9 +1070,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'reasoning', id: 'reasoning_001', @@ -1072,7 +1102,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should handle reasoning across multiple assistant messages', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'user', @@ -1123,9 +1153,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { role: 'user', content: [{ type: 'input_text', text: 'First user question' }], @@ -1174,7 +1205,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should handle complex reasoning sequences with tool interactions', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -1294,9 +1325,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ // First reasoning block (2 parts merged) { type: 'reasoning', @@ -1377,7 +1409,7 @@ describe('convertToOpenAIResponsesMessages', () => { describe('error handling', () => { it('should warn when reasoning part has no provider options', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -1390,9 +1422,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toHaveLength(0); + expect(result.input).toHaveLength(0); expect(result.warnings).toMatchInlineSnapshot(` [ @@ -1405,7 +1438,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should warn when reasoning part lacks OpenAI-specific reasoning ID provider options', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -1425,9 +1458,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toHaveLength(0); + expect(result.input).toHaveLength(0); expect(result.warnings).toMatchInlineSnapshot(` [ @@ -1444,7 +1478,7 @@ describe('convertToOpenAIResponsesMessages', () => { describe('tool messages', () => { it('should convert tool result parts', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'tool', @@ -1462,9 +1496,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'function_call_output', call_id: 'call_123', @@ -1474,7 +1509,7 @@ describe('convertToOpenAIResponsesMessages', () => { }); it('should convert multiple tool result parts in a single message', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'tool', @@ -1498,9 +1533,10 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); - expect(result.messages).toEqual([ + expect(result.input).toEqual([ { type: 'function_call_output', call_id: 'call_123', @@ -1515,9 +1551,52 @@ describe('convertToOpenAIResponsesMessages', () => { }); }); - describe('provider-executed tool calls', () => { - it('should exclude provider-executed tool calls and results from prompt', async () => { - const result = await convertToOpenAIResponsesMessages({ + describe('provider-executed tools', () => { + it('should convert single provider-executed tool call and result into item reference with store: true', async () => { + const result = await convertToOpenAIResponsesInput({ + prompt: [ + { + role: 'assistant', + content: [ + { + input: { code: 'example code', containerId: 'container_123' }, + providerExecuted: true, + toolCallId: + 'ci_68c2e2cf522c81908f3e2c1bccd1493b0b24aae9c6c01e4f', + toolName: 'code_interpreter', + type: 'tool-call', + }, + { + output: { + type: 'json', + value: { + outputs: [{ type: 'logs', logs: 'example logs' }], + }, + }, + toolCallId: + 'ci_68c2e2cf522c81908f3e2c1bccd1493b0b24aae9c6c01e4f', + toolName: 'code_interpreter', + type: 'tool-result', + }, + ], + }, + ], + systemMessageMode: 'system', + store: true, + }); + + expect(result.input).toMatchInlineSnapshot(` + [ + { + "id": "ci_68c2e2cf522c81908f3e2c1bccd1493b0b24aae9c6c01e4f", + "type": "item_reference", + }, + ] + `); + }); + + it('should exclude provider-executed tool calls and results from prompt with store: false', async () => { + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -1529,7 +1608,7 @@ describe('convertToOpenAIResponsesMessages', () => { { type: 'tool-call', toolCallId: 'ws_67cf2b3051e88190b006770db6fdb13d', - toolName: 'web_search_preview', + toolName: 'web_search', input: { query: 'San Francisco major news events June 22 2025', }, @@ -1538,7 +1617,7 @@ describe('convertToOpenAIResponsesMessages', () => { { type: 'tool-result', toolCallId: 'ws_67cf2b3051e88190b006770db6fdb13d', - toolName: 'web_search_preview', + toolName: 'web_search', output: { type: 'json', value: [ @@ -1556,11 +1635,12 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: false, }); expect(result).toMatchInlineSnapshot(` { - "messages": [ + "input": [ { "content": [ { @@ -1584,16 +1664,18 @@ describe('convertToOpenAIResponsesMessages', () => { ], "warnings": [ { - "message": "tool result parts in assistant messages are not supported for OpenAI responses", + "message": "Results for OpenAI tool web_search are not sent to the API when store is false", "type": "other", }, ], } `); }); + }); + describe('function tools', () => { it('should include client-side tool calls in prompt', async () => { - const result = await convertToOpenAIResponsesMessages({ + const result = await convertToOpenAIResponsesInput({ prompt: [ { role: 'assistant', @@ -1609,11 +1691,12 @@ describe('convertToOpenAIResponsesMessages', () => { }, ], systemMessageMode: 'system', + store: true, }); expect(result).toMatchInlineSnapshot(` { - "messages": [ + "input": [ { "arguments": "{"a":1,"b":2}", "call_id": "call-1", diff --git a/packages/openai/src/responses/convert-to-openai-responses-messages.ts b/packages/openai/src/responses/convert-to-openai-responses-input.ts similarity index 86% rename from packages/openai/src/responses/convert-to-openai-responses-messages.ts rename to packages/openai/src/responses/convert-to-openai-responses-input.ts index 12dc8eb957f2..64b18cd8577b 100644 --- a/packages/openai/src/responses/convert-to-openai-responses-messages.ts +++ b/packages/openai/src/responses/convert-to-openai-responses-input.ts @@ -1,15 +1,15 @@ import { LanguageModelV2CallWarning, LanguageModelV2Prompt, + LanguageModelV2ToolCallPart, UnsupportedFunctionalityError, } from '@ai-sdk/provider'; -import { parseProviderOptions } from '@ai-sdk/provider-utils'; +import { convertToBase64, parseProviderOptions } from '@ai-sdk/provider-utils'; import { z } from 'zod/v4'; import { - OpenAIResponsesPrompt, + OpenAIResponsesInput, OpenAIResponsesReasoning, } from './openai-responses-api-types'; -import { convertToBase64 } from '@ai-sdk/provider-utils'; /** * Check if a string is a file ID based on the given prefixes @@ -20,19 +20,21 @@ function isFileId(data: string, prefixes?: readonly string[]): boolean { return prefixes.some(prefix => data.startsWith(prefix)); } -export async function convertToOpenAIResponsesMessages({ +export async function convertToOpenAIResponsesInput({ prompt, systemMessageMode, fileIdPrefixes, + store, }: { prompt: LanguageModelV2Prompt; systemMessageMode: 'system' | 'developer' | 'remove'; fileIdPrefixes?: readonly string[]; + store: boolean; }): Promise<{ - messages: OpenAIResponsesPrompt; + input: OpenAIResponsesInput; warnings: Array; }> { - const messages: OpenAIResponsesPrompt = []; + const input: OpenAIResponsesInput = []; const warnings: Array = []; for (const { role, content } of prompt) { @@ -40,11 +42,11 @@ export async function convertToOpenAIResponsesMessages({ case 'system': { switch (systemMessageMode) { case 'system': { - messages.push({ role: 'system', content }); + input.push({ role: 'system', content }); break; } case 'developer': { - messages.push({ role: 'developer', content }); + input.push({ role: 'developer', content }); break; } case 'remove': { @@ -65,7 +67,7 @@ export async function convertToOpenAIResponsesMessages({ } case 'user': { - messages.push({ + input.push({ role: 'user', content: content.map((part, index) => { switch (part.type) { @@ -123,11 +125,12 @@ export async function convertToOpenAIResponsesMessages({ case 'assistant': { const reasoningMessages: Record = {}; + const toolCallParts: Record = {}; for (const part of content) { switch (part.type) { case 'text': { - messages.push({ + input.push({ role: 'assistant', content: [{ type: 'output_text', text: part.text }], id: @@ -136,11 +139,13 @@ export async function convertToOpenAIResponsesMessages({ break; } case 'tool-call': { + toolCallParts[part.toolCallId] = part; + if (part.providerExecuted) { break; } - messages.push({ + input.push({ type: 'function_call', call_id: part.toolCallId, name: part.toolName, @@ -151,11 +156,18 @@ export async function convertToOpenAIResponsesMessages({ break; } + // assistant tool result parts are from provider-executed tools: case 'tool-result': { - warnings.push({ - type: 'other', - message: `tool result parts in assistant messages are not supported for OpenAI responses`, - }); + if (store) { + // use item references to refer to tool results from built-in tools + input.push({ type: 'item_reference', id: part.toolCallId }); + } else { + warnings.push({ + type: 'other', + message: `Results for OpenAI tool ${part.toolName} are not sent to the API when store is false`, + }); + } + break; } @@ -193,7 +205,7 @@ export async function convertToOpenAIResponsesMessages({ providerOptions?.reasoningEncryptedContent, summary: summaryParts, }; - messages.push(reasoningMessages[reasoningId]); + input.push(reasoningMessages[reasoningId]); } else { existingReasoningMessage.summary.push(...summaryParts); } @@ -228,7 +240,7 @@ export async function convertToOpenAIResponsesMessages({ break; } - messages.push({ + input.push({ type: 'function_call_output', call_id: part.toolCallId, output: contentValue, @@ -245,7 +257,7 @@ export async function convertToOpenAIResponsesMessages({ } } - return { messages, warnings }; + return { input, warnings }; } const openaiResponsesReasoningProviderOptionsSchema = z.object({ diff --git a/packages/openai/src/responses/openai-responses-api-types.ts b/packages/openai/src/responses/openai-responses-api-types.ts index d1a9cea559f5..a9094bd21e68 100644 --- a/packages/openai/src/responses/openai-responses-api-types.ts +++ b/packages/openai/src/responses/openai-responses-api-types.ts @@ -1,17 +1,30 @@ import { JSONSchema7 } from '@ai-sdk/provider'; -export type OpenAIResponsesPrompt = Array; +export type OpenAIResponsesInput = Array; -export type OpenAIResponsesMessage = +export type OpenAIResponsesInputItem = | OpenAIResponsesSystemMessage | OpenAIResponsesUserMessage | OpenAIResponsesAssistantMessage | OpenAIResponsesFunctionCall | OpenAIResponsesFunctionCallOutput - | OpenAIWebSearchCall - | OpenAIComputerCall - | OpenAIFileSearchCall - | OpenAIResponsesReasoning; + | OpenAIResponsesComputerCall + | OpenAIResponsesReasoning + | OpenAIResponsesItemReference; + +export type OpenAIResponsesIncludeValue = + | 'web_search_call.action.sources' + | 'code_interpreter_call.outputs' + | 'computer_call_output.output.image_url' + | 'file_search_call.results' + | 'message.input_image.image_url' + | 'message.output_text.logprobs' + | 'reasoning.encrypted_content'; + +export type OpenAIResponsesIncludeOptions = + | Array + | undefined + | null; export type OpenAIResponsesSystemMessage = { role: 'system' | 'developer'; @@ -32,12 +45,7 @@ export type OpenAIResponsesUserMessage = { export type OpenAIResponsesAssistantMessage = { role: 'assistant'; - content: Array< - | { type: 'output_text'; text: string } - | OpenAIWebSearchCall - | OpenAIComputerCall - | OpenAIFileSearchCall - >; + content: Array<{ type: 'output_text'; text: string }>; id?: string; }; @@ -55,22 +63,53 @@ export type OpenAIResponsesFunctionCallOutput = { output: string; }; -export type OpenAIWebSearchCall = { - type: 'web_search_call'; +export type OpenAIResponsesComputerCall = { + type: 'computer_call'; id: string; status?: string; }; -export type OpenAIComputerCall = { - type: 'computer_call'; +export type OpenAIResponsesItemReference = { + type: 'item_reference'; id: string; - status?: string; }; -export type OpenAIFileSearchCall = { - type: 'file_search_call'; - id: string; - status?: string; +/** + * A filter used to compare a specified attribute key to a given value using a defined comparison operation. + */ +export type OpenAIResponsesFileSearchToolComparisonFilter = { + /** + * The key to compare against the value. + */ + key: string; + + /** + * Specifies the comparison operator: eq, ne, gt, gte, lt, lte. + */ + type: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte'; + + /** + * The value to compare against the attribute key; supports string, number, or boolean types. + */ + value: string | number | boolean; +}; + +/** + * Combine multiple filters using and or or. + */ +export type OpenAIResponsesFileSearchToolCompoundFilter = { + /** + * Type of operation: and or or. + */ + type: 'and' | 'or'; + + /** + * Array of filters to combine. Items can be ComparisonFilter or CompoundFilter. + */ + filters: Array< + | OpenAIResponsesFileSearchToolComparisonFilter + | OpenAIResponsesFileSearchToolCompoundFilter + >; }; export type OpenAIResponsesTool = @@ -79,13 +118,11 @@ export type OpenAIResponsesTool = name: string; description: string | undefined; parameters: JSONSchema7; - strict?: boolean; + strict: boolean | undefined; } | { type: 'web_search'; - filters?: { - allowed_domains?: string[]; - }; + filters: { allowed_domains: string[] | undefined } | undefined; search_context_size: 'low' | 'medium' | 'high' | undefined; user_location: | { @@ -116,21 +153,32 @@ export type OpenAIResponsesTool = } | { type: 'file_search'; - vector_store_ids?: string[]; - max_num_results?: number; - ranking_options?: { - ranker?: 'auto' | 'default-2024-08-21'; - }; - filters?: + vector_store_ids: string[]; + max_num_results: number | undefined; + ranking_options: + | { ranker?: string; score_threshold?: number } + | undefined; + filters: + | OpenAIResponsesFileSearchToolComparisonFilter + | OpenAIResponsesFileSearchToolCompoundFilter + | undefined; + } + | { + type: 'image_generation'; + background: 'auto' | 'opaque' | 'transparent' | undefined; + input_fidelity: 'low' | 'high' | undefined; + input_image_mask: | { - key: string; - type: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte'; - value: string | number | boolean; + file_id: string | undefined; + image_url: string | undefined; } - | { - type: 'and' | 'or'; - filters: any[]; - }; + | undefined; + model: string | undefined; + moderation: 'auto' | undefined; + output_compression: number | undefined; + output_format: 'png' | 'jpeg' | 'webp' | undefined; + quality: 'auto' | 'low' | 'medium' | 'high' | undefined; + size: 'auto' | '1024x1024' | '1024x1536' | '1536x1024' | undefined; }; export type OpenAIResponsesReasoning = { diff --git a/packages/openai/src/responses/openai-responses-language-model.test.ts b/packages/openai/src/responses/openai-responses-language-model.test.ts index 22dd1d93ff64..65c6d27a754e 100644 --- a/packages/openai/src/responses/openai-responses-language-model.test.ts +++ b/packages/openai/src/responses/openai-responses-language-model.test.ts @@ -1,18 +1,20 @@ import { + LanguageModelV2, LanguageModelV2FunctionTool, LanguageModelV2Prompt, } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, mockId, } from '@ai-sdk/provider-utils/test'; +import fs from 'node:fs'; +import { beforeEach, describe, expect, it } from 'vitest'; import { OpenAIResponsesLanguageModel } from './openai-responses-language-model'; import { openaiResponsesModelIds, openaiResponsesReasoningModelIds, } from './openai-responses-settings'; -import { beforeEach, describe, expect, it } from 'vitest'; const TEST_PROMPT: LanguageModelV2Prompt = [ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, @@ -63,6 +65,29 @@ describe('OpenAIResponsesLanguageModel', () => { 'https://api.openai.com/v1/responses': {}, }); + function prepareJsonFixtureResponse(filename: string) { + server.urls['https://api.openai.com/v1/responses'].response = { + type: 'json-value', + body: JSON.parse( + fs.readFileSync(`src/responses/__fixtures__/${filename}.json`, 'utf8'), + ), + }; + return; + } + + function prepareChunksFixtureResponse(filename: string) { + const chunks = fs + .readFileSync(`src/responses/__fixtures__/${filename}.chunks.txt`, 'utf8') + .split('\n') + .map(line => `data: ${line}\n\n`); + chunks.push('data: [DONE]\n\n'); + + server.urls['https://api.openai.com/v1/responses'].response = { + type: 'stream-chunks', + chunks, + }; + } + describe('doGenerate', () => { function prepareJsonResponse(body: any) { server.urls['https://api.openai.com/v1/responses'].response = { @@ -188,17 +213,36 @@ describe('OpenAIResponsesLanguageModel', () => { ], temperature: 0.5, topP: 0.3, + providerOptions: { + openai: { + maxToolCalls: 10, + }, + }, }); - expect(await server.calls[0].requestBodyJson).toStrictEqual({ - model: 'gpt-4o', - temperature: 0.5, - top_p: 0.3, - input: [ - { role: 'system', content: 'You are a helpful assistant.' }, - { role: 'user', content: [{ type: 'input_text', text: 'Hello' }] }, - ], - }); + expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` + { + "input": [ + { + "content": "You are a helpful assistant.", + "role": "system", + }, + { + "content": [ + { + "text": "Hello", + "type": "input_text", + }, + ], + "role": "user", + }, + ], + "max_tool_calls": 10, + "model": "gpt-4o", + "temperature": 0.5, + "top_p": 0.3, + } + `); expect(warnings).toStrictEqual([]); }); @@ -596,27 +640,6 @@ describe('OpenAIResponsesLanguageModel', () => { expect(warnings).toStrictEqual([]); }); - it('should send include provider option for file search results', async () => { - const { warnings } = await createModel('gpt-4o-mini').doGenerate({ - prompt: TEST_PROMPT, - providerOptions: { - openai: { - include: ['file_search_call.results'], - }, - }, - }); - - expect(await server.calls[0].requestBodyJson).toStrictEqual({ - model: 'gpt-4o-mini', - input: [ - { role: 'user', content: [{ type: 'input_text', text: 'Hello' }] }, - ], - include: ['file_search_call.results'], - }); - - expect(warnings).toStrictEqual([]); - }); - it('should send include provider option with multiple values', async () => { const { warnings } = await createModel('o3-mini').doGenerate({ prompt: TEST_PROMPT, @@ -929,425 +952,151 @@ describe('OpenAIResponsesLanguageModel', () => { expect(warnings).toStrictEqual([]); }); - it('should send web_search tool', async () => { + it('should warn about unsupported settings', async () => { const { warnings } = await createModel('gpt-4o').doGenerate({ - tools: [ - { - type: 'provider-defined', - id: 'openai.web_search_preview', - name: 'web_search_preview', - args: { - searchContextSize: 'high', - userLocation: { - type: 'approximate', - city: 'San Francisco', - }, - }, - }, - ], prompt: TEST_PROMPT, + stopSequences: ['\n\n'], + topK: 0.1, + presencePenalty: 0, + frequencyPenalty: 0, + seed: 42, }); - expect(await server.calls[0].requestBodyJson).toStrictEqual({ - model: 'gpt-4o', - tools: [ - { - type: 'web_search_preview', - search_context_size: 'high', - user_location: { type: 'approximate', city: 'San Francisco' }, - }, - ], - input: [ - { role: 'user', content: [{ type: 'input_text', text: 'Hello' }] }, - ], - }); - - expect(warnings).toStrictEqual([]); + expect(warnings).toStrictEqual([ + { type: 'unsupported-setting', setting: 'topK' }, + { type: 'unsupported-setting', setting: 'seed' }, + { type: 'unsupported-setting', setting: 'presencePenalty' }, + { type: 'unsupported-setting', setting: 'frequencyPenalty' }, + { type: 'unsupported-setting', setting: 'stopSequences' }, + ]); }); - it('should send web_search tool as tool_choice', async () => { - const { warnings } = await createModel('gpt-4o').doGenerate({ - toolChoice: { - type: 'tool', - toolName: 'web_search_preview', - }, - tools: [ + it('should extract logprobs in providerMetadata', async () => { + prepareJsonResponse({ + id: 'resp_67c97c0203188190a025beb4a75242bc', + object: 'response', + created_at: 1741257730, + status: 'completed', + error: null, + incomplete_details: null, + input: [], + instructions: null, + max_output_tokens: null, + model: 'gpt-4o-2024-07-18', + output: [ { - type: 'provider-defined', - id: 'openai.web_search_preview', - name: 'web_search_preview', - args: { - searchContextSize: 'high', - userLocation: { - type: 'approximate', - city: 'San Francisco', + id: 'msg_67c97c02656c81908e080dfdf4a03cd1', + type: 'message', + status: 'completed', + role: 'assistant', + content: [ + { + type: 'output_text', + text: 'answer text', + annotations: [], + logprobs: [ + { + token: 'Hello', + logprob: -0.0009994634, + top_logprobs: [ + { + token: 'Hello', + logprob: -0.0009994634, + }, + { + token: 'Hi', + logprob: -0.2, + }, + ], + }, + { + token: '!', + logprob: -0.13410144, + top_logprobs: [ + { + token: '!', + logprob: -0.13410144, + }, + ], + }, + ], }, - }, + ], }, ], - prompt: TEST_PROMPT, - }); - - expect(await server.calls[0].requestBodyJson).toStrictEqual({ - model: 'gpt-4o', - tool_choice: { type: 'web_search_preview' }, - tools: [ - { - type: 'web_search_preview', - search_context_size: 'high', - user_location: { type: 'approximate', city: 'San Francisco' }, + parallel_tool_calls: true, + previous_response_id: null, + reasoning: { + effort: null, + summary: null, + }, + store: true, + temperature: 1, + text: { + format: { + type: 'text', }, - ], - input: [ - { role: 'user', content: [{ type: 'input_text', text: 'Hello' }] }, - ], + }, + tool_choice: 'auto', + tools: [], + top_p: 1, + truncation: 'disabled', + usage: { + input_tokens: 345, + input_tokens_details: { + cached_tokens: 234, + }, + output_tokens: 538, + output_tokens_details: { + reasoning_tokens: 123, + }, + total_tokens: 572, + }, + user: null, + metadata: {}, }); - expect(warnings).toStrictEqual([]); - }); - - it('should send file_search tool', async () => { - const { warnings } = await createModel('gpt-4o').doGenerate({ - tools: [ - { - type: 'provider-defined', - id: 'openai.file_search', - name: 'file_search', - args: { - vectorStoreIds: ['vs_123', 'vs_456'], - maxNumResults: 10, - ranking: { - ranker: 'auto', - }, - }, - }, - ], + const result = await createModel('gpt-4o').doGenerate({ prompt: TEST_PROMPT, + providerOptions: { + openai: { + logprobs: 2, + }, + }, }); - expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` - { - "input": [ + expect(result.providerMetadata?.openai.logprobs).toMatchInlineSnapshot(` + [ + [ { - "content": [ + "logprob": -0.0009994634, + "token": "Hello", + "top_logprobs": [ { - "text": "Hello", - "type": "input_text", + "logprob": -0.0009994634, + "token": "Hello", + }, + { + "logprob": -0.2, + "token": "Hi", }, ], - "role": "user", }, - ], - "model": "gpt-4o", - "tools": [ { - "max_num_results": 10, - "ranking_options": { - "ranker": "auto", - }, - "type": "file_search", - "vector_store_ids": [ - "vs_123", - "vs_456", + "logprob": -0.13410144, + "token": "!", + "top_logprobs": [ + { + "logprob": -0.13410144, + "token": "!", + }, ], }, ], - } + ] `); - - expect(warnings).toStrictEqual([]); }); - - it('should send file_search tool as tool_choice', async () => { - const { warnings } = await createModel('gpt-4o').doGenerate({ - toolChoice: { - type: 'tool', - toolName: 'file_search', - }, - tools: [ - { - type: 'provider-defined', - id: 'openai.file_search', - name: 'file_search', - args: { - vectorStoreIds: ['vs_789'], - maxNumResults: 5, - }, - }, - ], - prompt: TEST_PROMPT, - }); - - expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` - { - "input": [ - { - "content": [ - { - "text": "Hello", - "type": "input_text", - }, - ], - "role": "user", - }, - ], - "model": "gpt-4o", - "tool_choice": { - "type": "file_search", - }, - "tools": [ - { - "max_num_results": 5, - "type": "file_search", - "vector_store_ids": [ - "vs_789", - ], - }, - ], - } - `); - - expect(warnings).toStrictEqual([]); - }); - - it('should send file_search tool with filters', async () => { - const { warnings } = await createModel('gpt-4o').doGenerate({ - tools: [ - { - type: 'provider-defined', - id: 'openai.file_search', - name: 'file_search', - args: { - vectorStoreIds: ['vs_123'], - maxNumResults: 5, - filters: { - key: 'author', - type: 'eq', - value: 'Jane Smith', - }, - }, - }, - ], - prompt: TEST_PROMPT, - }); - - expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` - { - "input": [ - { - "content": [ - { - "text": "Hello", - "type": "input_text", - }, - ], - "role": "user", - }, - ], - "model": "gpt-4o", - "tools": [ - { - "filters": { - "key": "author", - "type": "eq", - "value": "Jane Smith", - }, - "max_num_results": 5, - "type": "file_search", - "vector_store_ids": [ - "vs_123", - ], - }, - ], - } - `); - - expect(warnings).toStrictEqual([]); - }); - - it('should send file_search tool with minimal args', async () => { - const { warnings } = await createModel('gpt-4o').doGenerate({ - tools: [ - { - type: 'provider-defined', - id: 'openai.file_search', - name: 'file_search', - args: {}, - }, - ], - prompt: TEST_PROMPT, - }); - - expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` - { - "input": [ - { - "content": [ - { - "text": "Hello", - "type": "input_text", - }, - ], - "role": "user", - }, - ], - "model": "gpt-4o", - "tools": [ - { - "type": "file_search", - }, - ], - } - `); - - expect(warnings).toStrictEqual([]); - }); - - it('should warn about unsupported settings', async () => { - const { warnings } = await createModel('gpt-4o').doGenerate({ - prompt: TEST_PROMPT, - stopSequences: ['\n\n'], - topK: 0.1, - presencePenalty: 0, - frequencyPenalty: 0, - seed: 42, - }); - - expect(warnings).toStrictEqual([ - { type: 'unsupported-setting', setting: 'topK' }, - { type: 'unsupported-setting', setting: 'seed' }, - { type: 'unsupported-setting', setting: 'presencePenalty' }, - { type: 'unsupported-setting', setting: 'frequencyPenalty' }, - { type: 'unsupported-setting', setting: 'stopSequences' }, - ]); - }); - - it('should extract logprobs in providerMetadata', async () => { - prepareJsonResponse({ - id: 'resp_67c97c0203188190a025beb4a75242bc', - object: 'response', - created_at: 1741257730, - status: 'completed', - error: null, - incomplete_details: null, - input: [], - instructions: null, - max_output_tokens: null, - model: 'gpt-4o-2024-07-18', - output: [ - { - id: 'msg_67c97c02656c81908e080dfdf4a03cd1', - type: 'message', - status: 'completed', - role: 'assistant', - content: [ - { - type: 'output_text', - text: 'answer text', - annotations: [], - logprobs: [ - { - token: 'Hello', - logprob: -0.0009994634, - top_logprobs: [ - { - token: 'Hello', - logprob: -0.0009994634, - }, - { - token: 'Hi', - logprob: -0.2, - }, - ], - }, - { - token: '!', - logprob: -0.13410144, - top_logprobs: [ - { - token: '!', - logprob: -0.13410144, - }, - ], - }, - ], - }, - ], - }, - ], - parallel_tool_calls: true, - previous_response_id: null, - reasoning: { - effort: null, - summary: null, - }, - store: true, - temperature: 1, - text: { - format: { - type: 'text', - }, - }, - tool_choice: 'auto', - tools: [], - top_p: 1, - truncation: 'disabled', - usage: { - input_tokens: 345, - input_tokens_details: { - cached_tokens: 234, - }, - output_tokens: 538, - output_tokens_details: { - reasoning_tokens: 123, - }, - total_tokens: 572, - }, - user: null, - metadata: {}, - }); - - const result = await createModel('gpt-4o').doGenerate({ - prompt: TEST_PROMPT, - providerOptions: { - openai: { - logprobs: 2, - }, - }, - }); - - expect(result.providerMetadata?.openai.logprobs).toMatchInlineSnapshot(` - [ - [ - { - "logprob": -0.0009994634, - "token": "Hello", - "top_logprobs": [ - { - "logprob": -0.0009994634, - "token": "Hello", - }, - { - "logprob": -0.2, - "token": "Hi", - }, - ], - }, - { - "logprob": -0.13410144, - "token": "!", - "top_logprobs": [ - { - "logprob": -0.13410144, - "token": "!", - }, - ], - }, - ], - ] - `); - }); - }); + }); describe('reasoning', () => { it('should handle reasoning with summary', async () => { @@ -2158,219 +1907,116 @@ describe('OpenAIResponsesLanguageModel', () => { }); }); - describe('code interpreter', () => { - beforeEach(() => { - server.urls['https://api.openai.com/v1/responses'].response = { - type: 'json-value', - body: { - id: 'resp_68c12b837ca881a0a062ebb60494ae7700553426a98f13ca', - object: 'response', - created_at: 1757490051, - status: 'completed', - background: false, - error: null, - incomplete_details: null, - instructions: null, - max_output_tokens: null, - max_tool_calls: null, - model: 'gpt-5-nano-2025-08-07', - output: [ - { - id: 'rs_68c12b868cd081a09ec2d83759a43b9e00553426a98f13ca', - type: 'reasoning', - summary: [], - }, - { - id: 'ci_68c12b8a4e6481a0bd969d4488e6809700553426a98f13ca', - type: 'code_interpreter_call', - status: 'completed', - code: 'import random\nrandom.seed(0)\nn = 10000\nsums = []\nfor _ in range(n):\n a = random.randint(1,6)\n b = random.randint(1,6)\n sums.append(a+b)\ntotal = sum(sums)\nmean = total / n\nfrom collections import Counter\ncounts = Counter(sums)\ndist = {s: counts.get(s,0) for s in range(2,13)}\ntotal, mean, dist, sums[:20]', - container_id: - 'cntr_68c12b85cd34819190332dbb00ec850c0f117a6c6bf754ed', - outputs: null, - }, - { - id: 'rs_68c12b8cf96081a08764e212603bb16600553426a98f13ca', - type: 'reasoning', - summary: [], - }, - { - id: 'ci_68c12b8dfa3881a084c474e6fbd0220500553426a98f13ca', - type: 'code_interpreter_call', - status: 'completed', - code: "# Write sums to CSV\nimport csv\nwith open('/mnt/data/dice_sums_10000.csv','w', newline='') as f:\n writer = csv.writer(f)\n writer.writerow(['sum'])\n for s in sums:\n writer.writerow([s])\n# Write summary\nsummary = {\n 'n_trials': n,\n 'total_sum': total,\n 'mean_sum_per_trial': mean,\n 'distribution': {str(k): v for k,v in dist.items()}\n}\nimport json\nwith open('/mnt/data/dice_sums_summary.json','w') as f:\n json.dump(summary, f, indent=2)\n('/mnt/data/dice_sums_10000.csv', '/mnt/data/dice_sums_summary.json')", - container_id: - 'cntr_68c12b85cd34819190332dbb00ec850c0f117a6c6bf754ed', - outputs: null, - }, - { - id: 'rs_68c12b90775c81a0bdcb8c306da10e7700553426a98f13ca', - type: 'reasoning', - summary: [], - }, + describe('code interpreter tool', () => { + let result: Awaited>; + + beforeEach(async () => { + prepareJsonFixtureResponse('openai-code-interpreter-tool.1'); + + result = await createModel('gpt-5-nano').doGenerate({ + prompt: TEST_PROMPT, + tools: [ + { + type: 'provider-defined', + id: 'openai.code_interpreter', + name: 'code_interpreter', + args: {}, + }, + ], + }); + }); + + it('should send request body with include and tool', async () => { + expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` + { + "include": [ + "code_interpreter_call.outputs", + ], + "input": [ { - id: 'msg_68c12b93d98481a0b8696d68b6c5968100553426a98f13ca', - type: 'message', - status: 'completed', - content: [ + "content": [ { - type: 'output_text', - annotations: [ - { - type: 'container_file_citation', - container_id: - 'cntr_68c12b85cd34819190332dbb00ec850c0f117a6c6bf754ed', - end_index: 744, - file_id: 'cfile_68c12b969ca881919d2ad197c7790751', - filename: 'dice_sums_10000.csv', - start_index: 707, - }, - { - type: 'container_file_citation', - container_id: - 'cntr_68c12b85cd34819190332dbb00ec850c0f117a6c6bf754ed', - end_index: 818, - file_id: 'cfile_68c12b969cc88191846a76aa26a47fe8', - filename: 'dice_sums_summary.json', - start_index: 778, - }, - ], - logprobs: [], - text: 'I ran a simulation of rolling two fair dice 10,000 times and computed the sums for each trial.\n\nKey results\n- Total sum of all 10,000 trial sums: 69953\n- Average sum per trial: 6.9953\n- Distribution of sums (counts for sums 2 through 12):\n - 2: 285\n - 3: 552\n - 4: 818\n - 5: 1134\n - 6: 1359\n - 7: 1721\n - 8: 1378\n - 9: 1108\n - 10: 797\n - 11: 558\n - 12: 290\n\nSample of the first 20 trial sums\n[8, 4, 9, 7, 7, 7, 7, 5, 6, 8, 11, 5, 7, 7, 7, 6, 7, 8, 8, 9]\n\nFiles created\n- dice_sums_10000.csv: each row contains the sum of a trial (one column: "sum")\n- dice_sums_summary.json: a summary with n_trials, total_sum, mean_sum_per_trial, and the distribution\n\nDownload links\n- [Download the sums (CSV)](sandbox:/mnt/data/dice_sums_10000.csv)\n- [Download the summary (JSON)](sandbox:/mnt/data/dice_sums_summary.json)\n\nIf you want me to run again with a different seed, or to provide a fuller distribution table or a plotted histogram, tell me how you\u2019d like the results formatted.', + "text": "Hello", + "type": "input_text", }, ], - role: 'assistant', + "role": "user", }, ], - parallel_tool_calls: true, - previous_response_id: null, - prompt_cache_key: null, - reasoning: { - effort: 'medium', - summary: null, - }, - safety_identifier: null, - service_tier: 'default', - store: true, - temperature: 1.0, - text: { - format: { - type: 'text', - }, - verbosity: 'medium', - }, - tool_choice: 'auto', - tools: [ + "model": "gpt-5-nano", + "tools": [ { - type: 'code_interpreter', - container: { - type: 'auto', + "container": { + "type": "auto", }, + "type": "code_interpreter", }, ], - top_logprobs: 0, - top_p: 1.0, - truncation: 'disabled', - usage: { - input_tokens: 4621, - input_tokens_details: { - cached_tokens: 3584, - }, - output_tokens: 2094, - output_tokens_details: { - reasoning_tokens: 1728, - }, - total_tokens: 6715, - }, - user: null, - metadata: {}, - }, - }; + } + `); }); - it('should generate text response', async () => { - const result = await createModel('gpt-5-nano').doGenerate({ - prompt: TEST_PROMPT, - }); + it('should include code interpreter tool call and result in content', async () => { + expect(result.content).toMatchSnapshot(); + }); + }); - expect(result.content).toMatchInlineSnapshot(` - [ - { - "providerMetadata": { - "openai": { - "itemId": "rs_68c12b868cd081a09ec2d83759a43b9e00553426a98f13ca", - "reasoningEncryptedContent": null, - }, - }, - "text": "", - "type": "reasoning", - }, + describe('image generation tool', () => { + let result: Awaited>; + + beforeEach(async () => { + prepareJsonFixtureResponse('openai-image-generation-tool.1'); + + result = await createModel('gpt-5-nano').doGenerate({ + prompt: TEST_PROMPT, + tools: [ { - "providerMetadata": { - "openai": { - "itemId": "rs_68c12b8cf96081a08764e212603bb16600553426a98f13ca", - "reasoningEncryptedContent": null, - }, + type: 'provider-defined', + id: 'openai.image_generation', + name: 'image_generation', + args: { + outputFormat: 'webp', + quality: 'low', + size: '1024x1024', }, - "text": "", - "type": "reasoning", }, - { - "providerMetadata": { - "openai": { - "itemId": "rs_68c12b90775c81a0bdcb8c306da10e7700553426a98f13ca", - "reasoningEncryptedContent": null, - }, + ], + }); + }); + + it('should send request body with include and tool', async () => { + expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` + { + "input": [ + { + "content": [ + { + "text": "Hello", + "type": "input_text", + }, + ], + "role": "user", }, - "text": "", - "type": "reasoning", - }, - { - "providerMetadata": { - "openai": { - "itemId": "msg_68c12b93d98481a0b8696d68b6c5968100553426a98f13ca", - }, + ], + "model": "gpt-5-nano", + "tools": [ + { + "output_format": "webp", + "quality": "low", + "size": "1024x1024", + "type": "image_generation", }, - "text": "I ran a simulation of rolling two fair dice 10,000 times and computed the sums for each trial. - - Key results - - Total sum of all 10,000 trial sums: 69953 - - Average sum per trial: 6.9953 - - Distribution of sums (counts for sums 2 through 12): - - 2: 285 - - 3: 552 - - 4: 818 - - 5: 1134 - - 6: 1359 - - 7: 1721 - - 8: 1378 - - 9: 1108 - - 10: 797 - - 11: 558 - - 12: 290 - - Sample of the first 20 trial sums - [8, 4, 9, 7, 7, 7, 7, 5, 6, 8, 11, 5, 7, 7, 7, 6, 7, 8, 8, 9] - - Files created - - dice_sums_10000.csv: each row contains the sum of a trial (one column: "sum") - - dice_sums_summary.json: a summary with n_trials, total_sum, mean_sum_per_trial, and the distribution - - Download links - - [Download the sums (CSV)](sandbox:/mnt/data/dice_sums_10000.csv) - - [Download the summary (JSON)](sandbox:/mnt/data/dice_sums_summary.json) - - If you want me to run again with a different seed, or to provide a fuller distribution table or a plotted histogram, tell me how you’d like the results formatted.", - "type": "text", - }, - ] + ], + } `); }); - }); - describe('web search', () => { - const outputText = `Last week in San Francisco, several notable events and developments took place:\n\n**Bruce Lee Statue in Chinatown**\n\nThe Chinese Historical Society of America Museum announced plans to install a Bruce Lee statue in Chinatown. This initiative, supported by the Rose Pak Community Fund, the Bruce Lee Foundation, and Stand With Asians, aims to honor Lee's contributions to film and martial arts. Artist Arnie Kim has been commissioned for the project, with a fundraising goal of $150,000. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/07/bruce-lee-statue-sf-chinatown?utm_source=chatgpt.com))\n\n**Office Leasing Revival**\n\nThe Bay Area experienced a resurgence in office leasing, securing 11 of the largest U.S. office leases in 2024. This trend, driven by the tech industry's growth and advancements in generative AI, suggests a potential boost to downtown recovery through increased foot traffic. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/03/bay-area-office-leasing-activity?utm_source=chatgpt.com))\n\n**Spring Blooms in the Bay Area**\n\nWith the arrival of spring, several locations in the Bay Area are showcasing vibrant blooms. Notable spots include the Conservatory of Flowers, Japanese Tea Garden, Queen Wilhelmina Tulip Garden, and the San Francisco Botanical Garden, each offering unique floral displays. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/03/where-to-see-spring-blooms-bay-area?utm_source=chatgpt.com))\n\n**Oceanfront Great Highway Park**\n\nSan Francisco's long-awaited Oceanfront Great Highway park is set to open on April 12. This 43-acre, car-free park will span a two-mile stretch of the Great Highway from Lincoln Way to Sloat Boulevard, marking the largest pedestrianization project in California's history. The park follows voter approval of Proposition K, which permanently bans cars on part of the highway. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/03/great-highway-park-opening-april-recall-campaign?utm_source=chatgpt.com))\n\n**Warmer Spring Seasons**\n\nAn analysis by Climate Central revealed that San Francisco, along with most U.S. cities, is experiencing increasingly warmer spring seasons. Over a 55-year period from 1970 to 2024, the national average temperature during March through May rose by 2.4°F. This warming trend poses various risks, including early snowmelt and increased wildfire threats. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/03/climate-weather-spring-temperatures-warmer-sf?utm_source=chatgpt.com))\n\n\n# Key San Francisco Developments Last Week:\n- [Bruce Lee statue to be installed in SF Chinatown](https://www.axios.com/local/san-francisco/2025/03/07/bruce-lee-statue-sf-chinatown?utm_source=chatgpt.com)\n- [The Bay Area is set to make an office leasing comeback](https://www.axios.com/local/san-francisco/2025/03/03/bay-area-office-leasing-activity?utm_source=chatgpt.com)\n- [Oceanfront Great Highway park set to open in April](https://www.axios.com/local/san-francisco/2025/03/03/great-highway-park-opening-april-recall-campaign?utm_source=chatgpt.com)`; + it('should include generate image tool call and result in content', async () => { + expect(result.content).toMatchSnapshot(); + }); + }); + describe('web search tool', () => { beforeEach(() => { server.urls['https://api.openai.com/v1/responses'].response = { type: 'json-value', @@ -2411,7 +2057,7 @@ describe('OpenAIResponsesLanguageModel', () => { content: [ { type: 'output_text', - text: outputText, + text: `Last week in San Francisco, several notable events and developments took place:\n\n**Bruce Lee Statue in Chinatown**\n\nThe Chinese Historical Society of America Museum announced plans to install a Bruce Lee statue in Chinatown. This initiative, supported by the Rose Pak Community Fund, the Bruce Lee Foundation, and Stand With Asians, aims to honor Lee's contributions to film and martial arts. Artist Arnie Kim has been commissioned for the project, with a fundraising goal of $150,000. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/07/bruce-lee-statue-sf-chinatown?utm_source=chatgpt.com))\n\n**Office Leasing Revival**\n\nThe Bay Area experienced a resurgence in office leasing, securing 11 of the largest U.S. office leases in 2024. This trend, driven by the tech industry's growth and advancements in generative AI, suggests a potential boost to downtown recovery through increased foot traffic. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/03/bay-area-office-leasing-activity?utm_source=chatgpt.com))\n\n**Spring Blooms in the Bay Area**\n\nWith the arrival of spring, several locations in the Bay Area are showcasing vibrant blooms. Notable spots include the Conservatory of Flowers, Japanese Tea Garden, Queen Wilhelmina Tulip Garden, and the San Francisco Botanical Garden, each offering unique floral displays. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/03/where-to-see-spring-blooms-bay-area?utm_source=chatgpt.com))\n\n**Oceanfront Great Highway Park**\n\nSan Francisco's long-awaited Oceanfront Great Highway park is set to open on April 12. This 43-acre, car-free park will span a two-mile stretch of the Great Highway from Lincoln Way to Sloat Boulevard, marking the largest pedestrianization project in California's history. The park follows voter approval of Proposition K, which permanently bans cars on part of the highway. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/03/great-highway-park-opening-april-recall-campaign?utm_source=chatgpt.com))\n\n**Warmer Spring Seasons**\n\nAn analysis by Climate Central revealed that San Francisco, along with most U.S. cities, is experiencing increasingly warmer spring seasons. Over a 55-year period from 1970 to 2024, the national average temperature during March through May rose by 2.4°F. This warming trend poses various risks, including early snowmelt and increased wildfire threats. ([axios.com](https://www.axios.com/local/san-francisco/2025/03/03/climate-weather-spring-temperatures-warmer-sf?utm_source=chatgpt.com))\n\n\n# Key San Francisco Developments Last Week:\n- [Bruce Lee statue to be installed in SF Chinatown](https://www.axios.com/local/san-francisco/2025/03/07/bruce-lee-statue-sf-chinatown?utm_source=chatgpt.com)\n- [The Bay Area is set to make an office leasing comeback](https://www.axios.com/local/san-francisco/2025/03/03/bay-area-office-leasing-activity?utm_source=chatgpt.com)\n- [Oceanfront Great Highway park set to open in April](https://www.axios.com/local/san-francisco/2025/03/03/great-highway-park-opening-april-recall-campaign?utm_source=chatgpt.com)`, annotations: [ { type: 'url_citation', @@ -2457,53 +2103,164 @@ describe('OpenAIResponsesLanguageModel', () => { ], }, ], - parallel_tool_calls: true, - previous_response_id: null, - reasoning: { - effort: null, - summary: null, + parallel_tool_calls: true, + previous_response_id: null, + reasoning: { + effort: null, + summary: null, + }, + store: true, + temperature: 0, + text: { + format: { + type: 'text', + }, + }, + tool_choice: 'auto', + tools: [ + { + type: 'web_search', + search_context_size: 'medium', + user_location: { + type: 'approximate', + city: null, + country: 'US', + region: null, + timezone: null, + }, + }, + ], + top_p: 1, + truncation: 'disabled', + usage: { + input_tokens: 327, + input_tokens_details: { + cached_tokens: 0, + }, + output_tokens: 770, + output_tokens_details: { + reasoning_tokens: 0, + }, + total_tokens: 1097, + }, + user: null, + metadata: {}, + }, + }; + }); + + it('should send web_search tool', async () => { + const { warnings } = await createModel('gpt-4o').doGenerate({ + tools: [ + { + type: 'provider-defined', + id: 'openai.web_search', + name: 'web_search', + args: { + searchContextSize: 'high', + userLocation: { + type: 'approximate', + city: 'San Francisco', + }, + }, + }, + ], + prompt: TEST_PROMPT, + }); + + expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` + { + "include": [ + "web_search_call.action.sources", + ], + "input": [ + { + "content": [ + { + "text": "Hello", + "type": "input_text", + }, + ], + "role": "user", + }, + ], + "model": "gpt-4o", + "tools": [ + { + "search_context_size": "high", + "type": "web_search", + "user_location": { + "city": "San Francisco", + "type": "approximate", + }, + }, + ], + } + `); + + expect(warnings).toStrictEqual([]); + }); + + it('should send web_search tool as tool_choice', async () => { + const { warnings } = await createModel('gpt-4o').doGenerate({ + toolChoice: { + type: 'tool', + toolName: 'web_search', + }, + tools: [ + { + type: 'provider-defined', + id: 'openai.web_search', + name: 'web_search', + args: { + searchContextSize: 'high', + userLocation: { + type: 'approximate', + city: 'San Francisco', + }, + }, }, - store: true, - temperature: 0, - text: { - format: { - type: 'text', + ], + prompt: TEST_PROMPT, + }); + + expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` + { + "include": [ + "web_search_call.action.sources", + ], + "input": [ + { + "content": [ + { + "text": "Hello", + "type": "input_text", + }, + ], + "role": "user", }, + ], + "model": "gpt-4o", + "tool_choice": { + "type": "web_search", }, - tool_choice: 'auto', - tools: [ + "tools": [ { - type: 'web_search_preview', - search_context_size: 'medium', - user_location: { - type: 'approximate', - city: null, - country: 'US', - region: null, - timezone: null, + "search_context_size": "high", + "type": "web_search", + "user_location": { + "city": "San Francisco", + "type": "approximate", }, }, ], - top_p: 1, - truncation: 'disabled', - usage: { - input_tokens: 327, - input_tokens_details: { - cached_tokens: 0, - }, - output_tokens: 770, - output_tokens_details: { - reasoning_tokens: 0, - }, - total_tokens: 1097, - }, - user: null, - metadata: {}, - }, - }; + } + `); + + expect(warnings).toStrictEqual([]); }); - it('should generate text and sources', async () => { + it('should generate content', async () => { const result = await createModel('gpt-4o').doGenerate({ prompt: TEST_PROMPT, }); @@ -2514,7 +2271,7 @@ describe('OpenAIResponsesLanguageModel', () => { "input": "{"action":{"type":"search","query":"Vercel AI SDK next version features"}}", "providerExecuted": true, "toolCallId": "ws_67cf2b3051e88190b006770db6fdb13d", - "toolName": "web_search_preview", + "toolName": "web_search", "type": "tool-call", }, { @@ -2523,14 +2280,14 @@ describe('OpenAIResponsesLanguageModel', () => { "status": "completed", }, "toolCallId": "ws_67cf2b3051e88190b006770db6fdb13d", - "toolName": "web_search_preview", + "toolName": "web_search", "type": "tool-result", }, { "input": "{"action":{"type":"search"}}", "providerExecuted": true, "toolCallId": "ws_67cf2b3051e88190b006234456fdb13d", - "toolName": "web_search_preview", + "toolName": "web_search", "type": "tool-call", }, { @@ -2539,7 +2296,7 @@ describe('OpenAIResponsesLanguageModel', () => { "status": "completed", }, "toolCallId": "ws_67cf2b3051e88190b006234456fdb13d", - "toolName": "web_search_preview", + "toolName": "web_search", "type": "tool-result", }, { @@ -2615,233 +2372,254 @@ describe('OpenAIResponsesLanguageModel', () => { ] `); }); + }); - it('should handle file_search tool calls in generate', async () => { - server.urls['https://api.openai.com/v1/responses'].response = { - type: 'json-value', - body: { - id: 'resp_67cf3390786881908b27489d7e8cfb6b', - object: 'response', - created_at: 1741632400, - status: 'completed', - error: null, - incomplete_details: null, - input: [], - instructions: null, - max_output_tokens: null, - model: 'gpt-4o-mini-2024-07-18', - output: [ + describe('file search tool', () => { + let result: Awaited>; + + describe('without results include', () => { + beforeEach(async () => { + prepareJsonFixtureResponse('openai-file-search-tool.1'); + + result = await createModel('gpt-5-nano').doGenerate({ + prompt: TEST_PROMPT, + tools: [ { - type: 'file_search_call', - id: 'fs_67cf3390e9608190869b5d45698a7067', - status: 'completed', - queries: ['AI information'], - results: [ - { - attributes: { - file_id: 'file-123', - filename: 'ai_guide.pdf', - score: 0.95, - text: 'AI is a field of computer science', - }, + type: 'provider-defined', + id: 'openai.file_search', + name: 'file_search', + args: { + vectorStoreIds: ['vs_68caad8bd5d88191ab766cf043d89a18'], + maxNumResults: 5, + filters: { + key: 'author', + type: 'eq', + value: 'Jane Smith', }, - ], + ranking: { + ranker: 'auto', + scoreThreshold: 0.5, + }, + }, }, + ], + }); + }); + + it('should send request body with tool', async () => { + expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` + { + "input": [ { - id: 'msg_67cf33924ea88190b8c12bf68c1f6416', - type: 'message', - status: 'completed', - role: 'assistant', - content: [ + "content": [ { - type: 'output_text', - text: 'Based on the search results, here is the information you requested.', - annotations: [], + "text": "Hello", + "type": "input_text", }, ], + "role": "user", }, ], - parallel_tool_calls: true, - previous_response_id: null, - reasoning: { - effort: null, - summary: null, - }, - store: true, - temperature: 0, - text: { - format: { - type: 'text', + "model": "gpt-5-nano", + "tools": [ + { + "filters": { + "key": "author", + "type": "eq", + "value": "Jane Smith", + }, + "max_num_results": 5, + "ranking_options": { + "ranker": "auto", + "score_threshold": 0.5, + }, + "type": "file_search", + "vector_store_ids": [ + "vs_68caad8bd5d88191ab766cf043d89a18", + ], }, - }, - tool_choice: 'auto', + ], + } + `); + }); + + it('should include file search tool call and result in content', async () => { + expect(result.content).toMatchSnapshot(); + }); + }); + + describe('with results include', () => { + beforeEach(async () => { + prepareJsonFixtureResponse('openai-file-search-tool.2'); + + result = await createModel('gpt-5-nano').doGenerate({ + prompt: TEST_PROMPT, tools: [ { - type: 'file_search', + type: 'provider-defined', + id: 'openai.file_search', + name: 'file_search', + args: { + vectorStoreIds: ['vs_68caad8bd5d88191ab766cf043d89a18'], + maxNumResults: 5, + filters: { + key: 'author', + type: 'eq', + value: 'Jane Smith', + }, + ranking: { + ranker: 'auto', + scoreThreshold: 0.5, + }, + }, }, ], - top_p: 1, - truncation: 'disabled', - usage: { - input_tokens: 327, - input_tokens_details: { - cached_tokens: 0, - }, - output_tokens: 834, - output_tokens_details: { - reasoning_tokens: 0, + providerOptions: { + openai: { + include: ['file_search_call.results'], }, - total_tokens: 1161, }, - user: null, - metadata: {}, - }, - }; - - const result = await createModel('gpt-4o-mini').doGenerate({ - prompt: TEST_PROMPT, + }); }); - expect(result.content).toMatchInlineSnapshot(` - [ + it('should send request body with tool', async () => { + expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(` { - "input": "", - "providerExecuted": true, - "toolCallId": "fs_67cf3390e9608190869b5d45698a7067", - "toolName": "file_search", - "type": "tool-call", - }, - { - "providerExecuted": true, - "result": { - "queries": [ - "AI information", - ], - "results": [ - { - "attributes": { - "file_id": "file-123", - "filename": "ai_guide.pdf", - "score": 0.95, - "text": "AI is a field of computer science", + "include": [ + "file_search_call.results", + ], + "input": [ + { + "content": [ + { + "text": "Hello", + "type": "input_text", }, + ], + "role": "user", + }, + ], + "model": "gpt-5-nano", + "tools": [ + { + "filters": { + "key": "author", + "type": "eq", + "value": "Jane Smith", }, - ], - "status": "completed", - "type": "file_search_tool_result", - }, - "toolCallId": "fs_67cf3390e9608190869b5d45698a7067", - "toolName": "file_search", - "type": "tool-result", - }, - { - "providerMetadata": { - "openai": { - "itemId": "msg_67cf33924ea88190b8c12bf68c1f6416", + "max_num_results": 5, + "ranking_options": { + "ranker": "auto", + "score_threshold": 0.5, + }, + "type": "file_search", + "vector_store_ids": [ + "vs_68caad8bd5d88191ab766cf043d89a18", + ], }, - }, - "text": "Based on the search results, here is the information you requested.", - "type": "text", - }, - ] - `); + ], + } + `); + }); + + it('should include file search tool call and result in content', async () => { + expect(result.content).toMatchSnapshot(); + }); }); + }); - it('should handle web search with action query field', async () => { + it('should handle computer use tool calls', async () => { + function prepareJsonResponse(body: any) { server.urls['https://api.openai.com/v1/responses'].response = { type: 'json-value', - body: { - id: 'resp_test', - object: 'response', - created_at: 1741630255, + body, + }; + } + prepareJsonResponse({ + id: 'resp_computer_test', + object: 'response', + created_at: 1741630255, + status: 'completed', + error: null, + incomplete_details: null, + instructions: null, + max_output_tokens: null, + model: 'gpt-4o-mini', + output: [ + { + type: 'computer_call', + id: 'computer_67cf2b3051e88190b006770db6fdb13d', status: 'completed', - error: null, - incomplete_details: null, - instructions: null, - max_output_tokens: null, - model: 'o3-2025-04-16', - output: [ - { - type: 'web_search_call', - id: 'ws_test', - status: 'completed', - action: { - type: 'search', - query: 'Vercel AI SDK next version features', - }, - }, + }, + { + type: 'message', + id: 'msg_computer_test', + status: 'completed', + role: 'assistant', + content: [ { - type: 'message', - id: 'msg_test', - status: 'completed', - role: 'assistant', - content: [ - { - type: 'output_text', - text: 'Based on the search results, here are the upcoming features.', - annotations: [], - }, - ], + type: 'output_text', + text: "I've completed the computer task.", + annotations: [], }, ], - parallel_tool_calls: true, - previous_response_id: null, - reasoning: { effort: null, summary: null }, - store: true, - temperature: 0, - text: { format: { type: 'text' } }, - tool_choice: 'auto', - tools: [ - { type: 'web_search_preview', search_context_size: 'medium' }, - ], - top_p: 1, - truncation: 'disabled', - usage: { - input_tokens: 50, - input_tokens_details: { cached_tokens: 0 }, - output_tokens: 25, - output_tokens_details: { reasoning_tokens: 0 }, - total_tokens: 75, - }, - user: null, - metadata: {}, }, - }; + ], + usage: { input_tokens: 100, output_tokens: 50 }, + }); - const result = await createModel('o3-2025-04-16').doGenerate({ - prompt: TEST_PROMPT, - }); + const result = await createModel('gpt-4o-mini').doGenerate({ + prompt: [ + { + role: 'user' as const, + content: [ + { + type: 'text' as const, + text: 'Use the computer to complete a task.', + }, + ], + }, + ], + tools: [ + { + type: 'provider-defined', + id: 'openai.computer_use', + name: 'computer_use', + args: {}, + }, + ], + }); - expect(result.content).toMatchInlineSnapshot(` + expect(result.content).toMatchInlineSnapshot(` [ { - "input": "{"action":{"type":"search","query":"Vercel AI SDK next version features"}}", + "input": "", "providerExecuted": true, - "toolCallId": "ws_test", - "toolName": "web_search_preview", + "toolCallId": "computer_67cf2b3051e88190b006770db6fdb13d", + "toolName": "computer_use", "type": "tool-call", }, { "providerExecuted": true, "result": { "status": "completed", + "type": "computer_use_tool_result", }, - "toolCallId": "ws_test", - "toolName": "web_search_preview", + "toolCallId": "computer_67cf2b3051e88190b006770db6fdb13d", + "toolName": "computer_use", "type": "tool-result", }, { "providerMetadata": { "openai": { - "itemId": "msg_test", + "itemId": "msg_computer_test", }, }, - "text": "Based on the search results, here are the upcoming features.", + "text": "I've completed the computer task.", "type": "text", }, ] `); - }); }); describe('errors', () => { @@ -3259,108 +3037,6 @@ describe('OpenAIResponsesLanguageModel', () => { `); }); - it('should handle streaming web search with action query field', async () => { - server.urls['https://api.openai.com/v1/responses'].response = { - type: 'stream-chunks', - chunks: [ - `data:{"type":"response.created","response":{"id":"resp_test","object":"response","created_at":1741630255,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"o3-2025-04-16","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":"medium","summary":"auto"},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","search_context_size":"medium"}],"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}\n\n`, - `data:{"type":"response.output_item.added","output_index":0,"item":{"type":"web_search_call","id":"ws_test","status":"in_progress","action":{"type":"search","query":"Vercel AI SDK next version features"}}}\n\n`, - `data:{"type":"response.web_search_call.in_progress","output_index":0,"item_id":"ws_test"}\n\n`, - `data:{"type":"response.web_search_call.searching","output_index":0,"item_id":"ws_test"}\n\n`, - `data:{"type":"response.web_search_call.completed","output_index":0,"item_id":"ws_test"}\n\n`, - `data:{"type":"response.output_item.done","output_index":0,"item":{"type":"web_search_call","id":"ws_test","status":"completed","action":{"type":"search","query":"Vercel AI SDK next version features"}}}\n\n`, - `data:{"type":"response.output_item.added","output_index":1,"item":{"type":"message","id":"msg_test","status":"in_progress","role":"assistant","content":[]}}\n\n`, - `data:{"type":"response.content_part.added","item_id":"msg_test","output_index":1,"content_index":0,"part":{"type":"output_text","text":"","annotations":[]}}\n\n`, - `data:{"type":"response.output_text.delta","item_id":"msg_test","output_index":1,"content_index":0,"delta":"Based on the search results, here are the upcoming features."}\n\n`, - `data:{"type":"response.output_text.done","item_id":"msg_test","output_index":1,"content_index":0,"text":"Based on the search results, here are the upcoming features."}\n\n`, - `data:{"type":"response.content_part.done","item_id":"msg_test","output_index":1,"content_index":0,"part":{"type":"output_text","text":"Based on the search results, here are the upcoming features.","annotations":[]}}\n\n`, - `data:{"type":"response.output_item.done","output_index":1,"item":{"type":"message","id":"msg_test","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Based on the search results, here are the upcoming features.","annotations":[]}]}}\n\n`, - `data:{"type":"response.completed","response":{"id":"resp_test","object":"response","created_at":1741630255,"status":"completed","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"o3-2025-04-16","output":[{"type":"web_search_call","id":"ws_test","status":"completed","action":{"type":"search","query":"Vercel AI SDK next version features"}},{"type":"message","id":"msg_test","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Based on the search results, here are the upcoming features.","annotations":[]}]}],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":"medium","summary":"auto"},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","search_context_size":"medium"}],"top_p":1,"truncation":"disabled","usage":{"input_tokens":50,"input_tokens_details":{"cached_tokens":0},"output_tokens":25,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":75},"user":null,"metadata":{}}}\n\n`, - 'data: [DONE]\n\n', - ], - }; - - const { stream } = await createModel('o3-2025-04-16').doStream({ - prompt: TEST_PROMPT, - includeRawChunks: false, - }); - - const result = await convertReadableStreamToArray(stream); - expect(result).toMatchInlineSnapshot(` - [ - { - "type": "stream-start", - "warnings": [], - }, - { - "id": "resp_test", - "modelId": "o3-2025-04-16", - "timestamp": 2025-03-10T18:10:55.000Z, - "type": "response-metadata", - }, - { - "id": "ws_test", - "toolName": "web_search_preview", - "type": "tool-input-start", - }, - { - "id": "ws_test", - "type": "tool-input-end", - }, - { - "input": "{"action":{"type":"search","query":"Vercel AI SDK next version features"}}", - "providerExecuted": true, - "toolCallId": "ws_test", - "toolName": "web_search", - "type": "tool-call", - }, - { - "providerExecuted": true, - "result": { - "status": "completed", - }, - "toolCallId": "ws_test", - "toolName": "web_search", - "type": "tool-result", - }, - { - "id": "msg_test", - "providerMetadata": { - "openai": { - "itemId": "msg_test", - }, - }, - "type": "text-start", - }, - { - "delta": "Based on the search results, here are the upcoming features.", - "id": "msg_test", - "type": "text-delta", - }, - { - "id": "msg_test", - "type": "text-end", - }, - { - "finishReason": "stop", - "providerMetadata": { - "openai": { - "responseId": "resp_test", - }, - }, - "type": "finish", - "usage": { - "cachedInputTokens": 0, - "inputTokens": 50, - "outputTokens": 25, - "reasoningTokens": 0, - "totalTokens": 75, - }, - }, - ] - `); - }); - it('should send finish reason for incomplete response', async () => { server.urls['https://api.openai.com/v1/responses'].response = { type: 'stream-chunks', @@ -3766,63 +3442,58 @@ describe('OpenAIResponsesLanguageModel', () => { `); }); - it('should stream sources', async () => { - server.urls['https://api.openai.com/v1/responses'].response = { - type: 'stream-chunks', - chunks: [ - `data:{"type":"response.created","response":{"id":"resp_67cf3390786881908b27489d7e8cfb6b","object":"response","created_at":1741632400,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"summary":null},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}\n\n`, - `data:{"type":"response.in_progress","response":{"id":"resp_67cf3390786881908b27489d7e8cfb6b","object":"response","created_at":1741632400,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"summary":null},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}\n\n`, - `data:{"type":"response.output_item.added","output_index":0,"item":{"type":"web_search_call","id":"ws_67cf3390e9608190869b5d45698a7067","status":"in_progress"}}\n\n`, - `data:{"type":"response.web_search_call.in_progress","output_index":0,"item_id":"ws_67cf3390e9608190869b5d45698a7067"}\n\n`, - `data:{"type":"response.web_search_call.searching","output_index":0,"item_id":"ws_67cf3390e9608190869b5d45698a7067"}\n\n`, - `data:{"type":"response.web_search_call.completed","output_index":0,"item_id":"ws_67cf3390e9608190869b5d45698a7067"}\n\n`, - `data:{"type":"response.output_item.done","output_index":0,"item":{"type":"web_search_call","id":"ws_67cf3390e9608190869b5d45698a7067","status":"completed"}}\n\n`, - `data:{"type":"response.output_item.added","output_index":1,"item":{"type":"message","id":"msg_67cf33924ea88190b8c12bf68c1f6416","status":"in_progress","role":"assistant","content":[]}}\n\n`, - `data:{"type":"response.content_part.added","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"part":{"type":"output_text","text":"","annotations":[]}}\n\n`, - `data:{"type":"response.output_text.delta","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"delta":"Last week"}\n\n`, - `data:{"type":"response.output_text.delta","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"delta":" in San Francisco"}\n\n`, - `data:{"type":"response.output_text.annotation.added","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"annotation_index":0,"annotation":{"type":"url_citation","start_index":383,"end_index":493,"url":"https://www.sftourismtips.com/san-francisco-events-in-march.html?utm_source=chatgpt.com","title":"San Francisco Events in March 2025: Festivals, Theater & Easter"}}\n\n`, - `data:{"type":"response.output_text.delta","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"delta":" a themed party"}\n\n`, - `data:{"type":"response.output_text.delta","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"delta":"([axios.com](https://www.axios.com/local/san-francisco/2025/03/06/sf-events-march-what-to-do-giants-fanfest?utm_source=chatgpt.com))"}\n\n`, - `data:{"type":"response.output_text.annotation.added","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"annotation_index":1,"annotation":{"type":"url_citation","start_index":630,"end_index":762,"url":"https://www.axios.com/local/san-francisco/2025/03/06/sf-events-march-what-to-do-giants-fanfest?utm_source=chatgpt.com","title":"SF weekend events: Giants FanFest, crab crawl and more"}}\n\n`, - `data:{"type":"response.output_text.delta","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"delta":"."}\n\n`, - `data:{"type":"response.output_text.done","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"text":"Last week in San Francisco a themed..."}\n\n`, - `data:{"type":"response.content_part.done","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"part":{"type":"output_text","text":"Last week in San Francisco a themed party...","annotations":[{"type":"url_citation","start_index":383,"end_index":493,"url":"https://www.sftourismtips.com/san-francisco-events-in-march.html?utm_source=chatgpt.com","title":"San Francisco Events in March 2025: Festivals, Theater & Easter"},{"type":"url_citation","start_index":630,"end_index":762,"url":"https://www.axios.com/local/san-francisco/2025/03/06/sf-events-march-what-to-do-giants-fanfest?utm_source=chatgpt.com","title":"SF weekend events: Giants FanFest, crab crawl and more"}]}}\n\n`, - `data:{"type":"response.output_item.done","output_index":1,"item":{"type":"message","id":"msg_67cf33924ea88190b8c12bf68c1f6416","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Last week in San Francisco a themed party...","annotations":[{"type":"url_citation","start_index":383,"end_index":493,"url":"https://www.sftourismtips.com/san-francisco-events-in-march.html?utm_source=chatgpt.com","title":"San Francisco Events in March 2025: Festivals, Theater & Easter"},{"type":"url_citation","start_index":630,"end_index":762,"url":"https://www.axios.com/local/san-francisco/2025/03/06/sf-events-march-what-to-do-giants-fanfest?utm_source=chatgpt.com","title":"SF weekend events: Giants FanFest, crab crawl and more"}]}]}}\n\n`, - `data:{"type":"response.completed","response":{"id":"resp_67cf3390786881908b27489d7e8cfb6b","object":"response","created_at":1741632400,"status":"completed","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-mini-2024-07-18","output":[{"type":"web_search_call","id":"ws_67cf3390e9608190869b5d45698a7067","status":"completed"},{"type":"message","id":"msg_67cf33924ea88190b8c12bf68c1f6416","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Last week in San Francisco a themed party...","annotations":[{"type":"url_citation","start_index":383,"end_index":493,"url":"https://www.sftourismtips.com/san-francisco-events-in-march.html?utm_source=chatgpt.com","title":"San Francisco Events in March 2025: Festivals, Theater & Easter"},{"type":"url_citation","start_index":630,"end_index":762,"url":"https://www.axios.com/local/san-francisco/2025/03/06/sf-events-march-what-to-do-giants-fanfest?utm_source=chatgpt.com","title":"SF weekend events: Giants FanFest, crab crawl and more"}]}]}],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"summary":null},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_p":1,"truncation":"disabled","usage":{"input_tokens":327,"input_tokens_details":{"cached_tokens":0},"output_tokens":834,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":1161},"user":null,"metadata":{}}}\n\n`, - ], - }; + describe('web search tool', () => { + it('should handle streaming web search with action query field', async () => { + server.urls['https://api.openai.com/v1/responses'].response = { + type: 'stream-chunks', + chunks: [ + `data:{"type":"response.created","response":{"id":"resp_test","object":"response","created_at":1741630255,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"o3-2025-04-16","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":"medium","summary":"auto"},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search","search_context_size":"medium"}],"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}\n\n`, + `data:{"type":"response.output_item.added","output_index":0,"item":{"type":"web_search_call","id":"ws_test","status":"in_progress","action":{"type":"search","query":"Vercel AI SDK next version features"}}}\n\n`, + `data:{"type":"response.web_search_call.in_progress","output_index":0,"item_id":"ws_test"}\n\n`, + `data:{"type":"response.web_search_call.searching","output_index":0,"item_id":"ws_test"}\n\n`, + `data:{"type":"response.web_search_call.completed","output_index":0,"item_id":"ws_test"}\n\n`, + `data:{"type":"response.output_item.done","output_index":0,"item":{"type":"web_search_call","id":"ws_test","status":"completed","action":{"type":"search","query":"Vercel AI SDK next version features"}}}\n\n`, + `data:{"type":"response.output_item.added","output_index":1,"item":{"type":"message","id":"msg_test","status":"in_progress","role":"assistant","content":[]}}\n\n`, + `data:{"type":"response.content_part.added","item_id":"msg_test","output_index":1,"content_index":0,"part":{"type":"output_text","text":"","annotations":[]}}\n\n`, + `data:{"type":"response.output_text.delta","item_id":"msg_test","output_index":1,"content_index":0,"delta":"Based on the search results, here are the upcoming features."}\n\n`, + `data:{"type":"response.output_text.done","item_id":"msg_test","output_index":1,"content_index":0,"text":"Based on the search results, here are the upcoming features."}\n\n`, + `data:{"type":"response.content_part.done","item_id":"msg_test","output_index":1,"content_index":0,"part":{"type":"output_text","text":"Based on the search results, here are the upcoming features.","annotations":[]}}\n\n`, + `data:{"type":"response.output_item.done","output_index":1,"item":{"type":"message","id":"msg_test","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Based on the search results, here are the upcoming features.","annotations":[]}]}}\n\n`, + `data:{"type":"response.completed","response":{"id":"resp_test","object":"response","created_at":1741630255,"status":"completed","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"o3-2025-04-16","output":[{"type":"web_search_call","id":"ws_test","status":"completed","action":{"type":"search","query":"Vercel AI SDK next version features"}},{"type":"message","id":"msg_test","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Based on the search results, here are the upcoming features.","annotations":[]}]}],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":"medium","summary":"auto"},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search","search_context_size":"medium"}],"top_p":1,"truncation":"disabled","usage":{"input_tokens":50,"input_tokens_details":{"cached_tokens":0},"output_tokens":25,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":75},"user":null,"metadata":{}}}\n\n`, + 'data: [DONE]\n\n', + ], + }; - const { stream } = await createModel('gpt-4o-mini').doStream({ - prompt: TEST_PROMPT, - includeRawChunks: false, - }); + const { stream } = await createModel('o3-2025-04-16').doStream({ + prompt: TEST_PROMPT, + }); - expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(` + const result = await convertReadableStreamToArray(stream); + expect(result).toMatchInlineSnapshot(` [ { "type": "stream-start", "warnings": [], }, { - "id": "resp_67cf3390786881908b27489d7e8cfb6b", - "modelId": "gpt-4o-mini-2024-07-18", - "timestamp": 2025-03-10T18:46:40.000Z, + "id": "resp_test", + "modelId": "o3-2025-04-16", + "timestamp": 2025-03-10T18:10:55.000Z, "type": "response-metadata", }, { - "id": "ws_67cf3390e9608190869b5d45698a7067", - "toolName": "web_search_preview", + "id": "ws_test", + "toolName": "web_search", "type": "tool-input-start", }, { - "id": "ws_67cf3390e9608190869b5d45698a7067", + "id": "ws_test", "type": "tool-input-end", }, { - "input": "{}", + "input": "{"action":{"type":"search","query":"Vercel AI SDK next version features"}}", "providerExecuted": true, - "toolCallId": "ws_67cf3390e9608190869b5d45698a7067", + "toolCallId": "ws_test", "toolName": "web_search", "type": "tool-call", }, @@ -3831,155 +3502,61 @@ describe('OpenAIResponsesLanguageModel', () => { "result": { "status": "completed", }, - "toolCallId": "ws_67cf3390e9608190869b5d45698a7067", + "toolCallId": "ws_test", "toolName": "web_search", "type": "tool-result", }, { - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", + "id": "msg_test", "providerMetadata": { "openai": { - "itemId": "msg_67cf33924ea88190b8c12bf68c1f6416", + "itemId": "msg_test", }, }, "type": "text-start", }, { - "delta": "Last week", - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", - "type": "text-delta", - }, - { - "delta": " in San Francisco", - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", - "type": "text-delta", - }, - { - "id": "id-0", - "sourceType": "url", - "title": "San Francisco Events in March 2025: Festivals, Theater & Easter", - "type": "source", - "url": "https://www.sftourismtips.com/san-francisco-events-in-march.html?utm_source=chatgpt.com", - }, - { - "delta": " a themed party", - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", - "type": "text-delta", - }, - { - "delta": "([axios.com](https://www.axios.com/local/san-francisco/2025/03/06/sf-events-march-what-to-do-giants-fanfest?utm_source=chatgpt.com))", - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", - "type": "text-delta", - }, - { - "id": "id-1", - "sourceType": "url", - "title": "SF weekend events: Giants FanFest, crab crawl and more", - "type": "source", - "url": "https://www.axios.com/local/san-francisco/2025/03/06/sf-events-march-what-to-do-giants-fanfest?utm_source=chatgpt.com", - }, - { - "delta": ".", - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", + "delta": "Based on the search results, here are the upcoming features.", + "id": "msg_test", "type": "text-delta", }, { - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", + "id": "msg_test", "type": "text-end", }, { "finishReason": "stop", "providerMetadata": { "openai": { - "responseId": "resp_67cf3390786881908b27489d7e8cfb6b", + "responseId": "resp_test", }, }, "type": "finish", "usage": { "cachedInputTokens": 0, - "inputTokens": 327, - "outputTokens": 834, + "inputTokens": 50, + "outputTokens": 25, "reasoningTokens": 0, - "totalTokens": 1161, + "totalTokens": 75, }, }, ] `); - }); - - describe('errors', () => { - it('should stream error parts', async () => { - server.urls['https://api.openai.com/v1/responses'].response = { - type: 'stream-chunks', - chunks: [ - `data:{"type":"response.created","response":{"id":"resp_67cf3390786881908b27489d7e8cfb6b","object":"response","created_at":1741632400,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"summary":null},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search_preview","search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}\n\n`, - `data:{"type":"error","code":"ERR_SOMETHING","message":"Something went wrong","param":null,"sequence_number":1}\n\n`, - ], - }; + }); - const { stream } = await createModel('gpt-4o-mini').doStream({ - prompt: TEST_PROMPT, - includeRawChunks: false, - }); + it('should stream web search results (sources, tool calls, tool results)', async () => { + prepareChunksFixtureResponse('openai-web-search-tool'); - expect(await convertReadableStreamToArray(stream)) - .toMatchInlineSnapshot(` - [ - { - "type": "stream-start", - "warnings": [], - }, - { - "id": "resp_67cf3390786881908b27489d7e8cfb6b", - "modelId": "gpt-4o-mini-2024-07-18", - "timestamp": 2025-03-10T18:46:40.000Z, - "type": "response-metadata", - }, - { - "error": { - "code": "ERR_SOMETHING", - "message": "Something went wrong", - "param": null, - "sequence_number": 1, - "type": "error", - }, - "type": "error", - }, + const { stream } = await createModel('gpt-5-nano').doStream({ + tools: [ { - "finishReason": "unknown", - "providerMetadata": { - "openai": { - "responseId": "resp_67cf3390786881908b27489d7e8cfb6b", - }, - }, - "type": "finish", - "usage": { - "inputTokens": undefined, - "outputTokens": undefined, - "totalTokens": undefined, - }, - }, - ] - `); - }); - - it('should handle file_search tool calls', async () => { - server.urls['https://api.openai.com/v1/responses'].response = { - type: 'stream-chunks', - chunks: [ - `data:{"type":"response.created","response":{"id":"resp_67cf3390786881908b27489d7e8cfb6b","object":"response","created_at":1741632400,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"summary":null},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"file_search"}],"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}\n\n`, - `data:{"type":"response.output_item.added","output_index":0,"item":{"type":"file_search_call","id":"fs_67cf3390e9608190869b5d45698a7067","status":"in_progress"}}\n\n`, - `data:{"type":"response.output_item.done","output_index":0,"item":{"type":"file_search_call","id":"fs_67cf3390e9608190869b5d45698a7067","status":"completed"}}\n\n`, - `data:{"type":"response.output_item.added","output_index":1,"item":{"type":"message","id":"msg_67cf33924ea88190b8c12bf68c1f6416","status":"in_progress","role":"assistant","content":[]}}\n\n`, - `data:{"type":"response.output_text.delta","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"delta":"Based on the search results, here is the information you requested."}\n\n`, - `data:{"type":"response.output_item.done","output_index":1,"item":{"type":"message","id":"msg_67cf33924ea88190b8c12bf68c1f6416","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Based on the search results, here is the information you requested.","annotations":[]}]}}\n\n`, - `data:{"type":"response.completed","response":{"id":"resp_67cf3390786881908b27489d7e8cfb6b","object":"response","created_at":1741632400,"status":"completed","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-mini-2024-07-18","output":[{"type":"file_search_call","id":"fs_67cf3390e9608190869b5d45698a7067","status":"completed"},{"type":"message","id":"msg_67cf33924ea88190b8c12bf68c1f6416","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Based on the search results, here is the information you requested.","annotations":[]}]}],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"summary":null},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"file_search"}],"top_p":1,"truncation":"disabled","usage":{"input_tokens":327,"input_tokens_details":{"cached_tokens":0},"output_tokens":834,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":1161},"user":null,"metadata":{}}}\n\n`, + type: 'provider-defined', + id: 'openai.web_search', + name: 'web_search', + args: {}, + }, ], - }; - - const { stream } = await createModel('gpt-4o-mini').doStream({ prompt: TEST_PROMPT, - includeRawChunks: false, }); expect(await convertReadableStreamToArray(stream)) @@ -3990,86 +3567,482 @@ describe('OpenAIResponsesLanguageModel', () => { "warnings": [], }, { - "id": "resp_67cf3390786881908b27489d7e8cfb6b", - "modelId": "gpt-4o-mini-2024-07-18", - "timestamp": 2025-03-10T18:46:40.000Z, + "id": "resp_68c187cc09508192aa225af9734e2ed905ca09a4773fcd25", + "modelId": "gpt-5-nano-2025-08-07", + "timestamp": 2025-09-10T14:14:36.000Z, "type": "response-metadata", }, { - "id": "fs_67cf3390e9608190869b5d45698a7067", - "toolName": "file_search", + "id": "rs_68c187cc87a88192b58352081364836c05ca09a4773fcd25:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c187cc87a88192b58352081364836c05ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_68c187cc87a88192b58352081364836c05ca09a4773fcd25:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c187cc87a88192b58352081364836c05ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "id": "ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25", + "toolName": "web_search", + "type": "tool-input-start", + }, + { + "id": "ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25", + "type": "tool-input-end", + }, + { + "input": "{"action":{"type":"search","query":"Berlin news today"}}", + "providerExecuted": true, + "toolCallId": "ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25", + "toolName": "web_search", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "status": "completed", + }, + "toolCallId": "ws_68c187d0973881928c78c79e50ae028805ca09a4773fcd25", + "toolName": "web_search", + "type": "tool-result", + }, + { + "id": "rs_68c187d2484881929a3908a9ad4e745f05ca09a4773fcd25:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c187d2484881929a3908a9ad4e745f05ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_68c187d2484881929a3908a9ad4e745f05ca09a4773fcd25:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c187d2484881929a3908a9ad4e745f05ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "id": "ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25", + "toolName": "web_search", + "type": "tool-input-start", + }, + { + "id": "ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25", + "type": "tool-input-end", + }, + { + "input": "{"action":{"type":"search"}}", + "providerExecuted": true, + "toolCallId": "ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25", + "toolName": "web_search", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "status": "completed", + }, + "toolCallId": "ws_68c187d3954881929c1d6d96c46e4fef05ca09a4773fcd25", + "toolName": "web_search", + "type": "tool-result", + }, + { + "id": "rs_68c187d42c0481929f8e156e064bd0a105ca09a4773fcd25:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c187d42c0481929f8e156e064bd0a105ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_68c187d42c0481929f8e156e064bd0a105ca09a4773fcd25:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c187d42c0481929f8e156e064bd0a105ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "id": "ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25", + "toolName": "web_search", + "type": "tool-input-start", + }, + { + "id": "ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25", + "type": "tool-input-end", + }, + { + "input": "{"action":{"type":"search"}}", + "providerExecuted": true, + "toolCallId": "ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25", + "toolName": "web_search", + "type": "tool-call", + }, + { + "providerExecuted": true, + "result": { + "status": "completed", + }, + "toolCallId": "ws_68c187d4dd548192ab8473f8c95a4d8d05ca09a4773fcd25", + "toolName": "web_search", + "type": "tool-result", + }, + { + "id": "rs_68c187d592f481929b10ff6121241b1d05ca09a4773fcd25:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c187d592f481929b10ff6121241b1d05ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_68c187d592f481929b10ff6121241b1d05ca09a4773fcd25:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c187d592f481929b10ff6121241b1d05ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "id": "ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25", + "toolName": "web_search", "type": "tool-input-start", }, { - "id": "fs_67cf3390e9608190869b5d45698a7067", + "id": "ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25", "type": "tool-input-end", }, { - "input": "", + "input": "{"action":{"type":"search"}}", "providerExecuted": true, - "toolCallId": "fs_67cf3390e9608190869b5d45698a7067", - "toolName": "file_search", + "toolCallId": "ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25", + "toolName": "web_search", "type": "tool-call", }, { "providerExecuted": true, "result": { "status": "completed", - "type": "file_search_tool_result", }, - "toolCallId": "fs_67cf3390e9608190869b5d45698a7067", - "toolName": "file_search", + "toolCallId": "ws_68c187d70ba88192aad48510cff1b4c905ca09a4773fcd25", + "toolName": "web_search", "type": "tool-result", }, { - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", + "id": "rs_68c187d87fb481929fc9d6593d88c3dd05ca09a4773fcd25:0", + "providerMetadata": { + "openai": { + "itemId": "rs_68c187d87fb481929fc9d6593d88c3dd05ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-start", + }, + { + "id": "rs_68c187d87fb481929fc9d6593d88c3dd05ca09a4773fcd25:0", "providerMetadata": { "openai": { - "itemId": "msg_67cf33924ea88190b8c12bf68c1f6416", + "itemId": "rs_68c187d87fb481929fc9d6593d88c3dd05ca09a4773fcd25", + "reasoningEncryptedContent": null, + }, + }, + "type": "reasoning-end", + }, + { + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "providerMetadata": { + "openai": { + "itemId": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", }, }, "type": "text-start", }, { - "delta": "Based on the search results, here is the information you requested.", - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", + "delta": "Here’s what’s notable in Berlin today (September 10, 2025), based on three quick web searches: + + - Berlin Art Week 2025 kicks off today and runs through September 14. The city’s autumn art season opens with more than 100 venues, featuring exhibitions from Patti Smith, Mark Leckey, Katharina Grosse, Carrie Mae Weems, and more. ([wallpaper.com](https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025)) + + - The city is highlighting its 200-year Museum Island anniversary this year, with ongoing events and exhibitions around Berlin’s historic center. This is part of Berlin’s big year of cultural highlights. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events)) + + - 49h ICC: Open House is scheduled for September 11–14, offering guided tours and design talks at the former ICC Berlin. It’s one of the major architecture/design events associated with Berlin 2025. ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events)) + + - Open Monument Day is coming up on September 13–14, when many", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "id": "id-0", + "sourceType": "url", + "title": "What to see at Berlin Art Week 2025 | Wallpaper*", + "type": "source", + "url": "https://www.wallpaper.com/art/exhibitions-shows/berlin-art-week-2025", + }, + { + "id": "id-1", + "sourceType": "url", + "title": "Berlin 2025 – the main events | visitBerlin.de", + "type": "source", + "url": "https://www.visitberlin.de/en/berlin-2025-the-main-events", + }, + { + "id": "id-2", + "sourceType": "url", + "title": "Berlin 2025 – the main events | visitBerlin.de", + "type": "source", + "url": "https://www.visitberlin.de/en/berlin-2025-the-main-events", + }, + { + "delta": " historic sites around Berlin open to the public with special programs. If you’re in town this weekend, it’s a good chance to explore landmarks that aren’t usually accessible.", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "delta": " ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events)) + + - If you’re a sports fan, Berlin will host NFL games", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "id": "id-3", + "sourceType": "url", + "title": "Berlin 2025 – the main events | visitBerlin.de", + "type": "source", + "url": "https://www.visitberlin.de/en/berlin-2025-the-main-events", + }, + { + "delta": " in November 2025 (three regular-season games in the Olympic Stadium, with the Indianapolis Colts among", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "delta": " the teams). It’s part of Berlin’s ongoing slate of major events this year", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "delta": ". ([visitberlin.de](https://www.visitberlin.de/en/berlin-2025-the-main-events)) + + - For some broader", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "id": "id-4", + "sourceType": "url", + "title": "Berlin 2025 – the main events | visitBerlin.de", + "type": "source", + "url": "https://www.visitberlin.de/en/berlin-2025-the-main-events", + }, + { + "delta": " context, Berlin has been discussing its role in postwar security arrangements for Ukraine, with", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "delta": " German officials signaling readiness to increase support but delaying a formal deployment decision until broader conditions are", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "delta": " clearer. This", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", "type": "text-delta", }, { - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", + "delta": " was reported for early September 2025. ([reuters.com](https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/))", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "id": "id-5", + "sourceType": "url", + "title": "Berlin holds off decision on participation in postwar Ukraine force | Reuters", + "type": "source", + "url": "https://www.reuters.com/world/europe/berlin-postpones-decision-military-engagement-regarding-ukraine-2025-09-04/", + }, + { + "delta": " + + Would you like me to pull live updates or focus on a specific topic (arts,", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "delta": " politics, sports) from today?", + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", + "type": "text-delta", + }, + { + "id": "msg_68c187e279048192be3775da689aa25105ca09a4773fcd25", "type": "text-end", }, { "finishReason": "stop", "providerMetadata": { "openai": { - "responseId": "resp_67cf3390786881908b27489d7e8cfb6b", + "responseId": "resp_68c187cc09508192aa225af9734e2ed905ca09a4773fcd25", + "serviceTier": "default", }, }, "type": "finish", "usage": { - "cachedInputTokens": 0, - "inputTokens": 327, - "outputTokens": 834, - "reasoningTokens": 0, - "totalTokens": 1161, + "cachedInputTokens": 34560, + "inputTokens": 60093, + "outputTokens": 4080, + "reasoningTokens": 3648, + "totalTokens": 64173, }, }, ] `); }); + }); + + describe('file search tool', () => { + let result: Awaited>; + + describe('without results include', () => { + beforeEach(async () => { + prepareChunksFixtureResponse('openai-file-search-tool.1'); + + result = await createModel('gpt-5-nano').doStream({ + prompt: TEST_PROMPT, + tools: [ + { + type: 'provider-defined', + id: 'openai.file_search', + name: 'file_search', + args: { + vectorStoreIds: ['vs_68caad8bd5d88191ab766cf043d89a18'], + }, + }, + ], + }); + }); + + it('should stream file search results', async () => { + expect( + await convertReadableStreamToArray(result.stream), + ).toMatchSnapshot(); + }); + }); + + describe('with results include', () => { + beforeEach(async () => { + prepareChunksFixtureResponse('openai-file-search-tool.2'); + + result = await createModel('gpt-5-nano').doStream({ + prompt: TEST_PROMPT, + tools: [ + { + type: 'provider-defined', + id: 'openai.file_search', + name: 'file_search', + args: { + vectorStoreIds: ['vs_68caad8bd5d88191ab766cf043d89a18'], + }, + }, + ], + providerOptions: { + openai: { + include: ['file_search_call.results'], + }, + }, + }); + }); + + it('should stream file search results', async () => { + expect( + await convertReadableStreamToArray(result.stream), + ).toMatchSnapshot(); + }); + }); + }); + + describe('code interpreter tool', () => { + let result: Awaited>; + + beforeEach(async () => { + prepareChunksFixtureResponse('openai-code-interpreter-tool.1'); + + result = await createModel('gpt-5-nano').doStream({ + prompt: TEST_PROMPT, + tools: [ + { + type: 'provider-defined', + id: 'openai.code_interpreter', + name: 'code_interpreter', + args: {}, + }, + ], + }); + }); + + it('should stream code interpreter results', async () => { + expect( + await convertReadableStreamToArray(result.stream), + ).toMatchSnapshot(); + }); + }); + + describe('image generation tool', () => { + let result: Awaited>; + + beforeEach(async () => { + prepareChunksFixtureResponse('openai-image-generation-tool.1'); + + result = await createModel('gpt-5-nano').doStream({ + prompt: TEST_PROMPT, + tools: [ + { + type: 'provider-defined', + id: 'openai.image_generation', + name: 'image_generation', + args: {}, + }, + ], + }); + }); + + it('should stream code image generation results', async () => { + expect( + await convertReadableStreamToArray(result.stream), + ).toMatchSnapshot(); + }); + }); - it('should handle file_search tool calls with results', async () => { + describe('errors', () => { + it('should stream error parts', async () => { server.urls['https://api.openai.com/v1/responses'].response = { type: 'stream-chunks', chunks: [ - `data:{"type":"response.created","response":{"id":"resp_67cf3390786881908b27489d7e8cfb6b","object":"response","created_at":1741632400,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"summary":null},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"file_search"}],"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}\n\n`, - `data:{"type":"response.output_item.added","output_index":0,"item":{"type":"file_search_call","id":"fs_67cf3390e9608190869b5d45698a7067","status":"in_progress"}}\n\n`, - `data:{"type":"response.output_item.done","output_index":0,"item":{"type":"file_search_call","id":"fs_67cf3390e9608190869b5d45698a7067","status":"completed","queries":["AI information"],"results":[{"attributes":{"file_id":"file-123","filename":"ai_guide.pdf","score":0.95,"text":"AI is a field of computer science"}}]}}\n\n`, - `data:{"type":"response.output_item.added","output_index":1,"item":{"type":"message","id":"msg_67cf33924ea88190b8c12bf68c1f6416","status":"in_progress","role":"assistant","content":[]}}\n\n`, - `data:{"type":"response.output_text.delta","item_id":"msg_67cf33924ea88190b8c12bf68c1f6416","output_index":1,"content_index":0,"delta":"Based on the search results, here is the information you requested."}\n\n`, - `data:{"type":"response.output_item.done","output_index":1,"item":{"type":"message","id":"msg_67cf33924ea88190b8c12bf68c1f6416","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Based on the search results, here is the information you requested.","annotations":[]}]}}\n\n`, - `data:{"type":"response.completed","response":{"id":"resp_67cf3390786881908b27489d7e8cfb6b","object":"response","created_at":1741632400,"status":"completed","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-mini-2024-07-18","output":[{"type":"file_search_call","id":"fs_67cf3390e9608190869b5d45698a7067","status":"completed","queries":["AI information"],"results":[{"attributes":{"file_id":"file-123","filename":"ai_guide.pdf","score":0.95,"text":"AI is a field of computer science"}}]},{"type":"message","id":"msg_67cf33924ea88190b8c12bf68c1f6416","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Based on the search results, here is the information you requested.","annotations":[]}]}],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"summary":null},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"file_search"}],"top_p":1,"truncation":"disabled","usage":{"input_tokens":327,"input_tokens_details":{"cached_tokens":0},"output_tokens":834,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":1161},"user":null,"metadata":{}}}\n\n`, + `data:{"type":"response.created","response":{"id":"resp_67cf3390786881908b27489d7e8cfb6b","object":"response","created_at":1741632400,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"summary":null},"store":true,"temperature":0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[{"type":"web_search","search_context_size":"medium","user_location":{"type":"approximate","city":null,"country":"US","region":null,"timezone":null}}],"top_p":1,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}\n\n`, + `data:{"type":"error","code":"ERR_SOMETHING","message":"Something went wrong","param":null,"sequence_number":1}\n\n`, ], }; @@ -4080,92 +4053,43 @@ describe('OpenAIResponsesLanguageModel', () => { expect(await convertReadableStreamToArray(stream)) .toMatchInlineSnapshot(` - [ - { - "type": "stream-start", - "warnings": [], - }, - { - "id": "resp_67cf3390786881908b27489d7e8cfb6b", - "modelId": "gpt-4o-mini-2024-07-18", - "timestamp": 2025-03-10T18:46:40.000Z, - "type": "response-metadata", - }, - { - "id": "fs_67cf3390e9608190869b5d45698a7067", - "toolName": "file_search", - "type": "tool-input-start", - }, - { - "id": "fs_67cf3390e9608190869b5d45698a7067", - "type": "tool-input-end", - }, - { - "input": "", - "providerExecuted": true, - "toolCallId": "fs_67cf3390e9608190869b5d45698a7067", - "toolName": "file_search", - "type": "tool-call", - }, - { - "providerExecuted": true, - "result": { - "queries": [ - "AI information", - ], - "results": [ - { - "attributes": { - "file_id": "file-123", - "filename": "ai_guide.pdf", - "score": 0.95, - "text": "AI is a field of computer science", - }, - }, - ], - "status": "completed", - "type": "file_search_tool_result", - }, - "toolCallId": "fs_67cf3390e9608190869b5d45698a7067", - "toolName": "file_search", - "type": "tool-result", + [ + { + "type": "stream-start", + "warnings": [], + }, + { + "id": "resp_67cf3390786881908b27489d7e8cfb6b", + "modelId": "gpt-4o-mini-2024-07-18", + "timestamp": 2025-03-10T18:46:40.000Z, + "type": "response-metadata", + }, + { + "error": { + "code": "ERR_SOMETHING", + "message": "Something went wrong", + "param": null, + "sequence_number": 1, + "type": "error", }, - { - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", - "providerMetadata": { - "openai": { - "itemId": "msg_67cf33924ea88190b8c12bf68c1f6416", - }, + "type": "error", + }, + { + "finishReason": "unknown", + "providerMetadata": { + "openai": { + "responseId": "resp_67cf3390786881908b27489d7e8cfb6b", }, - "type": "text-start", - }, - { - "delta": "Based on the search results, here is the information you requested.", - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", - "type": "text-delta", - }, - { - "id": "msg_67cf33924ea88190b8c12bf68c1f6416", - "type": "text-end", }, - { - "finishReason": "stop", - "providerMetadata": { - "openai": { - "responseId": "resp_67cf3390786881908b27489d7e8cfb6b", - }, - }, - "type": "finish", - "usage": { - "cachedInputTokens": 0, - "inputTokens": 327, - "outputTokens": 834, - "reasoningTokens": 0, - "totalTokens": 1161, - }, + "type": "finish", + "usage": { + "inputTokens": undefined, + "outputTokens": undefined, + "totalTokens": undefined, }, - ] - `); + }, + ] + `); }); }); @@ -5020,230 +4944,6 @@ describe('OpenAIResponsesLanguageModel', () => { }); }); }); - - describe('server-side tools', () => { - const TEST_PROMPT = [ - { - role: 'user' as const, - content: [ - { - type: 'text' as const, - text: 'Search for recent news about San Francisco tech events, then check the status of our server-side tool implementation.', - }, - ], - }, - ]; - - function prepareJsonResponse(body: any) { - server.urls['https://api.openai.com/v1/responses'].response = { - type: 'json-value', - body, - }; - } - - it('should enable server-side web search when using openai.tools.webSearchPreview', async () => { - prepareJsonResponse({ - id: 'resp_67cf2b2f6bd081909be2c8054ddef0eb', - object: 'response', - created_at: 1741630255, - status: 'completed', - error: null, - incomplete_details: null, - instructions: null, - max_output_tokens: null, - model: 'gpt-4o-mini', - output: [ - { - type: 'web_search_call', - id: 'ws_67cf2b3051e88190b006770db6fdb13d', - status: 'completed', - }, - { - type: 'message', - id: 'msg_67cf2b35467481908f24412e4fd40d66', - status: 'completed', - role: 'assistant', - content: [ - { - type: 'output_text', - text: "As of June 23, 2025, here are some recent developments in San Francisco's tech scene:", - annotations: [ - { - type: 'url_citation', - start_index: 0, - end_index: 50, - url: 'https://www.eventbrite.sg/d/ca--san-francisco/tech-events/?utm_source=openai', - title: - 'Discover Tech Events & Activities in San Francisco, CA | Eventbrite', - }, - { - type: 'url_citation', - start_index: 51, - end_index: 100, - url: 'https://www.axios.com/2024/12/10/ai-sf-summit-2024-roundup?utm_source=openai', - title: 'AI+ SF Summit: AI agents are the next big thing', - }, - ], - }, - ], - }, - ], - usage: { input_tokens: 1359, output_tokens: 624 }, - }); - - const result = await createModel('gpt-4o-mini').doGenerate({ - prompt: TEST_PROMPT, - tools: [ - { - type: 'provider-defined', - id: 'openai.web_search_preview', - name: 'web_search_preview', - args: { - searchContextSize: 'high', - userLocation: { - type: 'approximate', - city: 'San Francisco', - region: 'California', - country: 'US', - }, - }, - }, - ], - }); - - expect(result.content).toMatchInlineSnapshot(` - [ - { - "input": "{}", - "providerExecuted": true, - "toolCallId": "ws_67cf2b3051e88190b006770db6fdb13d", - "toolName": "web_search_preview", - "type": "tool-call", - }, - { - "providerExecuted": true, - "result": { - "status": "completed", - }, - "toolCallId": "ws_67cf2b3051e88190b006770db6fdb13d", - "toolName": "web_search_preview", - "type": "tool-result", - }, - { - "providerMetadata": { - "openai": { - "itemId": "msg_67cf2b35467481908f24412e4fd40d66", - }, - }, - "text": "As of June 23, 2025, here are some recent developments in San Francisco's tech scene:", - "type": "text", - }, - { - "id": "id-0", - "sourceType": "url", - "title": "Discover Tech Events & Activities in San Francisco, CA | Eventbrite", - "type": "source", - "url": "https://www.eventbrite.sg/d/ca--san-francisco/tech-events/?utm_source=openai", - }, - { - "id": "id-1", - "sourceType": "url", - "title": "AI+ SF Summit: AI agents are the next big thing", - "type": "source", - "url": "https://www.axios.com/2024/12/10/ai-sf-summit-2024-roundup?utm_source=openai", - }, - ] - `); - }); - - it('should handle computer use tool calls', async () => { - prepareJsonResponse({ - id: 'resp_computer_test', - object: 'response', - created_at: 1741630255, - status: 'completed', - error: null, - incomplete_details: null, - instructions: null, - max_output_tokens: null, - model: 'gpt-4o-mini', - output: [ - { - type: 'computer_call', - id: 'computer_67cf2b3051e88190b006770db6fdb13d', - status: 'completed', - }, - { - type: 'message', - id: 'msg_computer_test', - status: 'completed', - role: 'assistant', - content: [ - { - type: 'output_text', - text: "I've completed the computer task.", - annotations: [], - }, - ], - }, - ], - usage: { input_tokens: 100, output_tokens: 50 }, - }); - - const result = await createModel('gpt-4o-mini').doGenerate({ - prompt: [ - { - role: 'user' as const, - content: [ - { - type: 'text' as const, - text: 'Use the computer to complete a task.', - }, - ], - }, - ], - tools: [ - { - type: 'provider-defined', - id: 'openai.computer_use', - name: 'computer_use', - args: {}, - }, - ], - }); - - expect(result.content).toMatchInlineSnapshot(` - [ - { - "input": "", - "providerExecuted": true, - "toolCallId": "computer_67cf2b3051e88190b006770db6fdb13d", - "toolName": "computer_use", - "type": "tool-call", - }, - { - "providerExecuted": true, - "result": { - "status": "completed", - "type": "computer_use_tool_result", - }, - "toolCallId": "computer_67cf2b3051e88190b006770db6fdb13d", - "toolName": "computer_use", - "type": "tool-result", - }, - { - "providerMetadata": { - "openai": { - "itemId": "msg_computer_test", - }, - }, - "text": "I've completed the computer task.", - "type": "text", - }, - ] - `); - }); - }); }); describe('fileIdPrefixes configuration', () => { diff --git a/packages/openai/src/responses/openai-responses-language-model.ts b/packages/openai/src/responses/openai-responses-language-model.ts index e997ba57d9ba..4fb85fa531fe 100644 --- a/packages/openai/src/responses/openai-responses-language-model.ts +++ b/packages/openai/src/responses/openai-responses-language-model.ts @@ -4,6 +4,7 @@ import { LanguageModelV2CallWarning, LanguageModelV2Content, LanguageModelV2FinishReason, + LanguageModelV2ProviderDefinedTool, LanguageModelV2StreamPart, LanguageModelV2Usage, SharedV2ProviderMetadata, @@ -20,8 +21,18 @@ import { import { z } from 'zod/v4'; import { OpenAIConfig } from '../openai-config'; import { openaiFailedResponseHandler } from '../openai-error'; -import { convertToOpenAIResponsesMessages } from './convert-to-openai-responses-messages'; +import { + codeInterpreterInputSchema, + codeInterpreterOutputSchema, +} from '../tool/code-interpreter'; +import { fileSearchOutputSchema } from '../tool/file-search'; +import { imageGenerationOutputSchema } from '../tool/image-generation'; +import { convertToOpenAIResponsesInput } from './convert-to-openai-responses-input'; import { mapOpenAIResponseFinishReason } from './map-openai-responses-finish-reason'; +import { + OpenAIResponsesIncludeOptions, + OpenAIResponsesIncludeValue, +} from './openai-responses-api-types'; import { prepareResponsesTools } from './openai-responses-prepare-tools'; import { OpenAIResponsesModelId } from './openai-responses-settings'; @@ -48,6 +59,44 @@ const webSearchCallItem = z.object({ .nullish(), }); +const fileSearchCallItem = z.object({ + type: z.literal('file_search_call'), + id: z.string(), + queries: z.array(z.string()), + results: z + .array( + z.object({ + attributes: z.record(z.string(), z.unknown()), + file_id: z.string(), + filename: z.string(), + score: z.number(), + text: z.string(), + }), + ) + .nullish(), +}); + +const codeInterpreterCallItem = z.object({ + type: z.literal('code_interpreter_call'), + id: z.string(), + code: z.string().nullable(), + container_id: z.string(), + outputs: z + .array( + z.discriminatedUnion('type', [ + z.object({ type: z.literal('logs'), logs: z.string() }), + z.object({ type: z.literal('image'), url: z.string() }), + ]), + ) + .nullable(), +}); + +const imageGenerationCallItem = z.object({ + type: z.literal('image_generation_call'), + id: z.string(), + result: z.string(), +}); + /** * `top_logprobs` request body argument can be set to an integer between * 0 and 20 specifying the number of most likely tokens to return at each @@ -135,38 +184,72 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { warnings.push({ type: 'unsupported-setting', setting: 'stopSequences' }); } - const { messages, warnings: messageWarnings } = - await convertToOpenAIResponsesMessages({ - prompt, - systemMessageMode: modelConfig.systemMessageMode, - fileIdPrefixes: this.config.fileIdPrefixes, - }); - - warnings.push(...messageWarnings); - const openaiOptions = await parseProviderOptions({ provider: 'openai', providerOptions, schema: openaiResponsesProviderOptionsSchema, }); + const { input, warnings: inputWarnings } = + await convertToOpenAIResponsesInput({ + prompt, + systemMessageMode: modelConfig.systemMessageMode, + fileIdPrefixes: this.config.fileIdPrefixes, + store: openaiOptions?.store ?? true, + }); + + warnings.push(...inputWarnings); + const strictJsonSchema = openaiOptions?.strictJsonSchema ?? false; + let include: OpenAIResponsesIncludeOptions = openaiOptions?.include; + + function addInclude(key: OpenAIResponsesIncludeValue) { + include = include != null ? [...include, key] : [key]; + } + + function hasOpenAITool(id: string) { + return ( + tools?.find( + tool => tool.type === 'provider-defined' && tool.id === id, + ) != null + ); + } + + // when logprobs are requested, automatically include them: const topLogprobs = typeof openaiOptions?.logprobs === 'number' ? openaiOptions?.logprobs : openaiOptions?.logprobs === true ? TOP_LOGPROBS_MAX : undefined; - const openaiOptionsInclude = topLogprobs - ? Array.isArray(openaiOptions?.include) - ? [...openaiOptions?.include, 'message.output_text.logprobs'] - : ['message.output_text.logprobs'] - : openaiOptions?.include; + + if (topLogprobs) { + addInclude('message.output_text.logprobs'); + } + + // when a web search tool is present, automatically include the sources: + const webSearchToolName = ( + tools?.find( + tool => + tool.type === 'provider-defined' && + (tool.id === 'openai.web_search' || + tool.id === 'openai.web_search_preview'), + ) as LanguageModelV2ProviderDefinedTool | undefined + )?.name; + + if (webSearchToolName) { + addInclude('web_search_call.action.sources'); + } + + // when a code interpreter tool is present, automatically include the outputs: + if (hasOpenAITool('openai.code_interpreter')) { + addInclude('code_interpreter_call.outputs'); + } const baseArgs = { model: this.modelId, - input: messages, + input, temperature, top_p: topP, max_output_tokens: maxOutputTokens, @@ -192,6 +275,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { }), // provider options: + max_tool_calls: openaiOptions?.maxToolCalls, metadata: openaiOptions?.metadata, parallel_tool_calls: openaiOptions?.parallelToolCalls, previous_response_id: openaiOptions?.previousResponseId, @@ -199,7 +283,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { user: openaiOptions?.user, instructions: openaiOptions?.instructions, service_tier: openaiOptions?.serviceTier, - include: openaiOptionsInclude, + include, prompt_cache_key: openaiOptions?.promptCacheKey, safety_identifier: openaiOptions?.safetyIdentifier, top_logprobs: topLogprobs, @@ -301,6 +385,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { }); return { + webSearchToolName, args: { ...baseArgs, tools: openaiTools, @@ -313,7 +398,11 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { async doGenerate( options: Parameters[0], ): Promise>> { - const { args: body, warnings } = await this.getArgs(options); + const { + args: body, + warnings, + webSearchToolName, + } = await this.getArgs(options); const url = this.config.url({ path: '/responses', modelId: this.modelId, @@ -376,9 +465,10 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { }), ), }), - z.object({ - type: z.literal('code_interpreter_call'), - }), + webSearchCallItem, + fileSearchCallItem, + codeInterpreterCallItem, + imageGenerationCallItem, z.object({ type: z.literal('function_call'), call_id: z.string(), @@ -386,30 +476,11 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { arguments: z.string(), id: z.string(), }), - webSearchCallItem, z.object({ type: z.literal('computer_call'), id: z.string(), status: z.string().optional(), }), - z.object({ - type: z.literal('file_search_call'), - id: z.string(), - status: z.string().optional(), - queries: z.array(z.string()).nullish(), - results: z - .array( - z.object({ - attributes: z.object({ - file_id: z.string(), - filename: z.string(), - score: z.number(), - text: z.string(), - }), - }), - ) - .nullish(), - }), z.object({ type: z.literal('reasoning'), id: z.string(), @@ -424,7 +495,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { ]), ), service_tier: z.string().nullish(), - incomplete_details: z.object({ reason: z.string() }).nullable(), + incomplete_details: z.object({ reason: z.string() }).nullish(), usage: usageSchema, }), ), @@ -474,6 +545,28 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { break; } + case 'image_generation_call': { + content.push({ + type: 'tool-call', + toolCallId: part.id, + toolName: 'image_generation', + input: '{}', + providerExecuted: true, + }); + + content.push({ + type: 'tool-result', + toolCallId: part.id, + toolName: 'image_generation', + result: { + result: part.result, + } satisfies z.infer, + providerExecuted: true, + }); + + break; + } + case 'message': { for (const contentPart of part.content) { if ( @@ -539,7 +632,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { content.push({ type: 'tool-call', toolCallId: part.id, - toolName: 'web_search_preview', + toolName: webSearchToolName ?? 'web_search', input: JSON.stringify({ action: part.action }), providerExecuted: true, }); @@ -547,10 +640,11 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { content.push({ type: 'tool-result', toolCallId: part.id, - toolName: 'web_search_preview', + toolName: webSearchToolName ?? 'web_search', result: { status: part.status }, providerExecuted: true, }); + break; } @@ -581,7 +675,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { type: 'tool-call', toolCallId: part.id, toolName: 'file_search', - input: '', + input: '{}', providerExecuted: true, }); @@ -590,11 +684,40 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { toolCallId: part.id, toolName: 'file_search', result: { - type: 'file_search_tool_result', - status: part.status || 'completed', - ...(part.queries && { queries: part.queries }), - ...(part.results && { results: part.results }), - }, + queries: part.queries, + results: + part.results?.map(result => ({ + attributes: result.attributes, + fileId: result.file_id, + filename: result.filename, + score: result.score, + text: result.text, + })) ?? null, + } satisfies z.infer, + providerExecuted: true, + }); + break; + } + + case 'code_interpreter_call': { + content.push({ + type: 'tool-call', + toolCallId: part.id, + toolName: 'code_interpreter', + input: JSON.stringify({ + code: part.code, + containerId: part.container_id, + } satisfies z.infer), + providerExecuted: true, + }); + + content.push({ + type: 'tool-result', + toolCallId: part.id, + toolName: 'code_interpreter', + result: { + outputs: part.outputs, + } satisfies z.infer, providerExecuted: true, }); break; @@ -645,7 +768,11 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { async doStream( options: Parameters[0], ): Promise>> { - const { args: body, warnings } = await this.getArgs(options); + const { + args: body, + warnings, + webSearchToolName, + } = await this.getArgs(options); const { responseHeaders, value: response } = await postJsonToApi({ url: this.config.url({ @@ -731,14 +858,14 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { }); } else if (value.item.type === 'web_search_call') { ongoingToolCalls[value.output_index] = { - toolName: 'web_search_preview', + toolName: webSearchToolName ?? 'web_search', toolCallId: value.item.id, }; controller.enqueue({ type: 'tool-input-start', id: value.item.id, - toolName: 'web_search_preview', + toolName: webSearchToolName ?? 'web_search', }); } else if (value.item.type === 'computer_call') { ongoingToolCalls[value.output_index] = { @@ -752,15 +879,20 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { toolName: 'computer_use', }); } else if (value.item.type === 'file_search_call') { - ongoingToolCalls[value.output_index] = { - toolName: 'file_search', - toolCallId: value.item.id, - }; - controller.enqueue({ - type: 'tool-input-start', - id: value.item.id, + type: 'tool-call', + toolCallId: value.item.id, toolName: 'file_search', + input: '{}', + providerExecuted: true, + }); + } else if (value.item.type === 'image_generation_call') { + controller.enqueue({ + type: 'tool-call', + toolCallId: value.item.id, + toolName: 'image_generation', + input: '{}', + providerExecuted: true, }); } else if (value.item.type === 'message') { controller.enqueue({ @@ -864,28 +996,51 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV2 { ongoingToolCalls[value.output_index] = undefined; controller.enqueue({ - type: 'tool-input-end', - id: value.item.id, + type: 'tool-result', + toolCallId: value.item.id, + toolName: 'file_search', + result: { + queries: value.item.queries, + results: + value.item.results?.map(result => ({ + attributes: result.attributes, + fileId: result.file_id, + filename: result.filename, + score: result.score, + text: result.text, + })) ?? null, + } satisfies z.infer, + providerExecuted: true, }); - + } else if (value.item.type === 'code_interpreter_call') { controller.enqueue({ type: 'tool-call', toolCallId: value.item.id, - toolName: 'file_search', - input: '', + toolName: 'code_interpreter', + input: JSON.stringify({ + code: value.item.code, + containerId: value.item.container_id, + } satisfies z.infer), providerExecuted: true, }); controller.enqueue({ type: 'tool-result', toolCallId: value.item.id, - toolName: 'file_search', + toolName: 'code_interpreter', result: { - type: 'file_search_tool_result', - status: value.item.status || 'completed', - ...(value.item.queries && { queries: value.item.queries }), - ...(value.item.results && { results: value.item.results }), - }, + outputs: value.item.outputs, + } satisfies z.infer, + providerExecuted: true, + }); + } else if (value.item.type === 'image_generation_call') { + controller.enqueue({ + type: 'tool-result', + toolCallId: value.item.id, + toolName: 'image_generation', + result: { + result: value.item.result, + } satisfies z.infer, providerExecuted: true, }); } else if (value.item.type === 'message') { @@ -1132,20 +1287,10 @@ const responseOutputItemAddedSchema = z.object({ z.object({ type: z.literal('file_search_call'), id: z.string(), - status: z.string(), - queries: z.array(z.string()).nullish(), - results: z - .array( - z.object({ - attributes: z.object({ - file_id: z.string(), - filename: z.string(), - score: z.number(), - text: z.string(), - }), - }), - ) - .optional(), + }), + z.object({ + type: z.literal('image_generation_call'), + id: z.string(), }), ]), }); @@ -1171,30 +1316,15 @@ const responseOutputItemDoneSchema = z.object({ arguments: z.string(), status: z.literal('completed'), }), + codeInterpreterCallItem, + imageGenerationCallItem, webSearchCallItem, + fileSearchCallItem, z.object({ type: z.literal('computer_call'), id: z.string(), status: z.literal('completed'), }), - z.object({ - type: z.literal('file_search_call'), - id: z.string(), - status: z.literal('completed'), - queries: z.array(z.string()).nullish(), - results: z - .array( - z.object({ - attributes: z.object({ - file_id: z.string(), - filename: z.string(), - score: z.number(), - text: z.string(), - }), - }), - ) - .nullish(), - }), ]), }); @@ -1412,16 +1542,6 @@ function getResponsesModelConfig(modelId: string): ResponsesModelConfig { // TODO AI SDK 6: use optional here instead of nullish const openaiResponsesProviderOptionsSchema = z.object({ - metadata: z.any().nullish(), - parallelToolCalls: z.boolean().nullish(), - previousResponseId: z.string().nullish(), - store: z.boolean().nullish(), - user: z.string().nullish(), - reasoningEffort: z.string().nullish(), - strictJsonSchema: z.boolean().nullish(), - instructions: z.string().nullish(), - reasoningSummary: z.string().nullish(), - serviceTier: z.enum(['auto', 'flex', 'priority']).nullish(), include: z .array( z.enum([ @@ -1431,9 +1551,7 @@ const openaiResponsesProviderOptionsSchema = z.object({ ]), ) .nullish(), - textVerbosity: z.enum(['low', 'medium', 'high']).nullish(), - promptCacheKey: z.string().nullish(), - safetyIdentifier: z.string().nullish(), + instructions: z.string().nullish(), /** * Return the log probabilities of the tokens. @@ -1450,6 +1568,26 @@ const openaiResponsesProviderOptionsSchema = z.object({ logprobs: z .union([z.boolean(), z.number().min(1).max(TOP_LOGPROBS_MAX)]) .optional(), + + /** + * The maximum number of total calls to built-in tools that can be processed in a response. + * This maximum number applies across all built-in tool calls, not per individual tool. + * Any further attempts to call a tool by the model will be ignored. + */ + maxToolCalls: z.number().nullish(), + + metadata: z.any().nullish(), + parallelToolCalls: z.boolean().nullish(), + previousResponseId: z.string().nullish(), + promptCacheKey: z.string().nullish(), + reasoningEffort: z.string().nullish(), + reasoningSummary: z.string().nullish(), + safetyIdentifier: z.string().nullish(), + serviceTier: z.enum(['auto', 'flex', 'priority']).nullish(), + store: z.boolean().nullish(), + strictJsonSchema: z.boolean().nullish(), + textVerbosity: z.enum(['low', 'medium', 'high']).nullish(), + user: z.string().nullish(), }); export type OpenAIResponsesProviderOptions = z.infer< diff --git a/packages/openai/src/responses/openai-responses-prepare-tools.test.ts b/packages/openai/src/responses/openai-responses-prepare-tools.test.ts index b8aa8e8ce1ce..1c90e1b9adb0 100644 --- a/packages/openai/src/responses/openai-responses-prepare-tools.test.ts +++ b/packages/openai/src/responses/openai-responses-prepare-tools.test.ts @@ -203,4 +203,63 @@ describe('prepareResponsesTools', () => { expect(result.toolWarnings).toEqual([]); }); }); + + describe('image generation', () => { + it('should prepare image_generation tool with all options', () => { + const result = prepareResponsesTools({ + tools: [ + { + type: 'provider-defined', + id: 'openai.image_generation', + name: 'image_generation', + args: { + background: 'opaque', + size: '1536x1024', + quality: 'high', + moderation: 'auto', + outputFormat: 'png', + outputCompression: 100, + }, + }, + ], + strictJsonSchema: false, + }); + + expect(result.tools).toEqual([ + { + type: 'image_generation', + background: 'opaque', + size: '1536x1024', + quality: 'high', + moderation: 'auto', + output_format: 'png', + output_compression: 100, + }, + ]); + expect(result.toolWarnings).toEqual([]); + }); + + it('should support tool choice selection for image_generation', () => { + const result = prepareResponsesTools({ + tools: [ + { + type: 'provider-defined', + id: 'openai.image_generation', + name: 'image_generation', + args: {}, + }, + ], + toolChoice: { type: 'tool', toolName: 'image_generation' }, + strictJsonSchema: false, + }); + + expect(result.tools).toEqual([ + { + type: 'image_generation', + }, + ]); + expect(result.toolChoice).toEqual({ type: 'image_generation' }); + expect(result.toolWarnings).toEqual([]); + }); + }); }); diff --git a/packages/openai/src/responses/openai-responses-prepare-tools.ts b/packages/openai/src/responses/openai-responses-prepare-tools.ts index b70930931191..3ed69181ea82 100644 --- a/packages/openai/src/responses/openai-responses-prepare-tools.ts +++ b/packages/openai/src/responses/openai-responses-prepare-tools.ts @@ -7,6 +7,7 @@ import { codeInterpreterArgsSchema } from '../tool/code-interpreter'; import { fileSearchArgsSchema } from '../tool/file-search'; import { webSearchArgsSchema } from '../tool/web-search'; import { webSearchPreviewArgsSchema } from '../tool/web-search-preview'; +import { imageGenerationArgsSchema } from '../tool/image-generation'; import { OpenAIResponsesTool } from './openai-responses-api-types'; export function prepareResponsesTools({ @@ -27,7 +28,8 @@ export function prepareResponsesTools({ | { type: 'web_search_preview' } | { type: 'web_search' } | { type: 'function'; name: string } - | { type: 'code_interpreter' }; + | { type: 'code_interpreter' } + | { type: 'image_generation' }; toolWarnings: LanguageModelV2CallWarning[]; } { // when the tools array is empty, change it to undefined to prevent errors: @@ -56,15 +58,20 @@ export function prepareResponsesTools({ switch (tool.id) { case 'openai.file_search': { const args = fileSearchArgsSchema.parse(tool.args); + openaiTools.push({ type: 'file_search', vector_store_ids: args.vectorStoreIds, max_num_results: args.maxNumResults, ranking_options: args.ranking - ? { ranker: args.ranking.ranker } + ? { + ranker: args.ranking.ranker, + score_threshold: args.ranking.scoreThreshold, + } : undefined, filters: args.filters, }); + break; } case 'openai.web_search_preview': { @@ -102,8 +109,25 @@ export function prepareResponsesTools({ }); break; } - default: { - toolWarnings.push({ type: 'unsupported-tool', tool }); + case 'openai.image_generation': { + const args = imageGenerationArgsSchema.parse(tool.args); + openaiTools.push({ + type: 'image_generation', + background: args.background, + input_fidelity: args.inputFidelity, + input_image_mask: args.inputImageMask + ? { + file_id: args.inputImageMask.fileId, + image_url: args.inputImageMask.imageUrl, + } + : undefined, + model: args.model, + size: args.size, + quality: args.quality, + moderation: args.moderation, + output_format: args.outputFormat, + output_compression: args.outputCompression, + }); break; } } @@ -132,6 +156,7 @@ export function prepareResponsesTools({ toolChoice: toolChoice.toolName === 'code_interpreter' || toolChoice.toolName === 'file_search' || + toolChoice.toolName === 'image_generation' || toolChoice.toolName === 'web_search_preview' || toolChoice.toolName === 'web_search' ? { type: toolChoice.toolName } diff --git a/packages/openai/src/speech/openai-speech-model.test.ts b/packages/openai/src/speech/openai-speech-model.test.ts index 1dc6ef4d379e..cad685112243 100644 --- a/packages/openai/src/speech/openai-speech-model.test.ts +++ b/packages/openai/src/speech/openai-speech-model.test.ts @@ -1,7 +1,11 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createOpenAI } from '../openai-provider'; import { OpenAISpeechModel } from './openai-speech-model'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('../version', () => ({ + VERSION: '0.0.0-test', +})); const provider = createOpenAI({ apiKey: 'test-api-key' }); const model = provider.speech('tts-1'); @@ -70,6 +74,10 @@ describe('doGenerate', () => { 'openai-organization': 'test-organization', 'openai-project': 'test-project', }); + + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/openai/0.0.0-test`, + ); }); it('should pass options', async () => { diff --git a/packages/openai/src/tool/code-interpreter.ts b/packages/openai/src/tool/code-interpreter.ts index 90fbf570eb44..3962cef80ac8 100644 --- a/packages/openai/src/tool/code-interpreter.ts +++ b/packages/openai/src/tool/code-interpreter.ts @@ -1,6 +1,22 @@ -import { createProviderDefinedToolFactory } from '@ai-sdk/provider-utils'; +import { createProviderDefinedToolFactoryWithOutputSchema } from '@ai-sdk/provider-utils'; import { z } from 'zod/v4'; +export const codeInterpreterInputSchema = z.object({ + code: z.string().nullish(), + containerId: z.string(), +}); + +export const codeInterpreterOutputSchema = z.object({ + outputs: z + .array( + z.discriminatedUnion('type', [ + z.object({ type: z.literal('logs'), logs: z.string() }), + z.object({ type: z.literal('image'), url: z.string() }), + ]), + ) + .nullish(), +}); + export const codeInterpreterArgsSchema = z.object({ container: z .union([ @@ -12,24 +28,62 @@ export const codeInterpreterArgsSchema = z.object({ .optional(), }); -export const codeInterpreterToolFactory = createProviderDefinedToolFactory< - {}, - { - /** - * The code interpreter container. - * Can be a container ID - * or an object that specifies uploaded file IDs to make available to your code. - */ - container?: string | { fileIds?: string[] }; - } ->({ - id: 'openai.code_interpreter', - name: 'code_interpreter', - inputSchema: z.object({}), -}); +type CodeInterpreterArgs = { + /** + * The code interpreter container. + * Can be a container ID + * or an object that specifies uploaded file IDs to make available to your code. + */ + container?: string | { fileIds?: string[] }; +}; + +export const codeInterpreterToolFactory = + createProviderDefinedToolFactoryWithOutputSchema< + { + /** + * The code to run, or null if not available. + */ + code?: string | null; + + /** + * The ID of the container used to run the code. + */ + containerId: string; + }, + { + /** + * The outputs generated by the code interpreter, such as logs or images. + * Can be null if no outputs are available. + */ + outputs?: Array< + | { + type: 'logs'; + + /** + * The logs output from the code interpreter. + */ + logs: string; + } + | { + type: 'image'; + + /** + * The URL of the image output from the code interpreter. + */ + url: string; + } + > | null; + }, + CodeInterpreterArgs + >({ + id: 'openai.code_interpreter', + name: 'code_interpreter', + inputSchema: codeInterpreterInputSchema, + outputSchema: codeInterpreterOutputSchema, + }); export const codeInterpreter = ( - args: Parameters[0] = {}, // default + args: CodeInterpreterArgs = {}, // default ) => { return codeInterpreterToolFactory(args); }; diff --git a/packages/openai/src/tool/file-search.ts b/packages/openai/src/tool/file-search.ts index af508aad897e..01829caade24 100644 --- a/packages/openai/src/tool/file-search.ts +++ b/packages/openai/src/tool/file-search.ts @@ -1,4 +1,8 @@ -import { createProviderDefinedToolFactory } from '@ai-sdk/provider-utils'; +import { createProviderDefinedToolFactoryWithOutputSchema } from '@ai-sdk/provider-utils'; +import { + OpenAIResponsesFileSearchToolComparisonFilter, + OpenAIResponsesFileSearchToolCompoundFilter, +} from '../responses/openai-responses-api-types'; import { z } from 'zod/v4'; const comparisonFilterSchema = z.object({ @@ -14,31 +18,82 @@ const compoundFilterSchema: z.ZodType = z.object({ ), }); -const filtersSchema = z.union([comparisonFilterSchema, compoundFilterSchema]); - export const fileSearchArgsSchema = z.object({ - vectorStoreIds: z.array(z.string()).optional(), + vectorStoreIds: z.array(z.string()), maxNumResults: z.number().optional(), ranking: z .object({ - ranker: z.enum(['auto', 'default-2024-08-21']).optional(), + ranker: z.string().optional(), + scoreThreshold: z.number().optional(), }) .optional(), - filters: filtersSchema.optional(), + filters: z.union([comparisonFilterSchema, compoundFilterSchema]).optional(), +}); + +export const fileSearchOutputSchema = z.object({ + queries: z.array(z.string()), + results: z + .array( + z.object({ + attributes: z.record(z.string(), z.unknown()), + fileId: z.string(), + filename: z.string(), + score: z.number(), + text: z.string(), + }), + ) + .nullable(), }); -export const fileSearch = createProviderDefinedToolFactory< +export const fileSearch = createProviderDefinedToolFactoryWithOutputSchema< + {}, { /** * The search query to execute. */ - query: string; + queries: string[]; + + /** + * The results of the file search tool call. + */ + results: + | null + | { + /** + * Set of 16 key-value pairs that can be attached to an object. + * This can be useful for storing additional information about the object + * in a structured format, and querying for objects via API or the dashboard. + * Keys are strings with a maximum length of 64 characters. + * Values are strings with a maximum length of 512 characters, booleans, or numbers. + */ + attributes: Record; + + /** + * The unique ID of the file. + */ + fileId: string; + + /** + * The name of the file. + */ + filename: string; + + /** + * The relevance score of the file - a value between 0 and 1. + */ + score: number; + + /** + * The text that was retrieved from the file. + */ + text: string; + }[]; }, { /** - * List of vector store IDs to search through. If not provided, searches all available vector stores. + * List of vector store IDs to search through. */ - vectorStoreIds?: string[]; + vectorStoreIds: string[]; /** * Maximum number of search results to return. Defaults to 10. @@ -49,27 +104,29 @@ export const fileSearch = createProviderDefinedToolFactory< * Ranking options for the search. */ ranking?: { - ranker?: 'auto' | 'default-2024-08-21'; + /** + * The ranker to use for the file search. + */ + ranker?: string; + + /** + * The score threshold for the file search, a number between 0 and 1. + * Numbers closer to 1 will attempt to return only the most relevant results, + * but may return fewer results. + */ + scoreThreshold?: number; }; /** - * A filter to apply based on file attributes. + * A filter to apply. */ filters?: - | { - key: string; - type: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte'; - value: string | number | boolean; - } - | { - type: 'and' | 'or'; - filters: any[]; - }; + | OpenAIResponsesFileSearchToolComparisonFilter + | OpenAIResponsesFileSearchToolCompoundFilter; } >({ id: 'openai.file_search', name: 'file_search', - inputSchema: z.object({ - query: z.string(), - }), + inputSchema: z.object({}), + outputSchema: fileSearchOutputSchema, }); diff --git a/packages/openai/src/tool/image-generation.ts b/packages/openai/src/tool/image-generation.ts new file mode 100644 index 000000000000..f3c7c3ff56bd --- /dev/null +++ b/packages/openai/src/tool/image-generation.ts @@ -0,0 +1,110 @@ +import { createProviderDefinedToolFactoryWithOutputSchema } from '@ai-sdk/provider-utils'; +import { z } from 'zod/v4'; + +export const imageGenerationArgsSchema = z + .object({ + background: z.enum(['auto', 'opaque', 'transparent']).optional(), + inputFidelity: z.enum(['low', 'high']).optional(), + inputImageMask: z + .object({ + fileId: z.string().optional(), + imageUrl: z.string().optional(), + }) + .optional(), + model: z.string().optional(), + moderation: z.enum(['auto']).optional(), + outputCompression: z.number().int().min(0).max(100).optional(), + outputFormat: z.enum(['png', 'jpeg', 'webp']).optional(), + quality: z.enum(['auto', 'low', 'medium', 'high']).optional(), + size: z.enum(['1024x1024', '1024x1536', '1536x1024', 'auto']).optional(), + }) + .strict(); + +export const imageGenerationOutputSchema = z.object({ + result: z.string(), +}); + +type ImageGenerationArgs = { + /** + * Background type for the generated image. Default is 'auto'. + */ + background?: 'auto' | 'opaque' | 'transparent'; + + /** + * Input fidelity for the generated image. Default is 'low'. + */ + inputFidelity?: 'low' | 'high'; + + /** + * Optional mask for inpainting. + * Contains image_url (string, optional) and file_id (string, optional). + */ + inputImageMask?: { + /** + * File ID for the mask image. + */ + fileId?: string; + + /** + * Base64-encoded mask image. + */ + imageUrl?: string; + }; + + /** + * The image generation model to use. Default: gpt-image-1. + */ + model?: string; + + /** + * Moderation level for the generated image. Default: auto. + */ + moderation?: 'auto'; + + /** + * Compression level for the output image. Default: 100. + */ + outputCompression?: number; + + /** + * The output format of the generated image. One of png, webp, or jpeg. + * Default: png + */ + outputFormat?: 'png' | 'jpeg' | 'webp'; + + /** + * The quality of the generated image. + * One of low, medium, high, or auto. Default: auto. + */ + quality?: 'auto' | 'low' | 'medium' | 'high'; + + /** + * The size of the generated image. + * One of 1024x1024, 1024x1536, 1536x1024, or auto. + * Default: auto. + */ + size?: 'auto' | '1024x1024' | '1024x1536' | '1536x1024'; +}; + +const imageGenerationToolFactory = + createProviderDefinedToolFactoryWithOutputSchema< + {}, + { + /** + * The generated image encoded in base64. + */ + result: string; + }, + ImageGenerationArgs + >({ + id: 'openai.image_generation', + name: 'image_generation', + inputSchema: z.object({}), + outputSchema: imageGenerationOutputSchema, + }); + +export const imageGeneration = ( + args: ImageGenerationArgs = {}, // default +) => { + return imageGenerationToolFactory(args); +}; diff --git a/packages/openai/src/transcription/openai-transcription-model.test.ts b/packages/openai/src/transcription/openai-transcription-model.test.ts index c8100a2bc546..47d80d6b1c23 100644 --- a/packages/openai/src/transcription/openai-transcription-model.test.ts +++ b/packages/openai/src/transcription/openai-transcription-model.test.ts @@ -1,9 +1,13 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { readFile } from 'node:fs/promises'; import path from 'node:path'; import { createOpenAI } from '../openai-provider'; import { OpenAITranscriptionModel } from './openai-transcription-model'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('../version', () => ({ + VERSION: '0.0.0-test', +})); const audioData = await readFile( path.join(__dirname, 'transcription-test.mp3'), @@ -114,6 +118,10 @@ describe('doGenerate', () => { 'openai-organization': 'test-organization', 'openai-project': 'test-project', }); + + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/openai/0.0.0-test`, + ); }); it('should extract the transcription text', async () => { diff --git a/packages/openai/src/version.ts b/packages/openai/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/openai/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/openai/tsup.config.ts b/packages/openai/tsup.config.ts index 87efcf0d5720..d0b56a7122cd 100644 --- a/packages/openai/tsup.config.ts +++ b/packages/openai/tsup.config.ts @@ -6,6 +6,12 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, { entry: ['src/internal/index.ts'], @@ -13,5 +19,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/openai/vitest.edge.config.js b/packages/openai/vitest.edge.config.js index 3dc49ba29774..7442befcc27a 100644 --- a/packages/openai/vitest.edge.config.js +++ b/packages/openai/vitest.edge.config.js @@ -1,4 +1,8 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +10,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, }); diff --git a/packages/openai/vitest.node.config.js b/packages/openai/vitest.node.config.js index b7e4a9cabd48..28e23c82c433 100644 --- a/packages/openai/vitest.node.config.js +++ b/packages/openai/vitest.node.config.js @@ -1,4 +1,8 @@ import { defineConfig } from 'vite'; +import { readFileSync } from 'node:fs'; +const version = JSON.parse( + readFileSync(new URL('./package.json', import.meta.url), 'utf-8'), +).version; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +10,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(version), + }, }); diff --git a/packages/perplexity/CHANGELOG.md b/packages/perplexity/CHANGELOG.md index 6a7be555813f..1a0aca15edfa 100644 --- a/packages/perplexity/CHANGELOG.md +++ b/packages/perplexity/CHANGELOG.md @@ -1,5 +1,52 @@ # @ai-sdk/perplexity +## 2.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 2.0.8 ### Patch Changes diff --git a/packages/perplexity/package.json b/packages/perplexity/package.json index 53a76460fa59..e67bfb6d1d92 100644 --- a/packages/perplexity/package.json +++ b/packages/perplexity/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/perplexity", - "version": "2.0.8", + "version": "2.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -33,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/perplexity/src/index.ts b/packages/perplexity/src/index.ts index c8d0dbdff943..bff5d76cb0ca 100644 --- a/packages/perplexity/src/index.ts +++ b/packages/perplexity/src/index.ts @@ -3,3 +3,4 @@ export type { PerplexityProvider, PerplexityProviderSettings, } from './perplexity-provider'; +export { VERSION } from './version'; diff --git a/packages/perplexity/src/perplexity-language-model.test.ts b/packages/perplexity/src/perplexity-language-model.test.ts index dfa4652796f3..54453a84ba90 100644 --- a/packages/perplexity/src/perplexity-language-model.test.ts +++ b/packages/perplexity/src/perplexity-language-model.test.ts @@ -1,8 +1,10 @@ +// TEST FILE DOES NOT USE THE PROVIDER `createPerplexity` + import { describe, it, expect } from 'vitest'; import { LanguageModelV2Prompt } from '@ai-sdk/provider'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { convertReadableStreamToArray, - createTestServer, mockId, } from '@ai-sdk/provider-utils/test'; import { z } from 'zod/v4'; diff --git a/packages/perplexity/src/perplexity-provider.ts b/packages/perplexity/src/perplexity-provider.ts index ebe356eefc57..19ad117bb611 100644 --- a/packages/perplexity/src/perplexity-provider.ts +++ b/packages/perplexity/src/perplexity-provider.ts @@ -1,18 +1,20 @@ import { LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, generateId, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { PerplexityLanguageModel } from './perplexity-language-model'; import { PerplexityLanguageModelId } from './perplexity-language-model-options'; +import { VERSION } from './version'; -export interface PerplexityProvider extends ProviderV2 { +export interface PerplexityProvider extends ProviderV3 { /** Creates an Perplexity chat model for text generation. */ @@ -50,14 +52,18 @@ or to provide a custom fetch implementation for e.g. testing. export function createPerplexity( options: PerplexityProviderSettings = {}, ): PerplexityProvider { - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'PERPLEXITY_API_KEY', - description: 'Perplexity', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'PERPLEXITY_API_KEY', + description: 'Perplexity', + })}`, + ...options.headers, + }, + `ai-sdk/perplexity/${VERSION}`, + ); const createLanguageModel = (modelId: PerplexityLanguageModelId) => { return new PerplexityLanguageModel(modelId, { diff --git a/packages/perplexity/src/version.ts b/packages/perplexity/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/perplexity/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/perplexity/tsup.config.ts b/packages/perplexity/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/perplexity/tsup.config.ts +++ b/packages/perplexity/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/perplexity/vitest.edge.config.js b/packages/perplexity/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/perplexity/vitest.edge.config.js +++ b/packages/perplexity/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/perplexity/vitest.node.config.js b/packages/perplexity/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/perplexity/vitest.node.config.js +++ b/packages/perplexity/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/provider-utils/CHANGELOG.md b/packages/provider-utils/CHANGELOG.md index 5b912367cd42..cd3f77d8181e 100644 --- a/packages/provider-utils/CHANGELOG.md +++ b/packages/provider-utils/CHANGELOG.md @@ -1,5 +1,43 @@ # @ai-sdk/provider-utils +## 3.1.0-beta.3 + +### Patch Changes + +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + +## 3.1.0-beta.2 + +### Patch Changes + +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + +## 3.1.0-beta.1 + +### Patch Changes + +- cbb1d35: Update for provider-util changeset after change in PR #8588 + +## 3.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + +## 3.0.9 + +### Patch Changes + +- 0294b58: feat(ai): set `ai`, `@ai-sdk/provider-utils`, and runtime in `user-agent` header + ## 3.0.8 ### Patch Changes diff --git a/packages/provider-utils/package.json b/packages/provider-utils/package.json index 91049ff97194..375cc425e234 100644 --- a/packages/provider-utils/package.json +++ b/packages/provider-utils/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/provider-utils", - "version": "3.0.8", + "version": "3.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/provider-utils/src/get-from-api.test.ts b/packages/provider-utils/src/get-from-api.test.ts index 8bb5788e56a3..868891efbd31 100644 --- a/packages/provider-utils/src/get-from-api.test.ts +++ b/packages/provider-utils/src/get-from-api.test.ts @@ -6,6 +6,16 @@ import { createStatusCodeErrorResponseHandler, } from './response-handler'; import { z } from 'zod/v4'; +import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent'; +import { withUserAgentSuffix } from './with-user-agent-suffix'; + +vi.mock('./get-runtime-environment-user-agent', async () => { + const actual = await vi.importActual('./get-runtime-environment-user-agent'); + return { + ...actual, + getRuntimeEnvironmentUserAgent: () => 'runtime/test-env', + }; +}); describe('getFromApi', () => { const mockSuccessResponse = { @@ -21,13 +31,17 @@ describe('getFromApi', () => { const mockHeaders = { 'Content-Type': 'application/json', Authorization: 'Bearer test', + 'user-agent': 'runtime/test-env', }; it('should successfully fetch and parse data', async () => { const mockFetch = vi.fn().mockResolvedValue( new Response(JSON.stringify(mockSuccessResponse), { status: 200, - headers: mockHeaders, + headers: withUserAgentSuffix( + mockHeaders, + getRuntimeEnvironmentUserAgent(), + ), }), ); @@ -44,7 +58,10 @@ describe('getFromApi', () => { 'https://api.test.com/data', expect.objectContaining({ method: 'GET', - headers: { Authorization: 'Bearer test' }, + headers: { + authorization: 'Bearer test', + 'user-agent': 'ai-sdk/provider-utils/0.0.0-test runtime/test-env', + }, }), ); }); @@ -130,7 +147,8 @@ describe('getFromApi', () => { 'https://api.test.com/data', expect.objectContaining({ headers: { - Authorization: 'Bearer test', + authorization: 'Bearer test', + 'user-agent': 'ai-sdk/provider-utils/0.0.0-test runtime/test-env', }, }), ); diff --git a/packages/provider-utils/src/get-from-api.ts b/packages/provider-utils/src/get-from-api.ts index 58178c7c701a..0a786dd069e6 100644 --- a/packages/provider-utils/src/get-from-api.ts +++ b/packages/provider-utils/src/get-from-api.ts @@ -3,8 +3,10 @@ import { extractResponseHeaders } from './extract-response-headers'; import { FetchFunction } from './fetch-function'; import { handleFetchError } from './handle-fetch-error'; import { isAbortError } from './is-abort-error'; -import { removeUndefinedEntries } from './remove-undefined-entries'; import { ResponseHandler } from './response-handler'; +import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent'; +import { withUserAgentSuffix } from './with-user-agent-suffix'; +import { VERSION } from './version'; // use function to allow for mocking in tests: const getOriginalFetch = () => globalThis.fetch; @@ -27,7 +29,11 @@ export const getFromApi = async ({ try { const response = await fetch(url, { method: 'GET', - headers: removeUndefinedEntries(headers), + headers: withUserAgentSuffix( + headers, + `ai-sdk/provider-utils/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ), signal: abortSignal, }); diff --git a/packages/provider-utils/src/get-runtime-environment-user-agent.test.ts b/packages/provider-utils/src/get-runtime-environment-user-agent.test.ts new file mode 100644 index 000000000000..e8bb86423d8d --- /dev/null +++ b/packages/provider-utils/src/get-runtime-environment-user-agent.test.ts @@ -0,0 +1,47 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +// Stabilize provider utils version used inside UA string construction +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); + +import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent'; + +describe('getRuntimeEnvironmentUserAgent', () => { + it('should return the correct user agent for browsers', () => { + expect( + getRuntimeEnvironmentUserAgent({ + window: true, + }), + ).toBe('runtime/browser'); + }); + + it('should return the correct user agent for test', () => { + expect( + getRuntimeEnvironmentUserAgent({ + navigator: { + userAgent: 'test', + }, + }), + ).toBe('runtime/test'); + }); + + it('should return the correct user agent for Edge Runtime', () => { + expect( + getRuntimeEnvironmentUserAgent({ + EdgeRuntime: true, + }), + ).toBe('runtime/vercel-edge'); + }); + + it('should return the correct user agent for Node.js', () => { + expect( + getRuntimeEnvironmentUserAgent({ + process: { + versions: { node: 'test' }, + version: 'test', + }, + }), + ).toBe('runtime/node.js/test'); + }); +}); diff --git a/packages/provider-utils/src/get-runtime-environment-user-agent.ts b/packages/provider-utils/src/get-runtime-environment-user-agent.ts new file mode 100644 index 000000000000..f553f735320b --- /dev/null +++ b/packages/provider-utils/src/get-runtime-environment-user-agent.ts @@ -0,0 +1,24 @@ +export function getRuntimeEnvironmentUserAgent( + globalThisAny: any = globalThis as any, +): string { + // Browsers + if (globalThisAny.window) { + return `runtime/browser`; + } + + // Cloudflare Workers / Deno / Bun / Node.js >= 21.1 + if (globalThisAny.navigator?.userAgent) { + return `runtime/${globalThisAny.navigator.userAgent.toLowerCase()}`; + } + + // Nodes.js < 21.1 + if (globalThisAny.process?.versions?.node) { + return `runtime/node.js/${globalThisAny.process.version.substring(0)}`; + } + + if (globalThisAny.EdgeRuntime) { + return `runtime/vercel-edge`; + } + + return 'runtime/unknown'; +} diff --git a/packages/provider-utils/src/index.ts b/packages/provider-utils/src/index.ts index 9b57dca02f36..ba02f6705d17 100644 --- a/packages/provider-utils/src/index.ts +++ b/packages/provider-utils/src/index.ts @@ -3,6 +3,8 @@ export { convertAsyncIteratorToReadableStream } from './convert-async-iterator-t export * from './delay'; export * from './extract-response-headers'; export * from './fetch-function'; +export { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent'; +export { withUserAgentSuffix } from './with-user-agent-suffix'; export { createIdGenerator, generateId, type IdGenerator } from './generate-id'; export * from './get-error-message'; export * from './get-from-api'; @@ -48,3 +50,6 @@ export { EventSourceParserStream, type EventSourceMessage, } from 'eventsource-parser/stream'; + +// user-agent exports +export { VERSION } from './version'; diff --git a/packages/provider-utils/src/post-to-api.ts b/packages/provider-utils/src/post-to-api.ts index 6595a56e014b..6e387dda3913 100644 --- a/packages/provider-utils/src/post-to-api.ts +++ b/packages/provider-utils/src/post-to-api.ts @@ -3,8 +3,10 @@ import { extractResponseHeaders } from './extract-response-headers'; import { FetchFunction } from './fetch-function'; import { handleFetchError } from './handle-fetch-error'; import { isAbortError } from './is-abort-error'; -import { removeUndefinedEntries } from './remove-undefined-entries'; import { ResponseHandler } from './response-handler'; +import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent'; +import { withUserAgentSuffix } from './with-user-agent-suffix'; +import { VERSION } from './version'; // use function to allow for mocking in tests: const getOriginalFetch = () => globalThis.fetch; @@ -95,7 +97,11 @@ export const postToApi = async ({ try { const response = await fetch(url, { method: 'POST', - headers: removeUndefinedEntries(headers), + headers: withUserAgentSuffix( + headers, + `ai-sdk/provider-utils/${VERSION}`, + getRuntimeEnvironmentUserAgent(), + ), body: body.content, signal: abortSignal, }); diff --git a/packages/provider-utils/src/test/index.ts b/packages/provider-utils/src/test/index.ts index cf0f28e20fcb..a8a334ea8f61 100644 --- a/packages/provider-utils/src/test/index.ts +++ b/packages/provider-utils/src/test/index.ts @@ -5,4 +5,3 @@ export * from './convert-readable-stream-to-array'; export * from './convert-response-stream-to-array'; export * from './is-node-version'; export * from './mock-id'; -export * from './test-server'; diff --git a/packages/provider-utils/src/version.ts b/packages/provider-utils/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/provider-utils/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/provider-utils/src/with-user-agent-suffix.test.ts b/packages/provider-utils/src/with-user-agent-suffix.test.ts new file mode 100644 index 000000000000..0c0a1ff8713c --- /dev/null +++ b/packages/provider-utils/src/with-user-agent-suffix.test.ts @@ -0,0 +1,58 @@ +import { describe, it, expect } from 'vitest'; + +import { withUserAgentSuffix } from './with-user-agent-suffix'; + +describe('withUserAgentSuffix', () => { + it('should create a new user-agent header when no existing user-agent exists', () => { + const headers = { + 'content-type': 'application/json', + authorization: 'Bearer token123', + }; + + const result = withUserAgentSuffix( + headers, + 'ai-sdk/0.0.0-test', + 'provider/test-openai', + ); + + expect(result['user-agent']).toBe('ai-sdk/0.0.0-test provider/test-openai'); + expect(result['content-type']).toBe('application/json'); + expect(result['authorization']).toBe('Bearer token123'); + }); + + it('should append suffix parts to existing user-agent header', () => { + const headers = { + 'user-agent': 'TestApp/0.0.0-test', + accept: 'application/json', + }; + + const result = withUserAgentSuffix( + headers, + 'ai-sdk/0.0.0-test', + 'provider/test-anthropic', + ); + + expect(result['user-agent']).toBe( + 'TestApp/0.0.0-test ai-sdk/0.0.0-test provider/test-anthropic', + ); + expect(result['accept']).toBe('application/json'); + }); + + it('should automatically remove undefined entries from headers', () => { + const headers = { + 'content-type': 'application/json', + authorization: undefined, + 'user-agent': 'TestApp/0.0.0-test', + accept: 'application/json', + 'cache-control': null, + }; + + const result = withUserAgentSuffix(headers as any, 'ai-sdk/0.0.0-test'); + + expect(result['user-agent']).toBe('TestApp/0.0.0-test ai-sdk/0.0.0-test'); + expect(result['content-type']).toBe('application/json'); + expect(result['accept']).toBe('application/json'); + expect(result['authorization']).toBeUndefined(); + expect(result['cache-control']).toBeUndefined(); + }); +}); diff --git a/packages/provider-utils/src/with-user-agent-suffix.ts b/packages/provider-utils/src/with-user-agent-suffix.ts new file mode 100644 index 000000000000..65bd8c898fe1 --- /dev/null +++ b/packages/provider-utils/src/with-user-agent-suffix.ts @@ -0,0 +1,30 @@ +import { removeUndefinedEntries } from './remove-undefined-entries'; + +/** + * Appends suffix parts to the `user-agent` header. + * If a `user-agent` header already exists, the suffix parts are appended to it. + * If no `user-agent` header exists, a new one is created with the suffix parts. + * Automatically removes undefined entries from the headers. + * + * @param headers - The original headers. + * @param userAgentSuffixParts - The parts to append to the `user-agent` header. + * @returns The new headers with the `user-agent` header set or updated. + */ +export function withUserAgentSuffix( + headers: HeadersInit | Record | undefined, + ...userAgentSuffixParts: string[] +): Record { + const cleanedHeaders = removeUndefinedEntries( + (headers as Record) ?? {}, + ); + const normalizedHeaders = new Headers(cleanedHeaders); + + const currentUserAgentHeader = normalizedHeaders.get('user-agent') || ''; + + normalizedHeaders.set( + 'user-agent', + [currentUserAgentHeader, ...userAgentSuffixParts].filter(Boolean).join(' '), + ); + + return Object.fromEntries(normalizedHeaders); +} diff --git a/packages/provider-utils/tsup.config.ts b/packages/provider-utils/tsup.config.ts index bd4682744e9c..499e424b8c21 100644 --- a/packages/provider-utils/tsup.config.ts +++ b/packages/provider-utils/tsup.config.ts @@ -9,6 +9,12 @@ export default defineConfig([ // Keep library target conservative for wide compatibility target: 'es2018', platform: 'node', + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, { entry: ['src/test/index.ts'], @@ -31,5 +37,11 @@ export default defineConfig([ 'vitest/dist/node/*', 'vitest/dist/node/chunks/*', ], + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/provider/CHANGELOG.md b/packages/provider/CHANGELOG.md index 9e3609f86e9e..baf05b036f67 100644 --- a/packages/provider/CHANGELOG.md +++ b/packages/provider/CHANGELOG.md @@ -1,5 +1,24 @@ # @ai-sdk/provider +## 2.1.0-beta.2 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` + +## 2.1.0-beta.1 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + ## 2.0.0 ### Major Changes diff --git a/packages/provider/package.json b/packages/provider/package.json index 892e979a6e81..9b1d9f709ae0 100644 --- a/packages/provider/package.json +++ b/packages/provider/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/provider", - "version": "2.0.0", + "version": "2.1.0-beta.2", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/provider/src/embedding-model/index.ts b/packages/provider/src/embedding-model/index.ts index 5640476d8b82..f0a4a20cc05d 100644 --- a/packages/provider/src/embedding-model/index.ts +++ b/packages/provider/src/embedding-model/index.ts @@ -1 +1,2 @@ +export * from './v3/index'; export * from './v2/index'; diff --git a/packages/provider/src/embedding-model/v3/embedding-model-v3-embedding.ts b/packages/provider/src/embedding-model/v3/embedding-model-v3-embedding.ts new file mode 100644 index 000000000000..1e295e5f70fe --- /dev/null +++ b/packages/provider/src/embedding-model/v3/embedding-model-v3-embedding.ts @@ -0,0 +1,5 @@ +/** +An embedding is a vector, i.e. an array of numbers. +It is e.g. used to represent a text as a vector of word embeddings. + */ +export type EmbeddingModelV3Embedding = Array; diff --git a/packages/provider/src/embedding-model/v3/embedding-model-v3.ts b/packages/provider/src/embedding-model/v3/embedding-model-v3.ts new file mode 100644 index 000000000000..eac4226b438e --- /dev/null +++ b/packages/provider/src/embedding-model/v3/embedding-model-v3.ts @@ -0,0 +1,113 @@ +import { + SharedV2Headers, + SharedV2ProviderOptions, + SharedV2ProviderMetadata, +} from '../../shared'; +import { EmbeddingModelV3Embedding } from './embedding-model-v3-embedding'; + +/** +Specification for an embedding model that implements the embedding model +interface version 1. + +VALUE is the type of the values that the model can embed. +This will allow us to go beyond text embeddings in the future, +e.g. to support image embeddings + */ +export type EmbeddingModelV3 = { + /** +The embedding model must specify which embedding model interface +version it implements. This will allow us to evolve the embedding +model interface and retain backwards compatibility. The different +implementation versions can be handled as a discriminated union +on our side. + */ + readonly specificationVersion: 'v3'; + + /** +Name of the provider for logging purposes. + */ + readonly provider: string; + + /** +Provider-specific model ID for logging purposes. + */ + readonly modelId: string; + + /** +Limit of how many embeddings can be generated in a single API call. + +Use Infinity for models that do not have a limit. + */ + readonly maxEmbeddingsPerCall: + | PromiseLike + | number + | undefined; + + /** +True if the model can handle multiple embedding calls in parallel. + */ + readonly supportsParallelCalls: PromiseLike | boolean; + + /** +Generates a list of embeddings for the given input text. + +Naming: "do" prefix to prevent accidental direct usage of the method +by the user. + */ + doEmbed(options: { + /** +List of values to embed. + */ + values: Array; + + /** +Abort signal for cancelling the operation. + */ + abortSignal?: AbortSignal; + + /** +Additional provider-specific options. They are passed through +to the provider from the AI SDK and enable provider-specific +functionality that can be fully encapsulated in the provider. + */ + providerOptions?: SharedV2ProviderOptions; + + /** + Additional HTTP headers to be sent with the request. + Only applicable for HTTP-based providers. + */ + headers?: Record; + }): PromiseLike<{ + /** +Generated embeddings. They are in the same order as the input values. + */ + embeddings: Array; + + /** +Token usage. We only have input tokens for embeddings. + */ + usage?: { tokens: number }; + + /** +Additional provider-specific metadata. They are passed through +from the provider to the AI SDK and enable provider-specific +results that can be fully encapsulated in the provider. + */ + providerMetadata?: SharedV2ProviderMetadata; + + /** +Optional response information for debugging purposes. + */ + response?: { + /** +Response headers. + */ + headers?: SharedV2Headers; + + /** + The response body. + */ + body?: unknown; + }; + }>; +}; diff --git a/packages/provider/src/embedding-model/v3/index.ts b/packages/provider/src/embedding-model/v3/index.ts new file mode 100644 index 000000000000..38f1a44032d7 --- /dev/null +++ b/packages/provider/src/embedding-model/v3/index.ts @@ -0,0 +1,2 @@ +export * from './embedding-model-v3'; +export * from './embedding-model-v3-embedding'; diff --git a/packages/provider/src/image-model/index.ts b/packages/provider/src/image-model/index.ts index 5640476d8b82..f0a4a20cc05d 100644 --- a/packages/provider/src/image-model/index.ts +++ b/packages/provider/src/image-model/index.ts @@ -1 +1,2 @@ +export * from './v3/index'; export * from './v2/index'; diff --git a/packages/provider/src/image-model/v3/image-model-v3-call-options.ts b/packages/provider/src/image-model/v3/image-model-v3-call-options.ts new file mode 100644 index 000000000000..9b3644a9d9d6 --- /dev/null +++ b/packages/provider/src/image-model/v3/image-model-v3-call-options.ts @@ -0,0 +1,60 @@ +import { SharedV2ProviderOptions } from '../../shared'; + +export type ImageModelV3CallOptions = { + /** +Prompt for the image generation. + */ + prompt: string; + + /** +Number of images to generate. + */ + n: number; + + /** +Size of the images to generate. +Must have the format `{width}x{height}`. +`undefined` will use the provider's default size. + */ + size: `${number}x${number}` | undefined; + + /** +Aspect ratio of the images to generate. +Must have the format `{width}:{height}`. +`undefined` will use the provider's default aspect ratio. + */ + aspectRatio: `${number}:${number}` | undefined; + + /** +Seed for the image generation. +`undefined` will use the provider's default seed. + */ + seed: number | undefined; + + /** +Additional provider-specific options that are passed through to the provider +as body parameters. + +The outer record is keyed by the provider name, and the inner +record is keyed by the provider-specific metadata key. +```ts +{ + "openai": { + "style": "vivid" + } +} +``` + */ + providerOptions: SharedV2ProviderOptions; + + /** +Abort signal for cancelling the operation. + */ + abortSignal?: AbortSignal; + + /** +Additional HTTP headers to be sent with the request. +Only applicable for HTTP-based providers. + */ + headers?: Record; +}; diff --git a/packages/provider/src/image-model/v3/image-model-v3-call-warning.ts b/packages/provider/src/image-model/v3/image-model-v3-call-warning.ts new file mode 100644 index 000000000000..eec316055dde --- /dev/null +++ b/packages/provider/src/image-model/v3/image-model-v3-call-warning.ts @@ -0,0 +1,16 @@ +import { ImageModelV3CallOptions } from './image-model-v3-call-options'; + +/** +Warning from the model provider for this call. The call will proceed, but e.g. +some settings might not be supported, which can lead to suboptimal results. + */ +export type ImageModelV3CallWarning = + | { + type: 'unsupported-setting'; + setting: keyof ImageModelV3CallOptions; + details?: string; + } + | { + type: 'other'; + message: string; + }; diff --git a/packages/provider/src/image-model/v3/image-model-v3.ts b/packages/provider/src/image-model/v3/image-model-v3.ts new file mode 100644 index 000000000000..a06fcd6b1c48 --- /dev/null +++ b/packages/provider/src/image-model/v3/image-model-v3.ts @@ -0,0 +1,104 @@ +import { JSONArray, JSONValue } from '../../json-value'; +import { ImageModelV3CallOptions } from './image-model-v3-call-options'; +import { ImageModelV3CallWarning } from './image-model-v3-call-warning'; + +export type ImageModelV3ProviderMetadata = Record< + string, + { + images: JSONArray; + } & JSONValue +>; + +type GetMaxImagesPerCallFunction = (options: { + modelId: string; +}) => PromiseLike | number | undefined; + +/** +Image generation model specification version 3. + */ +export type ImageModelV3 = { + /** +The image model must specify which image model interface +version it implements. This will allow us to evolve the image +model interface and retain backwards compatibility. The different +implementation versions can be handled as a discriminated union +on our side. + */ + readonly specificationVersion: 'v3'; + + /** +Name of the provider for logging purposes. + */ + readonly provider: string; + + /** +Provider-specific model ID for logging purposes. + */ + readonly modelId: string; + + /** +Limit of how many images can be generated in a single API call. +Can be set to a number for a fixed limit, to undefined to use +the global limit, or a function that returns a number or undefined, +optionally as a promise. + */ + readonly maxImagesPerCall: number | undefined | GetMaxImagesPerCallFunction; + + /** +Generates an array of images. + */ + doGenerate(options: ImageModelV3CallOptions): PromiseLike<{ + /** +Generated images as base64 encoded strings or binary data. +The images should be returned without any unnecessary conversion. +If the API returns base64 encoded strings, the images should be returned +as base64 encoded strings. If the API returns binary data, the images should +be returned as binary data. + */ + images: Array | Array; + + /** +Warnings for the call, e.g. unsupported settings. + */ + warnings: Array; + + /** +Additional provider-specific metadata. They are passed through +from the provider to the AI SDK and enable provider-specific +results that can be fully encapsulated in the provider. + +The outer record is keyed by the provider name, and the inner +record is provider-specific metadata. It always includes an +`images` key with image-specific metadata + +```ts +{ + "openai": { + "images": ["revisedPrompt": "Revised prompt here."] + } +} +``` + */ + providerMetadata?: ImageModelV3ProviderMetadata; + + /** +Response information for telemetry and debugging purposes. + */ + response: { + /** +Timestamp for the start of the generated response. + */ + timestamp: Date; + + /** +The ID of the response model that was used to generate the response. + */ + modelId: string; + + /** +Response headers. + */ + headers: Record | undefined; + }; + }>; +}; diff --git a/packages/provider/src/image-model/v3/index.ts b/packages/provider/src/image-model/v3/index.ts new file mode 100644 index 000000000000..9eb5613a1b67 --- /dev/null +++ b/packages/provider/src/image-model/v3/index.ts @@ -0,0 +1,6 @@ +export type { + ImageModelV3, + ImageModelV3ProviderMetadata, +} from './image-model-v3'; +export type { ImageModelV3CallOptions } from './image-model-v3-call-options'; +export type { ImageModelV3CallWarning } from './image-model-v3-call-warning'; diff --git a/packages/provider/src/provider/index.ts b/packages/provider/src/provider/index.ts index 5640476d8b82..f0a4a20cc05d 100644 --- a/packages/provider/src/provider/index.ts +++ b/packages/provider/src/provider/index.ts @@ -1 +1,2 @@ +export * from './v3/index'; export * from './v2/index'; diff --git a/packages/provider/src/provider/v3/index.ts b/packages/provider/src/provider/v3/index.ts new file mode 100644 index 000000000000..23561cb544d7 --- /dev/null +++ b/packages/provider/src/provider/v3/index.ts @@ -0,0 +1 @@ +export type { ProviderV3 } from './provider-v3'; diff --git a/packages/provider/src/provider/v3/provider-v3.ts b/packages/provider/src/provider/v3/provider-v3.ts new file mode 100644 index 000000000000..e595ef5aec46 --- /dev/null +++ b/packages/provider/src/provider/v3/provider-v3.ts @@ -0,0 +1,64 @@ +import { EmbeddingModelV3 } from '../../embedding-model/v3/embedding-model-v3'; +import { ImageModelV3 } from '../../image-model/v3/image-model-v3'; +import { LanguageModelV2 } from '../../language-model/v2/language-model-v2'; +import { SpeechModelV2 } from '../../speech-model/v2/speech-model-v2'; +import { TranscriptionModelV2 } from '../../transcription-model/v2/transcription-model-v2'; + +/** + * Provider for language, text embedding, and image generation models. + */ +export interface ProviderV3 { + /** +Returns the language model with the given id. +The model id is then passed to the provider function to get the model. + +@param {string} modelId - The id of the model to return. + +@returns {LanguageModel} The language model associated with the id + +@throws {NoSuchModelError} If no such model exists. + */ + languageModel(modelId: string): LanguageModelV2; + + /** +Returns the text embedding model with the given id. +The model id is then passed to the provider function to get the model. + +@param {string} modelId - The id of the model to return. + +@returns {LanguageModel} The language model associated with the id + +@throws {NoSuchModelError} If no such model exists. + */ + textEmbeddingModel(modelId: string): EmbeddingModelV3; + + /** +Returns the image model with the given id. +The model id is then passed to the provider function to get the model. + +@param {string} modelId - The id of the model to return. + +@returns {ImageModel} The image model associated with the id +*/ + imageModel(modelId: string): ImageModelV3; + + /** +Returns the transcription model with the given id. +The model id is then passed to the provider function to get the model. + +@param {string} modelId - The id of the model to return. + +@returns {TranscriptionModel} The transcription model associated with the id + */ + transcriptionModel?(modelId: string): TranscriptionModelV2; + + /** +Returns the speech model with the given id. +The model id is then passed to the provider function to get the model. + +@param {string} modelId - The id of the model to return. + +@returns {SpeechModel} The speech model associated with the id + */ + speechModel?(modelId: string): SpeechModelV2; +} diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 94cf65791680..c22ceaf7cc29 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,127 @@ # @ai-sdk/react +## 2.1.0-beta.9 + +### Patch Changes + +- Updated dependencies [ed329cb] +- Updated dependencies [177b475] +- Updated dependencies [522f6b8] + - ai@5.1.0-beta.9 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.8 + +### Patch Changes + +- Updated dependencies [7eca093] + - ai@5.1.0-beta.8 + +## 2.1.0-beta.7 + +### Patch Changes + +- Updated dependencies [5a4e732] + - ai@5.1.0-beta.7 + +## 2.1.0-beta.6 + +### Patch Changes + +- Updated dependencies [0c4822d] + - ai@5.1.0-beta.6 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.5 + +### Patch Changes + +- ai@5.1.0-beta.5 + +## 2.1.0-beta.4 + +### Patch Changes + +- ai@5.1.0-beta.4 + +## 2.1.0-beta.3 + +### Patch Changes + +- ai@5.1.0-beta.3 + +## 2.1.0-beta.2 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - ai@5.1.0-beta.2 + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [a7f6f81] + - ai@5.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - ai@5.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.45 + +### Patch Changes + +- Updated dependencies [76024fc] +- Updated dependencies [93d8b60] +- Updated dependencies [d8eb31f] + - ai@5.0.45 + +## 2.0.44 + +### Patch Changes + +- ai@5.0.44 + +## 2.0.43 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - ai@5.0.43 + +## 2.0.42 + +### Patch Changes + +- Updated dependencies [de5c066] + - ai@5.0.42 + +## 2.0.41 + +### Patch Changes + +- Updated dependencies [cd91e4b] + - ai@5.0.41 + +## 2.0.40 + +### Patch Changes + +- ai@5.0.40 + ## 2.0.39 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 26e9c254fdbb..02743fca2b51 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/react", - "version": "2.0.39", + "version": "2.1.0-beta.9", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -30,8 +30,9 @@ "CHANGELOG.md" ], "dependencies": { - "ai": "workspace:*", "@ai-sdk/provider-utils": "workspace:*", + "ai": "workspace:*", + "@ai-sdk/test-server": "workspace:*", "swr": "^2.2.5", "throttleit": "2.1.0" }, @@ -47,7 +48,7 @@ "eslint-config-vercel-ai": "workspace:*", "jsdom": "^24.0.0", "msw": "2.6.4", - "react-dom": "^18", + "react-dom": "^18 || ^19 || ^19.0.0-rc", "tsup": "^7.2.0", "typescript": "5.8.3", "zod": "3.25.76" diff --git a/packages/react/src/use-chat.ui.test.tsx b/packages/react/src/use-chat.ui.test.tsx index 96a468861cb7..7521413cf64a 100644 --- a/packages/react/src/use-chat.ui.test.tsx +++ b/packages/react/src/use-chat.ui.test.tsx @@ -2,9 +2,9 @@ /* eslint-disable @next/next/no-img-element */ import { createTestServer, - mockId, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; +import { mockId } from '@ai-sdk/provider-utils/test'; import '@testing-library/jest-dom/vitest'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; diff --git a/packages/react/src/use-completion.ui.test.tsx b/packages/react/src/use-completion.ui.test.tsx index 5cac42ba3306..debabd311de1 100644 --- a/packages/react/src/use-completion.ui.test.tsx +++ b/packages/react/src/use-completion.ui.test.tsx @@ -1,7 +1,7 @@ import { createTestServer, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; import '@testing-library/jest-dom/vitest'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; diff --git a/packages/react/src/use-object.ui.test.tsx b/packages/react/src/use-object.ui.test.tsx index a31293956a07..667630b304eb 100644 --- a/packages/react/src/use-object.ui.test.tsx +++ b/packages/react/src/use-object.ui.test.tsx @@ -1,7 +1,7 @@ import { createTestServer, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; import '@testing-library/jest-dom/vitest'; import { cleanup, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; diff --git a/packages/replicate/CHANGELOG.md b/packages/replicate/CHANGELOG.md index 7f9c0aff8ea2..0b896ade7ba8 100644 --- a/packages/replicate/CHANGELOG.md +++ b/packages/replicate/CHANGELOG.md @@ -1,5 +1,53 @@ # @ai-sdk/replicate +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.8 ### Patch Changes diff --git a/packages/replicate/package.json b/packages/replicate/package.json index 180f578308f9..e1e8d8bed799 100644 --- a/packages/replicate/package.json +++ b/packages/replicate/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/replicate", - "version": "1.0.8", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -33,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/replicate/src/index.ts b/packages/replicate/src/index.ts index 424468a295a7..74bccfe79fab 100644 --- a/packages/replicate/src/index.ts +++ b/packages/replicate/src/index.ts @@ -3,3 +3,4 @@ export type { ReplicateProvider, ReplicateProviderSettings, } from './replicate-provider'; +export { VERSION } from './version'; diff --git a/packages/replicate/src/replicate-image-model.test.ts b/packages/replicate/src/replicate-image-model.test.ts index dc439fc233f4..a958134a19ca 100644 --- a/packages/replicate/src/replicate-image-model.test.ts +++ b/packages/replicate/src/replicate-image-model.test.ts @@ -1,7 +1,11 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { createReplicate } from './replicate-provider'; import { ReplicateImageModel } from './replicate-image-model'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const prompt = 'The Loch Ness monster getting a manicure'; @@ -128,6 +132,10 @@ describe('doGenerate', () => { 'custom-request-header': 'request-header-value', prefer: 'wait', }); + + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/replicate/0.0.0-test`, + ); }); it('should extract the generated image from array response', async () => { diff --git a/packages/replicate/src/replicate-image-model.ts b/packages/replicate/src/replicate-image-model.ts index 5e1f53ee8ea7..907ff3cbbe81 100644 --- a/packages/replicate/src/replicate-image-model.ts +++ b/packages/replicate/src/replicate-image-model.ts @@ -1,4 +1,4 @@ -import type { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider'; +import type { ImageModelV3, ImageModelV3CallWarning } from '@ai-sdk/provider'; import type { Resolvable } from '@ai-sdk/provider-utils'; import { FetchFunction, @@ -23,8 +23,8 @@ interface ReplicateImageModelConfig { }; } -export class ReplicateImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class ReplicateImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; readonly maxImagesPerCall = 1; get provider(): string { @@ -45,10 +45,10 @@ export class ReplicateImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; const [modelId, version] = this.modelId.split(':'); diff --git a/packages/replicate/src/replicate-provider.ts b/packages/replicate/src/replicate-provider.ts index 5480728b5213..b6a42ec56cec 100644 --- a/packages/replicate/src/replicate-provider.ts +++ b/packages/replicate/src/replicate-provider.ts @@ -1,8 +1,9 @@ -import { NoSuchModelError, ProviderV2 } from '@ai-sdk/provider'; +import { NoSuchModelError, ProviderV3 } from '@ai-sdk/provider'; import type { FetchFunction } from '@ai-sdk/provider-utils'; -import { loadApiKey } from '@ai-sdk/provider-utils'; +import { loadApiKey, withUserAgentSuffix } from '@ai-sdk/provider-utils'; import { ReplicateImageModel } from './replicate-image-model'; import { ReplicateImageModelId } from './replicate-image-settings'; +import { VERSION } from './version'; export interface ReplicateProviderSettings { /** @@ -29,7 +30,7 @@ or to provide a custom fetch implementation for e.g. testing. fetch?: FetchFunction; } -export interface ReplicateProvider extends ProviderV2 { +export interface ReplicateProvider extends ProviderV3 { /** * Creates a Replicate image generation model. */ @@ -51,14 +52,17 @@ export function createReplicate( new ReplicateImageModel(modelId, { provider: 'replicate', baseURL: options.baseURL ?? 'https://api.replicate.com/v1', - headers: { - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiToken, - environmentVariableName: 'REPLICATE_API_TOKEN', - description: 'Replicate', - })}`, - ...options.headers, - }, + headers: withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiToken, + environmentVariableName: 'REPLICATE_API_TOKEN', + description: 'Replicate', + })}`, + ...options.headers, + }, + `ai-sdk/replicate/${VERSION}`, + ), fetch: options.fetch, }); diff --git a/packages/replicate/src/version.ts b/packages/replicate/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/replicate/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/replicate/tsup.config.ts b/packages/replicate/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/replicate/tsup.config.ts +++ b/packages/replicate/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/replicate/vitest.edge.config.js b/packages/replicate/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/replicate/vitest.edge.config.js +++ b/packages/replicate/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/replicate/vitest.node.config.js b/packages/replicate/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/replicate/vitest.node.config.js +++ b/packages/replicate/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/revai/CHANGELOG.md b/packages/revai/CHANGELOG.md index c23eb164e11f..aac12e4ae4ab 100644 --- a/packages/revai/CHANGELOG.md +++ b/packages/revai/CHANGELOG.md @@ -1,5 +1,52 @@ # @ai-sdk/revai +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.8 ### Patch Changes diff --git a/packages/revai/package.json b/packages/revai/package.json index 309b825deb76..e88e2be80241 100644 --- a/packages/revai/package.json +++ b/packages/revai/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/revai", - "version": "1.0.8", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -18,6 +18,7 @@ "type-check": "tsc --noEmit", "prettier-check": "prettier --check \"./**/*.ts*\"", "test": "pnpm test:node && pnpm test:edge", + "test:watch": "vitest --config vitest.node.config.js", "test:edge": "vitest --config vitest.edge.config.js --run", "test:node": "vitest --config vitest.node.config.js --run", "test:node:watch": "vitest --config vitest.node.config.js --watch" @@ -32,7 +33,8 @@ }, "dependencies": { "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/revai/src/index.ts b/packages/revai/src/index.ts index c6325dc8842d..f756417588e9 100644 --- a/packages/revai/src/index.ts +++ b/packages/revai/src/index.ts @@ -1,2 +1,3 @@ export { createRevai, revai } from './revai-provider'; export type { RevaiProvider, RevaiProviderSettings } from './revai-provider'; +export { VERSION } from './version'; diff --git a/packages/revai/src/revai-provider.ts b/packages/revai/src/revai-provider.ts index 7a69fd130a27..8065e8c8c5ef 100644 --- a/packages/revai/src/revai-provider.ts +++ b/packages/revai/src/revai-provider.ts @@ -1,13 +1,18 @@ import { TranscriptionModelV2, - ProviderV2, + ProviderV3, NoSuchModelError, } from '@ai-sdk/provider'; -import { FetchFunction, loadApiKey } from '@ai-sdk/provider-utils'; +import { + FetchFunction, + loadApiKey, + withUserAgentSuffix, +} from '@ai-sdk/provider-utils'; import { RevaiTranscriptionModel } from './revai-transcription-model'; import { RevaiTranscriptionModelId } from './revai-transcription-options'; +import { VERSION } from './version'; -export interface RevaiProvider extends ProviderV2 { +export interface RevaiProvider extends ProviderV3 { ( modelId: 'machine', settings?: {}, @@ -45,14 +50,18 @@ Create a Rev.ai provider instance. export function createRevai( options: RevaiProviderSettings = {}, ): RevaiProvider { - const getHeaders = () => ({ - authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'REVAI_API_KEY', - description: 'Rev.ai', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'REVAI_API_KEY', + description: 'Rev.ai', + })}`, + ...options.headers, + }, + `ai-sdk/revai/${VERSION}`, + ); const createTranscriptionModel = (modelId: RevaiTranscriptionModelId) => new RevaiTranscriptionModel(modelId, { diff --git a/packages/revai/src/revai-transcription-model.test.ts b/packages/revai/src/revai-transcription-model.test.ts index 34e13c9246bc..bf3fb7455ce7 100644 --- a/packages/revai/src/revai-transcription-model.test.ts +++ b/packages/revai/src/revai-transcription-model.test.ts @@ -1,9 +1,13 @@ -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { RevaiTranscriptionModel } from './revai-transcription-model'; import { createRevai } from './revai-provider'; import { readFile } from 'node:fs/promises'; import path from 'node:path'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); const audioData = await readFile(path.join(__dirname, 'transcript-test.mp3')); const provider = createRevai({ apiKey: 'test-api-key' }); @@ -201,6 +205,10 @@ describe('doGenerate', () => { 'custom-provider-header': 'provider-header-value', 'custom-request-header': 'request-header-value', }); + + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/revai/0.0.0-test`, + ); }); it('should extract the transcription text', async () => { diff --git a/packages/revai/src/version.ts b/packages/revai/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/revai/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/revai/tsup.config.ts b/packages/revai/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/revai/tsup.config.ts +++ b/packages/revai/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/revai/vitest.edge.config.js b/packages/revai/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/revai/vitest.edge.config.js +++ b/packages/revai/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/revai/vitest.node.config.js b/packages/revai/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/revai/vitest.node.config.js +++ b/packages/revai/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/rsc/CHANGELOG.md b/packages/rsc/CHANGELOG.md index 02f76d4090ac..aeb4d88954c5 100644 --- a/packages/rsc/CHANGELOG.md +++ b/packages/rsc/CHANGELOG.md @@ -1,5 +1,128 @@ # @ai-sdk/rsc +## 1.1.0-beta.9 + +### Patch Changes + +- Updated dependencies [ed329cb] +- Updated dependencies [177b475] +- Updated dependencies [522f6b8] + - @ai-sdk/provider@2.1.0-beta.2 + - ai@5.1.0-beta.9 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.8 + +### Patch Changes + +- Updated dependencies [7eca093] + - ai@5.1.0-beta.8 + +## 1.1.0-beta.7 + +### Patch Changes + +- Updated dependencies [5a4e732] + - ai@5.1.0-beta.7 + +## 1.1.0-beta.6 + +### Patch Changes + +- Updated dependencies [0c4822d] + - @ai-sdk/provider@2.1.0-beta.1 + - ai@5.1.0-beta.6 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.5 + +### Patch Changes + +- ai@5.1.0-beta.5 + +## 1.1.0-beta.4 + +### Patch Changes + +- ai@5.1.0-beta.4 + +## 1.1.0-beta.3 + +### Patch Changes + +- ai@5.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- Updated dependencies [cbb1d35] + - @ai-sdk/provider-utils@3.1.0-beta.1 + - ai@5.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [a7f6f81] + - ai@5.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - ai@5.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.45 + +### Patch Changes + +- Updated dependencies [76024fc] +- Updated dependencies [93d8b60] +- Updated dependencies [d8eb31f] + - ai@5.0.45 + +## 1.0.44 + +### Patch Changes + +- ai@5.0.44 + +## 1.0.43 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - ai@5.0.43 + +## 1.0.42 + +### Patch Changes + +- Updated dependencies [de5c066] + - ai@5.0.42 + +## 1.0.41 + +### Patch Changes + +- Updated dependencies [cd91e4b] + - ai@5.0.41 + +## 1.0.40 + +### Patch Changes + +- ai@5.0.40 + ## 1.0.39 ### Patch Changes diff --git a/packages/rsc/package.json b/packages/rsc/package.json index c7ac35434e36..e9806d03280a 100644 --- a/packages/rsc/package.json +++ b/packages/rsc/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/rsc", - "version": "1.0.39", + "version": "1.1.0-beta.9", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/rsc-client.mjs", diff --git a/packages/rsc/tests/e2e/next-server/CHANGELOG.md b/packages/rsc/tests/e2e/next-server/CHANGELOG.md index 301c5517a42e..027b7d364278 100644 --- a/packages/rsc/tests/e2e/next-server/CHANGELOG.md +++ b/packages/rsc/tests/e2e/next-server/CHANGELOG.md @@ -1,5 +1,115 @@ # ai-core-e2e-next-server +## 0.0.1-beta.0 + +### Patch Changes + +- Updated dependencies [ed329cb] +- Updated dependencies [177b475] +- Updated dependencies [522f6b8] + - ai@5.1.0-beta.9 + +## 0.0.1-beta.0 + +### Patch Changes + +- Updated dependencies [7eca093] + - ai@5.1.0-beta.8 + +## 0.0.1-beta.0 + +### Patch Changes + +- Updated dependencies [5a4e732] + - ai@5.1.0-beta.7 + +## 0.0.1-beta.0 + +### Patch Changes + +- Updated dependencies [0c4822d] + - ai@5.1.0-beta.6 + +## 0.0.1-beta.0 + +### Patch Changes + +- ai@5.1.0-beta.5 + +## 0.0.1-beta.0 + +### Patch Changes + +- ai@5.1.0-beta.4 + +## 0.0.1-beta.0 + +### Patch Changes + +- ai@5.1.0-beta.3 + +## 0.0.1-beta.0 + +### Patch Changes + +- ai@5.1.0-beta.2 + +## 0.0.1-beta.0 + +### Patch Changes + +- Updated dependencies [a7f6f81] + - ai@5.1.0-beta.1 + +## 0.0.1-beta.0 + +### Patch Changes + +- Updated dependencies [78928cb] + - ai@5.1.0-beta.0 + +## 0.0.1 + +### Patch Changes + +- Updated dependencies [76024fc] +- Updated dependencies [93d8b60] +- Updated dependencies [d8eb31f] + - ai@5.0.45 + +## 0.0.1 + +### Patch Changes + +- ai@5.0.44 + +## 0.0.1 + +### Patch Changes + +- Updated dependencies [0294b58] + - ai@5.0.43 + +## 0.0.1 + +### Patch Changes + +- Updated dependencies [de5c066] + - ai@5.0.42 + +## 0.0.1 + +### Patch Changes + +- Updated dependencies [cd91e4b] + - ai@5.0.41 + +## 0.0.1 + +### Patch Changes + +- ai@5.0.40 + ## 0.0.1 ### Patch Changes diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 0310a780f1ea..927384f35330 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,127 @@ # @ai-sdk/svelte +## 3.1.0-beta.9 + +### Patch Changes + +- Updated dependencies [ed329cb] +- Updated dependencies [177b475] +- Updated dependencies [522f6b8] + - ai@5.1.0-beta.9 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 3.1.0-beta.8 + +### Patch Changes + +- Updated dependencies [7eca093] + - ai@5.1.0-beta.8 + +## 3.1.0-beta.7 + +### Patch Changes + +- Updated dependencies [5a4e732] + - ai@5.1.0-beta.7 + +## 3.1.0-beta.6 + +### Patch Changes + +- Updated dependencies [0c4822d] + - ai@5.1.0-beta.6 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 3.1.0-beta.5 + +### Patch Changes + +- ai@5.1.0-beta.5 + +## 3.1.0-beta.4 + +### Patch Changes + +- ai@5.1.0-beta.4 + +## 3.1.0-beta.3 + +### Patch Changes + +- ai@5.1.0-beta.3 + +## 3.1.0-beta.2 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - ai@5.1.0-beta.2 + +## 3.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [a7f6f81] + - ai@5.1.0-beta.1 + +## 3.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - ai@5.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 3.0.45 + +### Patch Changes + +- Updated dependencies [76024fc] +- Updated dependencies [93d8b60] +- Updated dependencies [d8eb31f] + - ai@5.0.45 + +## 3.0.44 + +### Patch Changes + +- ai@5.0.44 + +## 3.0.43 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - ai@5.0.43 + +## 3.0.42 + +### Patch Changes + +- Updated dependencies [de5c066] + - ai@5.0.42 + +## 3.0.41 + +### Patch Changes + +- Updated dependencies [cd91e4b] + - ai@5.0.41 + +## 3.0.40 + +### Patch Changes + +- ai@5.0.40 + ## 3.0.39 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index a113e5eeff97..f9b0127ce1ba 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/svelte", - "version": "3.0.39", + "version": "3.1.0-beta.9", "license": "Apache-2.0", "scripts": { "build": "pnpm prepack", @@ -52,17 +52,18 @@ } }, "dependencies": { - "ai": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*", + "ai": "workspace:*" }, "devDependencies": { - "@types/node": "20.17.24", "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", "@sveltejs/package": "^2.0.0", "@sveltejs/vite-plugin-svelte": "^5.0.3", "@testing-library/jest-dom": "^6.6.3", "@testing-library/svelte": "^5.2.4", + "@types/node": "20.17.24", "@vercel/ai-tsconfig": "workspace:*", "eslint": "^9.18.0", "eslint-plugin-svelte": "^3.0.0", diff --git a/packages/svelte/src/chat.svelte.test.ts b/packages/svelte/src/chat.svelte.test.ts index 587e21ee2266..207798ee75a1 100644 --- a/packages/svelte/src/chat.svelte.test.ts +++ b/packages/svelte/src/chat.svelte.test.ts @@ -1,8 +1,8 @@ import { createTestServer, - mockId, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; +import { mockId } from '@ai-sdk/provider-utils/test'; import { DefaultChatTransport, isToolUIPart, diff --git a/packages/svelte/src/completion.svelte.test.ts b/packages/svelte/src/completion.svelte.test.ts index e7b36cf8cf73..653b55dcffa3 100644 --- a/packages/svelte/src/completion.svelte.test.ts +++ b/packages/svelte/src/completion.svelte.test.ts @@ -1,7 +1,7 @@ import { createTestServer, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; import { render } from '@testing-library/svelte'; import type { UIMessageChunk } from 'ai'; import { Completion } from './completion.svelte.js'; diff --git a/packages/svelte/src/structured-object.svelte.test.ts b/packages/svelte/src/structured-object.svelte.test.ts index 10cb6c086fbf..c12ef6250828 100644 --- a/packages/svelte/src/structured-object.svelte.test.ts +++ b/packages/svelte/src/structured-object.svelte.test.ts @@ -1,7 +1,7 @@ import { createTestServer, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; import { render } from '@testing-library/svelte'; import { z } from 'zod/v4'; import { StructuredObject } from './structured-object.svelte.js'; diff --git a/packages/test-server/CHANGELOG.md b/packages/test-server/CHANGELOG.md new file mode 100644 index 000000000000..8b9c55560f9a --- /dev/null +++ b/packages/test-server/CHANGELOG.md @@ -0,0 +1,7 @@ +# @ai-sdk/test-server + +## 1.0.0-beta.0 + +### Major Changes + +- 953d0f2: feat(packages/test-server): Add `test-server` as a package diff --git a/packages/test-server/package.json b/packages/test-server/package.json new file mode 100644 index 000000000000..c8c259ee562a --- /dev/null +++ b/packages/test-server/package.json @@ -0,0 +1,66 @@ +{ + "name": "@ai-sdk/test-server", + "version": "1.0.0-beta.0", + "license": "Apache-2.0", + "sideEffects": false, + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist/**/*", + "CHANGELOG.md" + ], + "scripts": { + "build": "pnpm clean && tsup --tsconfig tsconfig.build.json", + "build:watch": "pnpm clean && tsup --watch", + "clean": "rm -rf dist *.tsbuildinfo", + "lint": "eslint \"./**/*.ts*\"", + "type-check": "tsc --build", + "prettier-check": "prettier --check \"./**/*.ts*\"", + "test": "pnpm test:node && pnpm test:edge", + "test:update": "pnpm test:node -u", + "test:watch": "vitest --config vitest.node.config.js", + "test:edge": "vitest --config vitest.edge.config.js --run", + "test:node": "vitest --config vitest.node.config.js --run" + }, + "exports": { + "./package.json": "./package.json", + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.js" + }, + "./with-vitest": { + "types": "./dist/with-vitest.d.ts", + "import": "./dist/with-vitest.mjs", + "module": "./dist/with-vitest.mjs", + "require": "./dist/with-vitest.js" + } + }, + "devDependencies": { + "@types/node": "20.17.24", + "@vercel/ai-tsconfig": "workspace:*", + "tsup": "^8", + "msw": "^2.7.0", + "typescript": "5.8.3" + }, + "engines": { + "node": ">=18" + }, + "publishConfig": { + "access": "public" + }, + "homepage": "https://ai-sdk.dev/docs", + "repository": { + "type": "git", + "url": "git+https://github.com/vercel/ai.git" + }, + "bugs": { + "url": "https://github.com/vercel/ai/issues" + }, + "keywords": [ + "ai", + "test-server", + "msw" + ] +} \ No newline at end of file diff --git a/packages/test-server/src/convert-array-to-readable-stream.ts b/packages/test-server/src/convert-array-to-readable-stream.ts new file mode 100644 index 000000000000..ac945e5e34b8 --- /dev/null +++ b/packages/test-server/src/convert-array-to-readable-stream.ts @@ -0,0 +1,15 @@ +export function convertArrayToReadableStream( + values: T[], +): ReadableStream { + return new ReadableStream({ + start(controller) { + try { + for (const value of values) { + controller.enqueue(value); + } + } finally { + controller.close(); + } + }, + }); +} diff --git a/packages/provider-utils/src/test/test-server.ts b/packages/test-server/src/create-test-server.ts similarity index 93% rename from packages/provider-utils/src/test/test-server.ts rename to packages/test-server/src/create-test-server.ts index c5d0301a7862..cc15e8362687 100644 --- a/packages/provider-utils/src/test/test-server.ts +++ b/packages/test-server/src/create-test-server.ts @@ -1,7 +1,6 @@ import { http, HttpResponse, JsonBodyType } from 'msw'; import { setupServer } from 'msw/node'; import { convertArrayToReadableStream } from './convert-array-to-readable-stream'; -import { beforeAll, beforeEach, afterAll } from 'vitest'; export type UrlResponse = | { @@ -67,8 +66,7 @@ class TestServerCall { return this.request!.headers.get('content-type')?.startsWith( 'multipart/form-data', ) - ? // For multipart/form-data, return the form data entries as an object - this.request!.formData().then(formData => { + ? this.request!.formData().then(formData => { const entries: Record = {}; formData.forEach((value, key) => { entries[key] = value; @@ -85,15 +83,19 @@ class TestServerCall { get requestHeaders() { const requestHeaders = this.request!.headers; - // convert headers to object for easier comparison const headersObject: Record = {}; requestHeaders.forEach((value, key) => { + if (key.toLowerCase() === 'user-agent') return; headersObject[key] = value; }); return headersObject; } + get requestUserAgent(): string | undefined { + return this.request!.headers.get('user-agent') ?? undefined; + } + get requestUrlSearchParams() { return new URL(this.request!.url).searchParams; } @@ -118,8 +120,9 @@ export function createTestServer< ): { urls: UrlHandlers; calls: TestServerCall[]; + server: { start: () => void; stop: () => void; reset: () => void }; } { - const originalRoutes = structuredClone(routes); // deep copy + const originalRoutes = structuredClone(routes); const mswServer = setupServer( ...Object.entries(routes).map(([url, handler]) => { @@ -219,30 +222,30 @@ export function createTestServer< let calls: TestServerCall[] = []; - beforeAll(() => { + const start = () => { mswServer.listen(); - }); + }; - beforeEach(() => { + const reset = () => { mswServer.resetHandlers(); - // set the responses back to the original values Object.entries(originalRoutes).forEach(([url, handler]) => { routes[url].response = handler.response; }); calls = []; - }); + }; - afterAll(() => { + const stop = () => { mswServer.close(); - }); + }; return { urls: routes as UrlHandlers, get calls() { return calls; }, + server: { start, stop, reset }, }; } diff --git a/packages/test-server/src/index.ts b/packages/test-server/src/index.ts new file mode 100644 index 000000000000..a7c979dddcbc --- /dev/null +++ b/packages/test-server/src/index.ts @@ -0,0 +1,7 @@ +export { + createTestServer, + TestResponseController, + type UrlResponse, + type UrlHandler, + type UrlHandlers, +} from './create-test-server'; diff --git a/packages/test-server/src/with-vitest.test.ts b/packages/test-server/src/with-vitest.test.ts new file mode 100644 index 000000000000..64d29f0d100d --- /dev/null +++ b/packages/test-server/src/with-vitest.test.ts @@ -0,0 +1,101 @@ +import { describe, it, expect } from 'vitest'; +import { createTestServer, TestResponseController } from './with-vitest'; + +describe('createTestServer', () => { + it('should create a test server with basic functionality', () => { + const server = createTestServer({ + 'https://api.example.com/test': { + response: { + type: 'json-value', + body: { message: 'hello world' }, + }, + }, + }); + + expect(server).toBeDefined(); + expect(server.urls).toBeDefined(); + expect(server.calls).toBeDefined(); + expect(Array.isArray(server.calls)).toBe(true); + expect(server.calls.length).toBe(0); + }); + + it('should handle response mutations', () => { + const server = createTestServer({ + 'https://api.example.com/test': { + response: { + type: 'json-value', + body: { count: 1 }, + }, + }, + }); + + // Should be able to mutate responses + server.urls['https://api.example.com/test'].response = { + type: 'json-value', + body: { count: 2 }, + }; + + expect(server.urls['https://api.example.com/test'].response).toEqual({ + type: 'json-value', + body: { count: 2 }, + }); + }); + + it('should support different response types', () => { + const server = createTestServer({ + 'https://api.example.com/json': { + response: { + type: 'json-value', + body: { test: true }, + }, + }, + 'https://api.example.com/stream': { + response: { + type: 'stream-chunks', + chunks: ['chunk1', 'chunk2'], + }, + }, + 'https://api.example.com/error': { + response: { + type: 'error', + status: 400, + body: 'Bad Request', + }, + }, + }); + + expect(server.urls['https://api.example.com/json'].response).toEqual({ + type: 'json-value', + body: { test: true }, + }); + + expect(server.urls['https://api.example.com/stream'].response).toEqual({ + type: 'stream-chunks', + chunks: ['chunk1', 'chunk2'], + }); + + expect(server.urls['https://api.example.com/error'].response).toEqual({ + type: 'error', + status: 400, + body: 'Bad Request', + }); + }); +}); + +describe('TestResponseController', () => { + it('should create a controller with stream access', () => { + const controller = new TestResponseController(); + + expect(controller).toBeDefined(); + expect(controller.stream).toBeDefined(); + expect(controller.stream).toBeInstanceOf(ReadableStream); + }); + + it('should have write, error, and close methods', () => { + const controller = new TestResponseController(); + + expect(typeof controller.write).toBe('function'); + expect(typeof controller.error).toBe('function'); + expect(typeof controller.close).toBe('function'); + }); +}); diff --git a/packages/test-server/src/with-vitest.ts b/packages/test-server/src/with-vitest.ts new file mode 100644 index 000000000000..8196cd71e58e --- /dev/null +++ b/packages/test-server/src/with-vitest.ts @@ -0,0 +1,57 @@ +import { beforeAll, beforeEach, afterAll } from 'vitest'; +import { + createTestServer as createCoreTestServer, + TestResponseController, + type UrlResponse, + type UrlHandler, + type UrlHandlers, +} from './index'; + +export function createTestServer< + URLS extends { + [url: string]: { + response?: + | UrlResponse + | UrlResponse[] + | ((options: { callNumber: number }) => UrlResponse); + }; + }, +>( + routes: URLS, +): { + urls: UrlHandlers; + calls: Array<{ + readonly requestBodyJson: Promise; + readonly requestBodyMultipart: Promise | null> | null; + readonly requestCredentials: RequestCredentials; + readonly requestHeaders: Record; + readonly requestUserAgent: string | undefined; + readonly requestUrlSearchParams: URLSearchParams; + readonly requestUrl: string; + readonly requestMethod: string; + }>; +} { + const server = createCoreTestServer(routes); + + beforeAll(() => { + server.server.start(); + }); + + beforeEach(() => { + server.server.reset(); + }); + + afterAll(() => { + server.server.stop(); + }); + + return { + urls: server.urls, + get calls() { + return server.calls; + }, + }; +} + +export { TestResponseController }; +export type { UrlResponse, UrlHandler, UrlHandlers }; diff --git a/packages/test-server/tsconfig.build.json b/packages/test-server/tsconfig.build.json new file mode 100644 index 000000000000..6242aec27cfe --- /dev/null +++ b/packages/test-server/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "composite": false + } + } + \ No newline at end of file diff --git a/packages/test-server/tsconfig.json b/packages/test-server/tsconfig.json new file mode 100644 index 000000000000..6b9d536feb75 --- /dev/null +++ b/packages/test-server/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "./node_modules/@vercel/ai-tsconfig/ts-library.json", + "compilerOptions": { + "composite": true, + "rootDir": "src", + "outDir": "dist" + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "dist", + "build", + "node_modules", + "tsup.config.ts" + ], + "references": [ + { + "path": "../provider" + } + ] + } + \ No newline at end of file diff --git a/packages/test-server/tsup.config.ts b/packages/test-server/tsup.config.ts new file mode 100644 index 000000000000..8b70cfbd5748 --- /dev/null +++ b/packages/test-server/tsup.config.ts @@ -0,0 +1,32 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig([ + { + entry: ['src/index.ts'], + format: ['cjs', 'esm'], + dts: true, + sourcemap: true, + target: 'es2018', + platform: 'node', + }, + { + entry: ['src/with-vitest.ts'], + format: ['cjs', 'esm'], + dts: true, + sourcemap: true, + target: 'es2020', + platform: 'node', + external: [ + 'chai', + 'msw', + 'msw/*', + 'vitest', + 'vitest/*', + '@vitest/*', + 'vitest/dist/*', + 'vitest/dist/chunks/*', + 'vitest/dist/node/*', + 'vitest/dist/node/chunks/*', + ], + }, +]); diff --git a/packages/test-server/vitest.edge.config.js b/packages/test-server/vitest.edge.config.js new file mode 100644 index 000000000000..3dc49ba29774 --- /dev/null +++ b/packages/test-server/vitest.edge.config.js @@ -0,0 +1,9 @@ +import { defineConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + test: { + environment: 'edge-runtime', + include: ['**/*.test.ts', '**/*.test.tsx'], + }, +}); diff --git a/packages/test-server/vitest.node.config.js b/packages/test-server/vitest.node.config.js new file mode 100644 index 000000000000..b7e4a9cabd48 --- /dev/null +++ b/packages/test-server/vitest.node.config.js @@ -0,0 +1,9 @@ +import { defineConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + test: { + environment: 'node', + include: ['**/*.test.ts', '**/*.test.tsx'], + }, +}); diff --git a/packages/togetherai/CHANGELOG.md b/packages/togetherai/CHANGELOG.md index e6b54b074305..cfc381dae91a 100644 --- a/packages/togetherai/CHANGELOG.md +++ b/packages/togetherai/CHANGELOG.md @@ -1,5 +1,73 @@ # @ai-sdk/togetherai +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/openai-compatible@1.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 0c4822d: feat: `EmbeddingModelV3` +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/openai-compatible@1.1.0-beta.2 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/openai-compatible@1.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/openai-compatible@1.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.18 + +### Patch Changes + +- Updated dependencies [28363da] + - @ai-sdk/openai-compatible@1.0.18 + +## 1.0.17 + +### Patch Changes + +- Updated dependencies [3aed04c] + - @ai-sdk/openai-compatible@1.0.17 + +## 1.0.16 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/openai-compatible@1.0.16 + ## 1.0.15 ### Patch Changes diff --git a/packages/togetherai/package.json b/packages/togetherai/package.json index f13862d78736..92e99eb539ea 100644 --- a/packages/togetherai/package.json +++ b/packages/togetherai/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/togetherai", - "version": "1.0.15", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -34,7 +34,8 @@ "dependencies": { "@ai-sdk/openai-compatible": "workspace:*", "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/togetherai/src/index.ts b/packages/togetherai/src/index.ts index 00170cb32954..2383ec72c02a 100644 --- a/packages/togetherai/src/index.ts +++ b/packages/togetherai/src/index.ts @@ -4,3 +4,4 @@ export type { TogetherAIProviderSettings, } from './togetherai-provider'; export type { OpenAICompatibleErrorData as TogetherAIErrorData } from '@ai-sdk/openai-compatible'; +export { VERSION } from './version'; diff --git a/packages/togetherai/src/togetherai-image-model.test.ts b/packages/togetherai/src/togetherai-image-model.test.ts index a739a7883838..328be7ded236 100644 --- a/packages/togetherai/src/togetherai-image-model.test.ts +++ b/packages/togetherai/src/togetherai-image-model.test.ts @@ -1,5 +1,5 @@ import { FetchFunction } from '@ai-sdk/provider-utils'; -import { createTestServer } from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; import { describe, expect, it } from 'vitest'; import { TogetherAIImageModel } from './togetherai-image-model'; @@ -238,7 +238,7 @@ describe('constructor', () => { expect(model.provider).toBe('togetherai'); expect(model.modelId).toBe('stabilityai/stable-diffusion-xl'); - expect(model.specificationVersion).toBe('v2'); + expect(model.specificationVersion).toBe('v3'); expect(model.maxImagesPerCall).toBe(1); }); }); diff --git a/packages/togetherai/src/togetherai-image-model.ts b/packages/togetherai/src/togetherai-image-model.ts index 4a473f06fdac..2e80ad69f81f 100644 --- a/packages/togetherai/src/togetherai-image-model.ts +++ b/packages/togetherai/src/togetherai-image-model.ts @@ -1,4 +1,4 @@ -import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider'; +import { ImageModelV3, ImageModelV3CallWarning } from '@ai-sdk/provider'; import { combineHeaders, createJsonResponseHandler, @@ -19,8 +19,8 @@ interface TogetherAIImageModelConfig { }; } -export class TogetherAIImageModel implements ImageModelV2 { - readonly specificationVersion = 'v2'; +export class TogetherAIImageModel implements ImageModelV3 { + readonly specificationVersion = 'v3'; readonly maxImagesPerCall = 1; get provider(): string { @@ -40,10 +40,10 @@ export class TogetherAIImageModel implements ImageModelV2 { providerOptions, headers, abortSignal, - }: Parameters[0]): Promise< - Awaited> + }: Parameters[0]): Promise< + Awaited> > { - const warnings: Array = []; + const warnings: Array = []; if (size != null) { warnings.push({ diff --git a/packages/togetherai/src/togetherai-provider.test.ts b/packages/togetherai/src/togetherai-provider.test.ts index 0a2a3af2db6a..0a9b2919f629 100644 --- a/packages/togetherai/src/togetherai-provider.test.ts +++ b/packages/togetherai/src/togetherai-provider.test.ts @@ -3,8 +3,8 @@ import { OpenAICompatibleCompletionLanguageModel, OpenAICompatibleEmbeddingModel, } from '@ai-sdk/openai-compatible'; -import { LanguageModelV2, EmbeddingModelV2 } from '@ai-sdk/provider'; -import { loadApiKey } from '@ai-sdk/provider-utils'; +import { LanguageModelV2, EmbeddingModelV3 } from '@ai-sdk/provider'; +import { loadApiKey, withUserAgentSuffix } from '@ai-sdk/provider-utils'; import { TogetherAIImageModel } from './togetherai-image-model'; import { createTogetherAI } from './togetherai-provider'; import { describe, it, expect, vi, beforeEach, Mock } from 'vitest'; @@ -19,10 +19,14 @@ vi.mock('@ai-sdk/openai-compatible', () => ({ OpenAICompatibleEmbeddingModel: vi.fn(), })); -vi.mock('@ai-sdk/provider-utils', () => ({ - loadApiKey: vi.fn().mockReturnValue('mock-api-key'), - withoutTrailingSlash: vi.fn(url => url), -})); +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + loadApiKey: vi.fn().mockReturnValue('mock-api-key'), + withoutTrailingSlash: vi.fn(url => url), + }; +}); vi.mock('./togetherai-image-model', () => ({ TogetherAIImageModel: vi.fn(), @@ -30,7 +34,7 @@ vi.mock('./togetherai-image-model', () => ({ describe('TogetherAIProvider', () => { let mockLanguageModel: LanguageModelV2; - let mockEmbeddingModel: EmbeddingModelV2; + let mockEmbeddingModel: EmbeddingModelV3; let createOpenAICompatibleMock: Mock; beforeEach(() => { @@ -39,8 +43,8 @@ describe('TogetherAIProvider', () => { // Add any required methods for LanguageModelV2 } as LanguageModelV2; mockEmbeddingModel = { - // Add any required methods for EmbeddingModelV2 - } as EmbeddingModelV2; + // Add any required methods for EmbeddingModelV3 + } as EmbeddingModelV3; // Reset mocks vi.clearAllMocks(); diff --git a/packages/togetherai/src/togetherai-provider.ts b/packages/togetherai/src/togetherai-provider.ts index 266b68025c9b..5c5e7378a31b 100644 --- a/packages/togetherai/src/togetherai-provider.ts +++ b/packages/togetherai/src/togetherai-provider.ts @@ -1,8 +1,8 @@ import { LanguageModelV2, - EmbeddingModelV2, - ProviderV2, - ImageModelV2, + EmbeddingModelV3, + ProviderV3, + ImageModelV3, } from '@ai-sdk/provider'; import { OpenAICompatibleChatLanguageModel, @@ -13,12 +13,14 @@ import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { TogetherAIChatModelId } from './togetherai-chat-options'; import { TogetherAIEmbeddingModelId } from './togetherai-embedding-options'; import { TogetherAICompletionModelId } from './togetherai-completion-options'; import { TogetherAIImageModel } from './togetherai-image-model'; import { TogetherAIImageModelId } from './togetherai-image-settings'; +import { VERSION } from './version'; export interface TogetherAIProviderSettings { /** @@ -40,7 +42,7 @@ or to provide a custom fetch implementation for e.g. testing. fetch?: FetchFunction; } -export interface TogetherAIProvider extends ProviderV2 { +export interface TogetherAIProvider extends ProviderV3 { /** Creates a model for text generation. */ @@ -66,17 +68,17 @@ Creates a text embedding model for text generation. */ textEmbeddingModel( modelId: TogetherAIEmbeddingModelId, - ): EmbeddingModelV2; + ): EmbeddingModelV3; /** Creates a model for image generation. */ - image(modelId: TogetherAIImageModelId): ImageModelV2; + image(modelId: TogetherAIImageModelId): ImageModelV3; /** Creates a model for image generation. */ - imageModel(modelId: TogetherAIImageModelId): ImageModelV2; + imageModel(modelId: TogetherAIImageModelId): ImageModelV3; } export function createTogetherAI( @@ -85,14 +87,18 @@ export function createTogetherAI( const baseURL = withoutTrailingSlash( options.baseURL ?? 'https://api.together.xyz/v1/', ); - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'TOGETHER_AI_API_KEY', - description: 'TogetherAI', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'TOGETHER_AI_API_KEY', + description: 'TogetherAI', + })}`, + ...options.headers, + }, + `ai-sdk/togetherai/${VERSION}`, + ); interface CommonModelConfig { provider: string; diff --git a/packages/togetherai/src/version.ts b/packages/togetherai/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/togetherai/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/togetherai/tsup.config.ts b/packages/togetherai/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/togetherai/tsup.config.ts +++ b/packages/togetherai/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/togetherai/vitest.edge.config.js b/packages/togetherai/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/togetherai/vitest.edge.config.js +++ b/packages/togetherai/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/togetherai/vitest.node.config.js b/packages/togetherai/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/togetherai/vitest.node.config.js +++ b/packages/togetherai/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/valibot/CHANGELOG.md b/packages/valibot/CHANGELOG.md index 976c04f4ca60..7d2f0143ee0f 100644 --- a/packages/valibot/CHANGELOG.md +++ b/packages/valibot/CHANGELOG.md @@ -1,5 +1,42 @@ # @ai-sdk/valibot +## 1.1.0-beta.3 + +### Patch Changes + +- @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [cbb1d35] + - @ai-sdk/provider-utils@3.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.9 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + ## 1.0.8 ### Patch Changes diff --git a/packages/valibot/package.json b/packages/valibot/package.json index fb1cd93b8a85..cfc81d12765a 100644 --- a/packages/valibot/package.json +++ b/packages/valibot/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/valibot", - "version": "1.0.8", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/vercel/CHANGELOG.md b/packages/vercel/CHANGELOG.md index 8a5e825526a5..2ecbc39fd268 100644 --- a/packages/vercel/CHANGELOG.md +++ b/packages/vercel/CHANGELOG.md @@ -1,5 +1,69 @@ # @ai-sdk/vercel +## 1.1.0-beta.3 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/openai-compatible@1.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 1.1.0-beta.2 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/openai-compatible@1.1.0-beta.2 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 1.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [cbb1d35] + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/openai-compatible@1.1.0-beta.1 + +## 1.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/openai-compatible@1.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 1.0.18 + +### Patch Changes + +- Updated dependencies [28363da] + - @ai-sdk/openai-compatible@1.0.18 + +## 1.0.17 + +### Patch Changes + +- Updated dependencies [3aed04c] + - @ai-sdk/openai-compatible@1.0.17 + +## 1.0.16 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/openai-compatible@1.0.16 + ## 1.0.15 ### Patch Changes diff --git a/packages/vercel/package.json b/packages/vercel/package.json index 36da99106c95..398dcf5e7684 100644 --- a/packages/vercel/package.json +++ b/packages/vercel/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/vercel", - "version": "1.0.15", + "version": "1.1.0-beta.3", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/vercel/src/index.ts b/packages/vercel/src/index.ts index bc224eeb7903..485da827ddd7 100644 --- a/packages/vercel/src/index.ts +++ b/packages/vercel/src/index.ts @@ -1,3 +1,4 @@ export { createVercel, vercel } from './vercel-provider'; export type { VercelProvider, VercelProviderSettings } from './vercel-provider'; export type { OpenAICompatibleErrorData as VercelErrorData } from '@ai-sdk/openai-compatible'; +export { VERSION } from './version'; diff --git a/packages/vercel/src/vercel-provider.test.ts b/packages/vercel/src/vercel-provider.test.ts index 6b6bce9e5a2d..805b216e0f59 100644 --- a/packages/vercel/src/vercel-provider.test.ts +++ b/packages/vercel/src/vercel-provider.test.ts @@ -12,10 +12,14 @@ vi.mock('@ai-sdk/openai-compatible', () => ({ OpenAICompatibleCompletionLanguageModel: vi.fn(), })); -vi.mock('@ai-sdk/provider-utils', () => ({ - loadApiKey: vi.fn().mockReturnValue('mock-api-key'), - withoutTrailingSlash: vi.fn(url => url), -})); +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + loadApiKey: vi.fn().mockReturnValue('mock-api-key'), + withoutTrailingSlash: vi.fn(url => url), + }; +}); vi.mock('./vercel-image-model', () => ({ VercelImageModel: vi.fn(), diff --git a/packages/vercel/src/vercel-provider.ts b/packages/vercel/src/vercel-provider.ts index fa00cb9cd80c..625c256977cd 100644 --- a/packages/vercel/src/vercel-provider.ts +++ b/packages/vercel/src/vercel-provider.ts @@ -1,15 +1,17 @@ import { LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { OpenAICompatibleChatLanguageModel } from '@ai-sdk/openai-compatible'; import { FetchFunction, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { VercelChatModelId } from './vercel-chat-options'; +import { VERSION } from './version'; export interface VercelProviderSettings { /** @@ -31,7 +33,7 @@ or to provide a custom fetch implementation for e.g. testing. fetch?: FetchFunction; } -export interface VercelProvider extends ProviderV2 { +export interface VercelProvider extends ProviderV3 { /** Creates a model for text generation. */ @@ -49,14 +51,18 @@ export function createVercel( const baseURL = withoutTrailingSlash( options.baseURL ?? 'https://api.v0.dev/v1', ); - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'VERCEL_API_KEY', - description: 'Vercel', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'VERCEL_API_KEY', + description: 'Vercel', + })}`, + ...options.headers, + }, + `ai-sdk/vercel/${VERSION}`, + ); interface CommonModelConfig { provider: string; diff --git a/packages/vercel/src/version.ts b/packages/vercel/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/vercel/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/vercel/tsup.config.ts b/packages/vercel/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/vercel/tsup.config.ts +++ b/packages/vercel/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/vercel/vitest.edge.config.js b/packages/vercel/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/vercel/vitest.edge.config.js +++ b/packages/vercel/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/vercel/vitest.node.config.js b/packages/vercel/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/vercel/vitest.node.config.js +++ b/packages/vercel/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/vue/CHANGELOG.md b/packages/vue/CHANGELOG.md index 22a125f2991c..bea6399fe6c8 100644 --- a/packages/vue/CHANGELOG.md +++ b/packages/vue/CHANGELOG.md @@ -1,5 +1,128 @@ # @ai-sdk/vue +## 2.1.0-beta.9 + +### Patch Changes + +- Updated dependencies [ed329cb] +- Updated dependencies [177b475] +- Updated dependencies [522f6b8] + - ai@5.1.0-beta.9 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.8 + +### Patch Changes + +- Updated dependencies [7eca093] + - ai@5.1.0-beta.8 + +## 2.1.0-beta.7 + +### Patch Changes + +- Updated dependencies [5a4e732] + - ai@5.1.0-beta.7 + +## 2.1.0-beta.6 + +### Patch Changes + +- Updated dependencies [0c4822d] + - ai@5.1.0-beta.6 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.5 + +### Patch Changes + +- ai@5.1.0-beta.5 + +## 2.1.0-beta.4 + +### Patch Changes + +- ai@5.1.0-beta.4 + +## 2.1.0-beta.3 + +### Patch Changes + +- ai@5.1.0-beta.3 + +## 2.1.0-beta.2 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - ai@5.1.0-beta.2 + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [a7f6f81] + - ai@5.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - ai@5.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.45 + +### Patch Changes + +- Updated dependencies [76024fc] +- Updated dependencies [93d8b60] +- Updated dependencies [d8eb31f] + - ai@5.0.45 + +## 2.0.44 + +### Patch Changes + +- ai@5.0.44 + +## 2.0.43 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - ai@5.0.43 + +## 2.0.42 + +### Patch Changes + +- Updated dependencies [de5c066] + - ai@5.0.42 + +## 2.0.41 + +### Patch Changes + +- Updated dependencies [cd91e4b] + - ai@5.0.41 + +## 2.0.40 + +### Patch Changes + +- b75beb0: Add useObject support to Vue + - ai@5.0.40 + ## 2.0.39 ### Patch Changes diff --git a/packages/vue/package.json b/packages/vue/package.json index 52af8c47426d..2122c588cf9d 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/vue", - "version": "2.0.39", + "version": "2.1.0-beta.9", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -30,8 +30,9 @@ "CHANGELOG.md" ], "dependencies": { - "ai": "workspace:*", "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*", + "ai": "workspace:*", "swrv": "^1.0.4" }, "devDependencies": { @@ -50,11 +51,15 @@ "vitest": "2.1.4" }, "peerDependencies": { - "vue": "^3.3.4" + "vue": "^3.3.4", + "zod": "^3.25.76 || ^4" }, "peerDependenciesMeta": { "vue": { "optional": true + }, + "zod": { + "optional": true } }, "engines": { diff --git a/packages/vue/src/TestUseObjectComponent.vue b/packages/vue/src/TestUseObjectComponent.vue new file mode 100644 index 000000000000..c1e1f793ae00 --- /dev/null +++ b/packages/vue/src/TestUseObjectComponent.vue @@ -0,0 +1,45 @@ + + + diff --git a/packages/vue/src/TestUseObjectCustomTransportComponent.vue b/packages/vue/src/TestUseObjectCustomTransportComponent.vue new file mode 100644 index 000000000000..ad03c4d2e2e1 --- /dev/null +++ b/packages/vue/src/TestUseObjectCustomTransportComponent.vue @@ -0,0 +1,35 @@ + + + diff --git a/packages/vue/src/chat.vue.ui.test.tsx b/packages/vue/src/chat.vue.ui.test.tsx index 0516e57e4f63..7174c654aae1 100644 --- a/packages/vue/src/chat.vue.ui.test.tsx +++ b/packages/vue/src/chat.vue.ui.test.tsx @@ -1,7 +1,7 @@ import { createTestServer, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; import '@testing-library/jest-dom/vitest'; import userEvent from '@testing-library/user-event'; import { screen, waitFor } from '@testing-library/vue'; diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index 2722bb568750..5e9d33a48d9d 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -1,2 +1,3 @@ export * from './use-completion'; export { Chat } from './chat.vue'; +export * from './use-object'; diff --git a/packages/vue/src/use-completion.ui.test.ts b/packages/vue/src/use-completion.ui.test.ts index e1823e446d09..f1f07df84536 100644 --- a/packages/vue/src/use-completion.ui.test.ts +++ b/packages/vue/src/use-completion.ui.test.ts @@ -1,7 +1,7 @@ import { createTestServer, TestResponseController, -} from '@ai-sdk/provider-utils/test'; +} from '@ai-sdk/test-server/with-vitest'; import '@testing-library/jest-dom/vitest'; import userEvent from '@testing-library/user-event'; import { findByText, screen } from '@testing-library/vue'; diff --git a/packages/vue/src/use-object.ts b/packages/vue/src/use-object.ts new file mode 100644 index 000000000000..6aeaf7d29b0a --- /dev/null +++ b/packages/vue/src/use-object.ts @@ -0,0 +1,234 @@ +import { ref, type Ref } from 'vue'; +import swrv from 'swrv'; +import { + isAbortError, + safeValidateTypes, + type FetchFunction, + type InferSchema, +} from '@ai-sdk/provider-utils'; +import { + asSchema, + type DeepPartial, + isDeepEqualData, + parsePartialJson, + type Schema, +} from 'ai'; +import * as z3 from 'zod/v3'; +import * as z4 from 'zod/v4'; + +// use function to allow for mocking in tests +const getOriginalFetch = () => fetch; + +export type Experimental_UseObjectOptions< + SCHEMA extends z4.core.$ZodType | z3.Schema | Schema, + RESULT, +> = { + /** API endpoint that streams JSON chunks matching the schema */ + api: string; + + /** Zod or AI schema that defines the final object shape */ + schema: SCHEMA; + + /** Shared state key. If omitted a random one is generated */ + id?: string; + + /** Initial partial value */ + initialValue?: DeepPartial; + + /** Optional custom fetch implementation */ + fetch?: FetchFunction; + + /** Called when stream ends */ + onFinish?: (event: { + object: RESULT | undefined; + error: Error | undefined; + }) => Promise | void; + + /** Called on error */ + onError?: (error: Error) => void; + + /** Extra request headers */ + headers?: Record | Headers; + + /** Request credentials mode. Defaults to 'same-origin' if omitted */ + credentials?: RequestCredentials; +}; + +export type Experimental_UseObjectHelpers = { + /** POST the input and start streaming */ + submit: (input: INPUT) => void; + + /** Current partial object, updated as chunks arrive */ + object: Ref | undefined>; + + /** Latest error if any */ + error: Ref; + + /** Loading flag for the in-flight request */ + isLoading: Ref; + + /** Abort the current request. Keeps current partial object. */ + stop: () => void; + + /** Abort and clear all state */ + clear: () => void; +}; + +let uniqueId = 0; + +// @ts-expect-error - some issues with the default export of useSWRV +const useSWRV = (swrv.default as (typeof import('swrv'))['default']) || swrv; +const store: Record = {}; + +export const experimental_useObject = function useObject< + SCHEMA extends z4.core.$ZodType | z3.Schema | Schema, + RESULT = InferSchema, + INPUT = any, +>({ + api, + id, + schema, + initialValue, + fetch, + onError, + onFinish, + headers, + credentials, +}: Experimental_UseObjectOptions< + SCHEMA, + RESULT +>): Experimental_UseObjectHelpers { + // Generate an unique id for the object if not provided. + const completionId = id || `completion-${uniqueId++}`; + + const key = `${api}|${completionId}`; + const { data, mutate: originalMutate } = useSWRV< + DeepPartial | undefined + >(key, () => (key in store ? store[key] : initialValue)); + + const { data: isLoading, mutate: mutateLoading } = useSWRV( + `${completionId}-loading`, + null, + ); + + isLoading.value ??= false; + data.value ||= initialValue as DeepPartial | undefined; + + const mutateObject = (value: DeepPartial | undefined) => { + store[key] = value; + return originalMutate(); + }; + + const error = ref(undefined); + let abortController: AbortController | null = null; + + const stop = async () => { + if (abortController) { + try { + abortController.abort(); + } catch { + // ignore + } finally { + abortController = null; + } + } + await mutateLoading(() => false); + }; + + const clearObject = async () => { + error.value = undefined; + await mutateLoading(() => false); + await mutateObject(undefined); + // Need to explicitly set the value to undefined to trigger a re-render + data.value = undefined; + }; + + const clear = async () => { + await stop(); + await clearObject(); + }; + + const submit = async (input: INPUT) => { + try { + await clearObject(); + await mutateLoading(() => true); + + abortController = new AbortController(); + + const actualFetch = fetch ?? getOriginalFetch(); + const response = await actualFetch(api, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...(headers as any), + }, + credentials: credentials ?? 'same-origin', + signal: abortController.signal, + body: JSON.stringify(input), + }); + + if (!response.ok) { + throw new Error( + (await response.text()) || 'Failed to fetch the response.', + ); + } + + if (!response.body) { + throw new Error('The response body is empty.'); + } + + let accumulatedText = ''; + let latestObject: DeepPartial | undefined = undefined; + + await response.body.pipeThrough(new TextDecoderStream()).pipeTo( + new WritableStream({ + async write(chunk) { + accumulatedText += chunk; + const { value } = await parsePartialJson(accumulatedText); + const currentObject = value as DeepPartial; + if (!isDeepEqualData(latestObject, currentObject)) { + latestObject = currentObject; + await mutateObject(currentObject); + } + }, + async close() { + await mutateLoading(() => false); + abortController = null; + + if (onFinish) { + const validationResult = await safeValidateTypes({ + value: latestObject, + schema: asSchema(schema), + }); + + onFinish( + validationResult.success + ? { + object: validationResult.value as RESULT, + error: undefined, + } + : { object: undefined, error: validationResult.error }, + ); + } + }, + }), + ); + } catch (err: unknown) { + if (isAbortError(err)) return; + + if (onError && err instanceof Error) onError(err); + + await mutateLoading(() => false); + error.value = err instanceof Error ? err : new Error(String(err)); + } + }; + + return { + submit, + object: data, + error, + isLoading, + stop, + clear, + }; +}; diff --git a/packages/vue/src/use-object.ui.test.tsx b/packages/vue/src/use-object.ui.test.tsx new file mode 100644 index 000000000000..291370a8101f --- /dev/null +++ b/packages/vue/src/use-object.ui.test.tsx @@ -0,0 +1,250 @@ +import { + createTestServer, + TestResponseController, +} from '@ai-sdk/test-server/with-vitest'; +import '@testing-library/jest-dom/vitest'; +import { cleanup, screen, waitFor } from '@testing-library/vue'; +import userEvent from '@testing-library/user-event'; +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { setupTestComponent } from './setup-test-component'; +import TestUseObjectComponent from './TestUseObjectComponent.vue'; +import TestUseObjectCustomTransportComponent from './TestUseObjectCustomTransportComponent.vue'; + +const server = createTestServer({ + '/api/use-object': {}, +}); + +describe('text stream', () => { + afterEach(() => { + vi.restoreAllMocks(); + cleanup(); + }); + + describe('basic component', () => { + setupTestComponent(TestUseObjectComponent); + + describe("when the API returns 'Hello, world!'", () => { + beforeEach(async () => { + server.urls['/api/use-object'].response = { + type: 'stream-chunks', + chunks: ['{ ', '"content": "Hello, ', 'world', '!"'], + }; + await userEvent.click(screen.getByTestId('submit-button')); + }); + + it('should render stream', async () => { + await screen.findByTestId('object'); + expect(screen.getByTestId('object')).toHaveTextContent( + JSON.stringify({ content: 'Hello, world!' }), + ); + }); + + it("should send 'test' to the API", async () => { + expect(await server.calls[0].requestBodyJson).toBe('test-input'); + }); + + it('should not have an error', async () => { + await screen.findByTestId('error'); + expect(screen.getByTestId('error')).toBeEmptyDOMElement(); + expect(screen.getByTestId('on-error-result')).toBeEmptyDOMElement(); + }); + }); + + describe('isLoading', () => { + it('should be true while loading', async () => { + const controller = new TestResponseController(); + server.urls['/api/use-object'].response = { + type: 'controlled-stream', + controller, + }; + + controller.write('{"content": '); + await userEvent.click(screen.getByTestId('submit-button')); + + // wait for element "loading" to have text content "true": + await waitFor(() => { + expect(screen.getByTestId('loading')).toHaveTextContent('true'); + }); + + controller.write('"Hello, world!"}'); + controller.close(); + + // wait for element "loading" to have text content "false": + await waitFor(() => { + expect(screen.getByTestId('loading')).toHaveTextContent('false'); + }); + }); + }); + + it('should abort the stream and not consume any more data', async () => { + const controller = new TestResponseController(); + server.urls['/api/use-object'].response = { + type: 'controlled-stream', + controller, + }; + + controller.write('{"content": "h'); + await userEvent.click(screen.getByTestId('submit-button')); + + // wait for element "loading" and "object" to have text content: + await waitFor(() => { + expect(screen.getByTestId('loading')).toHaveTextContent('true'); + }); + await waitFor(() => { + expect(screen.getByTestId('object')).toHaveTextContent( + '{"content":"h"}', + ); + }); + + // click stop button: + await userEvent.click(screen.getByTestId('stop-button')); + + // wait for element "loading" to have text content "false": + await waitFor(() => { + expect(screen.getByTestId('loading')).toHaveTextContent('false'); + }); + + // this should not be consumed any more: + await expect(controller.write('ello, world!"}')).rejects.toThrow(); + await expect(controller.close()).rejects.toThrow(); + + // should only show start of object: + await waitFor(() => { + expect(screen.getByTestId('object')).toHaveTextContent( + '{"content":"h"}', + ); + }); + }); + + it('should stop and clear the object state after a call to submit then clear', async () => { + const controller = new TestResponseController(); + server.urls['/api/use-object'].response = { + type: 'controlled-stream', + controller, + }; + + controller.write('{"content": "h'); + await userEvent.click(screen.getByTestId('submit-button')); + + await waitFor(() => { + expect(screen.getByTestId('loading')).toHaveTextContent('true'); + }); + await waitFor(() => { + expect(screen.getByTestId('object')).toHaveTextContent( + '{"content":"h"}', + ); + }); + + await userEvent.click(screen.getByTestId('clear-button')); + + await expect(controller.write('ello, world!"}')).rejects.toThrow(); + await expect(controller.close()).rejects.toThrow(); + + await waitFor(() => { + expect(screen.getByTestId('loading')).toHaveTextContent('false'); + expect(screen.getByTestId('error')).toBeEmptyDOMElement(); + expect(screen.getByTestId('object')).toBeEmptyDOMElement(); + }); + }); + + describe('when the API returns a 404', () => { + it('should render error', async () => { + server.urls['/api/use-object'].response = { + type: 'error', + status: 404, + body: 'Not found', + }; + + await userEvent.click(screen.getByTestId('submit-button')); + + await screen.findByTestId('error'); + expect(screen.getByTestId('error')).toHaveTextContent('Not found'); + expect(screen.getByTestId('on-error-result')).toHaveTextContent( + 'Not found', + ); + expect(screen.getByTestId('loading')).toHaveTextContent('false'); + }); + }); + + describe('onFinish', () => { + it('should be called with an object when the stream finishes and the object matches the schema', async () => { + server.urls['/api/use-object'].response = { + type: 'stream-chunks', + chunks: ['{ ', '"content": "Hello, ', 'world', '!"', '}'], + }; + + await userEvent.click(screen.getByTestId('submit-button')); + + expect(screen.getByTestId('on-finish-calls')).toHaveTextContent( + JSON.stringify([ + { object: { content: 'Hello, world!' }, error: undefined }, + ]), + ); + }); + + it('should be called with an error when the stream finishes and the object does not match the schema', async () => { + server.urls['/api/use-object'].response = { + type: 'stream-chunks', + chunks: ['{ ', '"content-wrong": "Hello, ', 'world', '!"', '}'], + }; + + await userEvent.click(screen.getByTestId('submit-button')); + + expect(screen.getByTestId('on-finish-calls')).toHaveTextContent( + 'ZodError', + ); + }); + }); + + it('should clear the object state after a call to clear', async () => { + server.urls['/api/use-object'].response = { + type: 'stream-chunks', + chunks: ['{ ', '"content": "Hello, ', 'world', '!"', '}'], + }; + + await userEvent.click(screen.getByTestId('submit-button')); + + await screen.findByTestId('object'); + expect(screen.getByTestId('object')).toHaveTextContent( + JSON.stringify({ content: 'Hello, world!' }), + ); + + await userEvent.click(screen.getByTestId('clear-button')); + + await waitFor(() => { + expect(screen.getByTestId('object')).toBeEmptyDOMElement(); + expect(screen.getByTestId('error')).toBeEmptyDOMElement(); + expect(screen.getByTestId('loading')).toHaveTextContent('false'); + }); + }); + }); + + describe('custom transport', () => { + setupTestComponent(TestUseObjectCustomTransportComponent); + + it('should send custom headers', async () => { + server.urls['/api/use-object'].response = { + type: 'stream-chunks', + chunks: ['{ ', '"content": "Hello, ', 'world', '!"', '}'], + }; + + await userEvent.click(screen.getByTestId('submit-button')); + + expect(server.calls[0].requestHeaders).toStrictEqual({ + 'content-type': 'application/json', + authorization: 'Bearer TEST_TOKEN', + 'x-custom-header': 'CustomValue', + }); + }); + + it('should send custom credentials', async () => { + server.urls['/api/use-object'].response = { + type: 'stream-chunks', + chunks: ['{ ', '"content": "Authenticated ', 'content', '!"', '}'], + }; + + await userEvent.click(screen.getByTestId('submit-button')); + expect(server.calls[0].requestCredentials).toBe('include'); + }); + }); +}); diff --git a/packages/xai/CHANGELOG.md b/packages/xai/CHANGELOG.md index 21601d2977e2..ff2b03b0ad32 100644 --- a/packages/xai/CHANGELOG.md +++ b/packages/xai/CHANGELOG.md @@ -1,5 +1,84 @@ # @ai-sdk/xai +## 2.1.0-beta.4 + +### Patch Changes + +- ed329cb: feat: `Provider-V3` +- 522f6b8: feat: `ImageModelV3` +- Updated dependencies [ed329cb] +- Updated dependencies [522f6b8] + - @ai-sdk/openai-compatible@1.1.0-beta.3 + - @ai-sdk/provider@2.1.0-beta.2 + - @ai-sdk/provider-utils@3.1.0-beta.3 + +## 2.1.0-beta.3 + +### Patch Changes + +- 1cad0ab: feat: add provider version to user-agent header +- Updated dependencies [0c4822d] + - @ai-sdk/openai-compatible@1.1.0-beta.2 + - @ai-sdk/provider@2.1.0-beta.1 + - @ai-sdk/provider-utils@3.1.0-beta.2 + +## 2.1.0-beta.2 + +### Patch Changes + +- 1861f6f: feat(xai) add grok-4-fast model ids + +## 2.1.0-beta.1 + +### Patch Changes + +- Updated dependencies [953d0f2] +- Updated dependencies [cbb1d35] + - @ai-sdk/test-server@1.0.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.1 + - @ai-sdk/openai-compatible@1.1.0-beta.1 + +## 2.1.0-beta.0 + +### Minor Changes + +- 78928cb: release: start 5.1 beta + +### Patch Changes + +- Updated dependencies [78928cb] + - @ai-sdk/openai-compatible@1.1.0-beta.0 + - @ai-sdk/provider@2.1.0-beta.0 + - @ai-sdk/provider-utils@3.1.0-beta.0 + +## 2.0.20 + +### Patch Changes + +- 3a10095: added new xai x live search fields + +## 2.0.19 + +### Patch Changes + +- Updated dependencies [28363da] + - @ai-sdk/openai-compatible@1.0.18 + +## 2.0.18 + +### Patch Changes + +- Updated dependencies [3aed04c] + - @ai-sdk/openai-compatible@1.0.17 + +## 2.0.17 + +### Patch Changes + +- Updated dependencies [0294b58] + - @ai-sdk/provider-utils@3.0.9 + - @ai-sdk/openai-compatible@1.0.16 + ## 2.0.16 ### Patch Changes diff --git a/packages/xai/package.json b/packages/xai/package.json index b12e488fc025..4030f5efb1ac 100644 --- a/packages/xai/package.json +++ b/packages/xai/package.json @@ -1,6 +1,6 @@ { "name": "@ai-sdk/xai", - "version": "2.0.16", + "version": "2.1.0-beta.4", "license": "Apache-2.0", "sideEffects": false, "main": "./dist/index.js", @@ -34,7 +34,8 @@ "dependencies": { "@ai-sdk/openai-compatible": "workspace:*", "@ai-sdk/provider": "workspace:*", - "@ai-sdk/provider-utils": "workspace:*" + "@ai-sdk/provider-utils": "workspace:*", + "@ai-sdk/test-server": "workspace:*" }, "devDependencies": { "@types/node": "20.17.24", diff --git a/packages/xai/src/index.ts b/packages/xai/src/index.ts index 09c4d4b55273..733e399e0844 100644 --- a/packages/xai/src/index.ts +++ b/packages/xai/src/index.ts @@ -2,3 +2,4 @@ export type { XaiProviderOptions } from './xai-chat-options'; export type { XaiErrorData } from './xai-error'; export { createXai, xai } from './xai-provider'; export type { XaiProvider, XaiProviderSettings } from './xai-provider'; +export { VERSION } from './version'; diff --git a/packages/xai/src/version.ts b/packages/xai/src/version.ts new file mode 100644 index 000000000000..7a35d46f5d20 --- /dev/null +++ b/packages/xai/src/version.ts @@ -0,0 +1,6 @@ +// Version string of this package injected at build time. +declare const __PACKAGE_VERSION__: string | undefined; +export const VERSION: string = + typeof __PACKAGE_VERSION__ !== 'undefined' + ? __PACKAGE_VERSION__ + : '0.0.0-test'; diff --git a/packages/xai/src/xai-chat-language-model.test.ts b/packages/xai/src/xai-chat-language-model.test.ts index 2bdd7e2d1895..a4f0386fc289 100644 --- a/packages/xai/src/xai-chat-language-model.test.ts +++ b/packages/xai/src/xai-chat-language-model.test.ts @@ -1,16 +1,19 @@ import { LanguageModelV2Prompt } from '@ai-sdk/provider'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; -import { - convertReadableStreamToArray, - createTestServer, -} from '@ai-sdk/provider-utils/test'; +import { createTestServer } from '@ai-sdk/test-server/with-vitest'; +import { convertReadableStreamToArray } from '@ai-sdk/provider-utils/test'; import { XaiChatLanguageModel } from './xai-chat-language-model'; +import { createXai } from './xai-provider'; const TEST_PROMPT: LanguageModelV2Prompt = [ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }, ]; +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', +})); + const testConfig = { provider: 'xai.chat', baseURL: 'https://api.x.ai/v1', @@ -309,6 +312,7 @@ describe('XaiChatLanguageModel', () => { authorization: 'Bearer test-api-key', 'Custom-Provider-Header': 'provider-header-value', }), + generateId: () => 'test-id', }); @@ -329,6 +333,26 @@ describe('XaiChatLanguageModel', () => { }); }); + it('should include provider user agent when using createXai', async () => { + prepareJsonResponse({ content: '' }); + + const xai = createXai({ + apiKey: 'test-api-key', + headers: { 'Custom-Provider-Header': 'provider-header-value' }, + }); + + const modelWithHeaders = xai.chat('grok-beta'); + + await modelWithHeaders.doGenerate({ + prompt: TEST_PROMPT, + headers: { 'Custom-Request-Header': 'request-header-value' }, + }); + + expect(server.calls[0].requestUserAgent).toContain( + `ai-sdk/xai/0.0.0-test`, + ); + }); + it('should send request body', async () => { prepareJsonResponse({ content: '' }); @@ -409,7 +433,10 @@ describe('XaiChatLanguageModel', () => { }, { type: 'x', - xHandles: ['grok'], + includedXHandles: ['grok'], + excludedXHandles: ['openai'], + postFavoriteCount: 5, + postViewCount: 50, }, { type: 'news', @@ -439,7 +466,10 @@ describe('XaiChatLanguageModel', () => { }, { type: 'x', - x_handles: ['grok'], + included_x_handles: ['grok'], + excluded_x_handles: ['openai'], + post_favorite_count: 5, + post_view_count: 50, }, { type: 'news', @@ -581,7 +611,10 @@ describe('XaiChatLanguageModel', () => { }, { type: 'x', - xHandles: ['openai', 'deepmind'], + includedXHandles: ['openai', 'deepmind'], + excludedXHandles: ['grok'], + postFavoriteCount: 10, + postViewCount: 100, }, ], }, @@ -612,7 +645,10 @@ describe('XaiChatLanguageModel', () => { }, { type: 'x', - x_handles: ['openai', 'deepmind'], + included_x_handles: ['openai', 'deepmind'], + excluded_x_handles: ['grok'], + post_favorite_count: 10, + post_view_count: 100, }, ], }, diff --git a/packages/xai/src/xai-chat-language-model.ts b/packages/xai/src/xai-chat-language-model.ts index c3990c0215f3..efc469f4aae1 100644 --- a/packages/xai/src/xai-chat-language-model.ts +++ b/packages/xai/src/xai-chat-language-model.ts @@ -176,7 +176,10 @@ export class XaiChatLanguageModel implements LanguageModelV2 { safe_search: source.safeSearch, }), ...(source.type === 'x' && { - x_handles: source.xHandles, + excluded_x_handles: source.excludedXHandles, + included_x_handles: source.includedXHandles ?? source.xHandles, + post_favorite_count: source.postFavoriteCount, + post_view_count: source.postViewCount, }), ...(source.type === 'news' && { country: source.country, diff --git a/packages/xai/src/xai-chat-options.ts b/packages/xai/src/xai-chat-options.ts index 4b7035d1602b..1b2f2396334b 100644 --- a/packages/xai/src/xai-chat-options.ts +++ b/packages/xai/src/xai-chat-options.ts @@ -2,6 +2,8 @@ import { z } from 'zod/v4'; // https://console.x.ai and see "View models" export type XaiChatModelId = + | 'grok-4-fast-non-reasoning' + | 'grok-4-fast-reasoning' | 'grok-code-fast-1' | 'grok-4' | 'grok-4-0709' @@ -38,6 +40,13 @@ const webSourceSchema = z.object({ const xSourceSchema = z.object({ type: z.literal('x'), + excludedXHandles: z.array(z.string()).optional(), + includedXHandles: z.array(z.string()).optional(), + postFavoriteCount: z.number().int().optional(), + postViewCount: z.number().int().optional(), + /** + * @deprecated use `includedXHandles` instead + */ xHandles: z.array(z.string()).optional(), }); @@ -62,10 +71,6 @@ const searchSourceSchema = z.discriminatedUnion('type', [ // xai-specific provider options export const xaiProviderOptions = z.object({ - /** - * reasoning effort for reasoning models - * only supported by grok-3-mini and grok-3-mini-fast models - */ reasoningEffort: z.enum(['low', 'high']).optional(), searchParameters: z diff --git a/packages/xai/src/xai-provider.test.ts b/packages/xai/src/xai-provider.test.ts index 6107072afa7f..88d4fe2a3d10 100644 --- a/packages/xai/src/xai-provider.test.ts +++ b/packages/xai/src/xai-provider.test.ts @@ -23,11 +23,19 @@ vi.mock('./xai-image-model', () => ({ XaiImageModel: vi.fn(), })); -vi.mock('@ai-sdk/provider-utils', () => ({ - loadApiKey: vi.fn().mockReturnValue('mock-api-key'), - withoutTrailingSlash: vi.fn(url => url), - createJsonErrorResponseHandler: vi.fn().mockReturnValue(() => {}), - generateId: vi.fn().mockReturnValue('mock-id'), +vi.mock('@ai-sdk/provider-utils', async () => { + const actual = await vi.importActual('@ai-sdk/provider-utils'); + return { + ...actual, + loadApiKey: vi.fn().mockReturnValue('mock-api-key'), + withoutTrailingSlash: vi.fn(url => url), + createJsonErrorResponseHandler: vi.fn().mockReturnValue(() => {}), + generateId: vi.fn().mockReturnValue('mock-id'), + }; +}); + +vi.mock('./version', () => ({ + VERSION: '0.0.0-test', })); describe('xAIProvider', () => { @@ -150,8 +158,9 @@ describe('xAIProvider', () => { const headers = config.headers(); expect(headers).toMatchObject({ - Authorization: 'Bearer mock-api-key', - 'Custom-Header': 'test-value', + authorization: 'Bearer mock-api-key', + 'custom-header': 'test-value', + 'user-agent': 'ai-sdk/xai/0.0.0-test', }); }); }); diff --git a/packages/xai/src/xai-provider.ts b/packages/xai/src/xai-provider.ts index c2dc843c5774..f3cecf6769c5 100644 --- a/packages/xai/src/xai-provider.ts +++ b/packages/xai/src/xai-provider.ts @@ -3,28 +3,30 @@ import { ProviderErrorStructure, } from '@ai-sdk/openai-compatible'; import { - ImageModelV2, + ImageModelV3, LanguageModelV2, NoSuchModelError, - ProviderV2, + ProviderV3, } from '@ai-sdk/provider'; import { FetchFunction, generateId, loadApiKey, withoutTrailingSlash, + withUserAgentSuffix, } from '@ai-sdk/provider-utils'; import { XaiChatLanguageModel } from './xai-chat-language-model'; import { XaiChatModelId } from './xai-chat-options'; import { XaiErrorData, xaiErrorDataSchema } from './xai-error'; import { XaiImageModelId } from './xai-image-settings'; +import { VERSION } from './version'; const xaiErrorStructure: ProviderErrorStructure = { errorSchema: xaiErrorDataSchema, errorToMessage: data => data.error.message, }; -export interface XaiProvider extends ProviderV2 { +export interface XaiProvider extends ProviderV3 { /** Creates an Xai chat model for text generation. */ @@ -43,12 +45,12 @@ Creates an Xai chat model for text generation. /** Creates an Xai image model for image generation. */ - image(modelId: XaiImageModelId): ImageModelV2; + image(modelId: XaiImageModelId): ImageModelV3; /** Creates an Xai image model for image generation. */ - imageModel(modelId: XaiImageModelId): ImageModelV2; + imageModel(modelId: XaiImageModelId): ImageModelV3; } export interface XaiProviderSettings { @@ -78,14 +80,18 @@ export function createXai(options: XaiProviderSettings = {}): XaiProvider { const baseURL = withoutTrailingSlash( options.baseURL ?? 'https://api.x.ai/v1', ); - const getHeaders = () => ({ - Authorization: `Bearer ${loadApiKey({ - apiKey: options.apiKey, - environmentVariableName: 'XAI_API_KEY', - description: 'xAI API key', - })}`, - ...options.headers, - }); + const getHeaders = () => + withUserAgentSuffix( + { + Authorization: `Bearer ${loadApiKey({ + apiKey: options.apiKey, + environmentVariableName: 'XAI_API_KEY', + description: 'xAI API key', + })}`, + ...options.headers, + }, + `ai-sdk/xai/${VERSION}`, + ); const createLanguageModel = (modelId: XaiChatModelId) => { return new XaiChatLanguageModel(modelId, { diff --git a/packages/xai/tsup.config.ts b/packages/xai/tsup.config.ts index 3f92041b987c..411ecbaf4300 100644 --- a/packages/xai/tsup.config.ts +++ b/packages/xai/tsup.config.ts @@ -6,5 +6,11 @@ export default defineConfig([ format: ['cjs', 'esm'], dts: true, sourcemap: true, + define: { + __PACKAGE_VERSION__: JSON.stringify( + (await import('./package.json', { with: { type: 'json' } })).default + .version, + ), + }, }, ]); diff --git a/packages/xai/vitest.edge.config.js b/packages/xai/vitest.edge.config.js index 3dc49ba29774..3ece1aa35903 100644 --- a/packages/xai/vitest.edge.config.js +++ b/packages/xai/vitest.edge.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'edge-runtime', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/packages/xai/vitest.node.config.js b/packages/xai/vitest.node.config.js index b7e4a9cabd48..bf1b0442d8b8 100644 --- a/packages/xai/vitest.node.config.js +++ b/packages/xai/vitest.node.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import packageJson from './package.json'; // https://vitejs.dev/config/ export default defineConfig({ @@ -6,4 +7,7 @@ export default defineConfig({ environment: 'node', include: ['**/*.test.ts', '**/*.test.tsx'], }, + define: { + __PACKAGE_VERSION__: JSON.stringify(packageJson.version), + }, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f7788608fb65..827e7d91231e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 2.27.10 '@playwright/test': specifier: ^1.44.1 - version: 1.46.0 + version: 1.50.1 eslint: specifier: 8.57.1 version: 8.57.1 @@ -28,10 +28,10 @@ importers: version: 15.2.10 next: specifier: 15.0.0-canary.23 - version: 15.0.0-canary.23(@opentelemetry/api@1.9.0)(@playwright/test@1.46.0)(react-dom@19.0.0-rc-cc1ec60d0d-20240607(react@19.0.0-rc-cc1ec60d0d-20240607))(react@19.0.0-rc-cc1ec60d0d-20240607)(sass@1.85.0) + version: 15.0.0-canary.23(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.0.0-rc-cc1ec60d0d-20240607(react@19.0.0-rc-cc1ec60d0d-20240607))(react@19.0.0-rc-cc1ec60d0d-20240607)(sass@1.85.0) playwright: specifier: ^1.44.1 - version: 1.46.0 + version: 1.50.1 prettier: specifier: 3.5.3 version: 3.5.3 @@ -74,6 +74,9 @@ importers: '@ai-sdk/azure': specifier: workspace:* version: link:../../packages/azure + '@ai-sdk/baseten': + specifier: workspace:* + version: link:../../packages/baseten '@ai-sdk/cerebras': specifier: workspace:* version: link:../../packages/cerebras @@ -187,7 +190,7 @@ importers: version: 2.0.0 valibot: specifier: ^1.0.0-rc.0 || ^1.0.0 - version: 1.0.0-rc.0(typescript@5.8.3) + version: 1.1.0(typescript@5.8.3) zod: specifier: 3.25.76 version: 3.25.76 @@ -440,7 +443,7 @@ importers: version: 10.4.8 '@nestjs/schematics': specifier: ^10.2.3 - version: 10.2.3(chokidar@3.6.0)(typescript@5.5.4) + version: 10.2.3(chokidar@3.6.0)(typescript@5.8.3) '@nestjs/testing': specifier: ^10.4.12 version: 10.4.12(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.2)(@nestjs/platform-express@10.4.9) @@ -458,10 +461,10 @@ importers: version: 6.0.2 '@typescript-eslint/eslint-plugin': specifier: ^8.0.0 - version: 8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4) + version: 8.26.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) '@typescript-eslint/parser': specifier: ^8.0.0 - version: 8.6.0(eslint@8.57.1)(typescript@5.5.4) + version: 8.26.0(eslint@8.57.1)(typescript@5.8.3) '@vercel/ai-tsconfig': specifier: workspace:* version: link:../../tools/tsconfig @@ -473,13 +476,13 @@ importers: version: 10.0.2(eslint@8.57.1) eslint-plugin-prettier: specifier: ^5.0.0 - version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@10.0.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.3.3) + version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@10.0.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.5.3) jest: specifier: ^29.5.0 - version: 29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)) + version: 29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) prettier: specifier: ^3.0.0 - version: 3.3.3 + version: 3.5.3 source-map-support: specifier: ^0.5.21 version: 0.5.21 @@ -488,25 +491,22 @@ importers: version: 7.0.0 ts-jest: specifier: ^29.1.0 - version: 29.2.5(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)))(typescript@5.5.4) + version: 29.2.5(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)))(typescript@5.8.3) ts-loader: specifier: ^9.4.3 - version: 9.5.1(typescript@5.5.4)(webpack@5.96.1) + version: 9.5.1(typescript@5.8.3)(webpack@5.96.1) ts-node: specifier: ^10.9.1 - version: 10.9.2(@types/node@20.17.24)(typescript@5.5.4) + version: 10.9.2(@types/node@20.17.24)(typescript@5.8.3) tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 typescript: specifier: ^5.1.3 - version: 5.5.4 + version: 5.8.3 examples/next: dependencies: - '@ai-sdk/openai': - specifier: workspace:* - version: link:../../packages/openai '@ai-sdk/react': specifier: workspace:* version: link:../../packages/react @@ -518,7 +518,7 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 version: 18.3.1 @@ -582,7 +582,7 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.5.2(@opentelemetry/api@1.9.0)(@playwright/test@1.46.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 version: 18.3.1 @@ -640,16 +640,16 @@ importers: version: link:../../packages/ai geist: specifier: ^1.3.1 - version: 1.3.1(next@15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0)) + version: 1.3.1(next@15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0)) next: specifier: latest - version: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 - version: 18.2.0 + version: 18.3.1 react-dom: specifier: ^18 - version: 18.2.0(react@18.2.0) + version: 18.3.1(react@18.3.1) devDependencies: '@types/node': specifier: 20.17.24 @@ -659,13 +659,13 @@ importers: version: 18.3.3 '@types/react-dom': specifier: ^18 - version: 18.2.4 + version: 18.3.0 '@vercel/ai-tsconfig': specifier: workspace:* version: link:../../tools/tsconfig autoprefixer: specifier: ^10.4.14 - version: 10.4.19(postcss@8.4.49) + version: 10.4.20(postcss@8.5.3) concurrently: specifier: ^9.1.0 version: 9.1.0 @@ -677,10 +677,10 @@ importers: version: 14.2.3(eslint@8.57.1)(typescript@5.8.3) postcss: specifier: ^8.4.49 - version: 8.4.49 + version: 8.5.3 tailwindcss: specifier: ^3.4.15 - version: 3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) typescript: specifier: 5.8.3 version: 5.8.3 @@ -695,10 +695,10 @@ importers: version: link:../../packages/ai geist: specifier: ^1.3.1 - version: 1.3.1(next@15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0)) + version: 1.3.1(next@15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0)) next: specifier: latest - version: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 version: 18.3.1 @@ -723,10 +723,10 @@ importers: version: link:../../tools/eslint-config postcss: specifier: ^8.4.49 - version: 8.4.49 + version: 8.5.3 tailwindcss: specifier: ^3.4.15 - version: 3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) typescript: specifier: 5.8.3 version: 5.8.3 @@ -753,13 +753,13 @@ importers: version: 0.1.36(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.663.0)(@aws-sdk/credential-provider-node@3.662.0(@aws-sdk/client-sso-oidc@3.662.0(@aws-sdk/client-sts@3.662.0))(@aws-sdk/client-sts@3.662.0))(@smithy/util-utf8@2.3.0)(@upstash/redis@1.34.3)(@vercel/kv@0.2.4)(encoding@0.1.13)(fast-xml-parser@4.4.1)(ignore@5.3.2)(ioredis@5.4.1)(jsdom@26.0.0)(lodash@4.17.21)(openai@5.6.0(ws@8.18.0)(zod@3.25.76))(playwright@1.50.1)(redis@4.7.0)(ws@8.18.0) next: specifier: latest - version: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 - version: 18.2.0 + version: 18.3.1 react-dom: specifier: ^18 - version: 18.2.0(react@18.2.0) + version: 18.3.1(react@18.3.1) devDependencies: '@types/node': specifier: 20.17.24 @@ -769,13 +769,13 @@ importers: version: 18.3.3 '@types/react-dom': specifier: ^18 - version: 18.2.4 + version: 18.3.0 '@vercel/ai-tsconfig': specifier: workspace:* version: link:../../tools/tsconfig autoprefixer: specifier: ^10.4.14 - version: 10.4.16(postcss@8.4.49) + version: 10.4.20(postcss@8.5.3) eslint: specifier: 8.57.1 version: 8.57.1 @@ -784,10 +784,10 @@ importers: version: 14.2.3(eslint@8.57.1)(typescript@5.8.3) postcss: specifier: ^8.4.49 - version: 8.4.49 + version: 8.5.3 tailwindcss: specifier: ^3.4.15 - version: 3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) typescript: specifier: 5.8.3 version: 5.8.3 @@ -850,7 +850,7 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 version: 18.3.1 @@ -884,7 +884,7 @@ importers: version: link:../../tools/tsconfig autoprefixer: specifier: ^10.4.14 - version: 10.4.20(postcss@8.4.49) + version: 10.4.20(postcss@8.5.3) eslint: specifier: 8.57.1 version: 8.57.1 @@ -893,10 +893,10 @@ importers: version: 14.2.3(eslint@8.57.1)(typescript@5.8.3) postcss: specifier: ^8.4.49 - version: 8.4.49 + version: 8.5.3 tailwindcss: specifier: ^3.4.15 - version: 3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) typescript: specifier: 5.8.3 version: 5.8.3 @@ -911,13 +911,13 @@ importers: version: link:../../packages/react '@vercel/functions': specifier: latest - version: 2.0.0(@aws-sdk/credential-provider-web-identity@3.662.0(@aws-sdk/client-sts@3.662.0)) + version: 3.1.0(@aws-sdk/credential-provider-web-identity@3.662.0(@aws-sdk/client-sts@3.662.0)) ai: specifier: workspace:* version: link:../../packages/ai next: specifier: latest - version: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 version: 18.3.1 @@ -942,7 +942,7 @@ importers: version: link:../../tools/tsconfig autoprefixer: specifier: ^10.4.14 - version: 10.4.20(postcss@8.4.49) + version: 10.4.20(postcss@8.5.3) eslint: specifier: 8.57.1 version: 8.57.1 @@ -951,10 +951,10 @@ importers: version: 14.2.3(eslint@8.57.1)(typescript@5.8.3) postcss: specifier: ^8.4.49 - version: 8.4.49 + version: 8.5.3 tailwindcss: specifier: ^3.4.15 - version: 3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) typescript: specifier: 5.8.3 version: 5.8.3 @@ -972,13 +972,13 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 - version: 18.2.0 + version: 18.3.1 react-dom: specifier: ^18 - version: 18.2.0(react@18.2.0) + version: 18.3.1(react@18.3.1) zod: specifier: 3.25.76 version: 3.25.76 @@ -991,13 +991,13 @@ importers: version: 18.3.3 '@types/react-dom': specifier: ^18 - version: 18.2.4 + version: 18.3.0 '@vercel/ai-tsconfig': specifier: workspace:* version: link:../../tools/tsconfig autoprefixer: specifier: ^10.4.14 - version: 10.4.16(postcss@8.4.49) + version: 10.4.20(postcss@8.5.3) eslint: specifier: 8.57.1 version: 8.57.1 @@ -1006,10 +1006,10 @@ importers: version: 14.2.3(eslint@8.57.1)(typescript@5.4.5) postcss: specifier: ^8.4.49 - version: 8.4.49 + version: 8.5.3 tailwindcss: specifier: ^3.4.15 - version: 3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.4.5)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.4.5)) typescript: specifier: 5.4.5 version: 5.4.5 @@ -1039,13 +1039,13 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 - version: 18.2.0 + version: 18.3.1 react-dom: specifier: ^18 - version: 18.2.0(react@18.2.0) + version: 18.3.1(react@18.3.1) zod: specifier: 3.25.76 version: 3.25.76 @@ -1058,10 +1058,10 @@ importers: version: 18.3.3 '@types/react-dom': specifier: ^18 - version: 18.2.4 + version: 18.3.0 autoprefixer: specifier: ^10.4.14 - version: 10.4.19(postcss@8.4.49) + version: 10.4.20(postcss@8.5.3) eslint: specifier: 8.57.1 version: 8.57.1 @@ -1070,10 +1070,10 @@ importers: version: 14.2.3(eslint@8.57.1)(typescript@5.6.3) postcss: specifier: ^8.4.49 - version: 8.4.49 + version: 8.5.3 tailwindcss: specifier: ^3.4.15 - version: 3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)) typescript: specifier: 5.6.3 version: 5.6.3 @@ -1097,7 +1097,7 @@ importers: version: 0.55.0(@opentelemetry/api@1.9.0) '@sentry/nextjs': specifier: ^8.42.0 - version: 8.42.0(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0))(react@18.2.0)(webpack@5.98.0) + version: 8.42.0(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0))(react@18.3.1)(webpack@5.98.0) '@sentry/opentelemetry': specifier: 8.22.0 version: 8.22.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.27.0) @@ -1109,13 +1109,13 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 - version: 18.2.0 + version: 18.3.1 react-dom: specifier: ^18 - version: 18.2.0(react@18.2.0) + version: 18.3.1(react@18.3.1) zod: specifier: 3.25.76 version: 3.25.76 @@ -1128,13 +1128,13 @@ importers: version: 18.3.3 '@types/react-dom': specifier: ^18 - version: 18.2.4 + version: 18.3.0 '@vercel/ai-tsconfig': specifier: workspace:* version: link:../../tools/tsconfig autoprefixer: specifier: ^10.4.14 - version: 10.4.19(postcss@8.4.49) + version: 10.4.20(postcss@8.5.3) eslint: specifier: 8.57.1 version: 8.57.1 @@ -1143,10 +1143,10 @@ importers: version: 14.2.3(eslint@8.57.1)(typescript@5.8.3) postcss: specifier: ^8.4.49 - version: 8.4.49 + version: 8.5.3 tailwindcss: specifier: ^3.4.15 - version: 3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) typescript: specifier: 5.8.3 version: 5.8.3 @@ -1170,7 +1170,7 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) + version: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) react: specifier: ^18 version: 18.3.1 @@ -1195,7 +1195,7 @@ importers: version: link:../../tools/tsconfig autoprefixer: specifier: ^10.4.14 - version: 10.4.20(postcss@8.4.49) + version: 10.4.20(postcss@8.5.3) eslint: specifier: 8.57.1 version: 8.57.1 @@ -1204,10 +1204,10 @@ importers: version: 14.2.3(eslint@8.57.1)(typescript@5.8.3) postcss: specifier: ^8.4.49 - version: 8.4.49 + version: 8.5.3 tailwindcss: specifier: ^3.4.15 - version: 3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) typescript: specifier: 5.8.3 version: 5.8.3 @@ -1317,13 +1317,13 @@ importers: version: 9.21.0 '@sveltejs/adapter-vercel': specifier: ^5.5.2 - version: 5.6.3(@sveltejs/kit@2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(encoding@0.1.13)(rollup@4.34.9) + version: 5.6.3(@sveltejs/kit@2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(encoding@0.1.13)(rollup@4.34.9) '@sveltejs/kit': specifier: ^2.16.0 - version: 2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.0 - version: 5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) '@vercel/ai-tsconfig': specifier: workspace:* version: link:../../tools/tsconfig @@ -1347,7 +1347,7 @@ importers: version: 10.0.2(eslint@9.21.0(jiti@2.4.0)) eslint-plugin-svelte: specifier: ^3.0.0 - version: 3.0.3(eslint@9.21.0(jiti@2.4.0))(svelte@5.32.1)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)) + version: 3.0.3(eslint@9.21.0(jiti@2.4.0))(svelte@5.32.1)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)) globals: specifier: ^16.0.0 version: 16.0.0 @@ -1356,28 +1356,28 @@ importers: version: 5.32.1 svelte-check: specifier: ^4.0.0 - version: 4.1.1(picomatch@4.0.2)(svelte@5.32.1)(typescript@5.6.3) + version: 4.1.1(picomatch@4.0.2)(svelte@5.32.1)(typescript@5.8.3) tailwind-merge: specifier: ^3.0.2 version: 3.0.2 tailwind-variants: specifier: ^1.0.0 - version: 1.0.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3))) + version: 1.0.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3))) tailwindcss: specifier: ^3.4.17 - version: 3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)) + version: 3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)) tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3))) + version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3))) typescript: specifier: ^5.0.0 - version: 5.6.3 + version: 5.8.3 typescript-eslint: specifier: ^8.20.0 - version: 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) + version: 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3) vite: specifier: ^6.0.0 - version: 6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + version: 6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: 3.25.76 version: 3.25.76 @@ -1393,6 +1393,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server '@opentelemetry/api': specifier: 1.9.0 version: 1.9.0 @@ -1436,6 +1439,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server '@smithy/eventstream-codec': specifier: ^4.0.1 version: 4.0.1 @@ -1467,6 +1473,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server '@angular/core': specifier: '>=16.0.0' version: 19.2.14(rxjs@7.8.1)(zone.js@0.15.1) @@ -1510,6 +1519,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1519,7 +1531,7 @@ importers: version: link:../../tools/tsconfig tsup: specifier: ^8 - version: 8.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3) + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) typescript: specifier: 5.8.3 version: 5.8.3 @@ -1535,6 +1547,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1563,6 +1578,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1572,7 +1590,38 @@ importers: version: link:../../tools/tsconfig tsup: specifier: ^8 - version: 8.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3) + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) + typescript: + specifier: 5.8.3 + version: 5.8.3 + zod: + specifier: 3.25.76 + version: 3.25.76 + + packages/baseten: + dependencies: + '@ai-sdk/openai-compatible': + specifier: workspace:* + version: link:../openai-compatible + '@ai-sdk/provider': + specifier: workspace:* + version: link:../provider + '@ai-sdk/provider-utils': + specifier: workspace:* + version: link:../provider-utils + '@basetenlabs/performance-client': + specifier: ^0.0.8 + version: 0.0.8 + devDependencies: + '@types/node': + specifier: 20.17.24 + version: 20.17.24 + '@vercel/ai-tsconfig': + specifier: workspace:* + version: link:../../tools/tsconfig + tsup: + specifier: ^8 + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) typescript: specifier: 5.8.3 version: 5.8.3 @@ -1618,7 +1667,7 @@ importers: version: 12.1.0 debug: specifier: ^4.3.7 - version: 4.3.7 + version: 4.4.1(supports-color@9.4.0) jscodeshift: specifier: ^17.1.1 version: 17.1.1(@babel/preset-env@7.26.9(@babel/core@7.25.2)) @@ -1668,6 +1717,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1677,7 +1729,7 @@ importers: version: link:../../tools/tsconfig tsup: specifier: ^8 - version: 8.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3) + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) typescript: specifier: 5.8.3 version: 5.8.3 @@ -1693,6 +1745,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1721,6 +1776,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1774,6 +1832,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1799,6 +1860,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1827,6 +1891,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1853,6 +1920,9 @@ importers: specifier: workspace:* version: link:../provider-utils devDependencies: + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server '@types/node': specifier: 18.15.11 version: 18.15.11 @@ -1877,6 +1947,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1902,6 +1975,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1911,7 +1987,7 @@ importers: version: link:../../tools/tsconfig tsup: specifier: ^8 - version: 8.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3) + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) typescript: specifier: 5.8.3 version: 5.8.3 @@ -1933,6 +2009,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server google-auth-library: specifier: ^9.15.0 version: 9.15.0(encoding@0.1.13) @@ -1945,7 +2024,7 @@ importers: version: link:../../tools/tsconfig tsup: specifier: ^8 - version: 8.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3) + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) typescript: specifier: 5.8.3 version: 5.8.3 @@ -1961,6 +2040,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -1986,6 +2068,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2049,6 +2134,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2074,6 +2162,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2099,6 +2190,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2108,7 +2202,7 @@ importers: version: link:../../tools/tsconfig tsup: specifier: ^8 - version: 8.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3) + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) typescript: specifier: 5.8.3 version: 5.8.3 @@ -2124,6 +2218,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2133,7 +2230,7 @@ importers: version: link:../../tools/tsconfig tsup: specifier: ^8 - version: 8.2.4(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) typescript: specifier: 5.8.3 version: 5.8.3 @@ -2149,6 +2246,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2174,6 +2274,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2208,7 +2311,7 @@ importers: version: link:../../tools/tsconfig tsup: specifier: ^8 - version: 8.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3) + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) typescript: specifier: 5.8.3 version: 5.8.3 @@ -2236,7 +2339,7 @@ importers: version: 2.7.0(@types/node@20.17.24)(typescript@5.8.3) tsup: specifier: ^8 - version: 8.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3) + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) typescript: specifier: 5.8.3 version: 5.8.3 @@ -2249,15 +2352,18 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server ai: specifier: workspace:* version: link:../ai react: specifier: ^18 || ^19 || ^19.0.0-rc - version: 18.3.1 + version: 19.0.0-rc.1 swr: specifier: ^2.2.5 - version: 2.2.5(react@18.3.1) + version: 2.2.5(react@19.0.0-rc.1) throttleit: specifier: 2.1.0 version: 2.1.0 @@ -2267,7 +2373,7 @@ importers: version: 6.6.3 '@testing-library/react': specifier: ^16.0.1 - version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.2.4)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) + version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) '@testing-library/user-event': specifier: ^14.5.2 version: 14.5.2(@testing-library/dom@10.4.0) @@ -2279,7 +2385,7 @@ importers: version: 18.3.3 '@types/react-dom': specifier: ^18 - version: 18.2.4 + version: 18.3.0 '@vercel/ai-tsconfig': specifier: workspace:* version: link:../../tools/tsconfig @@ -2296,8 +2402,8 @@ importers: specifier: 2.6.4 version: 2.6.4(@types/node@20.17.24)(typescript@5.8.3) react-dom: - specifier: ^18 - version: 18.2.0(react@18.3.1) + specifier: ^18 || ^19 || ^19.0.0-rc + version: 19.0.0-rc.1(react@19.0.0-rc.1) tsup: specifier: ^7.2.0 version: 7.2.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3) @@ -2316,6 +2422,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2341,6 +2450,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2435,7 +2547,7 @@ importers: version: link:../../../../ai next: specifier: canary - version: 15.3.0-canary.43(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1)(sass@1.85.0) + version: 15.6.0-canary.13(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1)(sass@1.85.0) react: specifier: rc version: 19.0.0-rc.1 @@ -2448,6 +2560,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server ai: specifier: workspace:* version: link:../ai @@ -2460,16 +2575,16 @@ importers: version: 9.21.0 '@sveltejs/package': specifier: ^2.0.0 - version: 2.3.10(svelte@5.32.1)(typescript@5.6.3) + version: 2.3.10(svelte@5.32.1)(typescript@5.8.3) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 - version: 5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) '@testing-library/jest-dom': specifier: ^6.6.3 version: 6.6.3 '@testing-library/svelte': specifier: ^5.2.4 - version: 5.2.7(svelte@5.32.1)(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.6.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 5.2.7(svelte@5.32.1)(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.8.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) '@types/node': specifier: 20.17.24 version: 20.17.24 @@ -2481,7 +2596,7 @@ importers: version: 9.21.0(jiti@2.4.0) eslint-plugin-svelte: specifier: ^3.0.0 - version: 3.0.3(eslint@9.21.0(jiti@2.4.0))(svelte@5.32.1)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)) + version: 3.0.3(eslint@9.21.0(jiti@2.4.0))(svelte@5.32.1)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) globals: specifier: ^16.0.0 version: 16.0.0 @@ -2496,23 +2611,41 @@ importers: version: 5.32.1 svelte-check: specifier: ^4.0.0 - version: 4.1.1(picomatch@4.0.2)(svelte@5.32.1)(typescript@5.6.3) + version: 4.1.1(picomatch@4.0.2)(svelte@5.32.1)(typescript@5.8.3) typescript: specifier: ^5.0.0 - version: 5.6.3 + version: 5.8.3 typescript-eslint: specifier: ^8.20.0 - version: 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) + version: 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3) vite: specifier: ^6.0.0 - version: 6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + version: 6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) vitest: specifier: ^3.0.0 - version: 3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.6.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + version: 3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.8.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: 3.25.76 version: 3.25.76 + packages/test-server: + devDependencies: + '@types/node': + specifier: 20.17.24 + version: 20.17.24 + '@vercel/ai-tsconfig': + specifier: workspace:* + version: link:../../tools/tsconfig + msw: + specifier: ^2.7.0 + version: 2.7.0(@types/node@20.17.24)(typescript@5.8.3) + tsup: + specifier: ^8 + version: 8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0) + typescript: + specifier: 5.8.3 + version: 5.8.3 + packages/togetherai: dependencies: '@ai-sdk/openai-compatible': @@ -2524,6 +2657,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -2599,15 +2735,21 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server ai: specifier: workspace:* version: link:../ai swrv: specifier: ^1.0.4 - version: 1.0.4(vue@3.3.8(typescript@5.8.3)) + version: 1.0.4(vue@3.5.13(typescript@5.8.3)) vue: specifier: ^3.3.4 - version: 3.3.8(typescript@5.8.3) + version: 3.5.13(typescript@5.8.3) + zod: + specifier: ^3.25.76 || ^4 + version: 3.25.76 devDependencies: '@testing-library/jest-dom': specifier: ^6.6.3 @@ -2617,7 +2759,7 @@ importers: version: 14.5.2(@testing-library/dom@10.4.0) '@testing-library/vue': specifier: ^8.1.0 - version: 8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.3.8(typescript@5.8.3)))(vue@3.3.8(typescript@5.8.3)) + version: 8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.3)))(vue@3.5.13(typescript@5.8.3)) '@types/node': specifier: 20.17.24 version: 20.17.24 @@ -2626,7 +2768,7 @@ importers: version: link:../../tools/tsconfig '@vitejs/plugin-vue': specifier: 5.2.0 - version: 5.2.0(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))(vue@3.3.8(typescript@5.8.3)) + version: 5.2.0(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.3)) eslint: specifier: 8.57.1 version: 8.57.1 @@ -2660,6 +2802,9 @@ importers: '@ai-sdk/provider-utils': specifier: workspace:* version: link:../provider-utils + '@ai-sdk/test-server': + specifier: workspace:* + version: link:../test-server devDependencies: '@types/node': specifier: 20.17.24 @@ -3869,6 +4014,88 @@ packages: resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==} engines: {node: '>=6.9.0'} + '@basetenlabs/performance-client-android-arm-eabi@0.0.8': + resolution: {integrity: sha512-Ej6UO02/QNQdFfjWJ/9jVrr0ThF24Bq4BL4fnljNcvfzbJGtsJFlkIUzT+waj+ORyUuZePQU5bB0+gA0IpUvfg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + + '@basetenlabs/performance-client-android-arm64@0.0.8': + resolution: {integrity: sha512-yKKzSkK2+ktrZoZmObojURAJtY8JNILLC4RsNy07Cdp/fCzh9OTkknFoiOVXTspdILgBbvIkFbiJOkFZf9fiPQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@basetenlabs/performance-client-darwin-arm64@0.0.8': + resolution: {integrity: sha512-6HVXSYtPrBmWP1Icmkn4ccuEUPJqXPUQyBiGzF6dn3RIF2YtRYYqfpIPeBmwDXfBs/AaOOM81MjNDVGlp5gNRw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@basetenlabs/performance-client-darwin-x64@0.0.8': + resolution: {integrity: sha512-A+YBOMR2DdSH6BCV/8xIDwu2KoxQGiVkwwrQygXNCTXuWC+KJNoQ2UoOUsXpWZyI0JB6nm6UuOMSfV3bFOe6EQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@basetenlabs/performance-client-linux-arm-gnueabihf@0.0.8': + resolution: {integrity: sha512-P4QNm7YiYitSvd2gbfbvSabdLQLrKCTU9lam+4JgcHNf19hd9HZLjfDiqmEZ9apAxuOcd+3xYnM2ukNRJwP4qQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@basetenlabs/performance-client-linux-arm-musleabihf@0.0.8': + resolution: {integrity: sha512-PFv2SH/sfN8my9lZs+TVKOAyNGmQNx9NRjmXAAyXbrz3/DEp5y87MSuAKtK9jklUyrlzFJPkKJLbpQnBvCg79g==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@basetenlabs/performance-client-linux-arm64-gnu@0.0.8': + resolution: {integrity: sha512-4srDdNhaTIPBTjfwNhlD2bIF4MEIDxtyGK1umOxFZOBR2Yr9LaOP5ZVrYhkKiSHTdd4MsaL8+hlNL26L54WxXQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@basetenlabs/performance-client-linux-riscv64-gnu@0.0.8': + resolution: {integrity: sha512-MRgQg07l0hN+lzbcKAcJc0D0hZDxhH+WrRDig/U4TlpsWBweHKhk//IFpIn/nzmMrp3hAVZLsM4nbQZ6SWxnKw==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + + '@basetenlabs/performance-client-linux-x64-gnu@0.0.8': + resolution: {integrity: sha512-msLwWKcPkJJdjGocn5YtSm+kAVcSeSH6VjwidmM9FeHi0YcNZuXHWoBf8gkfP4muXDek5Ml4PVWfgvz7zFA2zw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@basetenlabs/performance-client-linux-x64-musl@0.0.8': + resolution: {integrity: sha512-tI9UMpl+35nwSPeCib/b0ao/bV11ZtLYrJeHaI3GERnCYZDOUje1qrLac1gYdikIuJycKtvucfkMRjc6dGNy/w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@basetenlabs/performance-client-win32-arm64-msvc@0.0.8': + resolution: {integrity: sha512-IH76vdeRyouecsLLIHs07XsXs+GWf1GaGVqT3HtkmwF0DRKTeLAWgdhyBjQc1+cC1fE+cO8N9OHjsbD0u8/5yg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@basetenlabs/performance-client-win32-ia32-msvc@0.0.8': + resolution: {integrity: sha512-oIS68FvHqwLfIHmZ5FHxveVpg83nln8VFm9ED9+xvElqhrFcP58yqkg5YLbXyqmCKno0e6QbpIK0LqKGdRaI8g==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@basetenlabs/performance-client-win32-x64-msvc@0.0.8': + resolution: {integrity: sha512-HWkuf+E7Hdj7iPfIs9ibTJC2kMvuNfB9hfloJccCuA2LffpkMcqZ4wOamEwbFSCe6bQ5Dxik3RsBFIUbQsbL9Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@basetenlabs/performance-client@0.0.8': + resolution: {integrity: sha512-D6BbLwJCldgAhxMdNTO/HTZpyvxFtR6lUv9Ht3UPHPg06lrofoKryRWL1oZmeJw1z4yP34Lj4KpKqa+bpUB9HA==} + engines: {node: '>= 10'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -4003,30 +4230,15 @@ packages: '@emnapi/runtime@1.2.0': resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==} - '@emnapi/runtime@1.4.0': - resolution: {integrity: sha512-64WYIf4UYcdLnbKn/umDlNjQDSS8AgZrI/R9+x5ilkUVFxXcA1Ebl+gQLc/6mERA4407Xof0R7wEyEuj091CVw==} - '@emnapi/runtime@1.5.0': resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} - '@esbuild/aix-ppc64@0.19.12': - resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.23.0': - resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.23.1': resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} engines: {node: '>=18'} @@ -4057,24 +4269,12 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.19.12': - resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.23.0': - resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.23.1': resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} engines: {node: '>=18'} @@ -4105,24 +4305,12 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.19.12': - resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.23.0': - resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.23.1': resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} engines: {node: '>=18'} @@ -4153,24 +4341,12 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.19.12': - resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.23.0': - resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.23.1': resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} engines: {node: '>=18'} @@ -4201,24 +4377,12 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.19.12': - resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.23.0': - resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.23.1': resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} engines: {node: '>=18'} @@ -4249,24 +4413,12 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.19.12': - resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.23.0': - resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.23.1': resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} engines: {node: '>=18'} @@ -4297,24 +4449,12 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.19.12': - resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.23.0': - resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.23.1': resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} engines: {node: '>=18'} @@ -4345,24 +4485,12 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.19.12': - resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.23.0': - resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.23.1': resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} engines: {node: '>=18'} @@ -4393,24 +4521,12 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.19.12': - resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.23.0': - resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.23.1': resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} engines: {node: '>=18'} @@ -4441,24 +4557,12 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.19.12': - resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.23.0': - resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.23.1': resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} engines: {node: '>=18'} @@ -4489,24 +4593,12 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.19.12': - resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.23.0': - resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.23.1': resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} engines: {node: '>=18'} @@ -4537,24 +4629,12 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.19.12': - resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.23.0': - resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.23.1': resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} engines: {node: '>=18'} @@ -4585,24 +4665,12 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.19.12': - resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.23.0': - resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.23.1': resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} engines: {node: '>=18'} @@ -4633,24 +4701,12 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.19.12': - resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.23.0': - resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.23.1': resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} engines: {node: '>=18'} @@ -4681,24 +4737,12 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.19.12': - resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.23.0': - resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.23.1': resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} engines: {node: '>=18'} @@ -4729,24 +4773,12 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.19.12': - resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.23.0': - resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.23.1': resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} engines: {node: '>=18'} @@ -4777,24 +4809,12 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.19.12': - resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.23.0': - resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.23.1': resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} engines: {node: '>=18'} @@ -4837,24 +4857,12 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.19.12': - resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.23.0': - resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.23.1': resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} engines: {node: '>=18'} @@ -4879,12 +4887,6 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.23.0': - resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.23.1': resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} engines: {node: '>=18'} @@ -4915,24 +4917,12 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.19.12': - resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.23.0': - resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.23.1': resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} engines: {node: '>=18'} @@ -4963,24 +4953,12 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.19.12': - resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.23.0': - resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.23.1': resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} engines: {node: '>=18'} @@ -5011,24 +4989,12 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.19.12': - resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.23.0': - resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.23.1': resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} engines: {node: '>=18'} @@ -5059,24 +5025,12 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.19.12': - resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.23.0': - resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.23.1': resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} engines: {node: '>=18'} @@ -5107,24 +5061,12 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.19.12': - resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.23.0': - resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.23.1': resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} engines: {node: '>=18'} @@ -5292,20 +5234,24 @@ packages: resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} engines: {node: '>=18.18'} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-arm64@0.34.1': - resolution: {integrity: sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==} + '@img/sharp-darwin-arm64@0.34.3': + resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-arm64@0.34.3': - resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} + '@img/sharp-darwin-arm64@0.34.4': + resolution: {integrity: sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] @@ -5316,14 +5262,14 @@ packages: cpu: [x64] os: [darwin] - '@img/sharp-darwin-x64@0.34.1': - resolution: {integrity: sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==} + '@img/sharp-darwin-x64@0.34.3': + resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-darwin-x64@0.34.3': - resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} + '@img/sharp-darwin-x64@0.34.4': + resolution: {integrity: sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] @@ -5333,13 +5279,13 @@ packages: cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.1.0': - resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==} + '@img/sharp-libvips-darwin-arm64@1.2.0': + resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.0': - resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} + '@img/sharp-libvips-darwin-arm64@1.2.3': + resolution: {integrity: sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==} cpu: [arm64] os: [darwin] @@ -5348,13 +5294,13 @@ packages: cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.1.0': - resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==} + '@img/sharp-libvips-darwin-x64@1.2.0': + resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.0': - resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} + '@img/sharp-libvips-darwin-x64@1.2.3': + resolution: {integrity: sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==} cpu: [x64] os: [darwin] @@ -5363,13 +5309,13 @@ packages: cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm64@1.1.0': - resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==} + '@img/sharp-libvips-linux-arm64@1.2.0': + resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm64@1.2.0': - resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} + '@img/sharp-libvips-linux-arm64@1.2.3': + resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} cpu: [arm64] os: [linux] @@ -5378,19 +5324,14 @@ packages: cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-arm@1.1.0': - resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==} - cpu: [arm] - os: [linux] - '@img/sharp-libvips-linux-arm@1.2.0': resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-ppc64@1.1.0': - resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==} - cpu: [ppc64] + '@img/sharp-libvips-linux-arm@1.2.3': + resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} + cpu: [arm] os: [linux] '@img/sharp-libvips-linux-ppc64@1.2.0': @@ -5398,18 +5339,23 @@ packages: cpu: [ppc64] os: [linux] + '@img/sharp-libvips-linux-ppc64@1.2.3': + resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} + cpu: [ppc64] + os: [linux] + '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-s390x@1.1.0': - resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==} + '@img/sharp-libvips-linux-s390x@1.2.0': + resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-s390x@1.2.0': - resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} + '@img/sharp-libvips-linux-s390x@1.2.3': + resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} cpu: [s390x] os: [linux] @@ -5418,13 +5364,13 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-libvips-linux-x64@1.1.0': - resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==} + '@img/sharp-libvips-linux-x64@1.2.0': + resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linux-x64@1.2.0': - resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} + '@img/sharp-libvips-linux-x64@1.2.3': + resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} cpu: [x64] os: [linux] @@ -5433,13 +5379,13 @@ packages: cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.1.0': - resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.0': + resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': + resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} cpu: [arm64] os: [linux] @@ -5448,13 +5394,13 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.1.0': - resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==} + '@img/sharp-libvips-linuxmusl-x64@1.2.0': + resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} + '@img/sharp-libvips-linuxmusl-x64@1.2.3': + resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} cpu: [x64] os: [linux] @@ -5464,14 +5410,14 @@ packages: cpu: [arm64] os: [linux] - '@img/sharp-linux-arm64@0.34.1': - resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==} + '@img/sharp-linux-arm64@0.34.3': + resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm64@0.34.3': - resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} + '@img/sharp-linux-arm64@0.34.4': + resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] @@ -5482,14 +5428,14 @@ packages: cpu: [arm] os: [linux] - '@img/sharp-linux-arm@0.34.1': - resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==} + '@img/sharp-linux-arm@0.34.3': + resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-arm@0.34.3': - resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} + '@img/sharp-linux-arm@0.34.4': + resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] @@ -5500,20 +5446,26 @@ packages: cpu: [ppc64] os: [linux] + '@img/sharp-linux-ppc64@0.34.4': + resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-s390x@0.34.1': - resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==} + '@img/sharp-linux-s390x@0.34.3': + resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-s390x@0.34.3': - resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} + '@img/sharp-linux-s390x@0.34.4': + resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] @@ -5524,14 +5476,14 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-linux-x64@0.34.1': - resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==} + '@img/sharp-linux-x64@0.34.3': + resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linux-x64@0.34.3': - resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} + '@img/sharp-linux-x64@0.34.4': + resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] @@ -5542,14 +5494,14 @@ packages: cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.1': - resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==} + '@img/sharp-linuxmusl-arm64@0.34.3': + resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.3': - resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} + '@img/sharp-linuxmusl-arm64@0.34.4': + resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] @@ -5560,14 +5512,14 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-x64@0.34.1': - resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==} + '@img/sharp-linuxmusl-x64@0.34.3': + resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-x64@0.34.3': - resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} + '@img/sharp-linuxmusl-x64@0.34.4': + resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] @@ -5577,13 +5529,13 @@ packages: engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-wasm32@0.34.1': - resolution: {integrity: sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==} + '@img/sharp-wasm32@0.34.3': + resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-wasm32@0.34.3': - resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} + '@img/sharp-wasm32@0.34.4': + resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] @@ -5593,20 +5545,26 @@ packages: cpu: [arm64] os: [win32] + '@img/sharp-win32-arm64@0.34.4': + resolution: {integrity: sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + '@img/sharp-win32-ia32@0.33.5': resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-ia32@0.34.1': - resolution: {integrity: sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==} + '@img/sharp-win32-ia32@0.34.3': + resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-ia32@0.34.3': - resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} + '@img/sharp-win32-ia32@0.34.4': + resolution: {integrity: sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] @@ -5617,14 +5575,14 @@ packages: cpu: [x64] os: [win32] - '@img/sharp-win32-x64@0.34.1': - resolution: {integrity: sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==} + '@img/sharp-win32-x64@0.34.3': + resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] - '@img/sharp-win32-x64@0.34.3': - resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} + '@img/sharp-win32-x64@0.34.4': + resolution: {integrity: sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -6846,17 +6804,11 @@ packages: '@next/env@15.0.0-canary.23': resolution: {integrity: sha512-lTWE0vMuSo2Vu4lj2NT5VFdFoRIDrc4cDhAKVT3At1LS10nKWKgjTtjE2uw4X1OXDEbvSNlDSe+asa5d/5O2Dg==} - '@next/env@15.2.4': - resolution: {integrity: sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==} - - '@next/env@15.3.0-canary.43': - resolution: {integrity: sha512-ogryUGufxhtidxr/42NY6+ADlvxt9Hq6Q/DOMS/20vGuePZ70wO6Z5m1RP3Q397RGgpe1gSWyYdlg+Mt7H4KeQ==} + '@next/env@15.5.3': + resolution: {integrity: sha512-RSEDTRqyihYXygx/OJXwvVupfr9m04+0vH8vyy0HfZ7keRto6VX9BbEk0J2PUk0VGy6YhklJUSrgForov5F9pw==} - '@next/env@15.3.3': - resolution: {integrity: sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==} - - '@next/env@15.5.2': - resolution: {integrity: sha512-Qe06ew4zt12LeO6N7j8/nULSOe3fMXE4dM6xgpBQNvdzyK1sv5y4oAP3bq4LamrvGCZtmRYnW8URFCeX5nFgGg==} + '@next/env@15.6.0-canary.13': + resolution: {integrity: sha512-5kaWAZnxRUehxQVnniAd9l9FWHFyWY7T1KGi7qW+GER1EDQTA46TZAWKgPo0oph7Okow/ePjomS2ONXZ+Et0zg==} '@next/eslint-plugin-next@14.2.3': resolution: {integrity: sha512-L3oDricIIjgj1AVnRdRor21gI7mShlSwU/1ZGHmqM3LzHhXXhdkrfeNY5zif25Bi5Dd7fiJHsbhoZCHfXYvlAw==} @@ -6867,26 +6819,14 @@ packages: cpu: [arm64] os: [darwin] - '@next/swc-darwin-arm64@15.2.4': - resolution: {integrity: sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-arm64@15.3.0-canary.43': - resolution: {integrity: sha512-eXrs8CyIBgdnMTNjku+h/xm61gmRCcKAT+tM2CjpEXbEqXBux5hRIakOk5kJJDu2fA2P3pzQGt5PRD1hg4srXA==} + '@next/swc-darwin-arm64@15.5.3': + resolution: {integrity: sha512-nzbHQo69+au9wJkGKTU9lP7PXv0d1J5ljFpvb+LnEomLtSbJkbZyEs6sbF3plQmiOB2l9OBtN2tNSvCH1nQ9Jg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-arm64@15.3.3': - resolution: {integrity: sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-arm64@15.5.2': - resolution: {integrity: sha512-8bGt577BXGSd4iqFygmzIfTYizHb0LGWqH+qgIF/2EDxS5JsSdERJKA8WgwDyNBZgTIIA4D8qUtoQHmxIIquoQ==} + '@next/swc-darwin-arm64@15.6.0-canary.13': + resolution: {integrity: sha512-IXkbwmg+4T+BMPnzNLLFNK0OxbdZhCBbhFTI43AvuL84P5plInGO+zt8OL2j+Mo65/poU5PzplFZZVblvBmCug==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -6897,26 +6837,14 @@ packages: cpu: [x64] os: [darwin] - '@next/swc-darwin-x64@15.2.4': - resolution: {integrity: sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-darwin-x64@15.3.0-canary.43': - resolution: {integrity: sha512-iRGvblEh/b2grxkkp9pT+yea9EzGNM4tLyUZoCzkejkU2jMLsn2DH6h3bQwCfEYZL3YFGsYmVISrVCOVi8LeMw==} + '@next/swc-darwin-x64@15.5.3': + resolution: {integrity: sha512-w83w4SkOOhekJOcA5HBvHyGzgV1W/XvOfpkrxIse4uPWhYTTRwtGEM4v/jiXwNSJvfRvah0H8/uTLBKRXlef8g==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-darwin-x64@15.3.3': - resolution: {integrity: sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-darwin-x64@15.5.2': - resolution: {integrity: sha512-2DjnmR6JHK4X+dgTXt5/sOCu/7yPtqpYt8s8hLkHFK3MGkka2snTv3yRMdHvuRtJVkPwCGsvBSwmoQCHatauFQ==} + '@next/swc-darwin-x64@15.6.0-canary.13': + resolution: {integrity: sha512-mygRYLZIwFI6dGQoTvvIJpHTrbgR8fm/9ZNC86ExY55LzhekwJv+M03dzcR7iQ5jazvPTQtuOlta8nnbKx2CZg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -6927,26 +6855,14 @@ packages: cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-gnu@15.2.4': - resolution: {integrity: sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-gnu@15.3.0-canary.43': - resolution: {integrity: sha512-IqknHGNxpL03uIutIuv7FPjGHuD/AnJVC5exi5g+C7P3f6JVvOjFLS264eqi91tVCXhN2LpcKNGwTlK81bJVVg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-gnu@15.3.3': - resolution: {integrity: sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw==} + '@next/swc-linux-arm64-gnu@15.5.3': + resolution: {integrity: sha512-+m7pfIs0/yvgVu26ieaKrifV8C8yiLe7jVp9SpcIzg7XmyyNE7toC1fy5IOQozmr6kWl/JONC51osih2RyoXRw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-gnu@15.5.2': - resolution: {integrity: sha512-3j7SWDBS2Wov/L9q0mFJtEvQ5miIqfO4l7d2m9Mo06ddsgUK8gWfHGgbjdFlCp2Ek7MmMQZSxpGFqcC8zGh2AA==} + '@next/swc-linux-arm64-gnu@15.6.0-canary.13': + resolution: {integrity: sha512-Sna39YXcObj1Zw15zg5HHBUdXhl6WQAVQfsmoIETCZ4FQSuSRw0UpDtiW6+bQGYAP5ScJWX2i14k6htrWBNL4A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -6957,26 +6873,14 @@ packages: cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.2.4': - resolution: {integrity: sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@15.3.0-canary.43': - resolution: {integrity: sha512-FbO0dnFsNe3f1LWTn4vyXTWTSrZdwNRnURYExSQ+0AINHphNfwKQNrPqVLrapQ9CAOCOz8R5p9Kf1++IsH3JJQ==} + '@next/swc-linux-arm64-musl@15.5.3': + resolution: {integrity: sha512-u3PEIzuguSenoZviZJahNLgCexGFhso5mxWCrrIMdvpZn6lkME5vc/ADZG8UUk5K1uWRy4hqSFECrON6UKQBbQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.3.3': - resolution: {integrity: sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@15.5.2': - resolution: {integrity: sha512-s6N8k8dF9YGc5T01UPQ08yxsK6fUow5gG1/axWc1HVVBYQBgOjca4oUZF7s4p+kwhkB1bDSGR8QznWrFZ/Rt5g==} + '@next/swc-linux-arm64-musl@15.6.0-canary.13': + resolution: {integrity: sha512-bqybRwJRLRagldV9l70URpRUFePsfnpBqlV3/JVlr0xkzcxYFvRejcuNS4tAA0iQ6HdpMwJBCRXLpie/q30O4A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -6987,26 +6891,14 @@ packages: cpu: [x64] os: [linux] - '@next/swc-linux-x64-gnu@15.2.4': - resolution: {integrity: sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-gnu@15.3.0-canary.43': - resolution: {integrity: sha512-MAaLEm8eO6Xir3YC3xLYDHDjLGogAAGRrxhuflvaqAtGQZ6NIMG4YjvAyramYTq/SwrUIDobggKxdQLtu8/pPQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-gnu@15.3.3': - resolution: {integrity: sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw==} + '@next/swc-linux-x64-gnu@15.5.3': + resolution: {integrity: sha512-lDtOOScYDZxI2BENN9m0pfVPJDSuUkAD1YXSvlJF0DKwZt0WlA7T7o3wrcEr4Q+iHYGzEaVuZcsIbCps4K27sA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-gnu@15.5.2': - resolution: {integrity: sha512-o1RV/KOODQh6dM6ZRJGZbc+MOAHww33Vbs5JC9Mp1gDk8cpEO+cYC/l7rweiEalkSm5/1WGa4zY7xrNwObN4+Q==} + '@next/swc-linux-x64-gnu@15.6.0-canary.13': + resolution: {integrity: sha512-FqE67dfImb3vKeROuIzh2eVzCwj7/95SYizfO/7oaU9UTKfblAj1whj2ESibz2Sx0bjQoK+OboflWnQwsmgkrQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -7017,26 +6909,14 @@ packages: cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.2.4': - resolution: {integrity: sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@15.3.0-canary.43': - resolution: {integrity: sha512-gdwF79/EQjY3zgcolO0jlDe0yfII9tXyXQeqL+uvzA8gZT5FpH0KkwSWzxj8EUswWzZcprbDa87sq8H0Eo+whw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@15.3.3': - resolution: {integrity: sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw==} + '@next/swc-linux-x64-musl@15.5.3': + resolution: {integrity: sha512-9vWVUnsx9PrY2NwdVRJ4dUURAQ8Su0sLRPqcCCxtX5zIQUBES12eRVHq6b70bbfaVaxIDGJN2afHui0eDm+cLg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.5.2': - resolution: {integrity: sha512-/VUnh7w8RElYZ0IV83nUcP/J4KJ6LLYliiBIri3p3aW2giF+PAVgZb6mk8jbQSB3WlTai8gEmCAr7kptFa1H6g==} + '@next/swc-linux-x64-musl@15.6.0-canary.13': + resolution: {integrity: sha512-Kacn33TqI8ljBOjERVU2hJcNohA3RKr2bZ621ca1STclUWQiwb9wMFfJdSUAzS8IOE1oP2WCYoNaN2SrxtHEJw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -7047,26 +6927,14 @@ packages: cpu: [arm64] os: [win32] - '@next/swc-win32-arm64-msvc@15.2.4': - resolution: {integrity: sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-arm64-msvc@15.3.0-canary.43': - resolution: {integrity: sha512-5WYne3jvo1478kUfe901wFxvPMdC8tRKundKIgU5Upe1HafMMS7ymm1hQ7CUpp3/1vY/R1TV1oKHHJfqDubiNg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-arm64-msvc@15.3.3': - resolution: {integrity: sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ==} + '@next/swc-win32-arm64-msvc@15.5.3': + resolution: {integrity: sha512-1CU20FZzY9LFQigRi6jM45oJMU3KziA5/sSG+dXeVaTm661snQP6xu3ykGxxwU5sLG3sh14teO/IOEPVsQMRfA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-arm64-msvc@15.5.2': - resolution: {integrity: sha512-sMPyTvRcNKXseNQ/7qRfVRLa0VhR0esmQ29DD6pqvG71+JdVnESJaHPA8t7bc67KD5spP3+DOCNLhqlEI2ZgQg==} + '@next/swc-win32-arm64-msvc@15.6.0-canary.13': + resolution: {integrity: sha512-2vvLWTlk9nKDkvMf8UkBdMbsheyzwQJRBXSngCzZY+85kU6JOQydvUz0D94oDwSyjh/kstUohODjJcCD1fon6g==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -7083,26 +6951,14 @@ packages: cpu: [x64] os: [win32] - '@next/swc-win32-x64-msvc@15.2.4': - resolution: {integrity: sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@next/swc-win32-x64-msvc@15.3.0-canary.43': - resolution: {integrity: sha512-xE3WZhwjb91eezecVsmXn/OtdISfMsIfS3t0ZXsS/+bMvO/LZLdcVBtl0Zy5yR+XJyKfXXmwpdYbL6WH4dGuQg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@next/swc-win32-x64-msvc@15.3.3': - resolution: {integrity: sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw==} + '@next/swc-win32-x64-msvc@15.5.3': + resolution: {integrity: sha512-JMoLAq3n3y5tKXPQwCK5c+6tmwkuFDa2XAxz8Wm4+IVthdBZdZGh+lmiLUHg9f9IDwIQpUjp+ysd6OkYTyZRZw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@next/swc-win32-x64-msvc@15.5.2': - resolution: {integrity: sha512-W5VvyZHnxG/2ukhZF/9Ikdra5fdNftxI6ybeVKYvBPDtyx7x4jPPSNduUkfH5fo3zG0JQ0bPxgy41af2JX5D4Q==} + '@next/swc-win32-x64-msvc@15.6.0-canary.13': + resolution: {integrity: sha512-pYgqoL50ibamU4ql3M5hqp/PhvSCw6LSu5wBc+aOWs4oPIaS6O30GvXZ4TwF/ERGUU6vYlXrhThYAIWPwP9Uig==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -8101,11 +7957,6 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@playwright/test@1.46.0': - resolution: {integrity: sha512-/QYft5VArOrGRP5pgkrfKksqsKA6CEFyGQ/gjNe6q0y4tZ1aaPfq4gIjudr1s3D+pXyrPRdsy4opKDrjBabE5w==} - engines: {node: '>=18'} - hasBin: true - '@playwright/test@1.50.1': resolution: {integrity: sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==} engines: {node: '>=18'} @@ -8275,16 +8126,6 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.14.1': - resolution: {integrity: sha512-fH8/o8nSUek8ceQnT7K4EQbSiV7jgkHq81m9lWZFIXjJ7lJzpWXbQFpT/Zh6OZYnpFykvzC3fbEvEAFZu03dPA==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm-eabi@4.20.0': - resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==} - cpu: [arm] - os: [android] - '@rollup/rollup-android-arm-eabi@4.34.8': resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==} cpu: [arm] @@ -8295,16 +8136,6 @@ packages: cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.14.1': - resolution: {integrity: sha512-Y/9OHLjzkunF+KGEoJr3heiD5X9OLa8sbT1lm0NYeKyaM3oMhhQFvPB0bNZYJwlq93j8Z6wSxh9+cyKQaxS7PQ==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-android-arm64@4.20.0': - resolution: {integrity: sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==} - cpu: [arm64] - os: [android] - '@rollup/rollup-android-arm64@4.34.8': resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==} cpu: [arm64] @@ -8315,16 +8146,6 @@ packages: cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.14.1': - resolution: {integrity: sha512-+kecg3FY84WadgcuSVm6llrABOdQAEbNdnpi5X3UwWiFVhZIZvKgGrF7kmLguvxHNQy+UuRV66cLVl3S+Rkt+Q==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-arm64@4.20.0': - resolution: {integrity: sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==} - cpu: [arm64] - os: [darwin] - '@rollup/rollup-darwin-arm64@4.34.8': resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==} cpu: [arm64] @@ -8335,16 +8156,6 @@ packages: cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.14.1': - resolution: {integrity: sha512-2pYRzEjVqq2TB/UNv47BV/8vQiXkFGVmPFwJb+1E0IFFZbIX8/jo1olxqqMbo6xCXf8kabANhp5bzCij2tFLUA==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.20.0': - resolution: {integrity: sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==} - cpu: [x64] - os: [darwin] - '@rollup/rollup-darwin-x64@4.34.8': resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==} cpu: [x64] @@ -8375,16 +8186,6 @@ packages: cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.14.1': - resolution: {integrity: sha512-mS6wQ6Do6/wmrF9aTFVpIJ3/IDXhg1EZcQFYHZLHqw6AzMBjTHWnCG35HxSqUNphh0EHqSM6wRTT8HsL1C0x5g==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-gnueabihf@4.20.0': - resolution: {integrity: sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm-gnueabihf@4.34.8': resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==} cpu: [arm] @@ -8395,11 +8196,6 @@ packages: cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.20.0': - resolution: {integrity: sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.34.8': resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==} cpu: [arm] @@ -8410,16 +8206,6 @@ packages: cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.14.1': - resolution: {integrity: sha512-p9rGKYkHdFMzhckOTFubfxgyIO1vw//7IIjBBRVzyZebWlzRLeNhqxuSaZ7kCEKVkm/kuC9fVRW9HkC/zNRG2w==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.20.0': - resolution: {integrity: sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.34.8': resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==} cpu: [arm64] @@ -8430,16 +8216,6 @@ packages: cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.14.1': - resolution: {integrity: sha512-nDY6Yz5xS/Y4M2i9JLQd3Rofh5OR8Bn8qe3Mv/qCVpHFlwtZSBYSPaU4mrGazWkXrdQ98GB//H0BirGR/SKFSw==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.20.0': - resolution: {integrity: sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-arm64-musl@4.34.8': resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==} cpu: [arm64] @@ -8460,16 +8236,6 @@ packages: cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.14.1': - resolution: {integrity: sha512-im7HE4VBL+aDswvcmfx88Mp1soqL9OBsdDBU8NqDEYtkri0qV0THhQsvZtZeNNlLeCUQ16PZyv7cqutjDF35qw==} - cpu: [ppc64le] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': - resolution: {integrity: sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==} - cpu: [ppc64] - os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==} cpu: [ppc64] @@ -8480,16 +8246,6 @@ packages: cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.14.1': - resolution: {integrity: sha512-RWdiHuAxWmzPJgaHJdpvUUlDz8sdQz4P2uv367T2JocdDa98iRw2UjIJ4QxSyt077mXZT2X6pKfT2iYtVEvOFw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.20.0': - resolution: {integrity: sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==} - cpu: [riscv64] - os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.34.8': resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==} cpu: [riscv64] @@ -8500,16 +8256,6 @@ packages: cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.14.1': - resolution: {integrity: sha512-VMgaGQ5zRX6ZqV/fas65/sUGc9cPmsntq2FiGmayW9KMNfWVG/j0BAqImvU4KTeOOgYSf1F+k6at1UfNONuNjA==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.20.0': - resolution: {integrity: sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==} - cpu: [s390x] - os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.34.8': resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==} cpu: [s390x] @@ -8520,16 +8266,6 @@ packages: cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.14.1': - resolution: {integrity: sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.20.0': - resolution: {integrity: sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-gnu@4.34.8': resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==} cpu: [x64] @@ -8540,16 +8276,6 @@ packages: cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.14.1': - resolution: {integrity: sha512-JNEG/Ti55413SsreTguSx0LOVKX902OfXIKVg+TCXO6Gjans/k9O6ww9q3oLGjNDaTLxM+IHFMeXy/0RXL5R/g==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.20.0': - resolution: {integrity: sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-musl@4.34.8': resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==} cpu: [x64] @@ -8560,16 +8286,6 @@ packages: cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.14.1': - resolution: {integrity: sha512-ryS22I9y0mumlLNwDFYZRDFLwWh3aKaC72CWjFcFvxK0U6v/mOkM5Up1bTbCRAhv3kEIwW2ajROegCIQViUCeA==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-arm64-msvc@4.20.0': - resolution: {integrity: sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==} - cpu: [arm64] - os: [win32] - '@rollup/rollup-win32-arm64-msvc@4.34.8': resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==} cpu: [arm64] @@ -8580,16 +8296,6 @@ packages: cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.14.1': - resolution: {integrity: sha512-TdloItiGk+T0mTxKx7Hp279xy30LspMso+GzQvV2maYePMAWdmrzqSNZhUpPj3CGw12aGj57I026PgLCTu8CGg==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.20.0': - resolution: {integrity: sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==} - cpu: [ia32] - os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.34.8': resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==} cpu: [ia32] @@ -8600,16 +8306,6 @@ packages: cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.14.1': - resolution: {integrity: sha512-wQGI+LY/Py20zdUPq+XCem7JcPOyzIJBm3dli+56DJsQOHbnXZFEwgmnC6el1TPAfC8lBT3m+z69RmLykNUbew==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.20.0': - resolution: {integrity: sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==} - cpu: [x64] - os: [win32] - '@rollup/rollup-win32-x64-msvc@4.34.8': resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==} cpu: [x64] @@ -9058,9 +8754,6 @@ packages: svelte: ^5.0.0 vite: ^6.0.0 - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/helpers@0.5.11': resolution: {integrity: sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==} @@ -9210,9 +8903,6 @@ packages: '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} @@ -9287,6 +8977,9 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/mysql@2.15.26': resolution: {integrity: sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==} @@ -9329,9 +9022,6 @@ packages: '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react-dom@18.2.4': - resolution: {integrity: sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==} - '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} @@ -9412,17 +9102,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/eslint-plugin@8.6.0': - resolution: {integrity: sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@typescript-eslint/parser@7.2.0': resolution: {integrity: sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==} engines: {node: ^16.0.0 || >=18.0.0} @@ -9440,16 +9119,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/parser@8.6.0': - resolution: {integrity: sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@typescript-eslint/scope-manager@7.2.0': resolution: {integrity: sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==} engines: {node: ^16.0.0 || >=18.0.0} @@ -9458,10 +9127,6 @@ packages: resolution: {integrity: sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.6.0': - resolution: {integrity: sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.26.0': resolution: {integrity: sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -9469,15 +9134,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.6.0': - resolution: {integrity: sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@typescript-eslint/types@7.2.0': resolution: {integrity: sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==} engines: {node: ^16.0.0 || >=18.0.0} @@ -9486,10 +9142,6 @@ packages: resolution: {integrity: sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.6.0': - resolution: {integrity: sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@7.2.0': resolution: {integrity: sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==} engines: {node: ^16.0.0 || >=18.0.0} @@ -9505,15 +9157,6 @@ packages: peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/typescript-estree@8.6.0': - resolution: {integrity: sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@typescript-eslint/utils@8.26.0': resolution: {integrity: sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -9521,12 +9164,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.6.0': - resolution: {integrity: sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - '@typescript-eslint/visitor-keys@7.2.0': resolution: {integrity: sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==} engines: {node: ^16.0.0 || >=18.0.0} @@ -9535,10 +9172,6 @@ packages: resolution: {integrity: sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.6.0': - resolution: {integrity: sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -9581,9 +9214,9 @@ packages: resolution: {integrity: sha512-5aF+bDYGFx5WgxGE+CeOWWI8GYD1I/JxAWl+R//+MgNjkTPpCKkUVjdchFOr622rEu2wuHAOtpLr5HYg7/uRAA==} engines: {node: '>=16.14'} - '@vercel/functions@2.0.0': - resolution: {integrity: sha512-BSwIihLHoV18gerKZJyGuqd3rtaYM6rJvET1kOwKktshucyaHXTJel7Cxegs+sdX0NZqsX4LO2MFnMU2jG01Cw==} - engines: {node: '>= 18'} + '@vercel/functions@3.1.0': + resolution: {integrity: sha512-V+p8dO+sg1VjiJJUO5rYPp1KG17SzDcR74OWwW7Euyde6L8U5wuTMe9QfEOfLTiWPUPzN1MXZvLcYxqSYhKc4Q==} + engines: {node: '>= 20'} peerDependencies: '@aws-sdk/credential-provider-web-identity': '*' peerDependenciesMeta: @@ -9604,6 +9237,10 @@ packages: engines: {node: '>=18'} hasBin: true + '@vercel/oidc@3.0.0': + resolution: {integrity: sha512-XOoUcf/1VfGArUAfq0ELxk6TD7l4jGcrOsWjQibj4wYM74uNihzZ9gA46ywWegoqKWWdph4y5CKxGI9823deoA==} + engines: {node: '>= 20'} + '@vercel/otel@1.10.0': resolution: {integrity: sha512-bv1FXbFZlFbB89vyA2P9/kr6eZ42bMtXgqBJpgi+8yOrZU8rkg9wMi0TL//AgAf/qKtaryDm1sbCnkLHgCI3PQ==} engines: {node: '>=18'} @@ -9725,27 +9362,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@vue/compiler-core@3.3.8': - resolution: {integrity: sha512-hN/NNBUECw8SusQvDSqqcVv6gWq8L6iAktUR0UF3vGu2OhzRqcOiAno0FmBJWwxhYEXRlQJT5XnoKsVq1WZx4g==} - '@vue/compiler-core@3.5.13': resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} - '@vue/compiler-dom@3.3.8': - resolution: {integrity: sha512-+PPtv+p/nWDd0AvJu3w8HS0RIm/C6VGBIRe24b9hSyNWOAPEUosFZ5diwawwP8ip5sJ8n0Pe87TNNNHnvjs0FQ==} - '@vue/compiler-dom@3.5.13': resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} - '@vue/compiler-sfc@3.3.8': - resolution: {integrity: sha512-WMzbUrlTjfYF8joyT84HfwwXo+8WPALuPxhy+BZ6R4Aafls+jDBnSz8PDz60uFhuqFbl3HxRfxvDzrUf3THwpA==} - '@vue/compiler-sfc@3.5.13': resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} - '@vue/compiler-ssr@3.3.8': - resolution: {integrity: sha512-hXCqQL/15kMVDBuoBYpUnSYT8doDNwsjvm3jTefnXr+ytn294ySnT8NlsFHmTgKNjwpuFy7XVV8yTeLtNl/P6w==} - '@vue/compiler-ssr@3.5.13': resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} @@ -9763,46 +9388,26 @@ packages: '@vue/devtools-shared@7.6.4': resolution: {integrity: sha512-nD6CUvBEel+y7zpyorjiUocy0nh77DThZJ0k1GRnJeOmY3ATq2fWijEp7wk37gb023Cb0R396uYh5qMSBQ5WFg==} - '@vue/reactivity-transform@3.3.8': - resolution: {integrity: sha512-49CvBzmZNtcHua0XJ7GdGifM8GOXoUMOX4dD40Y5DxI3R8OUhMlvf2nvgUAcPxaXiV5MQQ1Nwy09ADpnLQUqRw==} - - '@vue/reactivity@3.3.8': - resolution: {integrity: sha512-ctLWitmFBu6mtddPyOKpHg8+5ahouoTCRtmAHZAXmolDtuZXfjL2T3OJ6DL6ezBPQB1SmMnpzjiWjCiMYmpIuw==} - '@vue/reactivity@3.5.12': resolution: {integrity: sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==} '@vue/reactivity@3.5.13': resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} - '@vue/runtime-core@3.3.8': - resolution: {integrity: sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==} - '@vue/runtime-core@3.5.12': resolution: {integrity: sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==} '@vue/runtime-core@3.5.13': resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} - '@vue/runtime-dom@3.3.8': - resolution: {integrity: sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==} - '@vue/runtime-dom@3.5.13': resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} - '@vue/server-renderer@3.3.8': - resolution: {integrity: sha512-zVCUw7RFskvPuNlPn/8xISbrf0zTWsTSdYTsUTN1ERGGZGVnRxM2QZ3x1OR32+vwkkCm0IW6HmJ49IsPm7ilLg==} - peerDependencies: - vue: 3.3.8 - '@vue/server-renderer@3.5.13': resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} peerDependencies: vue: 3.5.13 - '@vue/shared@3.3.8': - resolution: {integrity: sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==} - '@vue/shared@3.5.12': resolution: {integrity: sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==} @@ -10247,20 +9852,6 @@ packages: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} - autoprefixer@10.4.16: - resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - - autoprefixer@10.4.19: - resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - autoprefixer@10.4.20: resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} engines: {node: ^10 || ^12 || >=14} @@ -10420,24 +10011,10 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.22.1: - resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - browserslist@4.23.1: - resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - browserslist@4.23.3: resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -10484,12 +10061,6 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} - bundle-require@4.0.2: - resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - peerDependencies: - esbuild: '>=0.17' - bundle-require@4.2.1: resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -10565,12 +10136,6 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001591: - resolution: {integrity: sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==} - - caniuse-lite@1.0.30001637: - resolution: {integrity: sha512-1x0qRI1mD1o9e+7mBI7XtzFAP4XszbHaVWsMiGbSPLYekKTJF7K+FNk6AsXH4sUpc+qrsI3pVgf1Jdl/uGkuSQ==} - caniuse-lite@1.0.30001649: resolution: {integrity: sha512-fJegqZZ0ZX8HOWr6rcafGr72+xcgJKI9oWfDW5DrD7ExUtgZC7a7R7ZYmZqplh7XDocFdGeIFn7roAxhOeYrPQ==} @@ -10639,10 +10204,6 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} - chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -11314,6 +10875,10 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + detect-libc@2.1.0: + resolution: {integrity: sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==} + engines: {node: '>=8'} + detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -11433,9 +10998,6 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.4.812: - resolution: {integrity: sha512-7L8fC2Ey/b6SePDFKR2zHAy4mbdp1/38Yk5TsARO66W3hC5KEaeKMMHoxwtuH+jcu2AYLSn9QX04i95t6Fl1Hg==} - electron-to-chromium@1.5.182: resolution: {integrity: sha512-Lv65Btwv9W4J9pyODI6EWpdnhfvrve/us5h1WspW8B2Fb0366REPtY3hX7ounk1CkV/TBjWCEvCBBbYbmV0qCA==} @@ -11575,21 +11137,11 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.19.12: - resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} - engines: {node: '>=12'} - hasBin: true - esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true - esbuild@0.23.0: - resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.23.1: resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} engines: {node: '>=18'} @@ -12322,10 +11874,6 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true - glob@7.1.6: - resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} - deprecated: Glob versions prior to v9 are no longer supported - glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -14228,6 +13776,7 @@ packages: multer@1.4.4-lts.1: resolution: {integrity: sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==} engines: {node: '>= 6.0.0'} + deprecated: Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version. multicast-dns@7.2.5: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} @@ -14251,11 +13800,6 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - nanoid@3.3.8: resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -14313,55 +13857,13 @@ packages: sass: optional: true - next@15.2.4: - resolution: {integrity: sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==} + next@15.5.3: + resolution: {integrity: sha512-r/liNAx16SQj4D+XH/oI1dlpv9tdKJ6cONYPwwcCC46f2NjpaRWY+EKCzULfgQYV6YKXjHBchff2IZBSlZmJNw==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 - babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true - - next@15.3.0-canary.43: - resolution: {integrity: sha512-am6xpZIx2P0VJ26N7K2CImmznYUP65XS0e0nkYtypWf/RiMsScwmCqrA4qrEK9u/tiPlA+583IcQPos9yKLg1Q==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 - babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true - - next@15.3.3: - resolution: {integrity: sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 @@ -14376,9 +13878,9 @@ packages: sass: optional: true - next@15.5.2: - resolution: {integrity: sha512-H8Otr7abj1glFhbGnvUt3gz++0AF1+QoCXEBmd/6aKbfdFwrn0LpA836Ed5+00va/7HQSDD+mOoVhn3tNy3e/Q==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + next@15.6.0-canary.13: + resolution: {integrity: sha512-HU+QKFsIlXu7XOBYVQ3xPZMbO3Dp189vfh9aCy79KZMYhzbxXHR3SitFZjZI9FmLrcr7c6d8aEK+Pg70llg68g==} + engines: {node: '>=20.9.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -14422,6 +13924,7 @@ packages: node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -14458,9 +13961,6 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} @@ -14970,9 +14470,6 @@ packages: resolution: {integrity: sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==} engines: {node: '>= 8'} - picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} @@ -15047,21 +14544,11 @@ packages: pkg-types@1.2.1: resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} - playwright-core@1.46.0: - resolution: {integrity: sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==} - engines: {node: '>=18'} - hasBin: true - playwright-core@1.50.1: resolution: {integrity: sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==} engines: {node: '>=18'} hasBin: true - playwright@1.46.0: - resolution: {integrity: sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==} - engines: {node: '>=18'} - hasBin: true - playwright@1.50.1: resolution: {integrity: sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==} engines: {node: '>=18'} @@ -15153,18 +14640,6 @@ packages: ts-node: optional: true - postcss-load-config@4.0.1: - resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - postcss-load-config@4.0.2: resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} engines: {node: '>= 14'} @@ -15394,10 +14869,6 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.4.49: - resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.2: resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==} engines: {node: ^10 || ^12 || >=14} @@ -15441,11 +14912,6 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} - engines: {node: '>=14'} - hasBin: true - prettier@3.5.3: resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} engines: {node: '>=14'} @@ -15575,11 +15041,6 @@ packages: rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} - react-dom@18.2.0: - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 - react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -15622,10 +15083,6 @@ packages: react-dom: 18.3.0-canary-eb33bd747-20240312 webpack: ^5.59.0 - react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -15872,16 +15329,6 @@ packages: engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true - rollup@4.14.1: - resolution: {integrity: sha512-4LnHSdd3QK2pa1J6dFbfm1HN0D7vSK/ZuZTsdyUAlA6Rr1yTouUTL13HaDOGJVgby461AhrNGBS7sCGXXtT+SA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - rollup@4.20.0: - resolution: {integrity: sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - rollup@4.34.8: resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -15986,9 +15433,6 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} - scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} @@ -16103,14 +15547,14 @@ packages: resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - sharp@0.34.1: - resolution: {integrity: sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - sharp@0.34.3: resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.34.4: + resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -16233,6 +15677,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -16437,11 +15882,6 @@ packages: peerDependencies: postcss: ^8.4.31 - sucrase@3.34.0: - resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==} - engines: {node: '>=8'} - hasBin: true - sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -16450,6 +15890,7 @@ packages: superagent@9.0.2: resolution: {integrity: sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w==} engines: {node: '>=14.18.0'} + deprecated: Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net superjson@2.2.1: resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} @@ -16458,6 +15899,7 @@ packages: supertest@7.0.0: resolution: {integrity: sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==} engines: {node: '>=14.18.0'} + deprecated: Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} @@ -16903,44 +16345,6 @@ packages: typescript: optional: true - tsup@8.0.2: - resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@microsoft/api-extractor': - optional: true - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - - tsup@8.2.4: - resolution: {integrity: sha512-akpCPePnBnC/CXgRrcy72ZSntgIEUa1jN0oJbbvpALWKNOz1B7aM+UVDWGRGIO/T/PZugAESWDJUAb5FD48o8Q==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@microsoft/api-extractor': - optional: true - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - tsup@8.3.0: resolution: {integrity: sha512-ALscEeyS03IomcuNdFdc0YWGVIkwH1Ws7nfTbAPuoILvEV2hpGQAY72LIOjglGo4ShWpZfpBqP/jpQVCzqYQag==} engines: {node: '>=18'} @@ -17082,11 +16486,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.5.4: - resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.6.3: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} @@ -17280,12 +16679,6 @@ packages: unwasm@0.3.9: resolution: {integrity: sha512-LDxTx/2DkFURUd+BU1vUsF/moj0JsoTvl+2tcg2AUOiEzVturhGGx17/IMgGvKUYdZwr33EJHtChCJuhu9Ouvg==} - update-browserslist-db@1.0.16: - resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - update-browserslist-db@1.1.0: resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} hasBin: true @@ -17354,14 +16747,6 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} - valibot@1.0.0-rc.0: - resolution: {integrity: sha512-9ZUrOXOejY/WaIn8p0Z469R1qBAwNJeqq8jzOIDsl1qR8gqtObHQmyHLFli0UCkcGiTco5kH6/KPLWsTWE9b2g==} - peerDependencies: - typescript: '>=5' - peerDependenciesMeta: - typescript: - optional: true - valibot@1.1.0: resolution: {integrity: sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw==} peerDependencies: @@ -17661,14 +17046,6 @@ packages: peerDependencies: vue: ^3.2.0 - vue@3.3.8: - resolution: {integrity: sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - vue@3.5.13: resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} peerDependencies: @@ -17953,11 +17330,6 @@ packages: engines: {node: '>= 14'} hasBin: true - yaml@2.4.5: - resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} - engines: {node: '>= 14'} - hasBin: true - yaml@2.5.0: resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==} engines: {node: '>= 14'} @@ -18803,7 +18175,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.26.0 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -18823,7 +18195,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.26.0 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -18843,7 +18215,7 @@ snapshots: '@babel/traverse': 7.28.0 '@babel/types': 7.28.0 convert-source-map: 2.0.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -18863,7 +18235,7 @@ snapshots: '@babel/traverse': 7.28.0 '@babel/types': 7.28.0 convert-source-map: 2.0.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -19012,7 +18384,7 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.22.10 transitivePeerDependencies: @@ -19024,7 +18396,7 @@ snapshots: '@babel/core': 7.26.10 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.22.10 transitivePeerDependencies: @@ -20521,7 +19893,7 @@ snapshots: '@babel/parser': 7.26.2 '@babel/template': 7.25.9 '@babel/types': 7.26.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -20534,7 +19906,7 @@ snapshots: '@babel/parser': 7.28.0 '@babel/template': 7.27.2 '@babel/types': 7.28.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -20548,6 +19920,61 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@basetenlabs/performance-client-android-arm-eabi@0.0.8': + optional: true + + '@basetenlabs/performance-client-android-arm64@0.0.8': + optional: true + + '@basetenlabs/performance-client-darwin-arm64@0.0.8': + optional: true + + '@basetenlabs/performance-client-darwin-x64@0.0.8': + optional: true + + '@basetenlabs/performance-client-linux-arm-gnueabihf@0.0.8': + optional: true + + '@basetenlabs/performance-client-linux-arm-musleabihf@0.0.8': + optional: true + + '@basetenlabs/performance-client-linux-arm64-gnu@0.0.8': + optional: true + + '@basetenlabs/performance-client-linux-riscv64-gnu@0.0.8': + optional: true + + '@basetenlabs/performance-client-linux-x64-gnu@0.0.8': + optional: true + + '@basetenlabs/performance-client-linux-x64-musl@0.0.8': + optional: true + + '@basetenlabs/performance-client-win32-arm64-msvc@0.0.8': + optional: true + + '@basetenlabs/performance-client-win32-ia32-msvc@0.0.8': + optional: true + + '@basetenlabs/performance-client-win32-x64-msvc@0.0.8': + optional: true + + '@basetenlabs/performance-client@0.0.8': + optionalDependencies: + '@basetenlabs/performance-client-android-arm-eabi': 0.0.8 + '@basetenlabs/performance-client-android-arm64': 0.0.8 + '@basetenlabs/performance-client-darwin-arm64': 0.0.8 + '@basetenlabs/performance-client-darwin-x64': 0.0.8 + '@basetenlabs/performance-client-linux-arm-gnueabihf': 0.0.8 + '@basetenlabs/performance-client-linux-arm-musleabihf': 0.0.8 + '@basetenlabs/performance-client-linux-arm64-gnu': 0.0.8 + '@basetenlabs/performance-client-linux-riscv64-gnu': 0.0.8 + '@basetenlabs/performance-client-linux-x64-gnu': 0.0.8 + '@basetenlabs/performance-client-linux-x64-musl': 0.0.8 + '@basetenlabs/performance-client-win32-arm64-msvc': 0.0.8 + '@basetenlabs/performance-client-win32-ia32-msvc': 0.0.8 + '@basetenlabs/performance-client-win32-x64-msvc': 0.0.8 + '@bcoe/v8-coverage@0.2.3': {} '@bundled-es-modules/cookie@2.0.1': @@ -20757,25 +20184,14 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.4.0': - dependencies: - tslib: 2.8.1 - optional: true - '@emnapi/runtime@1.5.0': dependencies: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.19.12': - optional: true - '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.23.0': - optional: true - '@esbuild/aix-ppc64@0.23.1': optional: true @@ -20791,15 +20207,9 @@ snapshots: '@esbuild/android-arm64@0.18.20': optional: true - '@esbuild/android-arm64@0.19.12': - optional: true - '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.23.0': - optional: true - '@esbuild/android-arm64@0.23.1': optional: true @@ -20815,15 +20225,9 @@ snapshots: '@esbuild/android-arm@0.18.20': optional: true - '@esbuild/android-arm@0.19.12': - optional: true - '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.23.0': - optional: true - '@esbuild/android-arm@0.23.1': optional: true @@ -20839,15 +20243,9 @@ snapshots: '@esbuild/android-x64@0.18.20': optional: true - '@esbuild/android-x64@0.19.12': - optional: true - '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/android-x64@0.23.0': - optional: true - '@esbuild/android-x64@0.23.1': optional: true @@ -20863,15 +20261,9 @@ snapshots: '@esbuild/darwin-arm64@0.18.20': optional: true - '@esbuild/darwin-arm64@0.19.12': - optional: true - '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.23.0': - optional: true - '@esbuild/darwin-arm64@0.23.1': optional: true @@ -20887,15 +20279,9 @@ snapshots: '@esbuild/darwin-x64@0.18.20': optional: true - '@esbuild/darwin-x64@0.19.12': - optional: true - '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/darwin-x64@0.23.0': - optional: true - '@esbuild/darwin-x64@0.23.1': optional: true @@ -20911,15 +20297,9 @@ snapshots: '@esbuild/freebsd-arm64@0.18.20': optional: true - '@esbuild/freebsd-arm64@0.19.12': - optional: true - '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.23.0': - optional: true - '@esbuild/freebsd-arm64@0.23.1': optional: true @@ -20935,15 +20315,9 @@ snapshots: '@esbuild/freebsd-x64@0.18.20': optional: true - '@esbuild/freebsd-x64@0.19.12': - optional: true - '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.23.0': - optional: true - '@esbuild/freebsd-x64@0.23.1': optional: true @@ -20959,15 +20333,9 @@ snapshots: '@esbuild/linux-arm64@0.18.20': optional: true - '@esbuild/linux-arm64@0.19.12': - optional: true - '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-arm64@0.23.0': - optional: true - '@esbuild/linux-arm64@0.23.1': optional: true @@ -20983,15 +20351,9 @@ snapshots: '@esbuild/linux-arm@0.18.20': optional: true - '@esbuild/linux-arm@0.19.12': - optional: true - '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.23.0': - optional: true - '@esbuild/linux-arm@0.23.1': optional: true @@ -21007,15 +20369,9 @@ snapshots: '@esbuild/linux-ia32@0.18.20': optional: true - '@esbuild/linux-ia32@0.19.12': - optional: true - '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ia32@0.23.0': - optional: true - '@esbuild/linux-ia32@0.23.1': optional: true @@ -21031,15 +20387,9 @@ snapshots: '@esbuild/linux-loong64@0.18.20': optional: true - '@esbuild/linux-loong64@0.19.12': - optional: true - '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-loong64@0.23.0': - optional: true - '@esbuild/linux-loong64@0.23.1': optional: true @@ -21055,15 +20405,9 @@ snapshots: '@esbuild/linux-mips64el@0.18.20': optional: true - '@esbuild/linux-mips64el@0.19.12': - optional: true - '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-mips64el@0.23.0': - optional: true - '@esbuild/linux-mips64el@0.23.1': optional: true @@ -21079,15 +20423,9 @@ snapshots: '@esbuild/linux-ppc64@0.18.20': optional: true - '@esbuild/linux-ppc64@0.19.12': - optional: true - '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.23.0': - optional: true - '@esbuild/linux-ppc64@0.23.1': optional: true @@ -21103,15 +20441,9 @@ snapshots: '@esbuild/linux-riscv64@0.18.20': optional: true - '@esbuild/linux-riscv64@0.19.12': - optional: true - '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.23.0': - optional: true - '@esbuild/linux-riscv64@0.23.1': optional: true @@ -21127,15 +20459,9 @@ snapshots: '@esbuild/linux-s390x@0.18.20': optional: true - '@esbuild/linux-s390x@0.19.12': - optional: true - '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-s390x@0.23.0': - optional: true - '@esbuild/linux-s390x@0.23.1': optional: true @@ -21151,15 +20477,9 @@ snapshots: '@esbuild/linux-x64@0.18.20': optional: true - '@esbuild/linux-x64@0.19.12': - optional: true - '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-x64@0.23.0': - optional: true - '@esbuild/linux-x64@0.23.1': optional: true @@ -21181,15 +20501,9 @@ snapshots: '@esbuild/netbsd-x64@0.18.20': optional: true - '@esbuild/netbsd-x64@0.19.12': - optional: true - '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/netbsd-x64@0.23.0': - optional: true - '@esbuild/netbsd-x64@0.23.1': optional: true @@ -21202,9 +20516,6 @@ snapshots: '@esbuild/netbsd-x64@0.25.4': optional: true - '@esbuild/openbsd-arm64@0.23.0': - optional: true - '@esbuild/openbsd-arm64@0.23.1': optional: true @@ -21220,15 +20531,9 @@ snapshots: '@esbuild/openbsd-x64@0.18.20': optional: true - '@esbuild/openbsd-x64@0.19.12': - optional: true - '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.23.0': - optional: true - '@esbuild/openbsd-x64@0.23.1': optional: true @@ -21244,15 +20549,9 @@ snapshots: '@esbuild/sunos-x64@0.18.20': optional: true - '@esbuild/sunos-x64@0.19.12': - optional: true - '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.23.0': - optional: true - '@esbuild/sunos-x64@0.23.1': optional: true @@ -21268,15 +20567,9 @@ snapshots: '@esbuild/win32-arm64@0.18.20': optional: true - '@esbuild/win32-arm64@0.19.12': - optional: true - '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.23.0': - optional: true - '@esbuild/win32-arm64@0.23.1': optional: true @@ -21292,15 +20585,9 @@ snapshots: '@esbuild/win32-ia32@0.18.20': optional: true - '@esbuild/win32-ia32@0.19.12': - optional: true - '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.23.0': - optional: true - '@esbuild/win32-ia32@0.23.1': optional: true @@ -21316,15 +20603,9 @@ snapshots: '@esbuild/win32-x64@0.18.20': optional: true - '@esbuild/win32-x64@0.19.12': - optional: true - '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.23.0': - optional: true - '@esbuild/win32-x64@0.23.1': optional: true @@ -21358,7 +20639,7 @@ snapshots: '@eslint/config-array@0.19.2': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -21370,7 +20651,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -21384,7 +20665,7 @@ snapshots: '@eslint/eslintrc@3.3.0': dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -21495,7 +20776,7 @@ snapshots: '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -21508,14 +20789,12 @@ snapshots: '@humanwhocodes/retry@0.4.2': {} - '@img/sharp-darwin-arm64@0.33.5': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/colour@1.0.0': optional: true - '@img/sharp-darwin-arm64@0.34.1': + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.1.0 + '@img/sharp-libvips-darwin-arm64': 1.0.4 optional: true '@img/sharp-darwin-arm64@0.34.3': @@ -21523,14 +20802,14 @@ snapshots: '@img/sharp-libvips-darwin-arm64': 1.2.0 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-arm64@0.34.4': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.2.3 optional: true - '@img/sharp-darwin-x64@0.34.1': + '@img/sharp-darwin-x64@0.33.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.1.0 + '@img/sharp-libvips-darwin-x64': 1.0.4 optional: true '@img/sharp-darwin-x64@0.34.3': @@ -21538,97 +20817,102 @@ snapshots: '@img/sharp-libvips-darwin-x64': 1.2.0 optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-darwin-x64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.3 optional: true - '@img/sharp-libvips-darwin-arm64@1.1.0': + '@img/sharp-libvips-darwin-arm64@1.0.4': optional: true '@img/sharp-libvips-darwin-arm64@1.2.0': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-darwin-arm64@1.2.3': optional: true - '@img/sharp-libvips-darwin-x64@1.1.0': + '@img/sharp-libvips-darwin-x64@1.0.4': optional: true '@img/sharp-libvips-darwin-x64@1.2.0': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-darwin-x64@1.2.3': optional: true - '@img/sharp-libvips-linux-arm64@1.1.0': + '@img/sharp-libvips-linux-arm64@1.0.4': optional: true '@img/sharp-libvips-linux-arm64@1.2.0': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-arm64@1.2.3': optional: true - '@img/sharp-libvips-linux-arm@1.1.0': + '@img/sharp-libvips-linux-arm@1.0.5': optional: true '@img/sharp-libvips-linux-arm@1.2.0': optional: true - '@img/sharp-libvips-linux-ppc64@1.1.0': + '@img/sharp-libvips-linux-arm@1.2.3': optional: true '@img/sharp-libvips-linux-ppc64@1.2.0': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linux-ppc64@1.2.3': optional: true - '@img/sharp-libvips-linux-s390x@1.1.0': + '@img/sharp-libvips-linux-s390x@1.0.4': optional: true '@img/sharp-libvips-linux-s390x@1.2.0': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linux-s390x@1.2.3': optional: true - '@img/sharp-libvips-linux-x64@1.1.0': + '@img/sharp-libvips-linux-x64@1.0.4': optional: true '@img/sharp-libvips-linux-x64@1.2.0': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-libvips-linux-x64@1.2.3': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.1.0': + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': optional: true '@img/sharp-libvips-linuxmusl-arm64@1.2.0': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.1.0': + '@img/sharp-libvips-linuxmusl-x64@1.0.4': optional: true '@img/sharp-libvips-linuxmusl-x64@1.2.0': optional: true + '@img/sharp-libvips-linuxmusl-x64@1.2.3': + optional: true + '@img/sharp-linux-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-linux-arm64': 1.0.4 optional: true - '@img/sharp-linux-arm64@0.34.1': + '@img/sharp-linux-arm64@0.34.3': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.1.0 + '@img/sharp-libvips-linux-arm64': 1.2.0 optional: true - '@img/sharp-linux-arm64@0.34.3': + '@img/sharp-linux-arm64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.0 + '@img/sharp-libvips-linux-arm64': 1.2.3 optional: true '@img/sharp-linux-arm@0.33.5': @@ -21636,14 +20920,14 @@ snapshots: '@img/sharp-libvips-linux-arm': 1.0.5 optional: true - '@img/sharp-linux-arm@0.34.1': + '@img/sharp-linux-arm@0.34.3': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.1.0 + '@img/sharp-libvips-linux-arm': 1.2.0 optional: true - '@img/sharp-linux-arm@0.34.3': + '@img/sharp-linux-arm@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.0 + '@img/sharp-libvips-linux-arm': 1.2.3 optional: true '@img/sharp-linux-ppc64@0.34.3': @@ -21651,14 +20935,14 @@ snapshots: '@img/sharp-libvips-linux-ppc64': 1.2.0 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-ppc64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-ppc64': 1.2.3 optional: true - '@img/sharp-linux-s390x@0.34.1': + '@img/sharp-linux-s390x@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.1.0 + '@img/sharp-libvips-linux-s390x': 1.0.4 optional: true '@img/sharp-linux-s390x@0.34.3': @@ -21666,14 +20950,14 @@ snapshots: '@img/sharp-libvips-linux-s390x': 1.2.0 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-s390x@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.2.3 optional: true - '@img/sharp-linux-x64@0.34.1': + '@img/sharp-linux-x64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.1.0 + '@img/sharp-libvips-linux-x64': 1.0.4 optional: true '@img/sharp-linux-x64@0.34.3': @@ -21681,14 +20965,14 @@ snapshots: '@img/sharp-libvips-linux-x64': 1.2.0 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linux-x64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.2.3 optional: true - '@img/sharp-linuxmusl-arm64@0.34.1': + '@img/sharp-linuxmusl-arm64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 optional: true '@img/sharp-linuxmusl-arm64@0.34.3': @@ -21696,14 +20980,14 @@ snapshots: '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 optional: true - '@img/sharp-linuxmusl-x64@0.34.1': + '@img/sharp-linuxmusl-x64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.1.0 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 optional: true '@img/sharp-linuxmusl-x64@0.34.3': @@ -21711,17 +20995,22 @@ snapshots: '@img/sharp-libvips-linuxmusl-x64': 1.2.0 optional: true + '@img/sharp-linuxmusl-x64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + optional: true + '@img/sharp-wasm32@0.33.5': dependencies: '@emnapi/runtime': 1.2.0 optional: true - '@img/sharp-wasm32@0.34.1': + '@img/sharp-wasm32@0.34.3': dependencies: - '@emnapi/runtime': 1.4.0 + '@emnapi/runtime': 1.5.0 optional: true - '@img/sharp-wasm32@0.34.3': + '@img/sharp-wasm32@0.34.4': dependencies: '@emnapi/runtime': 1.5.0 optional: true @@ -21729,24 +21018,27 @@ snapshots: '@img/sharp-win32-arm64@0.34.3': optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-arm64@0.34.4': optional: true - '@img/sharp-win32-ia32@0.34.1': + '@img/sharp-win32-ia32@0.33.5': optional: true '@img/sharp-win32-ia32@0.34.3': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-ia32@0.34.4': optional: true - '@img/sharp-win32-x64@0.34.1': + '@img/sharp-win32-x64@0.33.5': optional: true '@img/sharp-win32-x64@0.34.3': optional: true + '@img/sharp-win32-x64@0.34.4': + optional: true + '@inquirer/checkbox@4.1.9(@types/node@20.17.24)': dependencies: '@inquirer/core': 10.1.14(@types/node@20.17.24) @@ -21965,41 +21257,6 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4))': - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 20.17.24 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))': dependencies: '@jest/console': 29.7.0 @@ -22034,7 +21291,6 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true '@jest/environment@29.7.0': dependencies: @@ -22709,7 +21965,7 @@ snapshots: '@koa/router@12.0.1': dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) http-errors: 2.0.0 koa-compose: 4.1.0 methods: 1.1.2 @@ -22719,7 +21975,7 @@ snapshots: '@kwsites/file-exists@1.1.1': dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -22851,14 +22107,14 @@ snapshots: '@mapbox/node-pre-gyp@1.0.11(encoding@0.1.13)': dependencies: - detect-libc: 2.0.3 + detect-libc: 2.0.4 https-proxy-agent: 5.0.1 make-dir: 3.1.0 node-fetch: 2.7.0(encoding@0.1.13) nopt: 5.0.0 npmlog: 5.0.1 rimraf: 3.0.2 - semver: 7.7.1 + semver: 7.7.2 tar: 6.2.0 transitivePeerDependencies: - encoding @@ -22867,11 +22123,11 @@ snapshots: '@mapbox/node-pre-gyp@2.0.0(encoding@0.1.13)': dependencies: consola: 3.2.3 - detect-libc: 2.0.3 + detect-libc: 2.0.4 https-proxy-agent: 7.0.6(supports-color@9.4.0) node-fetch: 2.7.0(encoding@0.1.13) nopt: 8.1.0 - semver: 7.7.1 + semver: 7.7.2 tar: 7.4.3 transitivePeerDependencies: - encoding @@ -23058,25 +22314,25 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/schematics@10.2.3(chokidar@3.6.0)(typescript@5.5.4)': + '@nestjs/schematics@10.2.3(chokidar@3.6.0)(typescript@5.6.3)': dependencies: '@angular-devkit/core': 17.3.11(chokidar@3.6.0) '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) comment-json: 4.2.5 jsonc-parser: 3.3.1 pluralize: 8.0.0 - typescript: 5.5.4 + typescript: 5.6.3 transitivePeerDependencies: - chokidar - '@nestjs/schematics@10.2.3(chokidar@3.6.0)(typescript@5.6.3)': + '@nestjs/schematics@10.2.3(chokidar@3.6.0)(typescript@5.8.3)': dependencies: '@angular-devkit/core': 17.3.11(chokidar@3.6.0) '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) comment-json: 4.2.5 jsonc-parser: 3.3.1 pluralize: 8.0.0 - typescript: 5.6.3 + typescript: 5.8.3 transitivePeerDependencies: - chokidar @@ -23101,13 +22357,9 @@ snapshots: '@next/env@15.0.0-canary.23': {} - '@next/env@15.2.4': {} - - '@next/env@15.3.0-canary.43': {} - - '@next/env@15.3.3': {} + '@next/env@15.5.3': {} - '@next/env@15.5.2': {} + '@next/env@15.6.0-canary.13': {} '@next/eslint-plugin-next@14.2.3': dependencies: @@ -23116,106 +22368,64 @@ snapshots: '@next/swc-darwin-arm64@15.0.0-canary.23': optional: true - '@next/swc-darwin-arm64@15.2.4': + '@next/swc-darwin-arm64@15.5.3': optional: true - '@next/swc-darwin-arm64@15.3.0-canary.43': - optional: true - - '@next/swc-darwin-arm64@15.3.3': - optional: true - - '@next/swc-darwin-arm64@15.5.2': + '@next/swc-darwin-arm64@15.6.0-canary.13': optional: true '@next/swc-darwin-x64@15.0.0-canary.23': optional: true - '@next/swc-darwin-x64@15.2.4': - optional: true - - '@next/swc-darwin-x64@15.3.0-canary.43': - optional: true - - '@next/swc-darwin-x64@15.3.3': + '@next/swc-darwin-x64@15.5.3': optional: true - '@next/swc-darwin-x64@15.5.2': + '@next/swc-darwin-x64@15.6.0-canary.13': optional: true '@next/swc-linux-arm64-gnu@15.0.0-canary.23': optional: true - '@next/swc-linux-arm64-gnu@15.2.4': + '@next/swc-linux-arm64-gnu@15.5.3': optional: true - '@next/swc-linux-arm64-gnu@15.3.0-canary.43': - optional: true - - '@next/swc-linux-arm64-gnu@15.3.3': - optional: true - - '@next/swc-linux-arm64-gnu@15.5.2': + '@next/swc-linux-arm64-gnu@15.6.0-canary.13': optional: true '@next/swc-linux-arm64-musl@15.0.0-canary.23': optional: true - '@next/swc-linux-arm64-musl@15.2.4': - optional: true - - '@next/swc-linux-arm64-musl@15.3.0-canary.43': - optional: true - - '@next/swc-linux-arm64-musl@15.3.3': + '@next/swc-linux-arm64-musl@15.5.3': optional: true - '@next/swc-linux-arm64-musl@15.5.2': + '@next/swc-linux-arm64-musl@15.6.0-canary.13': optional: true '@next/swc-linux-x64-gnu@15.0.0-canary.23': optional: true - '@next/swc-linux-x64-gnu@15.2.4': + '@next/swc-linux-x64-gnu@15.5.3': optional: true - '@next/swc-linux-x64-gnu@15.3.0-canary.43': - optional: true - - '@next/swc-linux-x64-gnu@15.3.3': - optional: true - - '@next/swc-linux-x64-gnu@15.5.2': + '@next/swc-linux-x64-gnu@15.6.0-canary.13': optional: true '@next/swc-linux-x64-musl@15.0.0-canary.23': optional: true - '@next/swc-linux-x64-musl@15.2.4': - optional: true - - '@next/swc-linux-x64-musl@15.3.0-canary.43': - optional: true - - '@next/swc-linux-x64-musl@15.3.3': + '@next/swc-linux-x64-musl@15.5.3': optional: true - '@next/swc-linux-x64-musl@15.5.2': + '@next/swc-linux-x64-musl@15.6.0-canary.13': optional: true '@next/swc-win32-arm64-msvc@15.0.0-canary.23': optional: true - '@next/swc-win32-arm64-msvc@15.2.4': + '@next/swc-win32-arm64-msvc@15.5.3': optional: true - '@next/swc-win32-arm64-msvc@15.3.0-canary.43': - optional: true - - '@next/swc-win32-arm64-msvc@15.3.3': - optional: true - - '@next/swc-win32-arm64-msvc@15.5.2': + '@next/swc-win32-arm64-msvc@15.6.0-canary.13': optional: true '@next/swc-win32-ia32-msvc@15.0.0-canary.23': @@ -23224,16 +22434,10 @@ snapshots: '@next/swc-win32-x64-msvc@15.0.0-canary.23': optional: true - '@next/swc-win32-x64-msvc@15.2.4': - optional: true - - '@next/swc-win32-x64-msvc@15.3.0-canary.43': - optional: true - - '@next/swc-win32-x64-msvc@15.3.3': + '@next/swc-win32-x64-msvc@15.5.3': optional: true - '@next/swc-win32-x64-msvc@15.5.2': + '@next/swc-win32-x64-msvc@15.6.0-canary.13': optional: true '@ngtools/webpack@19.2.15(@angular/compiler-cli@19.2.14(@angular/compiler@19.2.14)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.98.0(esbuild@0.25.4))': @@ -23266,7 +22470,7 @@ snapshots: '@npmcli/fs@4.0.0': dependencies: - semver: 7.7.1 + semver: 7.7.2 '@npmcli/git@6.0.3': dependencies: @@ -23276,7 +22480,7 @@ snapshots: npm-pick-manifest: 10.0.0 proc-log: 5.0.0 promise-retry: 2.0.1 - semver: 7.7.1 + semver: 7.7.2 which: 5.0.0 '@npmcli/installed-package-contents@3.0.0': @@ -23293,7 +22497,7 @@ snapshots: hosted-git-info: 8.1.0 json-parse-even-better-errors: 4.0.0 proc-log: 5.0.0 - semver: 7.7.1 + semver: 7.7.2 validate-npm-package-license: 3.0.4 '@npmcli/promise-spawn@8.0.2': @@ -24405,7 +23609,7 @@ snapshots: '@types/shimmer': 1.2.0 import-in-the-middle: 1.11.3 require-in-the-middle: 7.3.0 - semver: 7.7.1 + semver: 7.7.2 shimmer: 1.2.1 transitivePeerDependencies: - supports-color @@ -24780,14 +23984,9 @@ snapshots: '@pkgr/core@0.1.1': {} - '@playwright/test@1.46.0': - dependencies: - playwright: 1.46.0 - '@playwright/test@1.50.1': dependencies: playwright: 1.50.1 - optional: true '@polka/url@1.0.0-next.25': {} @@ -24972,48 +24171,24 @@ snapshots: optionalDependencies: rollup: 4.34.9 - '@rollup/rollup-android-arm-eabi@4.14.1': - optional: true - - '@rollup/rollup-android-arm-eabi@4.20.0': - optional: true - '@rollup/rollup-android-arm-eabi@4.34.8': optional: true '@rollup/rollup-android-arm-eabi@4.34.9': optional: true - '@rollup/rollup-android-arm64@4.14.1': - optional: true - - '@rollup/rollup-android-arm64@4.20.0': - optional: true - '@rollup/rollup-android-arm64@4.34.8': optional: true '@rollup/rollup-android-arm64@4.34.9': optional: true - '@rollup/rollup-darwin-arm64@4.14.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.20.0': - optional: true - '@rollup/rollup-darwin-arm64@4.34.8': optional: true '@rollup/rollup-darwin-arm64@4.34.9': optional: true - '@rollup/rollup-darwin-x64@4.14.1': - optional: true - - '@rollup/rollup-darwin-x64@4.20.0': - optional: true - '@rollup/rollup-darwin-x64@4.34.8': optional: true @@ -25032,45 +24207,24 @@ snapshots: '@rollup/rollup-freebsd-x64@4.34.9': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.14.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.20.0': - optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.34.8': optional: true '@rollup/rollup-linux-arm-gnueabihf@4.34.9': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.20.0': - optional: true - '@rollup/rollup-linux-arm-musleabihf@4.34.8': optional: true '@rollup/rollup-linux-arm-musleabihf@4.34.9': optional: true - '@rollup/rollup-linux-arm64-gnu@4.14.1': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.20.0': - optional: true - '@rollup/rollup-linux-arm64-gnu@4.34.8': optional: true '@rollup/rollup-linux-arm64-gnu@4.34.9': optional: true - '@rollup/rollup-linux-arm64-musl@4.14.1': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.20.0': - optional: true - '@rollup/rollup-linux-arm64-musl@4.34.8': optional: true @@ -25083,96 +24237,48 @@ snapshots: '@rollup/rollup-linux-loongarch64-gnu@4.34.9': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.14.1': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': - optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': optional: true '@rollup/rollup-linux-powerpc64le-gnu@4.34.9': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.14.1': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.20.0': - optional: true - '@rollup/rollup-linux-riscv64-gnu@4.34.8': optional: true '@rollup/rollup-linux-riscv64-gnu@4.34.9': optional: true - '@rollup/rollup-linux-s390x-gnu@4.14.1': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.20.0': - optional: true - '@rollup/rollup-linux-s390x-gnu@4.34.8': optional: true '@rollup/rollup-linux-s390x-gnu@4.34.9': optional: true - '@rollup/rollup-linux-x64-gnu@4.14.1': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.20.0': - optional: true - '@rollup/rollup-linux-x64-gnu@4.34.8': optional: true '@rollup/rollup-linux-x64-gnu@4.34.9': optional: true - '@rollup/rollup-linux-x64-musl@4.14.1': - optional: true - - '@rollup/rollup-linux-x64-musl@4.20.0': - optional: true - '@rollup/rollup-linux-x64-musl@4.34.8': optional: true '@rollup/rollup-linux-x64-musl@4.34.9': optional: true - '@rollup/rollup-win32-arm64-msvc@4.14.1': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.20.0': - optional: true - '@rollup/rollup-win32-arm64-msvc@4.34.8': optional: true '@rollup/rollup-win32-arm64-msvc@4.34.9': optional: true - '@rollup/rollup-win32-ia32-msvc@4.14.1': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.20.0': - optional: true - '@rollup/rollup-win32-ia32-msvc@4.34.8': optional: true '@rollup/rollup-win32-ia32-msvc@4.34.9': optional: true - '@rollup/rollup-win32-x64-msvc@4.14.1': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.20.0': - optional: true - '@rollup/rollup-win32-x64-msvc@4.34.8': optional: true @@ -25278,7 +24384,7 @@ snapshots: '@sentry/core@8.42.0': {} - '@sentry/nextjs@8.42.0(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0))(react@18.2.0)(webpack@5.98.0)': + '@sentry/nextjs@8.42.0(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0))(react@18.3.1)(webpack@5.98.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -25288,11 +24394,11 @@ snapshots: '@sentry/core': 8.42.0 '@sentry/node': 8.42.0 '@sentry/opentelemetry': 8.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.27.0) - '@sentry/react': 8.42.0(react@18.2.0) + '@sentry/react': 8.42.0(react@18.3.1) '@sentry/vercel-edge': 8.42.0 '@sentry/webpack-plugin': 2.22.6(encoding@0.1.13)(webpack@5.98.0) chalk: 3.0.0 - next: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0) + next: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -25374,12 +24480,12 @@ snapshots: '@opentelemetry/semantic-conventions': 1.27.0 '@sentry/core': 8.42.0 - '@sentry/react@8.42.0(react@18.2.0)': + '@sentry/react@8.42.0(react@18.3.1)': dependencies: '@sentry/browser': 8.42.0 '@sentry/core': 8.42.0 hoist-non-react-statics: 3.3.2 - react: 18.2.0 + react: 18.3.1 '@sentry/types@8.22.0': {} @@ -25397,7 +24503,7 @@ snapshots: '@sentry/bundler-plugin-core': 2.22.6(encoding@0.1.13) unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.98.0(esbuild@0.25.4) + webpack: 5.98.0 transitivePeerDependencies: - encoding - supports-color @@ -25835,9 +24941,9 @@ snapshots: dependencies: acorn: 8.14.1 - '@sveltejs/adapter-vercel@5.6.3(@sveltejs/kit@2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(encoding@0.1.13)(rollup@4.34.9)': + '@sveltejs/adapter-vercel@5.6.3(@sveltejs/kit@2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(encoding@0.1.13)(rollup@4.34.9)': dependencies: - '@sveltejs/kit': 2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + '@sveltejs/kit': 2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) '@vercel/nft': 0.29.2(encoding@0.1.13)(rollup@4.34.9) esbuild: 0.24.2 transitivePeerDependencies: @@ -25845,9 +24951,9 @@ snapshots: - rollup - supports-color - '@sveltejs/kit@2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': + '@sveltejs/kit@2.18.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) '@types/cookie': 0.6.0 cookie: 0.6.0 devalue: 5.1.1 @@ -25860,65 +24966,63 @@ snapshots: set-cookie-parser: 2.6.0 sirv: 3.0.0 svelte: 5.32.1 - vite: 6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) - '@sveltejs/package@2.3.10(svelte@5.32.1)(typescript@5.6.3)': + '@sveltejs/package@2.3.10(svelte@5.32.1)(typescript@5.8.3)': dependencies: chokidar: 4.0.3 kleur: 4.1.5 sade: 1.8.1 semver: 7.6.3 svelte: 5.32.1 - svelte2tsx: 0.7.34(svelte@5.32.1)(typescript@5.6.3) + svelte2tsx: 0.7.34(svelte@5.32.1)(typescript@5.8.3) transitivePeerDependencies: - typescript - '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) - debug: 4.4.0(supports-color@9.4.0) + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + debug: 4.4.1(supports-color@9.4.0) svelte: 5.32.1 - vite: 6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) - debug: 4.4.0(supports-color@9.4.0) + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + debug: 4.4.1(supports-color@9.4.0) svelte: 5.32.1 - vite: 6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': + '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) - debug: 4.4.0(supports-color@9.4.0) + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + debug: 4.4.1(supports-color@9.4.0) deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.17 svelte: 5.32.1 - vite: 6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) - vitefu: 1.0.6(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + vite: 6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vitefu: 1.0.6(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': + '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) - debug: 4.4.0(supports-color@9.4.0) + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.32.1)(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + debug: 4.4.1(supports-color@9.4.0) deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.17 svelte: 5.32.1 - vite: 6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) - vitefu: 1.0.6(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + vite: 6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vitefu: 1.0.6(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) transitivePeerDependencies: - supports-color - '@swc/counter@0.1.3': {} - '@swc/helpers@0.5.11': dependencies: tslib: 2.8.1 @@ -25959,44 +25063,44 @@ snapshots: lodash: 4.17.21 redent: 3.0.0 - '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.2.4)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': + '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.7 '@testing-library/dom': 10.4.0 react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) + react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.3 - '@types/react-dom': 18.2.4 + '@types/react-dom': 18.3.0 - '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1)': dependencies: '@babel/runtime': 7.25.7 '@testing-library/dom': 10.4.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0-rc.1 + react-dom: 19.0.0-rc.1(react@19.0.0-rc.1) optionalDependencies: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@testing-library/svelte@5.2.7(svelte@5.32.1)(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.6.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': + '@testing-library/svelte@5.2.7(svelte@5.32.1)(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))(vitest@3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.8.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: '@testing-library/dom': 10.4.0 svelte: 5.32.1 optionalDependencies: - vite: 6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) - vitest: 3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.6.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vitest: 3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.8.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) '@testing-library/user-event@14.5.2(@testing-library/dom@10.4.0)': dependencies: '@testing-library/dom': 10.4.0 - '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.3.8(typescript@5.8.3)))(vue@3.3.8(typescript@5.8.3))': + '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.3)))(vue@3.5.13(typescript@5.8.3))': dependencies: '@babel/runtime': 7.25.7 '@testing-library/dom': 9.3.3 - '@vue/test-utils': 2.4.2(@vue/server-renderer@3.5.13(vue@3.3.8(typescript@5.8.3)))(vue@3.3.8(typescript@5.8.3)) - vue: 3.3.8(typescript@5.8.3) + '@vue/test-utils': 2.4.2(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.3)))(vue@3.5.13(typescript@5.8.3)) + vue: 3.5.13(typescript@5.8.3) optionalDependencies: '@vue/compiler-sfc': 3.5.13 transitivePeerDependencies: @@ -26100,8 +25204,6 @@ snapshots: dependencies: '@types/estree': 1.0.6 - '@types/estree@1.0.5': {} - '@types/estree@1.0.6': {} '@types/express-serve-static-core@4.19.6': @@ -26194,6 +25296,8 @@ snapshots: '@types/ms@0.7.34': {} + '@types/ms@2.1.0': {} + '@types/mysql@2.15.26': dependencies: '@types/node': 20.17.24 @@ -26240,10 +25344,6 @@ snapshots: '@types/range-parser@1.2.7': {} - '@types/react-dom@18.2.4': - dependencies: - '@types/react': 18.3.3 - '@types/react-dom@18.3.0': dependencies: '@types/react': 18.3.3 @@ -26322,38 +25422,37 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 8.26.0(eslint@8.57.1)(typescript@5.8.3) '@typescript-eslint/scope-manager': 8.26.0 - '@typescript-eslint/type-utils': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) - '@typescript-eslint/utils': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) + '@typescript-eslint/type-utils': 8.26.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/utils': 8.26.0(eslint@8.57.1)(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.26.0 - eslint: 9.21.0(jiti@2.4.0) + eslint: 8.57.1 graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 2.0.1(typescript@5.6.3) - typescript: 5.6.3 + ts-api-utils: 2.0.1(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4)': + '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3))(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 8.6.0(eslint@8.57.1)(typescript@5.5.4) - '@typescript-eslint/scope-manager': 8.6.0 - '@typescript-eslint/type-utils': 8.6.0(eslint@8.57.1)(typescript@5.5.4) - '@typescript-eslint/utils': 8.6.0(eslint@8.57.1)(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 8.6.0 - eslint: 8.57.1 + '@typescript-eslint/parser': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/type-utils': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.26.0 + eslint: 9.21.0(jiti@2.4.0) graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.5.4) - optionalDependencies: - typescript: 5.5.4 + ts-api-utils: 2.0.1(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -26363,7 +25462,7 @@ snapshots: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.5) '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) eslint: 8.57.1 optionalDependencies: typescript: 5.4.5 @@ -26376,7 +25475,7 @@ snapshots: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) eslint: 8.57.1 optionalDependencies: typescript: 5.6.3 @@ -26389,7 +25488,7 @@ snapshots: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.8.3) '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) eslint: 8.57.1 optionalDependencies: typescript: 5.8.3 @@ -26402,35 +25501,34 @@ snapshots: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.8.3) '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) eslint: 9.21.0(jiti@2.4.0) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3)': + '@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.26.0 '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.26.0 - debug: 4.4.0(supports-color@9.4.0) - eslint: 9.21.0(jiti@2.4.0) - typescript: 5.6.3 + debug: 4.3.7 + eslint: 8.57.1 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.6.0(eslint@8.57.1)(typescript@5.5.4)': + '@typescript-eslint/parser@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3)': dependencies: - '@typescript-eslint/scope-manager': 8.6.0 - '@typescript-eslint/types': 8.6.0 - '@typescript-eslint/typescript-estree': 8.6.0(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 8.6.0 + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.26.0 debug: 4.3.7 - eslint: 8.57.1 - optionalDependencies: - typescript: 5.5.4 + eslint: 9.21.0(jiti@2.4.0) + typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -26444,45 +25542,37 @@ snapshots: '@typescript-eslint/types': 8.26.0 '@typescript-eslint/visitor-keys': 8.26.0 - '@typescript-eslint/scope-manager@8.6.0': - dependencies: - '@typescript-eslint/types': 8.6.0 - '@typescript-eslint/visitor-keys': 8.6.0 - - '@typescript-eslint/type-utils@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3)': + '@typescript-eslint/type-utils@8.26.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.6.3) - '@typescript-eslint/utils': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) - debug: 4.4.1 - eslint: 9.21.0(jiti@2.4.0) - ts-api-utils: 2.0.1(typescript@5.6.3) - typescript: 5.6.3 + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.26.0(eslint@8.57.1)(typescript@5.8.3) + debug: 4.4.1(supports-color@9.4.0) + eslint: 8.57.1 + ts-api-utils: 2.0.1(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.6.0(eslint@8.57.1)(typescript@5.5.4)': + '@typescript-eslint/type-utils@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.6.0(typescript@5.5.4) - '@typescript-eslint/utils': 8.6.0(eslint@8.57.1)(typescript@5.5.4) - debug: 4.4.0(supports-color@9.4.0) - ts-api-utils: 1.3.0(typescript@5.5.4) - optionalDependencies: - typescript: 5.5.4 + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3) + debug: 4.4.1(supports-color@9.4.0) + eslint: 9.21.0(jiti@2.4.0) + ts-api-utils: 2.0.1(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - - eslint - supports-color '@typescript-eslint/types@7.2.0': {} '@typescript-eslint/types@8.26.0': {} - '@typescript-eslint/types@8.6.0': {} - '@typescript-eslint/typescript-estree@7.2.0(typescript@5.4.5)': dependencies: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -26497,7 +25587,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -26512,7 +25602,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -26523,56 +25613,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.26.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@8.26.0(typescript@5.8.3)': dependencies: '@typescript-eslint/types': 8.26.0 '@typescript-eslint/visitor-keys': 8.26.0 - debug: 4.4.1 - fast-glob: 3.3.2 + debug: 4.4.1(supports-color@9.4.0) + fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.1 - ts-api-utils: 2.0.1(typescript@5.6.3) - typescript: 5.6.3 + semver: 7.7.2 + ts-api-utils: 2.0.1(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.6.0(typescript@5.5.4)': + '@typescript-eslint/utils@8.26.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: - '@typescript-eslint/types': 8.6.0 - '@typescript-eslint/visitor-keys': 8.6.0 - debug: 4.3.7 - fast-glob: 3.3.2 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.1 - ts-api-utils: 1.3.0(typescript@5.5.4) - optionalDependencies: - typescript: 5.5.4 + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.3) + eslint: 8.57.1 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3)': + '@typescript-eslint/utils@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3)': dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@9.21.0(jiti@2.4.0)) '@typescript-eslint/scope-manager': 8.26.0 '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.3) eslint: 9.21.0(jiti@2.4.0) - typescript: 5.6.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.6.0(eslint@8.57.1)(typescript@5.5.4)': - dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.6.0 - '@typescript-eslint/types': 8.6.0 - '@typescript-eslint/typescript-estree': 8.6.0(typescript@5.5.4) - eslint: 8.57.1 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - - typescript '@typescript-eslint/visitor-keys@7.2.0': dependencies: @@ -26584,11 +25659,6 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.0 - '@typescript-eslint/visitor-keys@8.6.0': - dependencies: - '@typescript-eslint/types': 8.6.0 - eslint-visitor-keys: 3.4.3 - '@ungap/structured-clone@1.3.0': {} '@unhead/dom@1.11.11': @@ -26648,7 +25718,9 @@ snapshots: throttleit: 2.1.0 undici: 5.28.4 - '@vercel/functions@2.0.0(@aws-sdk/credential-provider-web-identity@3.662.0(@aws-sdk/client-sts@3.662.0))': + '@vercel/functions@3.1.0(@aws-sdk/credential-provider-web-identity@3.662.0(@aws-sdk/client-sts@3.662.0))': + dependencies: + '@vercel/oidc': 3.0.0 optionalDependencies: '@aws-sdk/credential-provider-web-identity': 3.662.0(@aws-sdk/client-sts@3.662.0) @@ -26693,6 +25765,11 @@ snapshots: - rollup - supports-color + '@vercel/oidc@3.0.0': + dependencies: + '@types/ms': 2.1.0 + ms: 2.1.3 + '@vercel/otel@1.10.0(@opentelemetry/api-logs@0.55.0)(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.29.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-logs@0.55.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@1.29.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))': dependencies: '@opentelemetry/api': 1.9.0 @@ -26743,10 +25820,10 @@ snapshots: vite: 5.4.11(@types/node@20.17.24)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) vue: 3.5.13(typescript@5.8.3) - '@vitejs/plugin-vue@5.2.0(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))(vue@3.3.8(typescript@5.8.3))': + '@vitejs/plugin-vue@5.2.0(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.3))': dependencies: vite: 6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) - vue: 3.3.8(typescript@5.8.3) + vue: 3.5.13(typescript@5.8.3) '@vitest/expect@2.1.4': dependencies: @@ -26771,23 +25848,23 @@ snapshots: msw: 2.6.4(@types/node@20.17.24)(typescript@5.8.3) vite: 5.4.11(@types/node@20.17.24)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) - '@vitest/mocker@2.1.4(msw@2.7.0(@types/node@22.7.4)(typescript@5.8.3))(vite@5.4.11(@types/node@22.7.4)(less@4.2.2)(sass@1.85.0)(terser@5.39.0))': + '@vitest/mocker@2.1.4(msw@2.6.4(@types/node@20.17.24)(typescript@5.8.3))(vite@5.4.11(@types/node@22.7.4)(less@4.2.2)(sass@1.85.0)(terser@5.39.0))': dependencies: '@vitest/spy': 2.1.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - msw: 2.7.0(@types/node@22.7.4)(typescript@5.8.3) + msw: 2.6.4(@types/node@20.17.24)(typescript@5.8.3) vite: 5.4.11(@types/node@22.7.4)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) - '@vitest/mocker@3.0.7(msw@2.7.0(@types/node@20.17.24)(typescript@5.6.3))(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': + '@vitest/mocker@2.1.4(msw@2.7.0(@types/node@22.7.4)(typescript@5.8.3))(vite@5.4.11(@types/node@22.7.4)(less@4.2.2)(sass@1.85.0)(terser@5.39.0))': dependencies: - '@vitest/spy': 3.0.7 + '@vitest/spy': 2.1.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - msw: 2.7.0(@types/node@20.17.24)(typescript@5.6.3) - vite: 6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + msw: 2.7.0(@types/node@22.7.4)(typescript@5.8.3) + vite: 5.4.11(@types/node@22.7.4)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) '@vitest/mocker@3.0.7(msw@2.7.0(@types/node@20.17.24)(typescript@5.8.3))(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: @@ -26886,18 +25963,11 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-module-imports': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/parser': 7.26.2 + '@babel/parser': 7.28.0 '@vue/compiler-sfc': 3.5.13 transitivePeerDependencies: - supports-color - '@vue/compiler-core@3.3.8': - dependencies: - '@babel/parser': 7.26.2 - '@vue/shared': 3.3.8 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - '@vue/compiler-core@3.5.13': dependencies: '@babel/parser': 7.26.2 @@ -26906,32 +25976,14 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.3.8': - dependencies: - '@vue/compiler-core': 3.3.8 - '@vue/shared': 3.3.8 - '@vue/compiler-dom@3.5.13': dependencies: '@vue/compiler-core': 3.5.13 '@vue/shared': 3.5.13 - '@vue/compiler-sfc@3.3.8': - dependencies: - '@babel/parser': 7.26.2 - '@vue/compiler-core': 3.3.8 - '@vue/compiler-dom': 3.3.8 - '@vue/compiler-ssr': 3.3.8 - '@vue/reactivity-transform': 3.3.8 - '@vue/shared': 3.3.8 - estree-walker: 2.0.2 - magic-string: 0.30.17 - postcss: 8.5.3 - source-map-js: 1.2.1 - '@vue/compiler-sfc@3.5.13': dependencies: - '@babel/parser': 7.26.2 + '@babel/parser': 7.28.0 '@vue/compiler-core': 3.5.13 '@vue/compiler-dom': 3.5.13 '@vue/compiler-ssr': 3.5.13 @@ -26941,11 +25993,6 @@ snapshots: postcss: 8.5.3 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.3.8': - dependencies: - '@vue/compiler-dom': 3.3.8 - '@vue/shared': 3.3.8 - '@vue/compiler-ssr@3.5.13': dependencies: '@vue/compiler-dom': 3.5.13 @@ -26979,18 +26026,6 @@ snapshots: dependencies: rfdc: 1.4.1 - '@vue/reactivity-transform@3.3.8': - dependencies: - '@babel/parser': 7.26.2 - '@vue/compiler-core': 3.3.8 - '@vue/shared': 3.3.8 - estree-walker: 2.0.2 - magic-string: 0.30.17 - - '@vue/reactivity@3.3.8': - dependencies: - '@vue/shared': 3.3.8 - '@vue/reactivity@3.5.12': dependencies: '@vue/shared': 3.5.12 @@ -26999,11 +26034,6 @@ snapshots: dependencies: '@vue/shared': 3.5.13 - '@vue/runtime-core@3.3.8': - dependencies: - '@vue/reactivity': 3.3.8 - '@vue/shared': 3.3.8 - '@vue/runtime-core@3.5.12': dependencies: '@vue/reactivity': 3.5.12 @@ -27014,12 +26044,6 @@ snapshots: '@vue/reactivity': 3.5.13 '@vue/shared': 3.5.13 - '@vue/runtime-dom@3.3.8': - dependencies: - '@vue/runtime-core': 3.3.8 - '@vue/shared': 3.3.8 - csstype: 3.1.3 - '@vue/runtime-dom@3.5.13': dependencies: '@vue/reactivity': 3.5.13 @@ -27027,38 +26051,23 @@ snapshots: '@vue/shared': 3.5.13 csstype: 3.1.3 - '@vue/server-renderer@3.3.8(vue@3.3.8(typescript@5.8.3))': - dependencies: - '@vue/compiler-ssr': 3.3.8 - '@vue/shared': 3.3.8 - vue: 3.3.8(typescript@5.8.3) - - '@vue/server-renderer@3.5.13(vue@3.3.8(typescript@5.8.3))': - dependencies: - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - vue: 3.3.8(typescript@5.8.3) - optional: true - '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.3))': dependencies: '@vue/compiler-ssr': 3.5.13 '@vue/shared': 3.5.13 vue: 3.5.13(typescript@5.8.3) - '@vue/shared@3.3.8': {} - '@vue/shared@3.5.12': {} '@vue/shared@3.5.13': {} - '@vue/test-utils@2.4.2(@vue/server-renderer@3.5.13(vue@3.3.8(typescript@5.8.3)))(vue@3.3.8(typescript@5.8.3))': + '@vue/test-utils@2.4.2(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.3)))(vue@3.5.13(typescript@5.8.3))': dependencies: js-beautify: 1.14.11 - vue: 3.3.8(typescript@5.8.3) + vue: 3.5.13(typescript@5.8.3) vue-component-type-helpers: 1.8.22 optionalDependencies: - '@vue/server-renderer': 3.5.13(vue@3.3.8(typescript@5.8.3)) + '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.8.3)) '@webassemblyjs/ast@1.12.1': dependencies: @@ -27271,13 +26280,13 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color agent-base@7.1.1: dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -27521,7 +26530,7 @@ snapshots: ast-kit@1.3.1: dependencies: - '@babel/parser': 7.26.2 + '@babel/parser': 7.28.0 pathe: 1.1.2 ast-types-flow@0.0.8: {} @@ -27536,7 +26545,7 @@ snapshots: ast-walker-scope@0.6.2: dependencies: - '@babel/parser': 7.26.2 + '@babel/parser': 7.28.0 ast-kit: 1.3.1 astral-regex@2.0.0: {} @@ -27559,36 +26568,6 @@ snapshots: atomic-sleep@1.0.0: {} - autoprefixer@10.4.16(postcss@8.4.49): - dependencies: - browserslist: 4.22.1 - caniuse-lite: 1.0.30001591 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.0.0 - postcss: 8.4.49 - postcss-value-parser: 4.2.0 - - autoprefixer@10.4.19(postcss@8.4.49): - dependencies: - browserslist: 4.23.1 - caniuse-lite: 1.0.30001637 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.0.1 - postcss: 8.4.49 - postcss-value-parser: 4.2.0 - - autoprefixer@10.4.20(postcss@8.4.49): - dependencies: - browserslist: 4.23.3 - caniuse-lite: 1.0.30001649 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.0.1 - postcss: 8.4.49 - postcss-value-parser: 4.2.0 - autoprefixer@10.4.20(postcss@8.5.2): dependencies: browserslist: 4.23.3 @@ -27855,28 +26834,10 @@ snapshots: dependencies: balanced-match: 1.0.2 - braces@3.0.2: - dependencies: - fill-range: 7.1.1 - braces@3.0.3: dependencies: fill-range: 7.1.1 - browserslist@4.22.1: - dependencies: - caniuse-lite: 1.0.30001666 - electron-to-chromium: 1.4.812 - node-releases: 2.0.14 - update-browserslist-db: 1.0.16(browserslist@4.22.1) - - browserslist@4.23.1: - dependencies: - caniuse-lite: 1.0.30001666 - electron-to-chromium: 1.4.812 - node-releases: 2.0.14 - update-browserslist-db: 1.0.16(browserslist@4.23.1) - browserslist@4.23.3: dependencies: caniuse-lite: 1.0.30001666 @@ -27928,21 +26889,11 @@ snapshots: dependencies: run-applescript: 7.0.0 - bundle-require@4.0.2(esbuild@0.19.12): - dependencies: - esbuild: 0.19.12 - load-tsconfig: 0.2.5 - bundle-require@4.2.1(esbuild@0.18.20): dependencies: esbuild: 0.18.20 load-tsconfig: 0.2.5 - bundle-require@5.0.0(esbuild@0.23.0): - dependencies: - esbuild: 0.23.0 - load-tsconfig: 0.2.5 - bundle-require@5.0.0(esbuild@0.23.1): dependencies: esbuild: 0.23.1 @@ -28033,10 +26984,6 @@ snapshots: lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001591: {} - - caniuse-lite@1.0.30001637: {} - caniuse-lite@1.0.30001649: {} caniuse-lite@1.0.30001666: {} @@ -28103,18 +27050,6 @@ snapshots: check-error@2.1.1: {} - chokidar@3.5.3: - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -28427,21 +27362,6 @@ snapshots: crc-32: 1.2.2 readable-stream: 4.7.0 - create-jest@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - create-jest@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)): dependencies: '@jest/types': 29.6.3 @@ -28456,7 +27376,6 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true create-require@1.1.1: {} @@ -28631,15 +27550,15 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.0(supports-color@9.4.0): + debug@4.4.0: dependencies: ms: 2.1.3 - optionalDependencies: - supports-color: 9.4.0 - debug@4.4.1: + debug@4.4.1(supports-color@9.4.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 9.4.0 decamelize@1.2.0: {} @@ -28740,7 +27659,9 @@ snapshots: detect-libc@2.0.3: {} - detect-libc@2.0.4: + detect-libc@2.0.4: {} + + detect-libc@2.1.0: optional: true detect-newline@3.1.0: {} @@ -28848,7 +27769,7 @@ snapshots: '@one-ini/wasm': 0.1.1 commander: 10.0.1 minimatch: 9.0.1 - semver: 7.7.1 + semver: 7.7.2 ee-first@1.1.1: {} @@ -28856,8 +27777,6 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.4.812: {} - electron-to-chromium@1.5.182: {} electron-to-chromium@1.5.31: {} @@ -29064,32 +27983,6 @@ snapshots: '@esbuild/win32-ia32': 0.18.20 '@esbuild/win32-x64': 0.18.20 - esbuild@0.19.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -29116,33 +28009,6 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.23.0: - optionalDependencies: - '@esbuild/aix-ppc64': 0.23.0 - '@esbuild/android-arm': 0.23.0 - '@esbuild/android-arm64': 0.23.0 - '@esbuild/android-x64': 0.23.0 - '@esbuild/darwin-arm64': 0.23.0 - '@esbuild/darwin-x64': 0.23.0 - '@esbuild/freebsd-arm64': 0.23.0 - '@esbuild/freebsd-x64': 0.23.0 - '@esbuild/linux-arm': 0.23.0 - '@esbuild/linux-arm64': 0.23.0 - '@esbuild/linux-ia32': 0.23.0 - '@esbuild/linux-loong64': 0.23.0 - '@esbuild/linux-mips64el': 0.23.0 - '@esbuild/linux-ppc64': 0.23.0 - '@esbuild/linux-riscv64': 0.23.0 - '@esbuild/linux-s390x': 0.23.0 - '@esbuild/linux-x64': 0.23.0 - '@esbuild/netbsd-x64': 0.23.0 - '@esbuild/openbsd-arm64': 0.23.0 - '@esbuild/openbsd-x64': 0.23.0 - '@esbuild/sunos-x64': 0.23.0 - '@esbuild/win32-arm64': 0.23.0 - '@esbuild/win32-ia32': 0.23.0 - '@esbuild/win32-x64': 0.23.0 - esbuild@0.23.1: optionalDependencies: '@esbuild/aix-ppc64': 0.23.1 @@ -29367,7 +28233,7 @@ snapshots: eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.1): dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) enhanced-resolve: 5.17.1 eslint: 8.57.1 eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.1) @@ -29384,7 +28250,7 @@ snapshots: eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.1): dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) enhanced-resolve: 5.17.1 eslint: 8.57.1 eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.1) @@ -29401,7 +28267,7 @@ snapshots: eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.1): dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) enhanced-resolve: 5.17.1 eslint: 8.57.1 eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.1) @@ -29418,7 +28284,7 @@ snapshots: eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@9.21.0(jiti@2.4.0)): dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) enhanced-resolve: 5.17.1 eslint: 9.21.0(jiti@2.4.0) eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.21.0(jiti@2.4.0)) @@ -29625,10 +28491,10 @@ snapshots: safe-regex-test: 1.0.3 string.prototype.includes: 2.0.0 - eslint-plugin-prettier@5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@10.0.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.3.3): + eslint-plugin-prettier@5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@10.0.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.5.3): dependencies: eslint: 8.57.1 - prettier: 3.3.3 + prettier: 3.5.3 prettier-linter-helpers: 1.0.0 synckit: 0.9.1 optionalDependencies: @@ -29687,7 +28553,7 @@ snapshots: semver: 6.3.1 string.prototype.matchall: 4.0.11 - eslint-plugin-svelte@3.0.3(eslint@9.21.0(jiti@2.4.0))(svelte@5.32.1)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)): + eslint-plugin-svelte@3.0.3(eslint@9.21.0(jiti@2.4.0))(svelte@5.32.1)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)): dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@9.21.0(jiti@2.4.0)) '@jridgewell/sourcemap-codec': 1.5.0 @@ -29696,7 +28562,7 @@ snapshots: esutils: 2.0.3 known-css-properties: 0.35.0 postcss: 8.5.3 - postcss-load-config: 3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)) + postcss-load-config: 3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) postcss-safe-parser: 7.0.1(postcss@8.5.3) semver: 7.6.3 svelte-eslint-parser: 1.0.1(svelte@5.32.1) @@ -29705,7 +28571,7 @@ snapshots: transitivePeerDependencies: - ts-node - eslint-plugin-svelte@3.0.3(eslint@9.21.0(jiti@2.4.0))(svelte@5.32.1)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)): + eslint-plugin-svelte@3.0.3(eslint@9.21.0(jiti@2.4.0))(svelte@5.32.1)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)): dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@9.21.0(jiti@2.4.0)) '@jridgewell/sourcemap-codec': 1.5.0 @@ -29714,7 +28580,7 @@ snapshots: esutils: 2.0.3 known-css-properties: 0.35.0 postcss: 8.5.3 - postcss-load-config: 3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)) + postcss-load-config: 3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)) postcss-safe-parser: 7.0.1(postcss@8.5.3) semver: 7.6.3 svelte-eslint-parser: 1.0.1(svelte@5.32.1) @@ -29760,7 +28626,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -29807,7 +28673,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -30289,7 +29155,7 @@ snapshots: follow-redirects@1.15.9(debug@4.4.1): optionalDependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) for-each@0.3.3: dependencies: @@ -30446,13 +29312,9 @@ snapshots: - encoding - supports-color - geist@1.3.1(next@15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0)): - dependencies: - next: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0) - - geist@1.3.1(next@15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0)): + geist@1.3.1(next@15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0)): dependencies: - next: 15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) + next: 15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0) generic-pool@3.9.0: {} @@ -30560,15 +29422,6 @@ snapshots: package-json-from-dist: 1.0.0 path-scurry: 1.11.1 - glob@7.1.6: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -30816,14 +29669,14 @@ snapshots: http-proxy-agent@7.0.0: dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -30842,7 +29695,7 @@ snapshots: http-proxy-middleware@3.0.5: dependencies: '@types/http-proxy': 1.17.15 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) http-proxy: 1.18.1(debug@4.4.1) is-glob: 4.0.3 is-plain-object: 5.0.0 @@ -30863,21 +29716,21 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6(supports-color@9.4.0): dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -31064,7 +29917,7 @@ snapshots: dependencies: '@ioredis/commands': 1.2.0 cluster-key-slot: 1.1.2 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -31344,7 +30197,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -31423,25 +30276,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest-cli@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) @@ -31460,38 +30294,6 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true - - jest-config@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)): - dependencies: - '@babel/core': 7.26.10 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.10) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 20.17.24 - ts-node: 10.9.2(@types/node@20.17.24)(typescript@5.5.4) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color jest-config@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)): dependencies: @@ -31523,7 +30325,6 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros - supports-color - optional: true jest-diff@29.7.0: dependencies: @@ -31746,18 +30547,6 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)) - '@jest/types': 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) @@ -31769,7 +30558,6 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true jimp@0.14.0: dependencies: @@ -32025,7 +30813,7 @@ snapshots: koa-send@5.0.1: dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) http-errors: 1.8.1 resolve-path: 1.4.0 transitivePeerDependencies: @@ -32045,7 +30833,7 @@ snapshots: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.8.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -32479,7 +31267,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.1 + semver: 7.7.2 make-error@1.3.6: {} @@ -32755,7 +31543,7 @@ snapshots: micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.1 @@ -32995,32 +31783,6 @@ snapshots: transitivePeerDependencies: - '@types/node' - msw@2.7.0(@types/node@20.17.24)(typescript@5.6.3): - dependencies: - '@bundled-es-modules/cookie': 2.0.1 - '@bundled-es-modules/statuses': 1.0.1 - '@bundled-es-modules/tough-cookie': 0.1.6 - '@inquirer/confirm': 5.0.2(@types/node@20.17.24) - '@mswjs/interceptors': 0.37.5 - '@open-draft/deferred-promise': 2.2.0 - '@open-draft/until': 2.1.0 - '@types/cookie': 0.6.0 - '@types/statuses': 2.0.5 - graphql: 16.9.0 - headers-polyfill: 4.0.3 - is-node-process: 1.2.0 - outvariant: 1.4.3 - path-to-regexp: 6.3.0 - picocolors: 1.1.1 - strict-event-emitter: 0.5.1 - type-fest: 4.26.1 - yargs: 17.7.2 - optionalDependencies: - typescript: 5.6.3 - transitivePeerDependencies: - - '@types/node' - optional: true - msw@2.7.0(@types/node@20.17.24)(typescript@5.8.3): dependencies: '@bundled-es-modules/cookie': 2.0.1 @@ -33101,8 +31863,6 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nanoid@3.3.7: {} - nanoid@3.3.8: {} nanoid@5.0.8: {} @@ -33125,7 +31885,7 @@ snapshots: neo-async@2.6.2: {} - next@15.0.0-canary.23(@opentelemetry/api@1.9.0)(@playwright/test@1.46.0)(react-dom@19.0.0-rc-cc1ec60d0d-20240607(react@19.0.0-rc-cc1ec60d0d-20240607))(react@19.0.0-rc-cc1ec60d0d-20240607)(sass@1.85.0): + next@15.0.0-canary.23(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.0.0-rc-cc1ec60d0d-20240607(react@19.0.0-rc-cc1ec60d0d-20240607))(react@19.0.0-rc-cc1ec60d0d-20240607)(sass@1.85.0): dependencies: '@next/env': 15.0.0-canary.23 '@swc/helpers': 0.5.11 @@ -33147,34 +31907,6 @@ snapshots: '@next/swc-win32-ia32-msvc': 15.0.0-canary.23 '@next/swc-win32-x64-msvc': 15.0.0-canary.23 '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.46.0 - sass: 1.85.0 - sharp: 0.33.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - next@15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.85.0): - dependencies: - '@next/env': 15.2.4 - '@swc/counter': 0.1.3 - '@swc/helpers': 0.5.15 - busboy: 1.6.0 - caniuse-lite: 1.0.30001666 - postcss: 8.4.31 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.6(react@18.2.0) - optionalDependencies: - '@next/swc-darwin-arm64': 15.2.4 - '@next/swc-darwin-x64': 15.2.4 - '@next/swc-linux-arm64-gnu': 15.2.4 - '@next/swc-linux-arm64-musl': 15.2.4 - '@next/swc-linux-x64-gnu': 15.2.4 - '@next/swc-linux-x64-musl': 15.2.4 - '@next/swc-win32-arm64-msvc': 15.2.4 - '@next/swc-win32-x64-msvc': 15.2.4 - '@opentelemetry/api': 1.9.0 '@playwright/test': 1.50.1 sass: 1.85.0 sharp: 0.33.5 @@ -33182,112 +31914,54 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.2.4(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0): + next@15.5.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0): dependencies: - '@next/env': 15.2.4 - '@swc/counter': 0.1.3 + '@next/env': 15.5.3 '@swc/helpers': 0.5.15 - busboy: 1.6.0 caniuse-lite: 1.0.30001666 postcss: 8.4.31 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) styled-jsx: 5.1.6(react@18.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 15.2.4 - '@next/swc-darwin-x64': 15.2.4 - '@next/swc-linux-arm64-gnu': 15.2.4 - '@next/swc-linux-arm64-musl': 15.2.4 - '@next/swc-linux-x64-gnu': 15.2.4 - '@next/swc-linux-x64-musl': 15.2.4 - '@next/swc-win32-arm64-msvc': 15.2.4 - '@next/swc-win32-x64-msvc': 15.2.4 + '@next/swc-darwin-arm64': 15.5.3 + '@next/swc-darwin-x64': 15.5.3 + '@next/swc-linux-arm64-gnu': 15.5.3 + '@next/swc-linux-arm64-musl': 15.5.3 + '@next/swc-linux-x64-gnu': 15.5.3 + '@next/swc-linux-x64-musl': 15.5.3 + '@next/swc-win32-arm64-msvc': 15.5.3 + '@next/swc-win32-x64-msvc': 15.5.3 '@opentelemetry/api': 1.9.0 '@playwright/test': 1.50.1 sass: 1.85.0 - sharp: 0.33.5 + sharp: 0.34.3 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - next@15.3.0-canary.43(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1)(sass@1.85.0): + next@15.6.0-canary.13(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1)(sass@1.85.0): dependencies: - '@next/env': 15.3.0-canary.43 - '@swc/counter': 0.1.3 + '@next/env': 15.6.0-canary.13 '@swc/helpers': 0.5.15 - busboy: 1.6.0 caniuse-lite: 1.0.30001666 postcss: 8.4.31 react: 19.0.0-rc.1 react-dom: 19.0.0-rc.1(react@19.0.0-rc.1) styled-jsx: 5.1.6(react@19.0.0-rc.1) optionalDependencies: - '@next/swc-darwin-arm64': 15.3.0-canary.43 - '@next/swc-darwin-x64': 15.3.0-canary.43 - '@next/swc-linux-arm64-gnu': 15.3.0-canary.43 - '@next/swc-linux-arm64-musl': 15.3.0-canary.43 - '@next/swc-linux-x64-gnu': 15.3.0-canary.43 - '@next/swc-linux-x64-musl': 15.3.0-canary.43 - '@next/swc-win32-arm64-msvc': 15.3.0-canary.43 - '@next/swc-win32-x64-msvc': 15.3.0-canary.43 + '@next/swc-darwin-arm64': 15.6.0-canary.13 + '@next/swc-darwin-x64': 15.6.0-canary.13 + '@next/swc-linux-arm64-gnu': 15.6.0-canary.13 + '@next/swc-linux-arm64-musl': 15.6.0-canary.13 + '@next/swc-linux-x64-gnu': 15.6.0-canary.13 + '@next/swc-linux-x64-musl': 15.6.0-canary.13 + '@next/swc-win32-arm64-msvc': 15.6.0-canary.13 + '@next/swc-win32-x64-msvc': 15.6.0-canary.13 '@opentelemetry/api': 1.9.0 '@playwright/test': 1.50.1 sass: 1.85.0 - sharp: 0.34.1 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0): - dependencies: - '@next/env': 15.3.3 - '@swc/counter': 0.1.3 - '@swc/helpers': 0.5.15 - busboy: 1.6.0 - caniuse-lite: 1.0.30001666 - postcss: 8.4.31 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.6(react@18.3.1) - optionalDependencies: - '@next/swc-darwin-arm64': 15.3.3 - '@next/swc-darwin-x64': 15.3.3 - '@next/swc-linux-arm64-gnu': 15.3.3 - '@next/swc-linux-arm64-musl': 15.3.3 - '@next/swc-linux-x64-gnu': 15.3.3 - '@next/swc-linux-x64-musl': 15.3.3 - '@next/swc-win32-arm64-msvc': 15.3.3 - '@next/swc-win32-x64-msvc': 15.3.3 - '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.50.1 - sass: 1.85.0 - sharp: 0.34.1 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - next@15.5.2(@opentelemetry/api@1.9.0)(@playwright/test@1.46.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.0): - dependencies: - '@next/env': 15.5.2 - '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001727 - postcss: 8.4.31 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.6(react@18.3.1) - optionalDependencies: - '@next/swc-darwin-arm64': 15.5.2 - '@next/swc-darwin-x64': 15.5.2 - '@next/swc-linux-arm64-gnu': 15.5.2 - '@next/swc-linux-arm64-musl': 15.5.2 - '@next/swc-linux-x64-gnu': 15.5.2 - '@next/swc-linux-x64-musl': 15.5.2 - '@next/swc-win32-arm64-msvc': 15.5.2 - '@next/swc-win32-x64-msvc': 15.5.2 - '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.46.0 - sass: 1.85.0 - sharp: 0.34.3 + sharp: 0.34.4 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -33414,7 +32088,7 @@ snapshots: node-gyp-build-optional-packages@5.2.2: dependencies: - detect-libc: 2.0.3 + detect-libc: 2.0.4 optional: true node-gyp-build@4.6.1: {} @@ -33427,7 +32101,7 @@ snapshots: make-fetch-happen: 14.0.3 nopt: 8.1.0 proc-log: 5.0.0 - semver: 7.7.1 + semver: 7.7.2 tar: 7.4.3 tinyglobby: 0.2.14 which: 5.0.0 @@ -33436,8 +32110,6 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.14: {} - node-releases@2.0.18: {} node-releases@2.0.19: {} @@ -33468,7 +32140,7 @@ snapshots: npm-install-checks@7.1.1: dependencies: - semver: 7.7.1 + semver: 7.7.2 npm-normalize-package-bin@2.0.0: {} @@ -34084,8 +32756,6 @@ snapshots: transitivePeerDependencies: - debug - picocolors@1.0.0: {} - picocolors@1.0.1: {} picocolors@1.1.0: {} @@ -34155,23 +32825,13 @@ snapshots: mlly: 1.7.3 pathe: 1.1.2 - playwright-core@1.46.0: {} - - playwright-core@1.50.1: - optional: true - - playwright@1.46.0: - dependencies: - playwright-core: 1.46.0 - optionalDependencies: - fsevents: 2.3.2 + playwright-core@1.50.1: {} playwright@1.50.1: dependencies: playwright-core: 1.50.1 optionalDependencies: fsevents: 2.3.2 - optional: true plist@3.1.0: dependencies: @@ -34242,29 +32902,21 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.3 - postcss-load-config@3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)): + postcss-load-config@3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: postcss: 8.5.3 - ts-node: 10.9.2(@types/node@20.17.24)(typescript@5.6.3) + ts-node: 10.9.2(@types/node@20.17.24)(typescript@5.8.3) - postcss-load-config@3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)): + postcss-load-config@3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: postcss: 8.5.3 - ts-node: 10.9.2(@types/node@22.7.4)(typescript@5.6.3) - - postcss-load-config@4.0.1(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)): - dependencies: - lilconfig: 2.1.0 - yaml: 2.4.5 - optionalDependencies: - postcss: 8.5.3 - ts-node: 10.9.2(@types/node@20.17.24)(typescript@5.8.3) + ts-node: 10.9.2(@types/node@22.7.4)(typescript@5.8.3) postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.4.5)): dependencies: @@ -34290,13 +32942,13 @@ snapshots: postcss: 8.5.3 ts-node: 10.9.2(@types/node@20.17.24)(typescript@5.8.3) - postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)): + postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)): dependencies: lilconfig: 3.1.3 yaml: 2.7.0 optionalDependencies: postcss: 8.5.3 - ts-node: 10.9.2(@types/node@22.7.4)(typescript@5.6.3) + ts-node: 10.9.2(@types/node@22.7.4)(typescript@5.8.3) postcss-load-config@6.0.1(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(yaml@2.7.0): dependencies: @@ -34491,12 +33143,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.4.49: - dependencies: - nanoid: 3.3.7 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.2: dependencies: nanoid: 3.3.8 @@ -34532,8 +33178,6 @@ snapshots: prettier@2.8.8: {} - prettier@3.3.3: {} - prettier@3.5.3: {} pretty-bytes@6.1.1: {} @@ -34667,18 +33311,6 @@ snapshots: defu: 6.1.4 destr: 2.0.3 - react-dom@18.2.0(react@18.2.0): - dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 - - react-dom@18.2.0(react@18.3.1): - dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.0 - react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 @@ -34726,11 +33358,7 @@ snapshots: neo-async: 2.6.2 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - webpack: 5.98.0(esbuild@0.25.4) - - react@18.2.0: - dependencies: - loose-envify: 1.4.0 + webpack: 5.98.0 react@18.3.1: dependencies: @@ -34920,7 +33548,7 @@ snapshots: require-in-the-middle@7.3.0: dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) module-details-from-path: 1.0.3 resolve: 1.22.8 transitivePeerDependencies: @@ -35016,49 +33644,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - rollup@4.14.1: - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.14.1 - '@rollup/rollup-android-arm64': 4.14.1 - '@rollup/rollup-darwin-arm64': 4.14.1 - '@rollup/rollup-darwin-x64': 4.14.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.14.1 - '@rollup/rollup-linux-arm64-gnu': 4.14.1 - '@rollup/rollup-linux-arm64-musl': 4.14.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.14.1 - '@rollup/rollup-linux-riscv64-gnu': 4.14.1 - '@rollup/rollup-linux-s390x-gnu': 4.14.1 - '@rollup/rollup-linux-x64-gnu': 4.14.1 - '@rollup/rollup-linux-x64-musl': 4.14.1 - '@rollup/rollup-win32-arm64-msvc': 4.14.1 - '@rollup/rollup-win32-ia32-msvc': 4.14.1 - '@rollup/rollup-win32-x64-msvc': 4.14.1 - fsevents: 2.3.3 - - rollup@4.20.0: - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.20.0 - '@rollup/rollup-android-arm64': 4.20.0 - '@rollup/rollup-darwin-arm64': 4.20.0 - '@rollup/rollup-darwin-x64': 4.20.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.20.0 - '@rollup/rollup-linux-arm-musleabihf': 4.20.0 - '@rollup/rollup-linux-arm64-gnu': 4.20.0 - '@rollup/rollup-linux-arm64-musl': 4.20.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.20.0 - '@rollup/rollup-linux-riscv64-gnu': 4.20.0 - '@rollup/rollup-linux-s390x-gnu': 4.20.0 - '@rollup/rollup-linux-x64-gnu': 4.20.0 - '@rollup/rollup-linux-x64-musl': 4.20.0 - '@rollup/rollup-win32-arm64-msvc': 4.20.0 - '@rollup/rollup-win32-ia32-msvc': 4.20.0 - '@rollup/rollup-win32-x64-msvc': 4.20.0 - fsevents: 2.3.3 - rollup@4.34.8: dependencies: '@types/estree': 1.0.6 @@ -35192,10 +33777,6 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.23.0: - dependencies: - loose-envify: 1.4.0 - scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -35238,8 +33819,7 @@ snapshots: semver@7.7.1: {} - semver@7.7.2: - optional: true + semver@7.7.2: {} send@0.19.0: dependencies: @@ -35261,7 +33841,7 @@ snapshots: send@1.1.0: dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) destroy: 1.2.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -35374,34 +33954,6 @@ snapshots: '@img/sharp-win32-ia32': 0.33.5 '@img/sharp-win32-x64': 0.33.5 - sharp@0.34.1: - dependencies: - color: 4.2.3 - detect-libc: 2.0.3 - semver: 7.7.1 - optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.1 - '@img/sharp-darwin-x64': 0.34.1 - '@img/sharp-libvips-darwin-arm64': 1.1.0 - '@img/sharp-libvips-darwin-x64': 1.1.0 - '@img/sharp-libvips-linux-arm': 1.1.0 - '@img/sharp-libvips-linux-arm64': 1.1.0 - '@img/sharp-libvips-linux-ppc64': 1.1.0 - '@img/sharp-libvips-linux-s390x': 1.1.0 - '@img/sharp-libvips-linux-x64': 1.1.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 - '@img/sharp-libvips-linuxmusl-x64': 1.1.0 - '@img/sharp-linux-arm': 0.34.1 - '@img/sharp-linux-arm64': 0.34.1 - '@img/sharp-linux-s390x': 0.34.1 - '@img/sharp-linux-x64': 0.34.1 - '@img/sharp-linuxmusl-arm64': 0.34.1 - '@img/sharp-linuxmusl-x64': 0.34.1 - '@img/sharp-wasm32': 0.34.1 - '@img/sharp-win32-ia32': 0.34.1 - '@img/sharp-win32-x64': 0.34.1 - optional: true - sharp@0.34.3: dependencies: color: 4.2.3 @@ -35432,6 +33984,36 @@ snapshots: '@img/sharp-win32-x64': 0.34.3 optional: true + sharp@0.34.4: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.0 + semver: 7.7.2 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.4 + '@img/sharp-darwin-x64': 0.34.4 + '@img/sharp-libvips-darwin-arm64': 1.2.3 + '@img/sharp-libvips-darwin-x64': 1.2.3 + '@img/sharp-libvips-linux-arm': 1.2.3 + '@img/sharp-libvips-linux-arm64': 1.2.3 + '@img/sharp-libvips-linux-ppc64': 1.2.3 + '@img/sharp-libvips-linux-s390x': 1.2.3 + '@img/sharp-libvips-linux-x64': 1.2.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + '@img/sharp-linux-arm': 0.34.4 + '@img/sharp-linux-arm64': 0.34.4 + '@img/sharp-linux-ppc64': 0.34.4 + '@img/sharp-linux-s390x': 0.34.4 + '@img/sharp-linux-x64': 0.34.4 + '@img/sharp-linuxmusl-arm64': 0.34.4 + '@img/sharp-linuxmusl-x64': 0.34.4 + '@img/sharp-wasm32': 0.34.4 + '@img/sharp-win32-arm64': 0.34.4 + '@img/sharp-win32-ia32': 0.34.4 + '@img/sharp-win32-x64': 0.34.4 + optional: true + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -35476,7 +34058,7 @@ snapshots: dependencies: '@kwsites/file-exists': 1.1.1 '@kwsites/promise-deferred': 1.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -35525,7 +34107,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.3 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) socks: 2.8.6 transitivePeerDependencies: - supports-color @@ -35593,7 +34175,7 @@ snapshots: spdy-transport@3.0.0: dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -35604,7 +34186,7 @@ snapshots: spdy@4.0.2: dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -35781,11 +34363,6 @@ snapshots: dependencies: inline-style-parser: 0.2.4 - styled-jsx@5.1.6(react@18.2.0): - dependencies: - client-only: 0.0.1 - react: 18.2.0 - styled-jsx@5.1.6(react@18.3.1): dependencies: client-only: 0.0.1 @@ -35807,19 +34384,9 @@ snapshots: postcss: 8.5.3 postcss-selector-parser: 6.1.2 - sucrase@3.34.0: - dependencies: - '@jridgewell/gen-mapping': 0.3.8 - commander: 4.1.1 - glob: 7.1.6 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.6 - ts-interface-checker: 0.1.13 - sucrase@3.35.0: dependencies: - '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/gen-mapping': 0.3.12 commander: 4.1.1 glob: 10.4.5 lines-and-columns: 1.2.4 @@ -35831,7 +34398,7 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) fast-safe-stringify: 2.1.1 form-data: 4.0.0 formidable: 3.5.1 @@ -35868,7 +34435,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@4.1.1(picomatch@4.0.2)(svelte@5.32.1)(typescript@5.6.3): + svelte-check@4.1.1(picomatch@4.0.2)(svelte@5.32.1)(typescript@5.8.3): dependencies: '@jridgewell/trace-mapping': 0.3.25 chokidar: 4.0.1 @@ -35876,7 +34443,7 @@ snapshots: picocolors: 1.1.1 sade: 1.8.1 svelte: 5.32.1 - typescript: 5.6.3 + typescript: 5.8.3 transitivePeerDependencies: - picomatch @@ -35898,12 +34465,12 @@ snapshots: style-to-object: 1.0.8 svelte: 5.32.1 - svelte2tsx@0.7.34(svelte@5.32.1)(typescript@5.6.3): + svelte2tsx@0.7.34(svelte@5.32.1)(typescript@5.8.3): dependencies: dedent-js: 1.0.1 pascal-case: 3.1.2 svelte: 5.32.1 - typescript: 5.6.3 + typescript: 5.8.3 svelte@5.32.1: dependencies: @@ -35934,15 +34501,15 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 - swr@2.2.5(react@18.3.1): + swr@2.2.5(react@19.0.0-rc.1): dependencies: client-only: 0.0.1 - react: 18.3.1 - use-sync-external-store: 1.2.0(react@18.3.1) + react: 19.0.0-rc.1 + use-sync-external-store: 1.2.0(react@19.0.0-rc.1) - swrv@1.0.4(vue@3.3.8(typescript@5.8.3)): + swrv@1.0.4(vue@3.5.13(typescript@5.8.3)): dependencies: - vue: 3.3.8(typescript@5.8.3) + vue: 3.5.13(typescript@5.8.3) symbol-observable@4.0.0: {} @@ -35973,16 +34540,16 @@ snapshots: tailwind-merge@3.0.2: {} - tailwind-variants@1.0.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3))): + tailwind-variants@1.0.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3))): dependencies: tailwind-merge: 3.0.2 - tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)) + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)) - tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3))): + tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3))): dependencies: - tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)) + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)) - tailwindcss@3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.4.5)): + tailwindcss@3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -36001,7 +34568,7 @@ snapshots: postcss: 8.5.3 postcss-import: 15.1.0(postcss@8.5.3) postcss-js: 4.0.1(postcss@8.5.3) - postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.4.5)) + postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) postcss-nested: 6.2.0(postcss@8.5.3) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -36009,7 +34576,7 @@ snapshots: transitivePeerDependencies: - ts-node - tailwindcss@3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)): + tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.4.5)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -36020,7 +34587,7 @@ snapshots: glob-parent: 6.0.2 is-glob: 4.0.3 jiti: 1.21.6 - lilconfig: 2.1.0 + lilconfig: 3.1.3 micromatch: 4.0.8 normalize-path: 3.0.0 object-hash: 3.0.0 @@ -36028,7 +34595,7 @@ snapshots: postcss: 8.5.3 postcss-import: 15.1.0(postcss@8.5.3) postcss-js: 4.0.1(postcss@8.5.3) - postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)) + postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.4.5)) postcss-nested: 6.2.0(postcss@8.5.3) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -36036,7 +34603,7 @@ snapshots: transitivePeerDependencies: - ts-node - tailwindcss@3.4.15(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)): + tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -36047,7 +34614,7 @@ snapshots: glob-parent: 6.0.2 is-glob: 4.0.3 jiti: 1.21.6 - lilconfig: 2.1.0 + lilconfig: 3.1.3 micromatch: 4.0.8 normalize-path: 3.0.0 object-hash: 3.0.0 @@ -36055,7 +34622,7 @@ snapshots: postcss: 8.5.3 postcss-import: 15.1.0(postcss@8.5.3) postcss-js: 4.0.1(postcss@8.5.3) - postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) + postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3)) postcss-nested: 6.2.0(postcss@8.5.3) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -36090,7 +34657,7 @@ snapshots: transitivePeerDependencies: - ts-node - tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)): + tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -36109,7 +34676,7 @@ snapshots: postcss: 8.5.3 postcss-import: 15.1.0(postcss@8.5.3) postcss-js: 4.0.1(postcss@8.5.3) - postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3)) + postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3)) postcss-nested: 6.2.0(postcss@8.5.3) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -36180,6 +34747,15 @@ snapshots: optionalDependencies: esbuild: 0.25.4 + terser-webpack-plugin@5.3.14(webpack@5.98.0): + dependencies: + '@jridgewell/trace-mapping': 0.3.29 + jest-worker: 27.5.1 + schema-utils: 4.3.2 + serialize-javascript: 6.0.2 + terser: 5.39.0 + webpack: 5.98.0 + terser@5.31.3: dependencies: '@jridgewell/source-map': 0.3.6 @@ -36327,10 +34903,6 @@ snapshots: dependencies: typescript: 5.4.5 - ts-api-utils@1.3.0(typescript@5.5.4): - dependencies: - typescript: 5.5.4 - ts-api-utils@1.3.0(typescript@5.6.3): dependencies: typescript: 5.6.3 @@ -36339,24 +34911,24 @@ snapshots: dependencies: typescript: 5.8.3 - ts-api-utils@2.0.1(typescript@5.6.3): + ts-api-utils@2.0.1(typescript@5.8.3): dependencies: - typescript: 5.6.3 + typescript: 5.8.3 ts-interface-checker@0.1.13: {} - ts-jest@29.2.5(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)))(typescript@5.5.4): + ts-jest@29.2.5(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)))(typescript@5.8.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4)) + jest: 29.7.0(@types/node@20.17.24)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.6.3 - typescript: 5.5.4 + typescript: 5.8.3 yargs-parser: 21.1.1 optionalDependencies: '@babel/core': 7.26.10 @@ -36364,14 +34936,14 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.10) - ts-loader@9.5.1(typescript@5.5.4)(webpack@5.96.1): + ts-loader@9.5.1(typescript@5.8.3)(webpack@5.96.1): dependencies: chalk: 4.1.2 enhanced-resolve: 5.17.1 micromatch: 4.0.7 semver: 7.6.3 source-map: 0.7.4 - typescript: 5.5.4 + typescript: 5.8.3 webpack: 5.96.1 ts-node@10.9.2(@types/node@20.17.24)(typescript@5.4.5): @@ -36393,24 +34965,6 @@ snapshots: yn: 3.1.1 optional: true - ts-node@10.9.2(@types/node@20.17.24)(typescript@5.5.4): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.24 - acorn: 8.12.1 - acorn-walk: 8.3.3 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.5.4 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - ts-node@10.9.2(@types/node@20.17.24)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -36447,9 +35001,8 @@ snapshots: typescript: 5.8.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - optional: true - ts-node@10.9.2(@types/node@22.7.4)(typescript@5.6.3): + ts-node@10.9.2(@types/node@22.7.4)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -36463,7 +35016,7 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.6.3 + typescript: 5.8.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optional: true @@ -36499,7 +35052,7 @@ snapshots: bundle-require: 4.2.1(esbuild@0.18.20) cac: 6.7.14 chokidar: 3.6.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 esbuild: 0.18.20 execa: 5.1.1 globby: 11.1.0 @@ -36517,63 +35070,13 @@ snapshots: - supports-color - ts-node - tsup@8.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3))(typescript@5.8.3): - dependencies: - bundle-require: 4.0.2(esbuild@0.19.12) - cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.7 - esbuild: 0.19.12 - execa: 5.1.1 - globby: 11.1.0 - joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.3)) - resolve-from: 5.0.0 - rollup: 4.14.1 - source-map: 0.8.0-beta.0 - sucrase: 3.34.0 - tree-kill: 1.2.2 - optionalDependencies: - postcss: 8.5.3 - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - ts-node - - tsup@8.2.4(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.8.3)(yaml@2.7.0): - dependencies: - bundle-require: 5.0.0(esbuild@0.23.0) - cac: 6.7.14 - chokidar: 3.6.0 - consola: 3.2.3 - debug: 4.3.7 - esbuild: 0.23.0 - execa: 5.1.1 - globby: 11.1.0 - joycon: 3.1.1 - picocolors: 1.0.1 - postcss-load-config: 6.0.1(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(yaml@2.7.0) - resolve-from: 5.0.0 - rollup: 4.20.0 - source-map: 0.8.0-beta.0 - sucrase: 3.35.0 - tree-kill: 1.2.2 - optionalDependencies: - postcss: 8.5.3 - typescript: 5.8.3 - transitivePeerDependencies: - - jiti - - supports-color - - tsx - - yaml - tsup@8.3.0(jiti@2.4.0)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0): dependencies: bundle-require: 5.0.0(esbuild@0.23.1) cac: 6.7.14 chokidar: 3.6.0 consola: 3.2.3 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.3.7 esbuild: 0.23.1 execa: 5.1.1 joycon: 3.1.1 @@ -36583,7 +35086,7 @@ snapshots: rollup: 4.34.9 source-map: 0.8.0-beta.0 sucrase: 3.35.0 - tinyglobby: 0.2.10 + tinyglobby: 0.2.14 tree-kill: 1.2.2 optionalDependencies: postcss: 8.5.3 @@ -36600,7 +35103,7 @@ snapshots: cac: 6.7.14 chokidar: 3.6.0 consola: 3.2.3 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.3.7 esbuild: 0.23.1 execa: 5.1.1 joycon: 3.1.1 @@ -36610,7 +35113,7 @@ snapshots: rollup: 4.34.9 source-map: 0.8.0-beta.0 sucrase: 3.35.0 - tinyglobby: 0.2.10 + tinyglobby: 0.2.14 tree-kill: 1.2.2 optionalDependencies: postcss: 8.5.3 @@ -36631,7 +35134,7 @@ snapshots: tuf-js@3.1.0: dependencies: '@tufjs/models': 3.0.1 - debug: 4.4.1 + debug: 4.4.1(supports-color@9.4.0) make-fetch-happen: 14.0.3 transitivePeerDependencies: - supports-color @@ -36728,13 +35231,13 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3): + typescript-eslint@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) - '@typescript-eslint/parser': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) - '@typescript-eslint/utils': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3))(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3) + '@typescript-eslint/parser': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.8.3) eslint: 9.21.0(jiti@2.4.0) - typescript: 5.6.3 + typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -36742,8 +35245,6 @@ snapshots: typescript@5.4.5: {} - typescript@5.5.4: {} - typescript@5.6.3: {} typescript@5.8.3: {} @@ -36849,7 +35350,7 @@ snapshots: pkg-types: 1.2.1 scule: 1.3.0 strip-literal: 2.1.1 - tinyglobby: 0.2.10 + tinyglobby: 0.2.14 unplugin: 1.16.0 transitivePeerDependencies: - rollup @@ -36985,18 +35486,6 @@ snapshots: pkg-types: 1.2.1 unplugin: 1.16.0 - update-browserslist-db@1.0.16(browserslist@4.22.1): - dependencies: - browserslist: 4.22.1 - escalade: 3.2.0 - picocolors: 1.1.1 - - update-browserslist-db@1.0.16(browserslist@4.23.1): - dependencies: - browserslist: 4.23.1 - escalade: 3.2.0 - picocolors: 1.1.1 - update-browserslist-db@1.1.0(browserslist@4.23.3): dependencies: browserslist: 4.23.3 @@ -37042,9 +35531,9 @@ snapshots: urlpattern-polyfill@8.0.2: {} - use-sync-external-store@1.2.0(react@18.3.1): + use-sync-external-store@1.2.0(react@19.0.0-rc.1): dependencies: - react: 18.3.1 + react: 19.0.0-rc.1 utif@2.0.1: dependencies: @@ -37066,10 +35555,6 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - valibot@1.0.0-rc.0(typescript@5.8.3): - optionalDependencies: - typescript: 5.8.3 - valibot@1.1.0(typescript@5.8.3): optionalDependencies: typescript: 5.8.3 @@ -37100,7 +35585,7 @@ snapshots: vite-node@2.1.4(@types/node@20.17.24)(less@4.2.2)(sass@1.85.0)(terser@5.39.0): dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) pathe: 1.1.2 vite: 5.4.11(@types/node@20.17.24)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) transitivePeerDependencies: @@ -37117,7 +35602,7 @@ snapshots: vite-node@2.1.4(@types/node@22.7.4)(less@4.2.2)(sass@1.85.0)(terser@5.39.0): dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) pathe: 1.1.2 vite: 5.4.11(@types/node@22.7.4)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) transitivePeerDependencies: @@ -37134,10 +35619,10 @@ snapshots: vite-node@3.0.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0): dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -37159,7 +35644,7 @@ snapshots: chalk: 4.1.2 chokidar: 3.6.0 commander: 8.3.0 - fast-glob: 3.3.2 + fast-glob: 3.3.3 fs-extra: 11.2.0 npm-run-path: 4.0.1 strip-ansi: 6.0.1 @@ -37178,7 +35663,7 @@ snapshots: dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.1.3(rollup@4.34.9) - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.1(supports-color@9.4.0) error-stack-parser-es: 0.1.5 fs-extra: 11.2.0 open: 10.1.0 @@ -37246,13 +35731,13 @@ snapshots: tsx: 4.19.2 yaml: 2.7.0 - vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0): + vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0): dependencies: - esbuild: 0.24.2 + esbuild: 0.25.4 postcss: 8.5.3 rollup: 4.34.9 optionalDependencies: - '@types/node': 22.7.4 + '@types/node': 20.17.24 fsevents: 2.3.3 jiti: 2.4.0 less: 4.2.2 @@ -37261,13 +35746,13 @@ snapshots: tsx: 4.19.2 yaml: 2.7.0 - vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0): + vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0): dependencies: esbuild: 0.25.4 postcss: 8.5.3 rollup: 4.34.9 optionalDependencies: - '@types/node': 20.17.24 + '@types/node': 22.7.4 fsevents: 2.3.3 jiti: 2.4.0 less: 4.2.2 @@ -37276,13 +35761,13 @@ snapshots: tsx: 4.19.2 yaml: 2.7.0 - vitefu@1.0.6(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)): + vitefu@1.0.6(vite@6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)): optionalDependencies: - vite: 6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.2.7(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) - vitefu@1.0.6(vite@6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)): + vitefu@1.0.6(vite@6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)): optionalDependencies: - vite: 6.0.3(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) + vite: 6.2.7(@types/node@22.7.4)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0) vitest@2.1.4(@edge-runtime/vm@5.0.0)(@types/node@20.17.24)(jsdom@24.0.0)(less@4.2.2)(msw@2.6.4(@types/node@20.17.24)(typescript@5.8.3))(sass@1.85.0)(terser@5.39.0): dependencies: @@ -37324,7 +35809,7 @@ snapshots: vitest@2.1.4(@edge-runtime/vm@5.0.0)(@types/node@20.17.24)(jsdom@26.0.0)(less@4.2.2)(msw@2.6.4(@types/node@20.17.24)(typescript@5.8.3))(sass@1.85.0)(terser@5.39.0): dependencies: '@vitest/expect': 2.1.4 - '@vitest/mocker': 2.1.4(msw@2.6.4(@types/node@20.17.24)(typescript@5.8.3))(vite@5.4.11(@types/node@20.17.24)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)) + '@vitest/mocker': 2.1.4(msw@2.6.4(@types/node@20.17.24)(typescript@5.8.3))(vite@5.4.11(@types/node@22.7.4)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)) '@vitest/pretty-format': 2.1.4 '@vitest/runner': 2.1.4 '@vitest/snapshot': 2.1.4 @@ -37405,7 +35890,7 @@ snapshots: '@vitest/spy': 3.0.7 '@vitest/utils': 3.0.7 chai: 5.2.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 expect-type: 1.1.0 magic-string: 0.30.17 pathe: 2.0.3 @@ -37436,17 +35921,17 @@ snapshots: - tsx - yaml - vitest@3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.6.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0): + vitest@3.0.7(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@20.17.24)(jiti@2.4.0)(jsdom@26.0.0)(less@4.2.2)(msw@2.7.0(@types/node@20.17.24)(typescript@5.8.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0): dependencies: '@vitest/expect': 3.0.7 - '@vitest/mocker': 3.0.7(msw@2.7.0(@types/node@20.17.24)(typescript@5.6.3))(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) + '@vitest/mocker': 3.0.7(msw@2.7.0(@types/node@20.17.24)(typescript@5.8.3))(vite@6.0.3(@types/node@20.17.24)(jiti@2.4.0)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)) '@vitest/pretty-format': 3.0.7 '@vitest/runner': 3.0.7 '@vitest/snapshot': 3.0.7 '@vitest/spy': 3.0.7 '@vitest/utils': 3.0.7 chai: 5.2.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 expect-type: 1.1.0 magic-string: 0.30.17 pathe: 2.0.3 @@ -37482,7 +35967,7 @@ snapshots: vscode-languageclient@7.0.0: dependencies: minimatch: 3.1.2 - semver: 7.7.1 + semver: 7.7.2 vscode-languageserver-protocol: 3.16.0 vscode-languageserver-protocol@3.16.0: @@ -37513,16 +35998,6 @@ snapshots: '@vue/devtools-api': 6.6.4 vue: 3.5.13(typescript@5.8.3) - vue@3.3.8(typescript@5.8.3): - dependencies: - '@vue/compiler-dom': 3.3.8 - '@vue/compiler-sfc': 3.3.8 - '@vue/runtime-dom': 3.3.8 - '@vue/server-renderer': 3.3.8(vue@3.3.8(typescript@5.8.3)) - '@vue/shared': 3.3.8 - optionalDependencies: - typescript: 5.8.3 - vue@3.5.13(typescript@5.8.3): dependencies: '@vue/compiler-dom': 3.5.13 @@ -37665,6 +36140,36 @@ snapshots: - esbuild - uglify-js + webpack@5.98.0: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.6 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.14.1 + browserslist: 4.25.1 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.17.1 + es-module-lexer: 1.6.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.2 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.14(webpack@5.98.0) + watchpack: 2.4.2 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + webpack@5.98.0(esbuild@0.25.4): dependencies: '@types/eslint-scope': 3.7.7 @@ -37869,8 +36374,6 @@ snapshots: yaml@2.4.2: {} - yaml@2.4.5: {} - yaml@2.5.0: {} yaml@2.7.0: {} diff --git a/tsconfig.json b/tsconfig.json index 806af97491e2..6d524fe2f329 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ { "path": "packages/anthropic" }, { "path": "packages/assemblyai" }, { "path": "packages/azure" }, + { "path": "packages/baseten" }, { "path": "packages/cerebras" }, { "path": "packages/codemod" }, { "path": "packages/cohere" }, @@ -36,6 +37,7 @@ { "path": "packages/revai" }, { "path": "packages/rsc" }, { "path": "packages/svelte" }, + { "path": "packages/test-server" }, { "path": "packages/togetherai" }, { "path": "packages/valibot" }, { "path": "packages/vercel" },