diff --git a/.changeset/ai-sdk-tools-next.md b/.changeset/ai-sdk-tools-next.md new file mode 100644 index 000000000..a9a455da0 --- /dev/null +++ b/.changeset/ai-sdk-tools-next.md @@ -0,0 +1,9 @@ +--- +"@voltagent/core": patch +--- + +Publish the latest AI SDK v7 tool compatibility updates on the `next` channel. + +Raw AI SDK tools remain first-class, including native `contextSchema` and call-level +`toolsContext`, while VoltAgent metadata can be attached out-of-band with +`withVoltAgentMetadata`. diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000..091428cd1 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,64 @@ +{ + "mode": "pre", + "tag": "next", + "initialVersions": { + "voltagent-example-github-repo-analyzer": "0.1.0", + "voltagent-example-github-star-stories": "0.0.0", + "voltagent-example-next-js-chatbot-starter-template": "0.1.0", + "ai-ad-generator": "0.1.2", + "voltagent-example-with-agent-tool": "1.0.0", + "assistant-ui-starter": "0.1.2", + "voltagent-example-with-chat-sdk": "0.1.0", + "voltagent-example-cloudflare-workers": "1.0.0", + "voltagent-example-with-composio-mcp": "0.1.0", + "voltagent-copilotkit-client": "0.0.1", + "voltagent-with-copilotkit-server": "0.0.3", + "voltagent-example-with-google-drive-mcp-client": "0.0.0", + "with-jwt-auth": "1.0.5", + "voltagent-example-with-lancedb": "1.0.0", + "example-with-live-evals": "0.0.5", + "voltagent-example-with-mcp": "0.1.0", + "voltagent-example-with-mcp-elicitation": "0.1.0", + "voltagent-example-with-memory-rest-api": "1.0.0", + "voltagent-example-with-nestjs": "1.0.0", + "voltagent-example-netlify-functions": "1.0.0", + "voltagent-example-with-nextjs": "0.1.0", + "voltagent-example-with-nextjs-resumable-stream": "0.1.0", + "voltagent-example-with-offline-evals": "0.0.0", + "voltagent-example-with-planagents": "0.1.0", + "voltagent-example-with-rag-chatbot": "0.0.1", + "voltagent-example-with-resumable-streams": "1.0.0", + "voltagent-example-with-voltops-resumable-streams": "1.0.0", + "voltagent-example-with-zapier-mcp": "1.0.0", + "@voltagent/a2a-server": "2.0.3", + "@voltagent/ag-ui": "1.0.7", + "@voltagent/cli": "0.1.21", + "@voltagent/cloudflare-d1": "2.1.2", + "@voltagent/core": "2.9.0", + "create-voltagent-app": "0.2.19", + "@voltagent/docs-mcp": "2.0.2", + "@voltagent/evals": "2.0.4", + "@voltagent/internal": "1.0.3", + "@voltagent/langfuse-exporter": "2.0.3", + "@voltagent/libsql": "2.1.2", + "@voltagent/logger": "2.0.2", + "@voltagent/mcp-server": "2.0.2", + "@voltagent/postgres": "2.1.2", + "@voltagent/rag": "1.0.2", + "@voltagent/resumable-streams": "2.0.2", + "@voltagent/sandbox-blaxel": "2.1.1", + "@voltagent/sandbox-daytona": "2.0.3", + "@voltagent/sandbox-e2b": "2.0.3", + "@voltagent/scorers": "2.1.0", + "@voltagent/sdk": "2.0.3", + "@voltagent/server-core": "2.1.19", + "@voltagent/server-elysia": "2.0.9", + "@voltagent/server-hono": "2.0.14", + "@voltagent/serverless-hono": "2.0.12", + "@voltagent/supabase": "2.1.3", + "@voltagent/vercel-ai-exporter": "2.0.2", + "@voltagent/voice": "2.1.0", + "@voltagent/voltagent-memory": "1.0.4" + }, + "changesets": ["ai-sdk-tools-next", "voltagent-3-next"] +} diff --git a/.changeset/voltagent-3-next.md b/.changeset/voltagent-3-next.md new file mode 100644 index 000000000..8bad4d1e2 --- /dev/null +++ b/.changeset/voltagent-3-next.md @@ -0,0 +1,341 @@ +--- +"@voltagent/a2a-server": major +"@voltagent/ag-ui": major +"@voltagent/cli": major +"@voltagent/cloudflare-d1": major +"@voltagent/core": major +"@voltagent/docs-mcp": major +"@voltagent/evals": major +"@voltagent/internal": major +"@voltagent/langfuse-exporter": major +"@voltagent/libsql": major +"@voltagent/logger": major +"@voltagent/mcp-server": major +"@voltagent/postgres": major +"@voltagent/rag": major +"@voltagent/resumable-streams": major +"@voltagent/sandbox-blaxel": major +"@voltagent/sandbox-daytona": major +"@voltagent/sandbox-e2b": major +"@voltagent/scorers": major +"@voltagent/sdk": major +"@voltagent/server-core": major +"@voltagent/server-elysia": major +"@voltagent/server-hono": major +"@voltagent/serverless-hono": major +"@voltagent/supabase": major +"@voltagent/vercel-ai-exporter": major +"@voltagent/voice": major +"@voltagent/voltagent-memory": major +"create-voltagent-app": major +--- + +Release the first VoltAgent 3 prerelease on the `next` channel. + +VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + +### Install from the next channel + +```bash +pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next +pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 +``` + +If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + +```bash +pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next +``` + +### Runtime requirements + +VoltAgent 3 requires Node.js 22+ and ESM imports. + +```json +{ + "type": "module", + "engines": { + "node": ">=22" + } +} +``` + +Before: + +```js +const { Agent } = require("@voltagent/core"); +const { openai } = require("@ai-sdk/openai"); +``` + +After: + +```ts +import { Agent } from "@voltagent/core"; +import { openai } from "@ai-sdk/openai"; +``` + +### AI SDK v7 alignment + +Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + +```bash +pnpm add ai@^7 @ai-sdk/provider-utils@^5 +pnpm add @ai-sdk/openai@^4 +``` + +Common provider package upgrades: + +| Package | Version for AI SDK v7 | +| --------------------------- | --------------------- | +| `@ai-sdk/openai` | `^4` | +| `@ai-sdk/anthropic` | `^4` | +| `@ai-sdk/google` | `^4` | +| `@ai-sdk/azure` | `^4` | +| `@ai-sdk/groq` | `^4` | +| `@ai-sdk/mistral` | `^4` | +| `@ai-sdk/openai-compatible` | `^3` | +| `@ai-sdk/amazon-bedrock` | `^5` | +| `@ai-sdk/google-vertex` | `^5` | + +### Zod 4-only + +VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + +```bash +pnpm add zod@^4 +``` + +### Agent usage + +The object-style call shape is the preferred API. VoltAgent 3 derives agent generation options from AI SDK v7 `generateText` and `streamText`, so AI SDK settings stay at the top level while VoltAgent runtime concerns live under `voltagent`. + +```ts +const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, +}); +``` + +AI SDK v7 options such as `timeout`, `headers`, `include`, `activeTools`, `toolOrder`, `experimental_download`, `onChunk`, and stream lifecycle callbacks can be used directly on VoltAgent calls: + +```ts +const result = await agent.streamText({ + prompt: "Write a release note for this changelog", + timeout: { + totalMs: 30_000, + chunkMs: 5_000, + }, + include: { + rawChunks: true, + }, + onChunk: async ({ chunk }) => { + console.log(chunk.type); + }, + voltagent: { + context: { + requestId: "req-789", + }, + }, +}); +``` + +VoltAgent composes the fields it must own for framework behavior: `model`, `prompt`/`messages`, `tools`, `abortSignal`, `maxRetries`, `onStepEnd`, `onEnd`/`onFinish`, and `onError`. User callbacks are still accepted at the top level and are invoked after VoltAgent memory, guardrails, hooks, tracing, and recovery handling. + +Top-level AI SDK `toolsContext` is passed through for native AI SDK tools that declare `contextSchema`. Top-level AI SDK `runtimeContext`, `telemetry`, and `experimental_telemetry` are intentionally not exposed. Use `voltagent.context` for per-call application context and VoltAgent observability/OpenTelemetry configuration for telemetry. + +The same shape works for streaming: + +```ts +const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, +}); + +for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } +} +``` + +`fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + +### Tool usage + +VoltAgent now accepts AI SDK-style tool sets directly. Raw AI SDK tools are first-class, so the recommended custom tool API is `tool()` from `ai`. Add VoltAgent-specific metadata with `withVoltAgentMetadata` when you need hooks, tags, API metadata, or display metadata. + +```ts +import { tool } from "ai"; +import { Agent } from "@voltagent/core"; +import { openai } from "@ai-sdk/openai"; +import { z } from "zod"; + +const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, +}); +``` + +Native AI SDK tool options such as `contextSchema` work unchanged with call-level `toolsContext`: + +```ts +const weather = tool({ + description: "Get weather for a city", + inputSchema: z.object({ city: z.string() }), + contextSchema: z.object({ + apiKey: z.string(), + defaultUnit: z.enum(["celsius", "fahrenheit"]), + }), + execute: async ({ city }, { context }) => { + return fetchWeather(city, { + apiKey: context.apiKey, + unit: context.defaultUnit, + }); + }, +}); + +await agent.generateText({ + prompt: "What is the weather in San Francisco?", + tools: { weather }, + toolsContext: { + weather: { + apiKey: process.env.WEATHER_API_KEY!, + defaultUnit: "fahrenheit", + }, + }, +}); +``` + +VoltAgent-specific tool metadata is optional and stored out-of-band so it is not sent to the model provider: + +```ts +import { tool } from "ai"; +import { withVoltAgentMetadata } from "@voltagent/core"; + +const refundCustomer = withVoltAgentMetadata( + tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + contextSchema: z.object({ + actorId: z.string(), + permissions: z.array(z.string()), + }), + execute: async ({ orderId, reason }, { context }) => { + if (!context.permissions.includes("refund:write")) { + throw new Error("Not allowed to refund orders"); + } + + return issueRefund({ + orderId, + reason, + actorId: context.actorId, + }); + }, + }), + { + name: "Refund Customer", + purpose: "Issue customer refunds", + tags: ["billing", "dangerous", "customer-support"], + metadata: { + owner: "payments-team", + riskLevel: "high", + }, + } +); +``` + +Register the tool under the canonical name the model should call: + +```ts +const agent = new Agent({ + name: "Support Agent", + model, + tools: { + refundCustomer, + }, +}); +``` + +The ToolSet key remains the canonical `tool.name` used for tool calls, approval, routing, and telemetry correlation. VoltAgent metadata `name` is display metadata and is emitted as `tool.display_name` for Console and observability consumers. + +`tool()` from `@voltagent/core` remains available as a convenience wrapper when inline `voltagent` metadata is preferred. `createTool` is now a legacy compatibility helper for existing class-style tools. + +### Tool approval + +AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + +```ts +const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, +}); +``` + +Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + +### Structured output + +Prefer AI SDK v7-style `output` over `experimental_output`. + +```ts +import { Output } from "ai"; +import { z } from "zod"; + +const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), +}); + +console.log(result.output); +``` + +`generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + +### Migration checklist + +1. Upgrade local development, CI, and production to Node.js 22 or later. +2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. +3. Upgrade all `@voltagent/*` packages together from the `next` channel. +4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. +5. Upgrade `zod` to `^4`. +6. Replace `stepCountIs` with `isStepCount`. +7. Prefer `result.stream` over `result.fullStream`. +8. Prefer `output` over `experimental_output`. +9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 308e7b873..772e996da 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -36,7 +36,7 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: "pnpm" - name: Install Dependencies run: pnpm install @@ -63,7 +63,7 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: "pnpm" - name: Install Dependencies run: pnpm install @@ -111,7 +111,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: 'pnpm' - name: Creating .npmrc @@ -151,6 +151,18 @@ jobs: env: DATABASE_URL: postgresql://test:test@localhost:5432/voltagent_test + - name: Verify Changesets prerelease mode + run: | + node <<'NODE' + const pre = require("./.changeset/pre.json"); + + if (pre.mode !== "pre" || pre.tag !== "next") { + throw new Error( + 'Expected Changesets prerelease mode with tag "next". Run "pnpm changeset pre enter next" on the next branch before publishing.', + ); + } + NODE + - name: Create Release Pull Request or Publish to npm id: changesets uses: changesets/action@v1 diff --git a/docs/ai-sdk-first-vnext-plan.md b/docs/ai-sdk-first-vnext-plan.md new file mode 100644 index 000000000..a515ede60 --- /dev/null +++ b/docs/ai-sdk-first-vnext-plan.md @@ -0,0 +1,1241 @@ +# AI SDK First vNext Plan + +Status: draft +Related issue: https://github.com/VoltAgent/voltagent/issues/1373 + +## Goal + +Make VoltAgent vNext feel native to AI SDK users at the public boundary while preserving the orchestration features that make VoltAgent a framework. + +The target principle: + +> AI SDK-native at the boundary, VoltAgent-native in orchestration. + +This means AI SDK primitives such as `model`, `prompt`, `messages`, `tools`, `output`, `stopWhen`, `providerOptions`, and stream responses should be the default mental model. VoltAgent-specific capabilities such as memory, subagents, workflows, observability, guardrails, middleware, tool routing, feedback, evals, MCP, A2A, AG-UI, and VoltOps must remain first-class. + +## Non-Goals + +- Do not flatten VoltAgent into a thin `ai` package wrapper. +- Do not remove current public APIs until compatibility wrappers, tests, docs, and codemods exist. +- Do not remove `generateObject` or `streamObject` in the first migration step. They should become deprecated wrappers first. +- Do not lose the `provider/model` router experience without an explicit replacement. +- Do not change stream event semantics without updating server, AG-UI, MCP, A2A, resumable streams, and docs together. +- Do not preserve CommonJS runtime compatibility in vNext after the AI SDK 7 upgrade. AI SDK 7 is ESM-only, so vNext should be ESM-only instead of adding a fragile CJS bridge. + +## vNext Platform Decision + +Decision: VoltAgent vNext will target AI SDK 7, Zod 4, Node.js 22 or later, and ESM-only package output. + +This is an explicit compatibility boundary: + +- Set the repository and published package engine requirement to `node >=22`. +- Set published Zod peer ranges to `^4.0.0` and remove Zod 3 fallback code paths. +- Remove CommonJS runtime exports from vNext packages that depend on AI SDK or packages that depend on those packages. +- Prefer `"type": "module"` and ESM package exports for new vNext package metadata. +- Keep TypeScript declaration output for ESM consumers. +- Treat CommonJS support as a previous-major compatibility concern, not a vNext requirement. + +Rationale: + +- AI SDK 7 requires Node.js 22 or later. +- AI SDK 7 packages are ESM-only and no longer support `require()`. +- VoltAgent core, server, memory, scorer, and protocol packages import AI SDK types and runtime helpers throughout the public surface. +- Keeping CJS exports while depending on ESM-only AI SDK packages would create runtime paths that compile but fail for CommonJS users. + +Migration consequence: + +- Users on Node.js 20 must stay on the previous VoltAgent major or upgrade Node before adopting vNext. +- Users using `require("@voltagent/core")` must migrate to ESM imports. +- Users pinned to Zod 3 must upgrade to Zod 4 before adopting VoltAgent 3. +- Docs, examples, package exports, and migration guide must call this out clearly. + +## Protected Feature Surface + +These features need parity tests before major refactors. + +| Area | Protected behavior | Key files | +| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | +| Agent calls | `generateText(input, options)`, `streamText(input, options)`, object output, hooks, feedback, abort, usage, finish reason | `packages/core/src/agent/agent.ts`, `packages/core/src/agent/types.ts` | +| Tools | VoltAgent tools, AI SDK tools, provider tools, client-side tools, toolkits, `needsApproval`, `toModelOutput`, output schema, tool hooks | `packages/core/src/tool`, `packages/core/src/tool/manager` | +| Tool routing | Pool/expose/search/call tools, embedding search, `enforceSearchBeforeCall` | `packages/core/src/tool/routing` | +| Subagents | `delegate_task`, supervisor prompt, parallel handoff, stream metadata, bail, parent context propagation | `packages/core/src/agent/subagent` | +| Memory V2 | recent history, semantic memory, working memory, conversation steps, message metadata persistence, title generation | `packages/core/src/memory`, `packages/core/src/agent/memory-persist-queue.ts` | +| Guardrails | input block/rewrite, output block/rewrite, streaming redaction, speculative input guardrails | `packages/core/src/agent/guardrail.ts`, `packages/core/src/agent/streaming` | +| Middleware | input/output middleware, abort, retry, retry hooks | `packages/core/src/agent/middleware.ts` | +| Observability | root/child spans, tool/memory/retriever/embedding/guardrail/middleware/llm spans, VoltOps sync, logs, feedback | `packages/core/src/agent/open-telemetry`, `packages/core/src/observability` | +| Evals | live eval payloads, tool calls/results, subagent metadata, scorer spans, VoltOps result sync | `packages/core/src/agent/eval.ts`, `packages/core/src/eval`, `packages/scorers` | +| Workflows | `andAgent`, typed output, usage aggregation, suspend/resume/replay, workflow state persistence, stream attach | `packages/core/src/workflow`, `packages/server-core/src/handlers/workflow.handlers.ts` | +| Server adapters | REST/SSE, UI message streams, resumable streams, serverless, Hono routes | `packages/server-core`, `packages/server-hono`, `packages/resumable-streams` | +| Protocol adapters | MCP agent/tool/workflow exposure, A2A send/stream/cancel, AG-UI event mapping | `packages/mcp-server`, `packages/a2a-server`, `packages/ag-ui` | +| Model routing | direct AI SDK models, dynamic model values, fallback arrays, retries, provider/model strings, embedding model strings | `packages/core/src/registries/model-provider-registry.ts` | +| Workspace | filesystem, sandbox, search, skills, prompt hook injection, workspace tool policies | `packages/core/src/workspace` | +| PlanAgent | planning toolkit, task tool, ephemeral subagents, filesystem/tool result eviction | `packages/core/src/planagent` | + +## Proposed Public API Direction + +### Object-style calls + +Add object-style overloads while preserving current calls: + +```ts +await agent.generateText({ + prompt: "Summarize this", + model, + tools, + output, + stopWhen, + providerOptions, + voltagent: { + userId, + conversationId, + memory, + guardrails, + middleware, + toolRouting, + feedback, + parentSpan, + }, +}); +``` + +Existing usage must still work: + +```ts +await agent.generateText("Summarize this", { + userId, + conversationId, + output, +}); +``` + +### Namespacing rule + +Keep AI SDK-compatible fields top-level. Move VoltAgent runtime concerns into `voltagent` in the new object-style API. + +Initial compatibility should accept both: + +```ts +await agent.generateText({ + prompt: "Hello", + conversationId: "legacy-compatible", +}); + +await agent.generateText({ + prompt: "Hello", + voltagent: { + conversationId: "preferred-vnext", + }, +}); +``` + +If both are supplied, `voltagent.*` should win and a dev-time deprecation warning can be emitted later. + +## Step-by-Step Implementation Plan + +### Phase 0: Baseline and Feature Parity Tests + +Objective: lock current behavior before changing API shape. + +1. Create a parity tracking issue or checklist. +2. Add focused tests for the protected feature surface. +3. Prefer narrow tests around public behavior instead of snapshotting internals. +4. Add type tests for overload compatibility. +5. Run package-level tests before each refactor slice. + +Suggested test additions: + +- `packages/core/src/agent/agent.spec.ts` + - object output still works through `generateText` with `output`. + - current positional API remains unchanged. + - `onStepEnd`, `onRetry`, `onFallback`, `onEnd`, and `onError` still fire. + - abort and bail do not become retry/fallback candidates. +- `packages/core/src/agent/agent.spec-d.ts` + - positional API type compatibility. + - new object-style API type inference. + - `output: Output.object(...)` result inference. +- `packages/core/src/tool/manager/ToolManager.spec.ts` + - VoltAgent tool to AI SDK tool conversion. + - provider tools pass through. + - client-side tools omit `execute`. + - `needsApproval`, `toModelOutput`, and `outputSchema` are preserved. +- `packages/core/src/agent/subagent/*.spec.ts` + - `delegate_task` injection. + - parallel handoff. + - bail returns subagent result without supervisor post-processing. + - subagent stream metadata is forwarded. +- `packages/core/src/memory/*.spec.ts` + - conversation messages and conversation steps persist. + - semantic memory merge behavior. + - working memory read/update/clear tools. +- `packages/core/src/agent/guardrail*.spec.ts` + - input block/rewrite. + - output block/rewrite. + - streaming redaction across chunk boundaries. +- `packages/server-core/src/handlers/agent.handlers.spec.ts` + - REST generate. + - raw fullStream SSE. + - UI message stream response. + - resumable stream setup and resume. +- `packages/mcp-server`, `packages/a2a-server`, `packages/ag-ui` + - adapters still compile and consume the same result contracts. +- `packages/core/src/workflow/*` + - `andAgent` typed output. + - workflow usage aggregation. + - suspend/resume/replay state persistence. + +Exit criteria: + +- Parity tests cover all high-risk surfaces. +- Existing public API tests pass. +- Type tests cover old and new intended signatures. + +Validation commands: + +```bash +pnpm test --filter @voltagent/core +pnpm test --filter @voltagent/server-core +pnpm test --filter @voltagent/mcp-server +pnpm test --filter @voltagent/a2a-server +pnpm test --filter @voltagent/ag-ui +pnpm lint +``` + +Progress: + +- [x] Added core Agent parity coverage for successful `generateText` structured output with `Output.object`. +- [x] Added type coverage for `generateText` structured output inference. +- [x] Added explicit positional API compatibility tests before object-style overloads. +- [x] Added tool manager parity tests for provider/client-side/approval/output conversion. +- [x] Added focused subagent stream metadata and bail parity tests. +- [x] Added memory step persistence and working memory parity tests. +- [x] Added server/protocol adapter stream contract tests. +- [x] Added e2e runtime coverage for AI SDK tools, VoltAgent tools, tool approval, structured output, middleware/guardrails, subagent delegation, Hono agent routes, working memory, and tool routing. +- [x] Expanded e2e coverage for server `options.voltagent` normalization, streamed server tool calls, approval denial, guardrail blocks, subagent streaming delegation, model fallback, tool hooks, tool-routing approval, and LibSQL working memory persistence. + +### Phase 1: Add Agent Request Normalization + +Objective: introduce the new API shape without changing behavior. + +1. Add new request types near the current Agent generation options. +2. Add a small normalization helper that converts both call styles into the existing internal shape. +3. Keep the current execution pipeline intact. +4. Do not change stream events in this phase. + +Proposed types: + +```ts +type VoltAgentRuntimeOptions = { + userId?: string; + conversationId?: string; + memory?: RuntimeMemoryConfig; + guardrails?: RuntimeGuardrailConfig; + middleware?: RuntimeMiddlewareConfig; + toolRouting?: ToolRoutingConfig | false; + feedback?: AgentFeedbackOptions | boolean; + parentSpan?: Span; + parentAgentId?: string; + context?: Map | Record; +}; + +type AgentGenerateTextRequest = { + prompt?: string; + messages?: UIMessage[] | ModelMessage[]; + model?: AgentModelValue; + tools?: ToolSet | Array; + output?: Output.Output; + stopWhen?: StopCondition | StopCondition[]; + providerOptions?: ProviderOptions; + voltagent?: VoltAgentRuntimeOptions; +} & Partial; +``` + +Implementation notes: + +- Normalize `prompt` and `messages` into the existing `input`. +- Normalize `voltagent.context` into `OperationContext.context`. +- Keep legacy top-level VoltAgent options for compatibility. +- Prefer `request.voltagent.*` over legacy top-level equivalents. +- Avoid changing `BaseGenerationOptions` semantics until tests are green. + +Candidate files: + +- `packages/core/src/agent/agent.ts` +- `packages/core/src/agent/types.ts` +- possibly `packages/core/src/agent/generation-normalizer.ts` + +Exit criteria: + +- New object-style calls work. +- Old positional calls work. +- No behavior changes in server/MCP/A2A/AG-UI packages. + +Progress: + +- [x] Added object-style `generateText` and `streamText` request types. +- [x] Added a shared normalizer for `{ prompt | messages, options, ...overrides }`. +- [x] Kept positional calls on the existing execution pipeline. +- [x] Added runtime coverage for object-style request normalization. +- [x] Added type coverage for object-style `generateText` structured output inference and `streamText` return types. +- [x] Added A2A, MCP, and AG-UI adapter contract tests to keep protocol calls positional. + +### Phase 2: Unify Structured Output Around AI SDK `output` + +Objective: make `generateText` and `streamText` the primary structured-output path. + +1. Ensure `generateText({ output: Output.object(...) })` is fully typed and documented. +2. Convert internal scorer usage from `generateObject(prompt, schema)` to `generateText({ prompt, output })`. +3. Convert server object endpoints internally to `output` while preserving endpoint behavior. +4. Keep `generateObject` and `streamObject` as deprecated wrappers. +5. Add deprecation docs and examples. + +Candidate files: + +- `packages/core/src/agent/agent.ts` +- `packages/server-core/src/handlers/agent.handlers.ts` +- `packages/scorers/src/llm/*.ts` +- `website/docs/agents/overview.md` + +Exit criteria: + +- `generateObject` and `streamObject` are compatibility wrappers. +- All internal packages use `output` where possible. +- Existing object endpoint responses remain stable. + +Progress: + +- [x] Routed `generateObject` internally through AI SDK `generateText` with `Output.object`. +- [x] Converted LLM scorers from `generateObject(prompt, schema)` to `generateText({ prompt, output })`. +- [x] Updated scorer test helpers for AI SDK v3 provider response normalization. +- [x] Converted server object endpoint internally to `generateText(input, { output })`. +- [x] Expanded core and server `streamObject` contract tests before stream refactor. +- [x] Converted `streamObject` internally to `streamText({ output: Output.object(...) })` while preserving the deprecated public wrapper. + +### Phase 3: Preserve and Clarify VoltAgent Runtime Options + +Objective: keep orchestration options explicit in the new API. + +1. Add `voltagent` namespace support for runtime options. +2. Keep legacy options as aliases. +3. Add runtime warnings only after docs and codemods exist. +4. Update `processAgentOptions` in server-core to accept both shapes. +5. Update OpenAPI schemas for new object-style payloads. + +Candidate fields for `voltagent`: + +- `userId` +- `conversationId` +- `context` +- `memory` +- `conversationPersistence` +- `messageMetadataPersistence` +- `semanticMemory` +- `guardrails` +- `middleware` +- `toolRouting` +- `feedback` +- `parentSpan` +- `parentAgentId` +- `requestHeaders` +- `resumableStream` + +Exit criteria: + +- New namespaced options work in core and server-core. +- Legacy options still work. +- Server request body schemas accept both during transition. + +Progress: + +- [x] Added core `voltagent` namespace types for runtime options. +- [x] Normalized `voltagent.*` into existing runtime options with `voltagent` taking precedence over legacy top-level fields. +- [x] Prevented VoltAgent-only runtime fields from leaking into AI SDK call options. +- [x] Updated server-core `processAgentOptions` and stream resumable handling to accept normalized `voltagent` options. +- [x] Added OpenAPI schema coverage for `options.voltagent`. +- [x] Added docs examples and migration notes for `voltagent` namespace. +- [ ] Add runtime warnings after docs and codemods exist. + +### Phase 4: Internal AI SDK First Execution Cleanup + +Objective: simplify internals around AI SDK primitives without losing VoltAgent orchestration. + +1. Keep `prepareExecution` as the main orchestration boundary. +2. Separate AI SDK call construction from VoltAgent runtime preparation. +3. Ensure AI SDK options are passed through only after removing VoltAgent-specific fields. +4. Keep VoltAgent retry/fallback in control by continuing to set AI SDK `maxRetries: 0` where needed. +5. Keep `createStepHandler`, step persistence, eval payload building, and trace updates intact. + +Important constraints: + +- Do not delegate retry/fallback fully to AI SDK unless `onRetry`, `onFallback`, span semantics, and model arrays are preserved. +- Do not replace VoltAgent stream wrappers unless guardrails, subagent metadata, server streams, and AG-UI mappings stay stable. +- Do not bypass `prepareTools`, tool hooks, or tool routing. + +Exit criteria: + +- Internal code is easier to reason about. +- Public behavior remains unchanged. +- Parity tests remain green. + +Progress: + +- [x] Extracted AI SDK call option normalization so VoltAgent runtime fields are stripped in one place before `generateText`/`streamText` calls. + +### Phase 5: Provider Dependency Decoupling (Deferred) + +Decision: defer provider dependency decoupling out of the current AI SDK-first vNext scope. +For this plan, keep existing `provider/model` string resolution and current provider dependency behavior +unchanged. + +Rationale: + +- `model: "openai/gpt-..."` is widely used across docs, examples, and templates. +- Moving the router or provider dependencies changes installation and migration behavior. +- The current vNext work is already focused on AI SDK-first execution, `output`, and runtime option compatibility. +- Provider decoupling should be handled as a separate proposal with its own migration plan. + +Future follow-up, not in this scope: + +- Revisit whether model router should remain in core or move to an optional package. +- Preserve string model and embedding resolution if the split happens later. +- Update `create-voltagent-app`, docs, and examples only as part of that separate effort. + +### Phase 6: Ecosystem Package Updates + +Objective: update all dependent packages to the new compatibility layer. + +Packages to verify: + +- `packages/server-core` +- `packages/server-hono` +- `packages/mcp-server` +- `packages/a2a-server` +- `packages/ag-ui` +- `packages/resumable-streams` +- `packages/scorers` +- `packages/evals` +- `packages/create-voltagent-app` +- `packages/cli` +- examples under `examples/` +- docs under `website/docs` + +Required checks: + +- Server routes accept old and new payloads. +- `toUIMessageStreamResponse` still works. +- Raw `fullStream` SSE remains stable. +- MCP agent/tool/workflow adapters still expose useful schemas. +- A2A streaming still emits task updates. +- AG-UI still maps stream events to UI events. +- Resumable stream helpers still persist and resume UI message streams. + +Exit criteria: + +- All first-party packages compile. +- All affected package tests pass. +- Examples are updated or compatibility-tested. + +Progress: + +- [x] Verified `packages/ag-ui`, `packages/a2a-server`, `packages/mcp-server`, `packages/server-core`, `packages/scorers`, `packages/evals`, and `packages/create-voltagent-app` with targeted tests. +- [x] Fixed `packages/resumable-streams` chat handler types so they no longer depend on `Agent.streamText` overload inference. +- [x] Added a local `packages/resumable-streams` Vitest config so its package test command exits cleanly when no tests are present. +- [x] Verified `packages/server-hono` with runtime tests, typecheck, build, and route typing boundary cleanup. +- [x] Verified `packages/cli` with test and build. +- [x] Verified website docs with a production build. +- [x] Scanned examples for affected Agent API calls; no updates required for legacy-compatible wrapper usage. + +### Phase 7: Documentation, Codemods, and Migration Guide + +Objective: make the transition understandable and low-risk. + +Docs to add/update: + +- vNext migration guide. +- Agent overview with object-style calls. +- Tools guide showing AI SDK tools and VoltAgent tools together. +- Structured output guide using `output`. +- Memory guide showing `voltagent.memory`. +- Subagents guide confirming unchanged orchestration behavior. +- Server API docs showing old/new request body compatibility. +- Provider/model router migration guide. + +Codemods to consider: + +1. Convert `agent.generateText(input, options)` to `agent.generateText({ prompt: input, ...options })` where safe. +2. Convert `generateObject(input, schema, options)` to `generateText({ prompt: input, output: Output.object({ schema }), ...options })`. +3. Move legacy runtime options into `voltagent`. +4. Rewrite provider imports if provider packages are decoupled. + +Exit criteria: + +- Migration guide includes before/after examples. +- Executable codemods are optional; documented migration recipes are available for common cases. +- Deprecated APIs have clear removal timeline. + +Progress: + +- [x] Expanded the 1.x to 2.x migration guide with object-style Agent calls, `options.voltagent`, and `output`-based structured generation examples. +- [x] Added a dedicated structured output guide using `generateText`/`streamText` with AI SDK `Output`. +- [x] Updated Agent overview examples for object-style structured output and `voltagent.memory`. +- [x] Updated memory docs to show `voltagent.memory` for per-call user/conversation scope. +- [x] Updated tools docs to show VoltAgent tools alongside AI SDK provider-defined tools. +- [x] Updated server API docs to prefer `options.voltagent.memory` while documenting legacy compatibility. +- [x] Added sub-agent compatibility guidance confirming orchestration behavior is unchanged. +- [x] Added model router migration note confirming `provider/model` strings remain in scope. +- [x] Deferred executable codemods for this slice because the repo has no existing codemod infrastructure; use documented migration recipes for the first beta and revisit a CLI codemod command separately. + +### Phase 8: Release Gates + +Objective: ship vNext safely. + +Required before beta: + +- Core parity suite green. +- Dependent packages green. +- Docs for new API available. +- Deprecation warnings reviewed. +- Provider router story decided. +- No known server/MCP/A2A/AG-UI stream regressions. + +Required before stable: + +- `pnpm test:all` +- `pnpm build:all` +- `pnpm lint` +- package publint checks where relevant. +- migration guide published. +- examples updated. + +Progress: + +- [x] `pnpm lint` exits successfully. Existing warnings remain for the broken `examples/with-workspace/skills/playwright-cli` symlink and pre-existing complexity warnings. +- [x] `pnpm build:all` succeeds for all 29 build targets. +- [x] Website production build succeeds with existing tweet/private route/browserslist warnings. +- [x] Added local Vitest configs for `packages/cloudflare-d1` and `packages/voltagent-memory`; targeted package tests now exit cleanly. +- [x] Verified `packages/sandbox-blaxel` directly and through `pnpm test:all`. +- [x] Updated stale `packages/server-elysia` provider tests to mock the Node HTTP server path instead of Elysia's Bun-oriented `app.listen`. +- [x] `pnpm test:all` succeeds for all 26 test targets. +- [x] `pnpm publint:all` succeeds for all 14 publint targets, with existing package metadata suggestions only. + +### Phase 9: AI SDK 7, Node 22, and ESM-only Runtime + +Objective: upgrade VoltAgent vNext to AI SDK 7 while making the runtime boundary explicit: Node.js 22 or later and ESM-only package output. + +Reference: + +- Official AI SDK 7 migration guide: https://ai-sdk.dev/docs/migration-guides/migration-guide-7-0 + +Key upstream changes to account for: + +- AI SDK 7 requires Node.js 22 or later. +- AI SDK 7 packages are ESM-only. +- `ai` moves to `^7`. +- `@ai-sdk/provider` moves to `^4`. +- `@ai-sdk/provider-utils` moves to `^5`. +- `@ai-sdk/react` moves to `^4`. +- Most provider packages move to a new major, but not all providers share the same major number. +- `CallSettings` is replaced by `LanguageModelCallOptions` plus request option types. +- `stepCountIs` is renamed to `isStepCount`. +- `streamText` result access changes from `fullStream` to `stream`. +- AI SDK lifecycle callbacks use `onEnd` and `onStepEnd` instead of `onFinish` and `onStepFinish`. +- AI SDK tool execution callbacks and tool context names changed. +- Deprecated structured output fields such as `experimental_output` are removed. +- Usage result shapes changed; final-step fields moved under `finalStep` for multi-step results. + +#### 9.1 Package and Runtime Boundary + +1. Update root `package.json` engines from `node >=20` to `node >=22`. +2. Update package-level engines if any package declares its own Node range. +3. Convert vNext published packages to ESM-only output where they directly or indirectly rely on AI SDK. +4. Remove or stop advertising `require` exports for vNext package entrypoints. +5. Add `"type": "module"` where package metadata needs it for ESM-only output. +6. Keep `.d.ts` declarations and ESM `types` exports stable for TypeScript users. +7. Review `tsup.config.ts` files and remove `cjs` from `format` for affected packages. +8. Keep package source TypeScript as `NodeNext`/ESM-compatible. + +Primary packages to update: + +- `packages/core` +- `packages/server-core` +- `packages/server-hono` +- `packages/server-elysia` +- `packages/serverless-hono` +- `packages/resumable-streams` +- `packages/scorers` +- `packages/ag-ui` +- `packages/a2a-server` +- `packages/mcp-server` +- memory packages that expose `UIMessage` types: + - `packages/libsql` + - `packages/postgres` + - `packages/supabase` + - `packages/cloudflare-d1` + - `packages/voltagent-memory` +- packages that build against `@voltagent/core` public types: + - `packages/evals` + - `packages/cli` + - `packages/create-voltagent-app` + - `packages/docs-mcp` + +Exit criteria: + +- No vNext package that depends on AI SDK publishes a CommonJS runtime export. +- `pnpm build:all` produces ESM artifacts and TypeScript declarations. +- `pnpm publint:all` passes against the new export maps. + +#### 9.2 Dependency Upgrade + +1. Update all first-party `package.json` files that depend on `ai` from `^6.0.0` to `^7.0.0`. +2. Update `@ai-sdk/provider-utils` peer/dev ranges from `4.x` or `^4.0.0` to `^5.0.0`. +3. Add or update `@ai-sdk/provider` ranges to `^4.0.0` where packages reference provider-level types directly. +4. Update first-party provider dependencies in `packages/core`: + +| Package | Current family | v7-compatible family | +| --------------------------- | -------------- | -------------------- | +| `@ai-sdk/amazon-bedrock` | `^3` | `^5` | +| `@ai-sdk/anthropic` | `^3` | `^4` | +| `@ai-sdk/azure` | `^3` | `^4` | +| `@ai-sdk/cerebras` | `^2` | `^3` | +| `@ai-sdk/cohere` | `^3` | `^4` | +| `@ai-sdk/deepinfra` | `^2` | `^3` | +| `@ai-sdk/gateway` | `^3` | `^4` | +| `@ai-sdk/google` | `^3` | `^4` | +| `@ai-sdk/google-vertex` | `^3` | `^5` | +| `@ai-sdk/groq` | `^3` | `^4` | +| `@ai-sdk/mistral` | `^3` | `^4` | +| `@ai-sdk/openai` | `^3` | `^4` | +| `@ai-sdk/openai-compatible` | `^2` | `^3` | +| `@ai-sdk/perplexity` | `^3` | `^4` | +| `@ai-sdk/togetherai` | `^2` | `^3` | +| `@ai-sdk/vercel` | `^2` | `^3` | +| `@ai-sdk/xai` | `^3` | `^4` | + +5. Update examples using `@ai-sdk/openai` from `^3` to `^4`. +6. Update examples using `@ai-sdk/react` from `^3` to `^4`. +7. Run `pnpm install --lockfile-only --no-frozen-lockfile` after package updates. +8. Check third-party provider compatibility: + - `ollama-ai-provider-v2` + - `workers-ai-provider` + - `@aihubmix/ai-sdk-provider` + - `@gitlab/gitlab-ai-provider` + - `@mymediset/sap-ai-provider` + +Exit criteria: + +- The lockfile resolves AI SDK 7 and provider v7-compatible packages consistently. +- No first-party package keeps an `ai@^6` peer or dev dependency unless explicitly documented as previous-major-only. +- Third-party provider incompatibilities are documented or isolated. + +#### 9.3 Run AI SDK v7 Codemods + +1. Run the official codemod on source packages first: + +```bash +npx @ai-sdk/codemod v7 packages/core/src packages/server-core/src packages/resumable-streams/src packages/scorers/src +``` + +2. Run it on protocol and server adapters: + +```bash +npx @ai-sdk/codemod v7 packages/ag-ui/src packages/a2a-server/src packages/mcp-server/src packages/server-hono/src packages/server-elysia/src +``` + +3. Run it on examples only after core package builds: + +```bash +npx @ai-sdk/codemod v7 examples +``` + +4. Review every codemod diff manually. Do not accept broad semantic rewrites without checking VoltAgent compatibility. +5. Avoid running codemods over generated files, changelogs, archived deprecated package docs, or built artifacts. + +Exit criteria: + +- Codemod changes are reviewed and scoped. +- No generated or historical changelog content is accidentally rewritten. + +#### 9.4 Core Compatibility Layer + +Objective: move VoltAgent's AI SDK-facing public API to v7 names while keeping existing VoltAgent runtime behavior intact. + +1. Replace AI SDK `CallSettings` usage with the new v7 call option types. +2. Use AI SDK 7 callback names on the public Agent surface: + - `hooks.onStepEnd` + - `onEnd` for AI SDK stream/UI callbacks + - keep `needsApproval` on VoltAgent tools for backward compatibility +3. Pass AI SDK 7 callback names through at the AI SDK call boundary: + - VoltAgent `onStepEnd` → AI SDK `onStepEnd` + - VoltAgent stream `onEnd` → AI SDK `onEnd` +4. Replace internal `stepCountIs` imports and exports with `isStepCount`. +5. Export `isStepCount`; do not keep a public `stepCountIs` alias for vNext. +6. Adapt `fullStream` handling: + - internally consume AI SDK `stream` + - expose VoltAgent `stream` as the primary detailed event stream + - keep a deprecated `fullStream` alias only where it is low-cost during the transition + - keep server raw-stream endpoint semantics stable while consuming `stream` +7. Adapt result shape reads: + - inspect `usage`, `finishReason`, `text`, `toolCalls`, `toolResults`, and `steps` + - use `finalStep` where AI SDK v7 moves final-step-only fields +8. Remove any remaining `experimental_output` handling from active code paths. +9. Review tool execution options: + - update `ToolExecutionOptions` imports from provider-utils v5 + - map VoltAgent `needsApproval` to AI SDK 7 tool approval semantics where raw AI SDK tools are passed through + - keep VoltAgent tool approval behavior stable for existing users +10. Review tool context: + - replace AI SDK `experimental_context` assumptions with v7 `context`/`runtimeContext` semantics + - keep VoltAgent `OperationContext` separate from AI SDK runtime context +11. Update Google provider type names: + - replace `GoogleGenerativeAIProviderOptions` with v7-compatible Google provider option names + - update model provider registry builder names if provider exports changed + +Candidate files: + +- `packages/core/src/agent/agent.ts` +- `packages/core/src/agent/types.ts` +- `packages/core/src/agent/providers/base/types.ts` +- `packages/core/src/tool/index.ts` +- `packages/core/src/tool/manager/ToolManager.ts` +- `packages/core/src/workspace/tool-policy.ts` +- `packages/core/src/index.ts` +- `packages/core/src/registries/model-provider-registry.ts` +- `packages/core/src/registries/model-provider-registry.generated.ts` +- `packages/core/src/utils/usage-normalizer.ts` +- `packages/core/src/utils/usage-converter.ts` +- `packages/core/src/utils/message-converter.ts` + +Exit criteria: + +- Core typecheck passes. +- Core runtime tests pass. +- Public VoltAgent compatibility tests for `fullStream`, hooks, structured output, tool approval, and usage pass. + +#### 9.4.1 AI SDK-Style ToolSet Support + +Objective: support the user's requested direct AI SDK `tool()` usage while preserving VoltAgent-only tool features. + +Public API direction: + +```ts +import { tool } from "@voltagent/core"; + +const agent = new Agent({ + name: "assistant", + model, + instructions: "You are a helpful assistant.", + tools: { + get_weather: tool({ + description: "Get weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => ({ city, temperature: 72 }), + voltagent: { + tags: ["weather"], + needsApproval: true, + hooks: { + onStart: async ({ args }) => { + console.log(args); + }, + }, + }, + }), + }, +}); +``` + +Implementation plan: + +1. Re-export an AI SDK-compatible `tool()` helper from `@voltagent/core`. +2. Keep the returned value a regular AI SDK tool so it can be used anywhere AI SDK expects a tool. +3. Store `voltagent` metadata out-of-band so it is not passed to model providers. +4. Accept `ToolSet` records in `AgentOptions.tools`, dynamic tools, and per-call tools. +5. Let ToolSet object keys provide tool names, matching AI SDK conventions. +6. Preserve VoltAgent features for AI SDK tools: + - `voltagent.tags` + - `voltagent.needsApproval` + - `voltagent.hooks` + - `outputSchema` + - `providerOptions` + - `toModelOutput` + - observability spans + - agent-level `onToolStart`, `onToolEnd`, and `onToolError` +7. Keep existing `createTool` working as a compatibility API. +8. Update tool routing and API exposure to understand named AI SDK tools. +9. Add focused tests for ToolManager preparation and Agent hook execution. +10. Document migration from `createTool({ name, parameters })` to `tool({ inputSchema })` inside a ToolSet. +11. Support AI SDK v7 native call-level `toolApproval` and pass it through to `generateText`/`streamText`. +12. Let tool routing read the same `toolApproval` policy before executing hidden pool tools through `callTool`. + +Exit criteria: + +- `tools: { name: tool(...) }` works on `new Agent(...)`. +- Runtime and dynamic tools accept both arrays of VoltAgent tools and AI SDK `ToolSet` records. +- Tool hooks, agent hooks, tags, approval metadata, and output validation are preserved. +- Native `toolApproval` works for normal AI SDK tool execution and is enforced for tool routing pool calls. +- Existing `createTool` tests keep passing. +- Migration guide explains the new preferred tool style. + +#### 9.5 Server, Protocol, and Ecosystem Compatibility + +1. Update server raw stream handling to consume VoltAgent-compatible `fullStream` or the new AI SDK `stream` wrapper. +2. Keep REST and SSE response semantics stable. +3. Verify UI message stream helpers still work in server-core and resumable streams. +4. Update AG-UI to consume the stream alias without depending on removed AI SDK fields. +5. Update A2A and MCP tests to compile against the new core result contracts. +6. Update scorers to keep using `generateText({ output })`. +7. Update memory packages that import `UIMessage` types. +8. Update e2e message persistence tests for AI SDK v7 message part shape changes. + +Candidate files: + +- `packages/server-core/src/handlers/agent.handlers.ts` +- `packages/server-core/src/utils/options.ts` +- `packages/server-core/src/schemas/agent.schemas.ts` +- `packages/resumable-streams/src/chat-handlers.ts` +- `packages/ag-ui/src/voltagent-agent.ts` +- `packages/a2a-server/src` +- `packages/mcp-server/src` +- `packages/scorers/src` +- `packages/*/src/*memory*` + +Exit criteria: + +- Targeted tests pass for server-core, server-hono, server-elysia, AG-UI, A2A, MCP, resumable-streams, scorers, and memory packages. +- Raw SSE, UI message stream, resumable stream, AG-UI, MCP, and A2A contracts remain covered by tests. + +#### 9.6 Docs, Examples, and Migration Guide + +1. Add a migration guide section for: + - Node.js 22 minimum + - ESM-only imports + - removal of CommonJS `require` support + - AI SDK 7 package versions + - `stepCountIs` → `isStepCount` + - AI SDK `fullStream` → `stream` + - lifecycle callback rename to `onEnd` / `onStepEnd` + - tool approval compatibility +2. Update installation snippets: + - `ai@^7` + - `@ai-sdk/openai@^4` + - `@ai-sdk/react@^4` where UI hooks are used +3. Update examples to ESM-only assumptions. +4. Update `create-voltagent-app` templates. +5. Update docs that mention Node.js 20 support. +6. Avoid rewriting old changelog entries except adding a new vNext migration entry. + +Candidate files: + +- `website/docs/getting-started/migration-guide.md` +- `website/docs/getting-started/model-router.md` +- `website/docs/agents/overview.md` +- `website/docs/agents/structured-output.md` +- `website/docs/api/endpoints/agents.md` +- `packages/create-voltagent-app` +- `examples/*/package.json` + +Exit criteria: + +- Users can follow the migration guide from VoltAgent 2.x/AI SDK 6 to vNext/AI SDK 7. +- Website build succeeds. + +#### 9.6.1 Follow-up Audit: Remaining v2 Usage in Examples and website/docs + +Audit scope: + +- `examples` +- `website/docs` +- Exclude historical `CHANGELOG.md` files unless they are copied into live docs. + +Current finding: the first migration pass updated the core API docs and migration guide, but many live examples and topic docs still show v2-era usage. These should be cleaned before promoting the 3.x next release beyond early validation. + +1. Replace preferred tool examples from `createTool` to AI SDK-style `tool()`. + + Update live docs and examples so new code imports `tool` from `@voltagent/core`, uses `inputSchema`, and registers tools as a `ToolSet` object: + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { z } from "zod"; + + const tools = { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => ({ city, temperature: 72 }), + voltagent: { + tags: ["weather"], + }, + }), + }; + + const agent = new Agent({ + name: "assistant", + model: "openai/gpt-4o-mini", + tools, + }); + ``` + + Keep `createTool` only in migration/deprecation sections that explicitly explain legacy compatibility. + + Priority docs: + - `website/docs/agents/overview.md` + - `website/docs/agents/tools.md` + - `website/docs/tools/overview.md` + - `website/docs/tools/tool-routing.md` + - `website/docs/agents/context.md` + - `website/docs/agents/hooks.md` + - `website/docs/agents/cancellation.md` + - `website/docs/agents/dynamic-agents.md` + - `website/docs/agents/plan-agent.md` + - `website/docs/agents/mcp/mcp-server.md` + - `website/docs/integrations/nextjs.md` + - `website/docs/ui/assistant-ui.md` + - `website/docs/ui/copilotkit.md` + - `website/docs/workspaces/overview.md` + - `website/docs/workflows/steps/and-agent.md` + - `website/docs/workflows/steps/and-then.md` + - `website/docs/observability/logging.md` + + Priority examples: + - `examples/with-tools` + - `examples/with-tool-routing` + - `examples/with-client-side-tools` + - `examples/next-js-chatbot-starter-template` + - `examples/with-nextjs` + - `examples/with-nextjs-resumable-stream` + - `examples/with-assistant-ui` + - `examples/with-copilotkit` + - `examples/with-mcp-server` + - `examples/with-mcp-elicitation` + - `examples/with-a2a-server` + - `examples/with-playwright` + - `examples/with-whatsapp` + - `examples/with-ad-creator` + - `examples/github-repo-analyzer` + - `examples/github-star-stories` + - `examples/with-voltagent-exporter` + - `examples/with-langfuse` + - `examples/with-voltagent-actions` + +2. Update old tool field names in docs and examples. + + Replace v2-style tool fields in preferred examples: + - `parameters` -> `inputSchema` + - `name` inside the tool definition -> object key in the `tools` object + - VoltAgent-only tool metadata -> `voltagent` + - tool execution context access from `execute` -> AI SDK execution options or `voltagent.hooks` + + Do not rewrite workflow step schemas that intentionally use `inputSchema`; those are not tool API leftovers. + + Code/API follow-up found during audit: + - `ToolRoutingConfig.pool` and `ToolRoutingConfig.expose` currently accept arrays of class-style tools/toolkits/provider tools, but not named AI SDK `ToolSet` records. Do not convert tool-routing docs to `tool()` + object syntax until the type/runtime support exists. + - `createToolkit` can type-accept AI SDK tool objects, but array registration cannot infer names from a `ToolSet` key. Keep toolkit docs marked as compatibility-only until toolkit APIs support named AI SDK tools directly. + +3. Update agent docs for AI SDK compatibility boundaries. + + Add or expand a short section in agent docs explaining: + - AI SDK generation settings mostly pass through. + - VoltAgent owns `runtimeContext`, `toolsContext`, `telemetry`, `experimental_telemetry`, `maxRetries`, `abortSignal`, lifecycle callback composition, model resolution, messages, tools, and structured output wiring. + - Use VoltAgent `context`, `memory`, `voltagent` runtime options, hooks, and OpenTelemetry instead of AI SDK `runtimeContext`, `toolsContext`, or `telemetry`. + + Priority docs: + - `website/docs/agents/overview.md` + - `website/docs/agents/context.md` + - `website/docs/agents/hooks.md` + - `website/docs/getting-started/migration-guide.md` + - `website/docs/agents/tools.md` should link back to the agent-level ownership section. + +4. Normalize memory examples to the 3.x preferred envelope. + + Preferred new-code shape: + + ```ts + await agent.generateText("Continue the conversation", { + memory: { + userId: "user-123", + conversationId: "thread-456", + options: { + contextLimit: 10, + }, + }, + }); + ``` + + Update user-facing examples that still show top-level `userId`, `conversationId`, `contextLimit`, `semanticMemory`, `conversationPersistence`, or `messageMetadataPersistence`. Keep top-level fields only in migration sections, compatibility notes, REST API schema examples, or UI request payload examples where the HTTP contract still uses those names. + + Priority docs: + - `website/docs/agents/overview.md` + - `website/docs/agents/context.md` + - `website/docs/agents/memory.md` + - `website/docs/agents/memory/overview.md` + - `website/docs/agents/memory/in-memory.md` + - `website/docs/agents/memory/working-memory.md` + - `website/docs/agents/memory/semantic-search.md` + - `website/docs/agents/message-types.md` + - `website/docs/agents/resumable-streaming.md` + - `website/docs/rag/custom-retrievers.md` + + Priority examples: + - `examples/with-mcp-elicitation/src/index.ts` + - `examples/with-nextjs-resumable-stream` + - `examples/with-assistant-ui/app/api/chat/route.ts` + - `examples/with-whatsapp` + - `examples/with-vector-search/src/index.ts` + - `examples/with-workflow/src/index.ts` + - `examples/with-workflow-chain/src/index.ts` + +5. Update structured-output language and examples for VoltAgent 3.x. + + Replace live docs that say "`generateObject` and `streamObject` are deprecated in VoltAgent 2.x" with 3.x wording: + - `generateObject` and `streamObject` remain deprecated compatibility wrappers in 3.x. + - New code should use `generateText` or `streamText` with `output: Output.object(...)`. + + Priority files: + - `website/docs/agents/overview.md` + - `website/docs/agents/structured-output.md` + - `website/docs/agents/multi-modal.md` + - `website/docs/agents/hooks.md` + - `website/docs/agents/middleware.md` + - `website/docs/agents/subagents.md` + - `website/docs/agents/providers.md` + - `examples/with-live-evals/src/index.ts` + - `examples/with-offline-evals/src/experiments/scorers.ts` + + Do not change direct AI SDK `generateObject` calls used for dataset generation unless they are intended to demonstrate VoltAgent agent APIs. + +6. Update Node.js, ESM, and package version references. + + Replace Node.js 18/20 requirements in live examples and docs with Node.js 22+ for VoltAgent 3.x. + + Priority files found by audit: + - `website/docs/getting-started/quick-start.md` + - `website/docs/rag/pinecone.md` + - `website/docs/rag/qdrant.md` + - `website/docs/rag/chroma.md` + - `website/docs/rag/lancedb.md` + - `examples/with-zapier-mcp/README.md` + - `examples/with-mcp-server/README.md` + - `examples/with-amazon-bedrock/README.md` + - `examples/with-recipe-generator/README.md` + - `examples/with-planagents/README.md` + - `examples/with-anthropic/README.md` + - `examples/with-a2a-server/README.md` + - `examples/with-cerbos/README.md` + - `examples/with-chat-sdk/README.md` + - `examples/with-research-assistant/README.md` + - `examples/with-hugging-face-mcp/README.md` + - `examples/with-cloudflare-workers/README.md` + - `examples/with-voltagent-managed-memory/README.md` + - `examples/with-lancedb/README.md` + - `examples/with-nestjs/README.md` + - `examples/with-ad-creator/README.md` + - `examples/with-summarization/README.md` + - `examples/with-composio-mcp/README.md` + - `examples/with-netlify-functions/README.md` + - `examples/with-openrouter/README.md` + - `examples/with-mcp-elicitation/README.md` + + Package/version cleanup found by audit: + - `examples/with-client-side-tools/package.json` uses legacy `@voltagent/vercel-ai` and `@voltagent/vercel-ui`. These can be removed immediately because the example does not import them. + - `examples/with-a2a-server/package.json` uses `@voltagent/internal@^2.0.0-next.0`. + - `examples/with-airtable/package.json` uses `@voltagent/internal@^2.0.0-next.0`. + - `examples/with-nextjs-resumable-stream/package.json` uses `@voltagent/internal@^2.0.0-next.0`. + - `examples/with-copilotkit/server/package.json` uses `@voltagent/ag-ui@^2.0.0-next.0`. + - `examples/with-voltagent-managed-memory/package.json` uses `@voltagent/voltagent-memory@^2.0.0-next.0`. + - Keep workspace package ranges that still point at local `2.0.0-next.0` packages until the changeset version step bumps those packages. Moving them to `^3.0.0-next.0` before versioning breaks local `pnpm install` because the workspace package versions do not satisfy the range yet. + - `examples/with-playwright/tsconfig.json` still sets `"module": "CommonJS"`. + +7. Review legacy provider documentation. + + `website/docs/getting-started/providers-models.md` still contains an older native-provider migration section. Keep it only as a clearly labeled historical migration note and make the current 3.x recommendation direct AI SDK providers/model strings. + + `website/docs/community/contributing.md` mentions deprecated provider packages; verify the wording still matches the 3.x package policy. + +8. Telemetry docs cleanup. + + Ensure live docs do not imply AI SDK `telemetry` can be passed through `Agent` or `tool()`. The correct 3.x guidance is: + - Use VoltAgent OpenTelemetry/observability for Agent calls and VoltAgent-managed tools. + - Use AI SDK telemetry only when calling AI SDK directly outside VoltAgent. + - Provider-defined tools are passed through and may have provider-owned observability semantics. + + Priority docs: + - `website/docs/observability/overview.md` + - `website/docs/observability/logging.md` + - `website/docs/integrations/vercel-ai.md` + - `website/docs/agents/overview.md` + - `website/docs/agents/tools.md` + +Validation search gates after cleanup: + +```bash +rg -n "createTool" examples website/docs --glob '!**/CHANGELOG.md' +rg -n "parameters:\\s*z\\." examples website/docs --glob '!**/CHANGELOG.md' +rg -n "deprecated in VoltAgent 2\\.x|AI SDK v6|vNext|vnext" website/docs examples --glob '!**/CHANGELOG.md' +rg -n "Node\\.js 18|Node\\.js 20|Node 18|Node 20|v18 or|v20 or" website/docs examples --glob '!**/CHANGELOG.md' +rg -n "@voltagent/(internal|ag-ui|voltagent-memory|vercel-ai|vercel-ui).*\\\"[~^]?[12]\\." examples/**/package.json +rg -n "\"module\": \"CommonJS\"" examples/**/tsconfig.json +``` + +Expected exceptions: + +- `website/docs/getting-started/migration-guide.md` may intentionally contain legacy before/after snippets. +- Historical changelogs should not be rewritten. +- Direct AI SDK examples can still use AI SDK-native APIs when they are not demonstrating VoltAgent agent wrappers. +- REST API schema examples may still expose `userId` and `conversationId` if those are part of the HTTP contract. + +Exit criteria: + +- Preferred docs use `tool()` plus `inputSchema`. +- New examples do not recommend `createTool`. +- Agent docs clearly explain VoltAgent-owned AI SDK fields and telemetry ownership. +- New-code memory examples use the `memory` envelope. +- Structured-output docs say 3.x compatibility wrappers, not 2.x deprecation. +- Live prerequisites say Node.js 22+ for VoltAgent 3.x. +- Example package manifests do not depend on old VoltAgent 1.x/2.x companion packages. +- Website build succeeds after the cleanup. + +#### 9.7 Validation Gates for AI SDK 7 + +Run these after the v7 migration work, even though Phase 8 was already green before this new scope: + +```bash +pnpm lint +pnpm build:all +pnpm test:all +pnpm publint:all +pnpm --dir website build +``` + +Additional targeted checks: + +```bash +pnpm --filter @voltagent/core typecheck +pnpm --filter @voltagent/core test +pnpm --filter @voltagent/server-core typecheck +pnpm --filter @voltagent/server-core test +pnpm --filter @voltagent/server-hono typecheck +pnpm --filter @voltagent/server-hono test +pnpm --filter @voltagent/server-elysia test +pnpm --filter @voltagent/ag-ui test +pnpm --filter @voltagent/a2a-server test +pnpm --filter @voltagent/mcp-server test +pnpm --filter @voltagent/resumable-streams test +pnpm --filter @voltagent/scorers test +``` + +Progress: + +- [x] Decision made: vNext targets Node.js `>=22` and ESM-only. +- [x] Package/runtime metadata updated for Node.js 22 and ESM-only. +- [x] AI SDK dependencies upgraded to v7-compatible ranges. +- [x] AI SDK v7 codemods applied and reviewed. +- [x] Core AI SDK boundary updated for v7 call options, stream result shape, callback names, usage shape, and tool approval. +- [x] Added AI SDK-style `tool()` support with a VoltAgent metadata namespace and direct `ToolSet` support. +- [x] Added native AI SDK `toolApproval` pass-through and tool routing policy enforcement. +- [x] Server/protocol/ecosystem packages updated. +- [x] Initial migration guide, core docs, and templates updated for AI SDK 7, Node.js 22, and ESM-only. +- [x] Follow-up audit cleanup started: core agent/tool docs, selected safe ToolSet examples, Node.js 22 README/docs references, and legacy `@voltagent/vercel-*` example dependencies. +- [ ] Follow-up audit cleanup for remaining v2-era examples and website docs is complete. +- [x] `pnpm --filter @voltagent/core typecheck` passes. +- [x] `pnpm --filter @voltagent/core test` passes. +- [x] `pnpm --filter @voltagent/e2e exec vitest run --config vitest.config.mts src/agent-runtime.e2e.spec.ts` passes. +- [x] `pnpm --filter @voltagent/e2e exec vitest run --config vitest.config.mts src/message-persistence.libsql.e2e.spec.ts` passes. +- [x] `pnpm --filter @voltagent/e2e lint` passes. +- [x] `pnpm build:all` passes. +- [x] `pnpm lint` passes with existing warnings only. +- [ ] Remaining release gates: `pnpm test:all`, `pnpm publint:all`, and `pnpm --dir website build`. +- [ ] AI SDK 7 validation gates pass. + +## Suggested PR Slices + +1. Parity tests only. +2. Object-style type definitions and request normalizer. +3. Core `generateText` and `streamText` overload support. +4. `output`-first structured generation and deprecated object wrappers. +5. Server-core request/schema compatibility. +6. Scorers/evals migration to `output`. +7. MCP/A2A/AG-UI/resumable verification and fixes. +8. Docs and codemods. +9. Cleanup and deprecation warnings. +10. Node.js 22 and ESM-only package boundary. +11. AI SDK 7 dependency upgrade and codemod review. +12. AI SDK 7 core compatibility layer. +13. AI SDK-style `tool()` and direct `ToolSet` support. +14. AI SDK 7 server/protocol/ecosystem compatibility. +15. AI SDK 7 docs, examples, templates, and release gates. + +Each PR should include focused tests and avoid mixing refactors with behavior changes. + +## Open Decisions + +1. Should the namespace be called `voltagent`, `runtime`, or `metadata`? + - Current recommendation: `voltagent`, because it is explicit and avoids collisions with AI SDK fields. +2. Should `provider/model` string resolution remain in `@voltagent/core`? + - Current plan decision: yes. Keep the existing behavior unchanged for this scope; provider dependency decoupling is deferred. +3. Should `generateObject` and `streamObject` be removed in vNext or later? + - Current recommendation: deprecate in vNext, remove only in a later major. +4. Should stream part metadata remain VoltAgent-extended AI SDK parts or move to custom wrapper events? + - Current recommendation: keep current semantics until server/AG-UI/MCP/A2A have explicit compatibility layers. +5. How aggressive should codemods be? + - Current decision: defer executable codemods for this slice. If added later, keep them conservative and add TODO comments for ambiguous cases. +6. Should VoltAgent vNext preserve Node.js 20 support? + - Current decision: no. AI SDK 7 requires Node.js 22 or later, so vNext requires `node >=22`. +7. Should VoltAgent vNext preserve CommonJS runtime exports? + - Current decision: no. AI SDK 7 is ESM-only, so vNext should publish ESM-only runtime entrypoints instead of maintaining brittle CommonJS wrappers. + +## Risk Register + +| Risk | Impact | Mitigation | +| ---------------------------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------- | +| Stream part changes break AG-UI/server/resumable streams | High | Add stream contract tests before refactor | +| AI SDK 7 `stream` rename breaks VoltAgent `fullStream` consumers | High | Use `stream` in docs/server code and keep a deprecated `fullStream` alias during transition | +| AI SDK 7 callback renames break hooks | High | Rename public hooks to `onEnd`/`onStepEnd` for vNext and document the breaking change | +| Tool approval semantics regress during `needsApproval` migration | High | Preserve VoltAgent tool normalization and map to AI SDK 7 approval semantics in one place | +| Tool metadata lost when accepting raw AI SDK tools | High | Preserve VoltAgent tool normalization and manager APIs | +| Memory step persistence silently regresses | High | Add tests around conversation steps and subagent metadata | +| Guardrail streaming redaction breaks across chunk boundaries | High | Keep streaming guardrail tests and runner isolated | +| Model retry/fallback behavior changes | High | Keep VoltAgent retry loop and add retry/fallback tests | +| CommonJS users break on vNext | High | Make ESM-only and Node.js 22 requirements explicit in package metadata and migration docs | +| Package exports or publint fail after removing CJS output | High | Update export maps package-by-package and run `pnpm publint:all` | +| Zod 3 compatibility fallback hides broken app dependencies | Medium | Make VoltAgent 3 Zod 4-only in peer deps, examples, templates, docs, and converter code paths | +| Third-party providers are not AI SDK 7 compatible | Medium | Audit third-party providers, document incompatibilities, and isolate unsupported provider builders | +| Provider dependency decoupling expands scope | Medium | Deferred; keep existing router and provider dependency behavior unchanged in this plan | +| Server request schemas diverge from core API | Medium | Update schemas and processAgentOptions in same slice | +| Deprecated wrappers become maintenance burden | Medium | Keep wrappers thin and document removal timeline | +| Docs/examples accidentally show AI SDK 6 or CommonJS patterns | Medium | Update migration guide, templates, and examples after package migration | + +## Working Checklist + +- [ ] Phase 0 parity tests are merged. +- [ ] Phase 1 object-style request normalizer is merged. +- [ ] Phase 2 structured output uses `output` internally. +- [ ] Phase 3 `voltagent` namespace compatibility is merged. +- [ ] Phase 4 internal execution cleanup is merged. +- [x] Phase 5 provider dependency decoupling is deferred out of this plan. +- [x] Phase 6 ecosystem packages are updated. +- [x] Phase 7 docs are available; executable codemods are deferred to a separate follow-up. +- [x] Phase 8 release gates are green. +- [ ] Phase 9 AI SDK 7, Zod 4, Node.js 22, ESM-only, and AI SDK-style tool support is complete. + +## Current Recommendation + +Proceed in this order: + +1. Protect behavior with tests. +2. Add the new object-style API as a compatibility layer. +3. Move structured output to `output`. +4. Namespace VoltAgent runtime options. +5. Refactor internals after behavior is locked. +6. Keep provider routing unchanged in this scope. +7. Finish docs/codemod decisions and run release gates. +8. Apply the Node.js 22 and ESM-only package boundary. +9. Upgrade AI SDK dependencies to v7-compatible ranges. +10. Move Zod support to Zod 4-only across peers, examples, templates, and compatibility code. +11. Run and review AI SDK v7 codemods. +12. Update the core AI SDK boundary for v7 option, stream, callback, usage, and tool approval changes. +13. Add AI SDK-style `tool()` and direct `ToolSet` support while preserving VoltAgent tool features. +14. Update server, protocol, memory, scorer, docs, examples, and templates. +15. Re-run the full release gates for the AI SDK 7 scope. + +This order keeps the vNext direction moving while minimizing the chance of losing existing framework features. Phase 8 was green before the AI SDK 7 scope was added; Phase 9 intentionally reopens the release-gate work for the new runtime and dependency boundary. diff --git a/examples/base/package.json b/examples/base/package.json index e28668599..75811b9c6 100644 --- a/examples/base/package.json +++ b/examples/base/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-base", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/github-repo-analyzer/package.json b/examples/github-repo-analyzer/package.json index ad7668c92..16885de6a 100644 --- a/examples/github-repo-analyzer/package.json +++ b/examples/github-repo-analyzer/package.json @@ -2,18 +2,18 @@ "name": "voltagent-example-github-repo-analyzer", "version": "0.1.0", "dependencies": { - "@ai-sdk/openai": "^3.0.0", + "@ai-sdk/openai": "^4.0.0", "@octokit/rest": "^21.0.0", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", - "@voltagent/cli": "^0.1.21", + "@voltagent/cli": "^1.0.0-next.0", "tsx": "^4.21.0", "typescript": "^5.8.2" }, diff --git a/examples/github-star-stories/package.json b/examples/github-star-stories/package.json index 156b519f0..d7e6fd951 100644 --- a/examples/github-star-stories/package.json +++ b/examples/github-star-stories/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-github-star-stories", "version": "0.0.0", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "@voltagent/serverless-hono": "^2.0.12", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "@voltagent/serverless-hono": "^3.0.0-next.0", "dotenv": "^16.4.5", "wrangler": "^3.38.0", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/next-js-chatbot-starter-template/components/ai-elements/context.tsx b/examples/next-js-chatbot-starter-template/components/ai-elements/context.tsx index 4c86d0a12..e72c7eb6b 100644 --- a/examples/next-js-chatbot-starter-template/components/ai-elements/context.tsx +++ b/examples/next-js-chatbot-starter-template/components/ai-elements/context.tsx @@ -280,7 +280,7 @@ export const ContextReasoningUsage = ({ ...props }: ContextReasoningUsageProps) => { const { usage, modelId } = useContextValue(); - const reasoningTokens = usage?.reasoningTokens ?? 0; + const reasoningTokens = usage.outputTokenDetails.reasoningTokens ?? 0; if (children) { return children; @@ -313,7 +313,7 @@ export type ContextCacheUsageProps = ComponentProps<"div">; export const ContextCacheUsage = ({ className, children, ...props }: ContextCacheUsageProps) => { const { usage, modelId } = useContextValue(); - const cacheTokens = usage?.cachedInputTokens ?? 0; + const cacheTokens = usage.inputTokenDetails.cacheReadTokens ?? 0; if (children) { return children; diff --git a/examples/next-js-chatbot-starter-template/lib/tools/calculator.ts b/examples/next-js-chatbot-starter-template/lib/tools/calculator.ts index ef5456934..395d1d647 100644 --- a/examples/next-js-chatbot-starter-template/lib/tools/calculator.ts +++ b/examples/next-js-chatbot-starter-template/lib/tools/calculator.ts @@ -1,15 +1,14 @@ -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; /** * Calculator Tool * Performs basic arithmetic calculations */ -export const calculatorTool = createTool({ - name: "calculator", +export const calculatorTool = tool({ description: "Perform basic arithmetic calculations (addition, subtraction, multiplication, division, exponents, etc.)", - parameters: z.object({ + inputSchema: z.object({ expression: z .string() .describe("Mathematical expression to evaluate (e.g., '2 + 2', '10 * 5', '2 ** 8')"), diff --git a/examples/next-js-chatbot-starter-template/lib/tools/datetime.ts b/examples/next-js-chatbot-starter-template/lib/tools/datetime.ts index db660dd36..fc9fcc76b 100644 --- a/examples/next-js-chatbot-starter-template/lib/tools/datetime.ts +++ b/examples/next-js-chatbot-starter-template/lib/tools/datetime.ts @@ -1,14 +1,13 @@ -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; /** * Date Time Tool * Gets current date and time information */ -export const dateTimeTool = createTool({ - name: "getDateTime", +export const dateTimeTool = tool({ description: "Get the current date, time, and timezone information", - parameters: z.object({ + inputSchema: z.object({ timezone: z .string() .optional() diff --git a/examples/next-js-chatbot-starter-template/lib/tools/index.ts b/examples/next-js-chatbot-starter-template/lib/tools/index.ts index 59d9a23a3..83348d3aa 100644 --- a/examples/next-js-chatbot-starter-template/lib/tools/index.ts +++ b/examples/next-js-chatbot-starter-template/lib/tools/index.ts @@ -9,9 +9,13 @@ export { calculatorTool } from "./calculator"; export { dateTimeTool } from "./datetime"; export { randomNumberTool } from "./random"; -// Export as array for easy agent configuration +// Export as a ToolSet for agent configuration. Tool names come from object keys. import { calculatorTool } from "./calculator"; import { dateTimeTool } from "./datetime"; import { randomNumberTool } from "./random"; -export const defaultTools = [calculatorTool, dateTimeTool, randomNumberTool]; +export const defaultTools = { + calculator: calculatorTool, + getDateTime: dateTimeTool, + generateRandomNumber: randomNumberTool, +}; diff --git a/examples/next-js-chatbot-starter-template/lib/tools/random.ts b/examples/next-js-chatbot-starter-template/lib/tools/random.ts index 3bd825769..1d1355aa3 100644 --- a/examples/next-js-chatbot-starter-template/lib/tools/random.ts +++ b/examples/next-js-chatbot-starter-template/lib/tools/random.ts @@ -1,15 +1,14 @@ -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; /** * Random Number Tool * Generates random numbers within a specified range */ -export const randomNumberTool = createTool({ - name: "generateRandomNumber", +export const randomNumberTool = tool({ description: "Generate a random number within a specified range. Can generate single numbers or arrays of random numbers.", - parameters: z.object({ + inputSchema: z.object({ min: z.number().describe("Minimum value (inclusive)"), max: z.number().describe("Maximum value (inclusive)"), count: z diff --git a/examples/next-js-chatbot-starter-template/package.json b/examples/next-js-chatbot-starter-template/package.json index e29b079b4..0c707510f 100644 --- a/examples/next-js-chatbot-starter-template/package.json +++ b/examples/next-js-chatbot-starter-template/package.json @@ -2,7 +2,7 @@ "name": "voltagent-example-next-js-chatbot-starter-template", "version": "0.1.0", "dependencies": { - "@ai-sdk/react": "^3.0.0", + "@ai-sdk/react": "^4.0.0", "@libsql/client": "^0.15.0", "@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-collapsible": "^1.1.12", @@ -15,12 +15,12 @@ "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-use-controllable-state": "^1.2.2", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/server-hono": "^2.0.14", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", "@xyflow/react": "^12.9.2", - "ai": "^6.0.0", + "ai": "^7.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -45,7 +45,7 @@ "tailwind-merge": "^3.3.1", "tokenlens": "^1.3.1", "use-stick-to-bottom": "^1.1.1", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@tailwindcss/postcss": "^4.1.4", diff --git a/examples/with-a2a-server/README.md b/examples/with-a2a-server/README.md index f7cb475f0..8757fc18d 100644 --- a/examples/with-a2a-server/README.md +++ b/examples/with-a2a-server/README.md @@ -65,7 +65,7 @@ examples/with-a2a-server ## Prerequisites -- Node.js 20+ +- Node.js 22+ - `pnpm` - `OPENAI_API_KEY` in your environment (used by the example agent) diff --git a/examples/with-a2a-server/package.json b/examples/with-a2a-server/package.json index 365e20c88..b7dfa6fcc 100644 --- a/examples/with-a2a-server/package.json +++ b/examples/with-a2a-server/package.json @@ -1,13 +1,13 @@ { "name": "voltagent-example-with-a2a-server", "dependencies": { - "@voltagent/a2a-server": "^2.0.3", - "@voltagent/core": "^2.9.0", - "@voltagent/internal": "^1.0.3", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/a2a-server": "^3.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/internal": "^2.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-ad-creator/CHANGELOG.md b/examples/with-ad-creator/CHANGELOG.md index bb93fd9c5..dac0b8ea6 100644 --- a/examples/with-ad-creator/CHANGELOG.md +++ b/examples/with-ad-creator/CHANGELOG.md @@ -1,5 +1,16 @@ # ai-ad-generator +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies []: + - @voltagent/cli@1.0.0-next.0 + - @voltagent/core@3.0.0-next.0 + - @voltagent/libsql@3.0.0-next.0 + - @voltagent/logger@3.0.0-next.0 + - @voltagent/server-hono@3.0.0-next.0 + ## 0.1.2 ### Patch Changes diff --git a/examples/with-ad-creator/README.md b/examples/with-ad-creator/README.md index cd3f37c74..16206d418 100644 --- a/examples/with-ad-creator/README.md +++ b/examples/with-ad-creator/README.md @@ -25,7 +25,7 @@ AI Ad Generator automatically creates professional social media advertisements f ### Prerequisites -- Node.js 20+ +- Node.js 22+ - Git - OpenAI API Key - [Get yours here](https://platform.openai.com/api-keys) - BrowserBase Account - [Sign up here](https://browserbase.com) diff --git a/examples/with-ad-creator/package.json b/examples/with-ad-creator/package.json index 13e6e29d0..419b55f54 100644 --- a/examples/with-ad-creator/package.json +++ b/examples/with-ad-creator/package.json @@ -1,21 +1,21 @@ { "name": "ai-ad-generator", "description": "A VoltAgent application", - "version": "0.1.2", + "version": "0.1.3-next.0", "dependencies": { "@browserbasehq/sdk": "^2.6.0", "@browserbasehq/stagehand": "^2.5.0", "@google-cloud/aiplatform": "^5.7.0", "@google/generative-ai": "^0.24.1", - "@voltagent/cli": "^0.1.18", - "@voltagent/core": "^2.0.0", - "@voltagent/libsql": "^2.0.0", - "@voltagent/logger": "^2.0.0", - "@voltagent/server-hono": "^2.0.0", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "dotenv": "^16.4.5", "sharp": "^0.34.4", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@biomejs/biome": "^1.9.4", diff --git a/examples/with-ad-creator/src/tools/image-generation/instagram-ad-gemini.tool.ts b/examples/with-ad-creator/src/tools/image-generation/instagram-ad-gemini.tool.ts index c410309be..25699a593 100644 --- a/examples/with-ad-creator/src/tools/image-generation/instagram-ad-gemini.tool.ts +++ b/examples/with-ad-creator/src/tools/image-generation/instagram-ad-gemini.tool.ts @@ -132,8 +132,8 @@ Critical requirements: await fs.writeFile(referencePath, processedScreenshot); userContent.push({ - type: "image", - image: processedScreenshot, + type: "file", + data: processedScreenshot, mediaType: "image/png", }); diff --git a/examples/with-agent-tool/package.json b/examples/with-agent-tool/package.json index 9097de2cd..77192710e 100644 --- a/examples/with-agent-tool/package.json +++ b/examples/with-agent-tool/package.json @@ -4,9 +4,9 @@ "version": "1.0.0", "author": "", "dependencies": { - "@voltagent/core": "^2.9.0", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/core": "^3.0.0-next.1", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-airtable/package.json b/examples/with-airtable/package.json index 06db5e0f5..67949cc39 100644 --- a/examples/with-airtable/package.json +++ b/examples/with-airtable/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-airtable", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/internal": "^1.0.3", - "@voltagent/logger": "^2.0.2", - "@voltagent/sdk": "^2.0.3", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/internal": "^2.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/sdk": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-amazon-bedrock/README.md b/examples/with-amazon-bedrock/README.md index 775090ffa..bc14b9918 100644 --- a/examples/with-amazon-bedrock/README.md +++ b/examples/with-amazon-bedrock/README.md @@ -56,7 +56,7 @@ npm create voltagent-app@latest -- --example with-amazon-bedrock ### Prerequisites -- Node.js (v20 or newer) +- Node.js 22 or newer - npm, yarn, or pnpm - AWS Account with Amazon Bedrock access - AWS credentials configured diff --git a/examples/with-amazon-bedrock/package.json b/examples/with-amazon-bedrock/package.json index 38bbb2e6d..b0b80847e 100644 --- a/examples/with-amazon-bedrock/package.json +++ b/examples/with-amazon-bedrock/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-amazon-bedrock", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-anthropic/README.md b/examples/with-anthropic/README.md index 9d2844366..45b57ede1 100644 --- a/examples/with-anthropic/README.md +++ b/examples/with-anthropic/README.md @@ -6,7 +6,7 @@ An [VoltAgent](https://github.com/vercel/voltagent) application. ### Prerequisites -- Node.js (v20 or newer) +- Node.js 22 or newer - npm, yarn, or pnpm ### Installation diff --git a/examples/with-anthropic/package.json b/examples/with-anthropic/package.json index 2cccc8f0e..1bd462a5f 100644 --- a/examples/with-anthropic/package.json +++ b/examples/with-anthropic/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-anthropic", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-assistant-ui/CHANGELOG.md b/examples/with-assistant-ui/CHANGELOG.md index bcd785a73..f685b835e 100644 --- a/examples/with-assistant-ui/CHANGELOG.md +++ b/examples/with-assistant-ui/CHANGELOG.md @@ -1,5 +1,14 @@ # assistant-ui-starter +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/libsql@3.0.0-next.0 + - @voltagent/server-hono@3.0.0-next.0 + ## 0.1.2 ### Patch Changes diff --git a/examples/with-assistant-ui/package.json b/examples/with-assistant-ui/package.json index 35c342e85..98167125e 100644 --- a/examples/with-assistant-ui/package.json +++ b/examples/with-assistant-ui/package.json @@ -1,6 +1,6 @@ { "name": "assistant-ui-starter", - "version": "0.1.2", + "version": "0.1.3-next.0", "dependencies": { "@assistant-ui/react": "^0.11.47", "@assistant-ui/react-ai-sdk": "^1.1.16", @@ -12,10 +12,10 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tooltip": "^1.2.8", - "@voltagent/core": "^2.0.2", - "@voltagent/libsql": "^2.0.2", - "@voltagent/server-hono": "^2.0.2", - "ai": "^6.0.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "framer-motion": "^12.23.25", @@ -27,7 +27,7 @@ "remark-gfm": "^4.0.1", "tailwind-merge": "^3.3.1", "tw-animate-css": "^1.4.0", - "zod": "^3.25.76", + "zod": "^4.1.11", "zustand": "^5.0.9" }, "devDependencies": { diff --git a/examples/with-assistant-ui/voltagent/agents.ts b/examples/with-assistant-ui/voltagent/agents.ts index cd850d0ae..062cc2075 100644 --- a/examples/with-assistant-ui/voltagent/agents.ts +++ b/examples/with-assistant-ui/voltagent/agents.ts @@ -1,4 +1,4 @@ -import { Agent, createTool } from "@voltagent/core"; +import { Agent, tool } from "@voltagent/core"; import { z } from "zod"; import { sharedMemory } from "./memory"; @@ -13,10 +13,9 @@ const weatherOutputSchema = z.object({ message: z.string(), }); -const weatherTool = createTool({ - name: "getWeather", +const weatherTool = tool({ description: "Get the current weather for a specific location", - parameters: z.object({ + inputSchema: z.object({ location: z.string().describe("The city or location to get weather for"), }), outputSchema: weatherOutputSchema, @@ -43,7 +42,9 @@ export const assistantAgent = new Agent({ instructions: "You are a helpful AI that keeps responses concise, explains reasoning when useful, can gracefully describe any image or file attachments the user provides, and can call the getWeather tool for weather questions. Ask clarifying questions when context is missing.", model: "openai/gpt-4o-mini", - tools: [weatherTool], + tools: { + getWeather: weatherTool, + }, memory: sharedMemory, }); diff --git a/examples/with-auth/package.json b/examples/with-auth/package.json index 1aa9d04b0..6cb82bf10 100644 --- a/examples/with-auth/package.json +++ b/examples/with-auth/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-auth", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-cerbos/README.md b/examples/with-cerbos/README.md index f07848069..9cd25ac96 100644 --- a/examples/with-cerbos/README.md +++ b/examples/with-cerbos/README.md @@ -13,7 +13,7 @@ This example uses Cerbos as the Policy Decision Point (PDP) to enforce role-base ## Prerequisites -- Node.js 18+ +- Node.js 22+ - Docker (for running Cerbos) - OpenAI API key diff --git a/examples/with-cerbos/package.json b/examples/with-cerbos/package.json index 322b32978..ed40b2585 100644 --- a/examples/with-cerbos/package.json +++ b/examples/with-cerbos/package.json @@ -4,12 +4,12 @@ "dependencies": { "@cerbos/grpc": "^0.23.0", "@modelcontextprotocol/sdk": "^1.12.1", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "express": "^5.1.0", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-chat-sdk/README.md b/examples/with-chat-sdk/README.md index 5fb5b6a71..9031f8ce0 100644 --- a/examples/with-chat-sdk/README.md +++ b/examples/with-chat-sdk/README.md @@ -14,7 +14,7 @@ npm create voltagent-app@latest -- --example with-chat-sdk ## Prerequisites -- Node.js 20+ +- Node.js 22+ - pnpm - A Slack workspace where you can install apps - Redis instance diff --git a/examples/with-chat-sdk/lib/agent.ts b/examples/with-chat-sdk/lib/agent.ts index 9676b9728..8994a3d15 100644 --- a/examples/with-chat-sdk/lib/agent.ts +++ b/examples/with-chat-sdk/lib/agent.ts @@ -1,10 +1,9 @@ -import { Agent, createTool } from "@voltagent/core"; +import { Agent, tool } from "@voltagent/core"; import { z } from "zod"; -const getCurrentTimeTool = createTool({ - name: "getCurrentTime", +const getCurrentTimeTool = tool({ description: "Get the current date and time for a given IANA timezone.", - parameters: z.object({ + inputSchema: z.object({ timeZone: z .string() .default("UTC") @@ -45,5 +44,7 @@ export const slackAssistantAgent = new Agent({ "If the user asks for time in a city/timezone, call getCurrentTime.", ].join("\n"), model: "openai/gpt-4o-mini", - tools: [getCurrentTimeTool], + tools: { + getCurrentTime: getCurrentTimeTool, + }, }); diff --git a/examples/with-chat-sdk/package.json b/examples/with-chat-sdk/package.json index fe066801e..3d9e16891 100644 --- a/examples/with-chat-sdk/package.json +++ b/examples/with-chat-sdk/package.json @@ -5,14 +5,14 @@ "dependencies": { "@chat-adapter/slack": "^4.14.0", "@chat-adapter/state-redis": "^4.14.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "ai": "^7.0.0", "chat": "^4.14.0", "next": "^16.0.7", "react": "^19.2.3", "react-dom": "^19.2.3", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-chroma/package.json b/examples/with-chroma/package.json index d7cbcd308..2f97cf743 100644 --- a/examples/with-chroma/package.json +++ b/examples/with-chroma/package.json @@ -5,14 +5,14 @@ "@chroma-core/default-embed": "^0.1.8", "@chroma-core/ollama": "^0.1.7", "@chroma-core/openai": "^0.1.7", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "chromadb": "^3.0.4", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-client-side-tools/package.json b/examples/with-client-side-tools/package.json index c753d0d7a..53d8d6e44 100644 --- a/examples/with-client-side-tools/package.json +++ b/examples/with-client-side-tools/package.json @@ -2,17 +2,15 @@ "name": "voltagent-example-with-client-side-tools", "author": "", "dependencies": { - "@ai-sdk/react": "^3.0.0", + "@ai-sdk/react": "^4.0.0", "@libsql/client": "^0.15.0", - "@voltagent/core": "^2.9.0", - "@voltagent/server-hono": "^2.0.14", - "@voltagent/vercel-ai": "^1.0.0", - "@voltagent/vercel-ui": "^1.0.1", - "ai": "^6.0.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "next": "^16.0.7", "react": "^19.2.3", "react-dom": "^19.2.3", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-client-side-tools/voltagent/agents.ts b/examples/with-client-side-tools/voltagent/agents.ts index 575859830..7d7908227 100644 --- a/examples/with-client-side-tools/voltagent/agents.ts +++ b/examples/with-client-side-tools/voltagent/agents.ts @@ -1,27 +1,24 @@ -import { Agent, createTool } from "@voltagent/core"; +import { Agent, tool } from "@voltagent/core"; import { z } from "zod"; // Tools definitions - those without execute are automatically client-side const tools = { // Client-side automatic tool (no execute function) - getLocation: createTool({ - name: "getLocation", + getLocation: tool({ description: "Get the user's current location", - parameters: z.object({}), + inputSchema: z.object({}), }), // Client-side interactive tool - readClipboard: createTool({ - name: "readClipboard", + readClipboard: tool({ description: "Read the content from the user's clipboard (requires permission)", - parameters: z.object({}), + inputSchema: z.object({}), }), // Server-side tool (has execute function) - getWeather: createTool({ - name: "getWeather", + getWeather: tool({ description: "Get current weather for a city", - parameters: z.object({ + inputSchema: z.object({ city: z.string().describe("City name"), }), execute: async ({ city }) => { @@ -41,5 +38,5 @@ export const agent = new Agent({ name: "Assistant", instructions: "You are a helpful assistant that demonstrates client-side tools in VoltAgent.", model: "openai/gpt-4o-mini", - tools: Object.values(tools), + tools, }); diff --git a/examples/with-cloudflare-workers/README.md b/examples/with-cloudflare-workers/README.md index 89d7b848a..4192d3ee5 100644 --- a/examples/with-cloudflare-workers/README.md +++ b/examples/with-cloudflare-workers/README.md @@ -14,7 +14,7 @@ This example demonstrates how to deploy a VoltAgent AI agent to Cloudflare Worke ## Prerequisites -- Node.js 20+ installed +- Node.js 22+ installed - [Cloudflare account](https://dash.cloudflare.com/sign-up) (free tier available) - [OpenAI API key](https://platform.openai.com/api-keys) - [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) (installed via npm) diff --git a/examples/with-cloudflare-workers/package.json b/examples/with-cloudflare-workers/package.json index 6aa34738a..19f43e899 100644 --- a/examples/with-cloudflare-workers/package.json +++ b/examples/with-cloudflare-workers/package.json @@ -3,11 +3,11 @@ "description": "VoltAgent example for Cloudflare Workers deployment with in-memory storage", "version": "1.0.0", "dependencies": { - "@voltagent/core": "^2.9.0", - "@voltagent/serverless-hono": "^2.0.12", - "ai": "^6.0.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/serverless-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "hono": "^4.7.7", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@cloudflare/workers-types": "^4.20250408.0", diff --git a/examples/with-composio-mcp/README.md b/examples/with-composio-mcp/README.md index d10a7a05f..05ebfb36e 100644 --- a/examples/with-composio-mcp/README.md +++ b/examples/with-composio-mcp/README.md @@ -63,7 +63,7 @@ This example demonstrates how to integrate VoltAgent with Composio's Model Conte ## Prerequisites -- Node.js (v20 or later recommended) +- Node.js 22 or later - pnpm (or npm/yarn) - An OpenAI API key (or setup for another supported LLM provider) - A Composio MCP account (sign up at [https://mcp.composio.dev/](https://mcp.composio.dev/)) @@ -81,7 +81,6 @@ This example demonstrates how to integrate VoltAgent with Composio's Model Conte Replace `your_openai_api_key_here` with your actual OpenAI API key. Adjust the variable if using a different LLM provider. 2. **Create a Composio MCP Account:** - - Visit [https://mcp.composio.dev/](https://mcp.composio.dev/) - You can sign up using your Google account - Once logged in, you'll see the MCP dashboard diff --git a/examples/with-composio-mcp/package.json b/examples/with-composio-mcp/package.json index 8eb1adcb6..08a459b76 100644 --- a/examples/with-composio-mcp/package.json +++ b/examples/with-composio-mcp/package.json @@ -3,13 +3,13 @@ "description": "VoltAgent example demonstrating Composio MCP integration.", "version": "0.1.0", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-copilotkit/server/CHANGELOG.md b/examples/with-copilotkit/server/CHANGELOG.md index 600a80c1d..15c4d68eb 100644 --- a/examples/with-copilotkit/server/CHANGELOG.md +++ b/examples/with-copilotkit/server/CHANGELOG.md @@ -1,5 +1,15 @@ # voltagent-with-copilotkit-server +## 0.0.4-next.0 + +### Patch Changes + +- Updated dependencies []: + - @voltagent/ag-ui@2.0.0-next.0 + - @voltagent/cli@1.0.0-next.0 + - @voltagent/core@3.0.0-next.0 + - @voltagent/server-hono@3.0.0-next.0 + ## 0.0.3 ### Patch Changes diff --git a/examples/with-copilotkit/server/package.json b/examples/with-copilotkit/server/package.json index 8505da14e..fbb74c22b 100644 --- a/examples/with-copilotkit/server/package.json +++ b/examples/with-copilotkit/server/package.json @@ -1,14 +1,14 @@ { "name": "voltagent-with-copilotkit-server", - "version": "0.0.3", + "version": "0.0.4-next.0", "dependencies": { "@copilotkit/runtime": "^1.50.0", - "@voltagent/ag-ui": "^1.0.2", - "@voltagent/cli": "^0.1.20", - "@voltagent/core": "^2.0.2", - "@voltagent/server-hono": "^2.0.2", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/ag-ui": "^2.0.0-next.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "tsx": "^4.21.0", diff --git a/examples/with-custom-endpoints/package.json b/examples/with-custom-endpoints/package.json index 7a1241899..78a19e66a 100644 --- a/examples/with-custom-endpoints/package.json +++ b/examples/with-custom-endpoints/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-custom-endpoints", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-dynamic-parameters/package.json b/examples/with-dynamic-parameters/package.json index 68b16b6bb..b5e74bc78 100644 --- a/examples/with-dynamic-parameters/package.json +++ b/examples/with-dynamic-parameters/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-dynamic-parameters", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-dynamic-prompts/package.json b/examples/with-dynamic-prompts/package.json index c5570f123..29ee23924 100644 --- a/examples/with-dynamic-prompts/package.json +++ b/examples/with-dynamic-prompts/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-dynamic-prompts", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-feedback/package.json b/examples/with-feedback/package.json index c0a6145cb..07ddce61a 100644 --- a/examples/with-feedback/package.json +++ b/examples/with-feedback/package.json @@ -2,11 +2,11 @@ "name": "voltagent-example-with-feedback", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-google-ai/package.json b/examples/with-google-ai/package.json index 70b514c6d..faca9c031 100644 --- a/examples/with-google-ai/package.json +++ b/examples/with-google-ai/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-gemini-ai", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-google-drive-mcp/server/package.json b/examples/with-google-drive-mcp/server/package.json index 340558bbb..cbc4a5602 100644 --- a/examples/with-google-drive-mcp/server/package.json +++ b/examples/with-google-drive-mcp/server/package.json @@ -4,14 +4,14 @@ "dependencies": { "@hono/node-server": "^1.14.0", "@libsql/client": "^0.15.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", "composio-core": "^0.5.33", "hono": "^4.7.7", - "zod": "^3.25.76", + "zod": "^4.1.11", "zod-from-json-schema": "^0.5.0" }, "devDependencies": { diff --git a/examples/with-google-vertex-ai/package.json b/examples/with-google-vertex-ai/package.json index ef564fe34..d36c06e5d 100644 --- a/examples/with-google-vertex-ai/package.json +++ b/examples/with-google-vertex-ai/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-google-vertex-ai", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-groq-ai/package.json b/examples/with-groq-ai/package.json index 16d9d59ef..58c1e032f 100644 --- a/examples/with-groq-ai/package.json +++ b/examples/with-groq-ai/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-groq-ai", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-guardrails/package.json b/examples/with-guardrails/package.json index ed77eaa10..7116a4a42 100644 --- a/examples/with-guardrails/package.json +++ b/examples/with-guardrails/package.json @@ -2,11 +2,11 @@ "name": "voltagent-example-with-guardrails", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-hooks/package.json b/examples/with-hooks/package.json index ce9efa71f..9e0beee55 100644 --- a/examples/with-hooks/package.json +++ b/examples/with-hooks/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-hooks", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-hugging-face-mcp/README.md b/examples/with-hugging-face-mcp/README.md index bd32d6173..a48b92008 100644 --- a/examples/with-hugging-face-mcp/README.md +++ b/examples/with-hugging-face-mcp/README.md @@ -61,7 +61,7 @@ npm create voltagent-app@latest -- --example with-hugging-face-mcp ## Prerequisites -- Node.js (v20 or later recommended) +- Node.js 22 or later - pnpm (or npm/yarn) - An OpenAI API key (or setup for another supported LLM provider) - A Hugging Face account and API token (sign up at [https://huggingface.co/](https://huggingface.co/)) @@ -80,7 +80,6 @@ npm create voltagent-app@latest -- --example with-hugging-face-mcp Replace the placeholder values with your actual API keys. 2. **Get Your Hugging Face Token:** - - Visit [https://huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) - Create a new token with read access - Copy the token and add it to your `.env` file diff --git a/examples/with-hugging-face-mcp/package.json b/examples/with-hugging-face-mcp/package.json index 2c27d8912..848f74329 100644 --- a/examples/with-hugging-face-mcp/package.json +++ b/examples/with-hugging-face-mcp/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-hugging-face-mcp", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-jwt-auth/CHANGELOG.md b/examples/with-jwt-auth/CHANGELOG.md index 2d68ecc67..d37bc7b5d 100644 --- a/examples/with-jwt-auth/CHANGELOG.md +++ b/examples/with-jwt-auth/CHANGELOG.md @@ -1,5 +1,15 @@ # with-jwt-auth +## 1.0.6-next.0 + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/libsql@3.0.0-next.0 + - @voltagent/logger@3.0.0-next.0 + - @voltagent/server-hono@3.0.0-next.0 + ## 1.0.5 ### Patch Changes diff --git a/examples/with-jwt-auth/package.json b/examples/with-jwt-auth/package.json index afb8ae8b3..b79ca321e 100644 --- a/examples/with-jwt-auth/package.json +++ b/examples/with-jwt-auth/package.json @@ -1,14 +1,14 @@ { "name": "with-jwt-auth", - "version": "1.0.5", + "version": "1.0.6-next.0", "dependencies": { - "@voltagent/core": "^2.0.2", - "@voltagent/libsql": "^2.0.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.2", - "ai": "^6.0.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "jsonwebtoken": "^9.0.2", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/jsonwebtoken": "^9.0.10", diff --git a/examples/with-lancedb/README.md b/examples/with-lancedb/README.md index de5686a16..b814600a6 100644 --- a/examples/with-lancedb/README.md +++ b/examples/with-lancedb/README.md @@ -14,7 +14,7 @@ This example demonstrates how to use [LanceDB](https://lancedb.github.io/lancedb ## Prerequisites -- Node.js 20+ +- Node.js 22+ - OpenAI API Key (for embeddings and LLM) ## Getting Started diff --git a/examples/with-lancedb/package.json b/examples/with-lancedb/package.json index ba83b7fb6..7f0f1624f 100644 --- a/examples/with-lancedb/package.json +++ b/examples/with-lancedb/package.json @@ -4,14 +4,14 @@ "version": "1.0.0", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", + "@ai-sdk/openai": "^4.0.0", "@lancedb/lancedb": "^0.23.0", "@voltagent/core": "workspace:^", "@voltagent/libsql": "workspace:^", "@voltagent/logger": "workspace:^", "@voltagent/server-hono": "workspace:^", - "ai": "^6.0.0", - "zod": "^3.25.76" + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-langfuse/package.json b/examples/with-langfuse/package.json index aaa0fb3b2..5b229a5d0 100644 --- a/examples/with-langfuse/package.json +++ b/examples/with-langfuse/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-langfuse", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/langfuse-exporter": "^2.0.3", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/langfuse-exporter": "^3.0.0-next.0", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-live-evals/CHANGELOG.md b/examples/with-live-evals/CHANGELOG.md index dd0ea775e..3b50b96f9 100644 --- a/examples/with-live-evals/CHANGELOG.md +++ b/examples/with-live-evals/CHANGELOG.md @@ -1,5 +1,14 @@ # example-with-live-evals +## 0.0.6-next.0 + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/scorers@3.0.0-next.0 + - @voltagent/server-hono@3.0.0-next.0 + ## 0.0.5 ### Patch Changes diff --git a/examples/with-live-evals/package.json b/examples/with-live-evals/package.json index 5a77fdf24..4fb7adea0 100644 --- a/examples/with-live-evals/package.json +++ b/examples/with-live-evals/package.json @@ -1,11 +1,11 @@ { "name": "example-with-live-evals", - "version": "0.0.5", + "version": "0.0.6-next.0", "dependencies": { - "@voltagent/core": "^2.0.2", - "@voltagent/scorers": "^2.0.2", - "@voltagent/server-hono": "^2.0.2", - "zod": "^3.25.76" + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/scorers": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-mcp-elicitation/README.md b/examples/with-mcp-elicitation/README.md index 8c0fa80c8..43ee5e345 100644 --- a/examples/with-mcp-elicitation/README.md +++ b/examples/with-mcp-elicitation/README.md @@ -4,7 +4,7 @@ This example shows how to handle MCP `elicitation/create` requests from a VoltAg ## Prerequisites -- Node.js 18+ +- Node.js 22+ - OpenAI API key ## Setup diff --git a/examples/with-mcp-elicitation/package.json b/examples/with-mcp-elicitation/package.json index 7742c5f3f..d80578bb7 100644 --- a/examples/with-mcp-elicitation/package.json +++ b/examples/with-mcp-elicitation/package.json @@ -3,13 +3,13 @@ "description": "VoltAgent example showing MCP elicitation handling from a local MCP server.", "version": "0.1.0", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/mcp-server": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/mcp-server": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-mcp-server/README.md b/examples/with-mcp-server/README.md index 2bc42a739..8e43e5712 100644 --- a/examples/with-mcp-server/README.md +++ b/examples/with-mcp-server/README.md @@ -65,7 +65,7 @@ examples/with-mcp-server ## Prerequisites -- Node.js 20+ +- Node.js 22+ - `pnpm` - `OPENAI_API_KEY` in your environment (for the sample agent) diff --git a/examples/with-mcp-server/package.json b/examples/with-mcp-server/package.json index a154b0642..4390d5c76 100644 --- a/examples/with-mcp-server/package.json +++ b/examples/with-mcp-server/package.json @@ -1,12 +1,12 @@ { "name": "voltagent-example-with-mcp-server", "dependencies": { - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/mcp-server": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/mcp-server": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-mcp/package.json b/examples/with-mcp/package.json index 23cbfc287..b2149a6d8 100644 --- a/examples/with-mcp/package.json +++ b/examples/with-mcp/package.json @@ -3,13 +3,13 @@ "description": "VoltAgent example demonstrating MCP integration with a filesystem server.", "version": "0.1.0", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-memory-rest-api/package.json b/examples/with-memory-rest-api/package.json index 30f061521..4fd8cb208 100644 --- a/examples/with-memory-rest-api/package.json +++ b/examples/with-memory-rest-api/package.json @@ -3,11 +3,11 @@ "description": "Example showing how to access VoltAgent memory via REST API with PostgreSQL storage", "version": "1.0.0", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/postgres": "^2.1.2", - "@voltagent/server-hono": "^2.0.14" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/postgres": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-middleware/package.json b/examples/with-middleware/package.json index 1a544465c..81ad18ae6 100644 --- a/examples/with-middleware/package.json +++ b/examples/with-middleware/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-middleware", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-nestjs/README.md b/examples/with-nestjs/README.md index 8bc376db8..66254a122 100644 --- a/examples/with-nestjs/README.md +++ b/examples/with-nestjs/README.md @@ -22,7 +22,7 @@ This example demonstrates how to integrate VoltAgent with a NestJS application * ### Prerequisites -- Node.js 18+ and pnpm +- Node.js 22+ and pnpm - OpenAI API key ### Installation diff --git a/examples/with-nestjs/package.json b/examples/with-nestjs/package.json index 46acfc1a4..fa3bae483 100644 --- a/examples/with-nestjs/package.json +++ b/examples/with-nestjs/package.json @@ -6,14 +6,14 @@ "@nestjs/common": "^11.0.0", "@nestjs/core": "^11.0.0", "@nestjs/platform-express": "^11.0.0", - "@voltagent/core": "^2.9.0", - "@voltagent/server-core": "^2.1.19", - "@voltagent/server-hono": "^2.0.14", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/server-core": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", "hono": "^4.7.7", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "ws": "^8.18.1", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@nestjs/cli": "^11.0.0", diff --git a/examples/with-netlify-functions/README.md b/examples/with-netlify-functions/README.md index 5b51d20d9..4c9543b4d 100644 --- a/examples/with-netlify-functions/README.md +++ b/examples/with-netlify-functions/README.md @@ -1,17 +1,17 @@ # VoltAgent Netlify Functions Deployment Example -This example shows how to deploy a VoltAgent agent as a Netlify Function (Node 20 runtime) while keeping the full VoltAgent HTTP API available behind a single serverless entry point. +This example shows how to deploy a VoltAgent agent as a Netlify Function with a Node.js 22 runtime while keeping the full VoltAgent HTTP API available behind a single serverless entry point. ## Features -- ⚙️ Runs on Netlify Functions (AWS Lambda) with Node.js 20 +- ⚙️ Runs on Netlify Functions (AWS Lambda) with Node.js 22 - 🤖 Uses model strings like `openai/gpt-4o-mini` for completions - 🧰 Includes a sample weather tool - 🔁 `netlify.toml` redirects every route to the function so `/agents`, `/observability`, etc. continue to work ## Prerequisites -- Node.js 20+ +- Node.js 22+ - A Netlify account - [`netlify-cli`](https://docs.netlify.com/cli/get-started/) - An OpenAI API key (VoltOps keys optional) diff --git a/examples/with-netlify-functions/package.json b/examples/with-netlify-functions/package.json index 04472f5ec..6216d4e74 100644 --- a/examples/with-netlify-functions/package.json +++ b/examples/with-netlify-functions/package.json @@ -3,11 +3,11 @@ "description": "VoltAgent example deployed as a Netlify Function", "version": "1.0.0", "dependencies": { - "@voltagent/core": "^2.9.0", - "@voltagent/serverless-hono": "^2.0.12", - "ai": "^6.0.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/serverless-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "hono": "^4.7.7", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-nextjs-resumable-stream/app/api/chat/route.ts b/examples/with-nextjs-resumable-stream/app/api/chat/route.ts index d3bd69dd6..68a7e7854 100644 --- a/examples/with-nextjs-resumable-stream/app/api/chat/route.ts +++ b/examples/with-nextjs-resumable-stream/app/api/chat/route.ts @@ -66,7 +66,7 @@ export async function POST(req: Request) { return result.toUIMessageStreamResponse({ consumeSseStream: session.consumeSseStream, - onFinish: session.onFinish, + onEnd: session.onEnd, }); } catch (error) { console.error("[API] Chat error:", error); diff --git a/examples/with-nextjs-resumable-stream/components/ai-elements/context.tsx b/examples/with-nextjs-resumable-stream/components/ai-elements/context.tsx index 4c86d0a12..e72c7eb6b 100644 --- a/examples/with-nextjs-resumable-stream/components/ai-elements/context.tsx +++ b/examples/with-nextjs-resumable-stream/components/ai-elements/context.tsx @@ -280,7 +280,7 @@ export const ContextReasoningUsage = ({ ...props }: ContextReasoningUsageProps) => { const { usage, modelId } = useContextValue(); - const reasoningTokens = usage?.reasoningTokens ?? 0; + const reasoningTokens = usage.outputTokenDetails.reasoningTokens ?? 0; if (children) { return children; @@ -313,7 +313,7 @@ export type ContextCacheUsageProps = ComponentProps<"div">; export const ContextCacheUsage = ({ className, children, ...props }: ContextCacheUsageProps) => { const { usage, modelId } = useContextValue(); - const cacheTokens = usage?.cachedInputTokens ?? 0; + const cacheTokens = usage.inputTokenDetails.cacheReadTokens ?? 0; if (children) { return children; diff --git a/examples/with-nextjs-resumable-stream/package.json b/examples/with-nextjs-resumable-stream/package.json index 99d60070d..42b2cb69b 100644 --- a/examples/with-nextjs-resumable-stream/package.json +++ b/examples/with-nextjs-resumable-stream/package.json @@ -2,7 +2,7 @@ "name": "voltagent-example-with-nextjs-resumable-stream", "version": "0.1.0", "dependencies": { - "@ai-sdk/react": "^3.0.0", + "@ai-sdk/react": "^4.0.0", "@libsql/client": "^0.15.0", "@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-collapsible": "^1.1.12", @@ -16,14 +16,14 @@ "@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-use-controllable-state": "^1.2.2", "@tavily/core": "^0.6.3", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/internal": "^1.0.3", - "@voltagent/libsql": "^2.1.2", - "@voltagent/resumable-streams": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/internal": "^2.0.0-next.0", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/resumable-streams": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", "@xyflow/react": "^12.9.2", - "ai": "^6.0.0", + "ai": "^7.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -44,7 +44,7 @@ "tailwind-merge": "^3.3.1", "tokenlens": "^1.3.1", "use-stick-to-bottom": "^1.1.1", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@tailwindcss/postcss": "^4.1.4", diff --git a/examples/with-nextjs/package.json b/examples/with-nextjs/package.json index 06d3cd0cf..29bfb14aa 100644 --- a/examples/with-nextjs/package.json +++ b/examples/with-nextjs/package.json @@ -2,15 +2,15 @@ "name": "voltagent-example-with-nextjs", "version": "0.1.0", "dependencies": { - "@ai-sdk/react": "^3.0.0", + "@ai-sdk/react": "^4.0.0", "@libsql/client": "^0.15.0", "@tailwindcss/postcss": "^4.1.4", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "import-in-the-middle": "^1.14.2", "next": "^16.0.7", "npm-check-updates": "^17.1.18", @@ -19,7 +19,7 @@ "react-dom": "^19.2.3", "require-in-the-middle": "^7.5.2", "tailwindcss": "^4.1.4", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-nuxt/package.json b/examples/with-nuxt/package.json index a5192aa87..c825b52c6 100644 --- a/examples/with-nuxt/package.json +++ b/examples/with-nuxt/package.json @@ -3,14 +3,14 @@ "dependencies": { "@nuxt/eslint": "^1.9.0", "@nuxt/ui": "^4.0.0", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "nuxt": "^4.1.2", "vue": "^3.5.22", "vue-router": "^4.5.1", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "prettier": "^3.5.3" diff --git a/examples/with-offline-evals/package.json b/examples/with-offline-evals/package.json index 8d2806d3e..e97162b58 100644 --- a/examples/with-offline-evals/package.json +++ b/examples/with-offline-evals/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-offline-evals", "version": "0.0.0", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/evals": "^2.0.4", - "@voltagent/scorers": "^2.1.0", - "@voltagent/sdk": "^2.0.3", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/evals": "^3.0.0-next.0", + "@voltagent/scorers": "^3.0.0-next.0", + "@voltagent/sdk": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-ollama/package.json b/examples/with-ollama/package.json index 31d074b99..f9d5e049b 100644 --- a/examples/with-ollama/package.json +++ b/examples/with-ollama/package.json @@ -1,13 +1,13 @@ { "name": "voltagent-example-with-ollama", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "ollama-ai-provider-v2": "^1.5.3", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "ollama-ai-provider-v2": "^4.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-openrouter/README.md b/examples/with-openrouter/README.md index f1d464473..ea4769e1b 100644 --- a/examples/with-openrouter/README.md +++ b/examples/with-openrouter/README.md @@ -6,7 +6,7 @@ A [VoltAgent](https://github.com/VoltAgent/voltagent) application using OpenRout ### Prerequisites -- Node.js (v20 or newer) +- Node.js 22 or newer - npm, yarn, or pnpm - An OpenRouter API key diff --git a/examples/with-openrouter/package.json b/examples/with-openrouter/package.json index 4d11f7c8d..43227a569 100644 --- a/examples/with-openrouter/package.json +++ b/examples/with-openrouter/package.json @@ -2,13 +2,14 @@ "name": "voltagent-example-with-openrouter", "author": "", "dependencies": { - "@openrouter/ai-sdk-provider": "^2.3.1", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0" + "@openrouter/ai-sdk-provider": "^3.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-peaka-mcp/package.json b/examples/with-peaka-mcp/package.json index 76c06e081..aa063e3fb 100644 --- a/examples/with-peaka-mcp/package.json +++ b/examples/with-peaka-mcp/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-peaka-mcp", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-pinecone/package.json b/examples/with-pinecone/package.json index 8dbea8b83..89ea2addb 100644 --- a/examples/with-pinecone/package.json +++ b/examples/with-pinecone/package.json @@ -3,14 +3,14 @@ "author": "", "dependencies": { "@pinecone-database/pinecone": "^6.1.1", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "openai": "^4.91.0", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-planagents/README.md b/examples/with-planagents/README.md index 3f5dac26a..9d940bd27 100644 --- a/examples/with-planagents/README.md +++ b/examples/with-planagents/README.md @@ -4,7 +4,7 @@ Build a PlanAgent with planning, file system tools, and subagent support. This e ## Prerequisites -- Node.js (v20 or newer) +- Node.js 22 or newer - OpenAI API key - Tavily API key diff --git a/examples/with-planagents/package.json b/examples/with-planagents/package.json index 68c001197..498c45f48 100644 --- a/examples/with-planagents/package.json +++ b/examples/with-planagents/package.json @@ -4,13 +4,13 @@ "version": "0.1.0", "dependencies": { "@tavily/core": "^0.6.3", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-playwright/package.json b/examples/with-playwright/package.json index f8a38a6a1..0e8555bb1 100644 --- a/examples/with-playwright/package.json +++ b/examples/with-playwright/package.json @@ -6,16 +6,16 @@ "@playwright/browser-firefox": "1.51.1", "@playwright/browser-webkit": "1.51.1", "@playwright/test": "^1.51.1", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "axios": "^1.5.0", "playwright": "1.51.1", "uuid": "^9.0.1", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-playwright/tsconfig.json b/examples/with-playwright/tsconfig.json index 2e1a1377c..941aae37d 100644 --- a/examples/with-playwright/tsconfig.json +++ b/examples/with-playwright/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { "target": "ES2022", - "module": "CommonJS", - "moduleResolution": "Node", + "module": "NodeNext", + "moduleResolution": "NodeNext", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "allowImportingTsExtensions": true, diff --git a/examples/with-postgres/package.json b/examples/with-postgres/package.json index 44e7301f6..4e6d6a870 100644 --- a/examples/with-postgres/package.json +++ b/examples/with-postgres/package.json @@ -3,13 +3,13 @@ "description": "VoltAgent example demonstrating PostgreSQL integration for memory.", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/postgres": "^2.1.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/postgres": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-qdrant/package.json b/examples/with-qdrant/package.json index f06185b51..5e7c53595 100644 --- a/examples/with-qdrant/package.json +++ b/examples/with-qdrant/package.json @@ -3,14 +3,14 @@ "author": "", "dependencies": { "@qdrant/js-client-rest": "^1.15.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "openai": "^4.91.0", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-rag-chatbot/package.json b/examples/with-rag-chatbot/package.json index 1e7d67c40..51e7f910b 100644 --- a/examples/with-rag-chatbot/package.json +++ b/examples/with-rag-chatbot/package.json @@ -3,13 +3,13 @@ "description": "VoltAgent RAG Chatbot Example", "version": "0.0.1", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-recipe-generator/README.md b/examples/with-recipe-generator/README.md index 346f98022..58678965e 100644 --- a/examples/with-recipe-generator/README.md +++ b/examples/with-recipe-generator/README.md @@ -63,7 +63,7 @@ This example demonstrates how to integrate VoltAgent with Exa's Model Context Pr ## Prerequisites -- Node.js (v20 or later recommended) +- Node.js 22 or later - pnpm (or npm/yarn) - An OpenAI API key (or setup for another supported LLM provider) - An Exa API key (sign up at [https://exa.ai/](https://exa.ai/)) diff --git a/examples/with-recipe-generator/package.json b/examples/with-recipe-generator/package.json index 507940f97..acc056a2d 100644 --- a/examples/with-recipe-generator/package.json +++ b/examples/with-recipe-generator/package.json @@ -2,12 +2,12 @@ "name": "voltagent-example-recipe-generator", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-research-assistant/README.md b/examples/with-research-assistant/README.md index c83890271..6b81722ff 100644 --- a/examples/with-research-assistant/README.md +++ b/examples/with-research-assistant/README.md @@ -64,7 +64,7 @@ This example demonstrates how to build an AI-powered research assistant using Vo ## Prerequisites -- Node.js (v18 or later recommended) +- Node.js 22 or later - pnpm (or npm/yarn) - An OpenAI API key (or setup for another supported LLM provider) - An Exa API key (sign up at [https://exa.ai/](https://exa.ai/)) diff --git a/examples/with-research-assistant/package.json b/examples/with-research-assistant/package.json index a964dc4e6..e5971767e 100644 --- a/examples/with-research-assistant/package.json +++ b/examples/with-research-assistant/package.json @@ -2,12 +2,12 @@ "name": "voltagent-example-research-assistant", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-resumable-streams/package.json b/examples/with-resumable-streams/package.json index 163d1cd60..bda480064 100644 --- a/examples/with-resumable-streams/package.json +++ b/examples/with-resumable-streams/package.json @@ -4,11 +4,11 @@ "version": "1.0.0", "author": "", "dependencies": { - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/resumable-streams": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/resumable-streams": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-retries-fallback/package.json b/examples/with-retries-fallback/package.json index 4e553ec45..c24c01fbc 100644 --- a/examples/with-retries-fallback/package.json +++ b/examples/with-retries-fallback/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-retries-fallback", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-retrieval/package.json b/examples/with-retrieval/package.json index a881282b7..402f63096 100644 --- a/examples/with-retrieval/package.json +++ b/examples/with-retrieval/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-retrieval", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-slack/package.json b/examples/with-slack/package.json index 9d5ba8cb5..9eadd0475 100644 --- a/examples/with-slack/package.json +++ b/examples/with-slack/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-slack", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/sdk": "^2.0.3", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/sdk": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-subagents/package.json b/examples/with-subagents/package.json index aa3c01158..0f87b365d 100644 --- a/examples/with-subagents/package.json +++ b/examples/with-subagents/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-subagents", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-summarization/README.md b/examples/with-summarization/README.md index 3e8865eb3..3839eb289 100644 --- a/examples/with-summarization/README.md +++ b/examples/with-summarization/README.md @@ -4,7 +4,7 @@ Demonstrates agent summarization with a short trigger window so you can see summ ## Prerequisites -- Node.js (v20 or newer) +- Node.js 22 or newer - OpenAI API key (with access to `openai/gpt-5.1`) ## Setup diff --git a/examples/with-summarization/package.json b/examples/with-summarization/package.json index 952f94d9f..75b0c3333 100644 --- a/examples/with-summarization/package.json +++ b/examples/with-summarization/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-summarization", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-supabase/package.json b/examples/with-supabase/package.json index 82cdef57e..20678ff86 100644 --- a/examples/with-supabase/package.json +++ b/examples/with-supabase/package.json @@ -3,13 +3,13 @@ "author": "", "dependencies": { "@supabase/supabase-js": "^2.49.4", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "@voltagent/supabase": "^2.1.3", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "@voltagent/supabase": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-tavily-search/package.json b/examples/with-tavily-search/package.json index a92e16d6e..5aaf9b593 100644 --- a/examples/with-tavily-search/package.json +++ b/examples/with-tavily-search/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-tavily-search", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-thinking-tool/package.json b/examples/with-thinking-tool/package.json index e7288f43e..bbbcfd9b3 100644 --- a/examples/with-thinking-tool/package.json +++ b/examples/with-thinking-tool/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-thinking-tool", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-tool-routing/package.json b/examples/with-tool-routing/package.json index f594a7dea..38f5d4779 100644 --- a/examples/with-tool-routing/package.json +++ b/examples/with-tool-routing/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-tool-routing", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-tools/package.json b/examples/with-tools/package.json index 6da2e8c36..cfea09138 100644 --- a/examples/with-tools/package.json +++ b/examples/with-tools/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-tools", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-turso/package.json b/examples/with-turso/package.json index 2fe3656bb..a5dbb2114 100644 --- a/examples/with-turso/package.json +++ b/examples/with-turso/package.json @@ -3,13 +3,13 @@ "description": "VoltAgent example demonstrating Turso/LibSQL integration for memory.", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-vector-search/package.json b/examples/with-vector-search/package.json index 979066c94..e30ad7e72 100644 --- a/examples/with-vector-search/package.json +++ b/examples/with-vector-search/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-vector-search", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-vercel-ai/package.json b/examples/with-vercel-ai/package.json index 401db99a1..89884298c 100644 --- a/examples/with-vercel-ai/package.json +++ b/examples/with-vercel-ai/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-vercel-ai", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-viteval/package.json b/examples/with-viteval/package.json index 0afb61792..69345250b 100644 --- a/examples/with-viteval/package.json +++ b/examples/with-viteval/package.json @@ -2,16 +2,16 @@ "name": "voltagent-example-with-viteval", "author": "VoltAgent", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "consola": "^3.4.2", "envalid": "^8.1.0", "yargs": "^18.0.0", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@tsconfig/node24": "^24.0.1", diff --git a/examples/with-viteval/src/agents/general.dataset.ts b/examples/with-viteval/src/agents/general.dataset.ts index 0e4514d97..f89214298 100644 --- a/examples/with-viteval/src/agents/general.dataset.ts +++ b/examples/with-viteval/src/agents/general.dataset.ts @@ -10,7 +10,7 @@ export default defineDataset({ for (let i = 0; i < 10; i++) { const { object } = await generateObject({ model: "openai/gpt-5", - system: ` + instructions: ` You are an expert at generating test data for a general knowledge agent. You will generate a general knowledge question and the expected answer. `, prompt: "Generate a general knowledge question and the expected answer", diff --git a/examples/with-viteval/src/agents/geography.dataset.ts b/examples/with-viteval/src/agents/geography.dataset.ts index a76fa2353..dd6df9fdd 100644 --- a/examples/with-viteval/src/agents/geography.dataset.ts +++ b/examples/with-viteval/src/agents/geography.dataset.ts @@ -10,7 +10,7 @@ export default defineDataset({ for (let i = 0; i < 10; i++) { const { object } = await generateObject({ model: "openai/gpt-5", - system: ` + instructions: ` You are an expert at generating test data for a geography agent. You will generate a geography question and the expected answer. Focus on questions about countries, cities, landmarks, geographical features, climate, and cultural geography. `, diff --git a/examples/with-viteval/src/agents/history.dataset.ts b/examples/with-viteval/src/agents/history.dataset.ts index 1e5c99f4e..dbd36d392 100644 --- a/examples/with-viteval/src/agents/history.dataset.ts +++ b/examples/with-viteval/src/agents/history.dataset.ts @@ -10,7 +10,7 @@ export default defineDataset({ for (let i = 0; i < 10; i++) { const { object } = await generateObject({ model: "openai/gpt-5", - system: ` + instructions: ` You are an expert at generating test data for a history agent. You will generate a history question and the expected answer. Focus on questions about historical events, people, places, time periods, and cultural history. `, diff --git a/examples/with-viteval/src/agents/math.dataset.ts b/examples/with-viteval/src/agents/math.dataset.ts index f322877c2..69597979f 100644 --- a/examples/with-viteval/src/agents/math.dataset.ts +++ b/examples/with-viteval/src/agents/math.dataset.ts @@ -10,7 +10,7 @@ export default defineDataset({ for (let i = 0; i < 10; i++) { const { object } = await generateObject({ model: "openai/gpt-5", - system: ` + instructions: ` You are an expert at generating test data for a math agent. You will generate a math problem and the expected answer. Generate problems that can be solved with basic arithmetic operations (addition, subtraction, multiplication, division). `, diff --git a/examples/with-viteval/src/agents/science.dataset.ts b/examples/with-viteval/src/agents/science.dataset.ts index 070a26f06..634c43213 100644 --- a/examples/with-viteval/src/agents/science.dataset.ts +++ b/examples/with-viteval/src/agents/science.dataset.ts @@ -10,7 +10,7 @@ export default defineDataset({ for (let i = 0; i < 10; i++) { const { object } = await generateObject({ model: "openai/gpt-5", - system: ` + instructions: ` You are an expert at generating test data for a science agent. You will generate a science question and the expected answer. Focus on questions about physics, chemistry, biology, earth sciences, and scientific concepts. `, diff --git a/examples/with-viteval/src/agents/supervisor.dataset.ts b/examples/with-viteval/src/agents/supervisor.dataset.ts index c28deacf1..8ab32f77b 100644 --- a/examples/with-viteval/src/agents/supervisor.dataset.ts +++ b/examples/with-viteval/src/agents/supervisor.dataset.ts @@ -10,7 +10,7 @@ export default defineDataset({ categories.map(async ({ name, description }) => { const { object } = await generateObject({ model: "openai/gpt-5", - system: ` + instructions: ` You are an expert at generating test data. You will generate a question and the expected answer based on the provided category. Be succinct in you questions and answers. The question should be a single sentence, and the answer should be a single sentence or less. `, diff --git a/examples/with-voice-elevenlabs/package.json b/examples/with-voice-elevenlabs/package.json index 3d9b05741..83aa95aa8 100644 --- a/examples/with-voice-elevenlabs/package.json +++ b/examples/with-voice-elevenlabs/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-voice-elevenlabs", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "@voltagent/voice": "^2.1.0", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "@voltagent/voice": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-voice-openai/package.json b/examples/with-voice-openai/package.json index 440da61bc..c4eefb3e2 100644 --- a/examples/with-voice-openai/package.json +++ b/examples/with-voice-openai/package.json @@ -2,16 +2,16 @@ "name": "voltagent-example-with-voice-openai", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "@voltagent/voice": "^2.1.0", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "@voltagent/voice": "^3.0.0-next.0", + "ai": "^7.0.0", "dotenv": "^16.4.5", "openai": "^4.91.0", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-voice-xsai/package.json b/examples/with-voice-xsai/package.json index 9a950cd45..fc3f98736 100644 --- a/examples/with-voice-xsai/package.json +++ b/examples/with-voice-xsai/package.json @@ -2,16 +2,16 @@ "name": "voltagent-example-with-voice-xsai", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "@voltagent/voice": "^2.1.0", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "@voltagent/voice": "^3.0.0-next.0", + "ai": "^7.0.0", "dotenv": "^16.4.5", "openai": "^4.91.0", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-voltagent-actions/package.json b/examples/with-voltagent-actions/package.json index a98e61591..5760c8845 100644 --- a/examples/with-voltagent-actions/package.json +++ b/examples/with-voltagent-actions/package.json @@ -2,12 +2,12 @@ "name": "voltagent-example-with-voltagent-actions", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/sdk": "^2.0.3", - "@voltagent/server-hono": "^2.0.14", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/sdk": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-voltagent-exporter/package.json b/examples/with-voltagent-exporter/package.json index 6507f683b..08832ce22 100644 --- a/examples/with-voltagent-exporter/package.json +++ b/examples/with-voltagent-exporter/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-voltagent-exporter", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-voltagent-managed-memory/README.md b/examples/with-voltagent-managed-memory/README.md index a01a6efb2..e25076808 100644 --- a/examples/with-voltagent-managed-memory/README.md +++ b/examples/with-voltagent-managed-memory/README.md @@ -6,7 +6,7 @@ This example shows how to run VoltAgent with the hosted _VoltAgent Managed Memor 1. **VoltOps Project Keys** – create or reuse a VoltOps project and copy the **public** and **secret** API keys. 2. **Managed Memory Database** – create a managed database from VoltOps Console or the VoltOps API and note its name (e.g. `production-memory`). -3. **Node.js 20+** and **pnpm** (or your preferred package manager). +3. **Node.js 22+** and **pnpm** (or your preferred package manager). ## Setup diff --git a/examples/with-voltagent-managed-memory/package.json b/examples/with-voltagent-managed-memory/package.json index 1d6087d34..e0ced7170 100644 --- a/examples/with-voltagent-managed-memory/package.json +++ b/examples/with-voltagent-managed-memory/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-voltagent-managed-memory", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "@voltagent/voltagent-memory": "^1.0.4", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "@voltagent/voltagent-memory": "^2.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-voltops-resumable-streams/package.json b/examples/with-voltops-resumable-streams/package.json index 08928fce7..1aed44d50 100644 --- a/examples/with-voltops-resumable-streams/package.json +++ b/examples/with-voltops-resumable-streams/package.json @@ -4,11 +4,11 @@ "version": "1.0.0", "author": "", "dependencies": { - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/resumable-streams": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/resumable-streams": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-voltops-retrieval/package.json b/examples/with-voltops-retrieval/package.json index ad4c6fb04..e8a3454ec 100644 --- a/examples/with-voltops-retrieval/package.json +++ b/examples/with-voltops-retrieval/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-voltops-retrieval", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-whatsapp/package.json b/examples/with-whatsapp/package.json index 8183909e4..06562589a 100644 --- a/examples/with-whatsapp/package.json +++ b/examples/with-whatsapp/package.json @@ -3,14 +3,14 @@ "author": "", "dependencies": { "@supabase/supabase-js": "^2.49.4", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "dotenv": "^16.4.5", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-workflow-chain/package.json b/examples/with-workflow-chain/package.json index 68cbc33a2..c844f8f96 100644 --- a/examples/with-workflow-chain/package.json +++ b/examples/with-workflow-chain/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-workflow-chain", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-workflow/package.json b/examples/with-workflow/package.json index 7f658d698..86bd55167 100644 --- a/examples/with-workflow/package.json +++ b/examples/with-workflow/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-workflow", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-working-memory/package.json b/examples/with-working-memory/package.json index b98c15813..3eb062aa8 100644 --- a/examples/with-working-memory/package.json +++ b/examples/with-working-memory/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-working-memory", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-workspace/package.json b/examples/with-workspace/package.json index 4acf14515..425ceb80a 100644 --- a/examples/with-workspace/package.json +++ b/examples/with-workspace/package.json @@ -2,14 +2,14 @@ "name": "voltagent-example-with-workspace", "author": "", "dependencies": { - "@ai-sdk/openai": "^3.0.0", - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@ai-sdk/openai": "^4.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-xquik-tools/package.json b/examples/with-xquik-tools/package.json index 2084f7d55..d5903f95c 100644 --- a/examples/with-xquik-tools/package.json +++ b/examples/with-xquik-tools/package.json @@ -2,12 +2,12 @@ "name": "voltagent-example-with-xquik-tools", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-youtube-to-blog/package.json b/examples/with-youtube-to-blog/package.json index 8a42a5e59..bbdb20a8b 100644 --- a/examples/with-youtube-to-blog/package.json +++ b/examples/with-youtube-to-blog/package.json @@ -2,13 +2,13 @@ "name": "voltagent-example-with-youtube-to-blog", "author": "", "dependencies": { - "@voltagent/cli": "^0.1.21", - "@voltagent/core": "^2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/examples/with-zapier-mcp/README.md b/examples/with-zapier-mcp/README.md index 7d5a5abd6..f2feb560a 100644 --- a/examples/with-zapier-mcp/README.md +++ b/examples/with-zapier-mcp/README.md @@ -54,7 +54,7 @@ This example demonstrates how to integrate VoltAgent with a Zapier Model Context ## Prerequisites -- Node.js (v20 or later recommended) +- Node.js 22 or later - pnpm (or npm/yarn) - AWS credentials for Amazon Bedrock (see below) or you can use OpenAI - A Zapier MCP account (see [Zapier documentation](https://zapier.com/mcp/)) diff --git a/examples/with-zapier-mcp/package.json b/examples/with-zapier-mcp/package.json index 76cf73bc0..64701affa 100644 --- a/examples/with-zapier-mcp/package.json +++ b/examples/with-zapier-mcp/package.json @@ -4,12 +4,12 @@ "version": "1.0.0", "author": "", "dependencies": { - "@voltagent/core": "~2.9.0", - "@voltagent/libsql": "^2.1.2", - "@voltagent/logger": "^2.0.2", - "@voltagent/server-hono": "^2.0.14", - "ai": "^6.0.0", - "zod": "^3.25.76" + "@voltagent/core": "~3.0.0-next.1", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.1.11" }, "devDependencies": { "@types/node": "^24.2.1", diff --git a/package.json b/package.json index 94160b5dc..75a814b87 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "vitest": "^3.2.4" }, "engines": { - "node": ">=20", + "node": ">=22", "pnpm": ">=8" }, "license": "MIT", diff --git a/packages/a2a-server/CHANGELOG.md b/packages/a2a-server/CHANGELOG.md index a0e40965b..49f5fb2f5 100644 --- a/packages/a2a-server/CHANGELOG.md +++ b/packages/a2a-server/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/a2a-server +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + ## 2.0.3 ### Patch Changes diff --git a/packages/a2a-server/package.json b/packages/a2a-server/package.json index b3d536dc9..3ce5a2551 100644 --- a/packages/a2a-server/package.json +++ b/packages/a2a-server/package.json @@ -1,25 +1,20 @@ { "name": "@voltagent/a2a-server", "description": "VoltAgent A2A server implementation for exposing agents over the Agent-to-Agent protocol.", - "version": "2.0.3", + "version": "3.0.0-next.0", "dependencies": { "@a2a-js/sdk": "^0.2.5", - "@voltagent/internal": "^1.0.2", - "zod": "^3.25.76" + "@voltagent/internal": "^2.0.0-next.0", + "zod": "^4.1.11" }, "devDependencies": { - "@voltagent/core": "^2.0.2" + "@voltagent/core": "^3.0.0-next.0" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -27,9 +22,9 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0" + "@voltagent/core": "^3.0.0-next.0" }, "repository": { "type": "git", @@ -42,5 +37,6 @@ "test": "vitest", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/a2a-server/src/server.spec.ts b/packages/a2a-server/src/server.spec.ts index e981f9099..c259052ad 100644 --- a/packages/a2a-server/src/server.spec.ts +++ b/packages/a2a-server/src/server.spec.ts @@ -261,6 +261,17 @@ describe("A2AServer", () => { cachedInputTokens: 0, reasoningTokens: 0, }); + expect(streamText).toHaveBeenCalledTimes(1); + const [input, options] = streamText.mock.calls[0]; + expect(input).toBe("Hello"); + expect(options).toEqual( + expect.objectContaining({ + conversationId: chunks.at(-1)?.result?.contextId, + abortSignal: expect.any(AbortSignal), + }), + ); + expect(options).not.toHaveProperty("prompt"); + expect(options).not.toHaveProperty("messages"); }); it("propagates cancellation to streaming agents and returns a canceled task", async () => { diff --git a/packages/a2a-server/tsup.config.ts b/packages/a2a-server/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/a2a-server/tsup.config.ts +++ b/packages/a2a-server/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/ag-ui/CHANGELOG.md b/packages/ag-ui/CHANGELOG.md index 941eb4073..84678d8f9 100644 --- a/packages/ag-ui/CHANGELOG.md +++ b/packages/ag-ui/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/ag-ui +## 2.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + ## 1.0.7 ### Patch Changes diff --git a/packages/ag-ui/package.json b/packages/ag-ui/package.json index 2e0dfc2a1..6e23380fc 100644 --- a/packages/ag-ui/package.json +++ b/packages/ag-ui/package.json @@ -1,7 +1,7 @@ { "name": "@voltagent/ag-ui", "description": "AG-UI adapter for VoltAgent agents and CopilotKit runtimes.", - "version": "1.0.7", + "version": "2.0.0-next.0", "dependencies": { "rxjs": "^7.8.1" }, @@ -10,22 +10,17 @@ "@ag-ui/core": "^0.0.37", "@copilotkit/runtime": "^1.50.0", "@vitest/coverage-v8": "^3.2.4", - "@voltagent/core": "^2.6.13", - "@voltagent/internal": "^1.0.2", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/internal": "^2.0.0-next.0", "tsup": "^8.5.0", "typescript": "^5.8.2", "vitest": "^3.2.4" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -33,13 +28,13 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { "@ag-ui/client": ">=0.0.37", "@ag-ui/core": ">=0.0.37", "@copilotkit/runtime": "^1.50.0", - "@voltagent/core": ">=1.0.0", - "@voltagent/internal": "^1.0.0", + "@voltagent/core": ">=3.0.0-next.0", + "@voltagent/internal": "^2.0.0-next.0", "rxjs": "^7.8.1" }, "repository": { @@ -55,5 +50,6 @@ "publint": "publint --strict", "test": "vitest" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/ag-ui/src/voltagent-agent.spec.ts b/packages/ag-ui/src/voltagent-agent.spec.ts index e5c664756..44cf7472e 100644 --- a/packages/ag-ui/src/voltagent-agent.spec.ts +++ b/packages/ag-ui/src/voltagent-agent.spec.ts @@ -1,7 +1,8 @@ import { EventType } from "@ag-ui/core"; import type { RunErrorEvent, RunFinishedEvent } from "@ag-ui/core"; import { Observable, type Subscriber } from "rxjs"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; +import { VoltAgentAGUI } from "./voltagent-agent"; /** * Regression test for the RUN_FINISHED-after-RUN_ERROR bug in VoltAgentAGUI. @@ -126,3 +127,80 @@ describe("VoltAgentAGUI – error event handling", () => { expect((events[1] as { type: string }).type).toBe(EventType.RUN_FINISHED); }); }); + +describe("VoltAgentAGUI – VoltAgent call contract", () => { + it("streams converted messages through positional streamText messages and options", async () => { + const streamText = vi.fn(async () => ({ + fullStream: (async function* () { + yield { + type: "text-delta" as const, + id: "text-1", + messageId: "assistant-1", + text: "Hello back", + }; + })(), + })); + const logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); + + try { + const adapter = new VoltAgentAGUI({ + agent: { + id: "support-agent", + name: "Support Agent", + streamText, + } as any, + deriveUserId: () => "user-1", + }); + + const events: unknown[] = []; + await new Promise((resolve, reject) => { + const observable = adapter.run({ + threadId: "thread-1", + runId: "run-1", + messages: [{ id: "msg-1", role: "user", content: "Hello" }], + state: { screen: "checkout" }, + context: [{ description: "route", value: "checkout" }], + forwardedProps: { source: "copilot" }, + } as any) as unknown as Observable; + + observable.subscribe({ + next: (event) => events.push(event), + error: reject, + complete: resolve, + }); + }); + + expect(streamText).toHaveBeenCalledTimes(1); + const [messages, options] = streamText.mock.calls[0]; + expect(messages).toEqual([ + expect.objectContaining({ + id: "msg-1", + role: "user", + content: "Hello", + }), + ]); + expect(options).toEqual( + expect.objectContaining({ + conversationId: "thread-1", + userId: "user-1", + abortSignal: expect.any(AbortSignal), + }), + ); + expect(options.context).toBeInstanceOf(Map); + expect(options.context.get("agui:context")).toEqual( + expect.objectContaining({ + state: { screen: "checkout" }, + context: [{ description: "route", value: "checkout" }], + forwardedProps: { source: "copilot" }, + }), + ); + expect(options).not.toHaveProperty("prompt"); + expect(options).not.toHaveProperty("messages"); + expect( + events.some((event) => (event as { type?: string }).type === EventType.RUN_FINISHED), + ).toBe(true); + } finally { + logSpy.mockRestore(); + } + }); +}); diff --git a/packages/ag-ui/src/voltagent-agent.ts b/packages/ag-ui/src/voltagent-agent.ts index b6993232b..56ac26092 100644 --- a/packages/ag-ui/src/voltagent-agent.ts +++ b/packages/ag-ui/src/voltagent-agent.ts @@ -107,7 +107,7 @@ export class VoltAgentAGUI extends AbstractAgent { debugLog("calling agent.streamText", { messagesLength: voltMessages.length }); const result = await this.agent.streamText(voltMessages as any, streamOptions); - for await (const part of result.fullStream) { + for await (const part of result.stream) { debugLog("fullStream part", { partType: part.type, id: (part as any).id }); if ((part.type === "start" || part.type === "start-step") && part.messageId) { currentMessageId = part.messageId; diff --git a/packages/ag-ui/tsup.config.ts b/packages/ag-ui/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/ag-ui/tsup.config.ts +++ b/packages/ag-ui/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 5e6f2cffc..aef32b79f 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,231 @@ # @voltagent/cli +## 1.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/evals@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + - @voltagent/sdk@3.0.0-next.0 + ## 0.1.21 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 77278b793..a110f8264 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,14 +1,14 @@ { "name": "@voltagent/cli", "description": "CLI tool for VoltAgent applications", - "version": "0.1.21", + "version": "1.0.0-next.0", "bin": { "volt": "dist/index.js" }, "dependencies": { - "@voltagent/evals": "^2.0.2", - "@voltagent/internal": "^1.0.2", - "@voltagent/sdk": "^2.0.2", + "@voltagent/evals": "^3.0.0-next.0", + "@voltagent/internal": "^2.0.0-next.0", + "@voltagent/sdk": "^3.0.0-next.0", "adm-zip": "^0.5.12", "boxen": "^5.1.2", "bundle-require": "^5.1.0", @@ -43,7 +43,7 @@ "@vitest/coverage-v8": "^3.2.4" }, "engines": { - "node": ">=20" + "node": ">=22" }, "files": [ "dist" @@ -70,5 +70,6 @@ "start": "node dist/index.js", "test": "vitest", "test:coverage": "vitest run --coverage" - } + }, + "type": "module" } diff --git a/packages/cli/tsup.config.ts b/packages/cli/tsup.config.ts index 1c92f3c8d..7d7feb39e 100644 --- a/packages/cli/tsup.config.ts +++ b/packages/cli/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/cloudflare-d1/CHANGELOG.md b/packages/cloudflare-d1/CHANGELOG.md index 7d2b4fca9..4948c8add 100644 --- a/packages/cloudflare-d1/CHANGELOG.md +++ b/packages/cloudflare-d1/CHANGELOG.md @@ -1,5 +1,231 @@ # @voltagent/cloudflare-d1 +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + - @voltagent/logger@3.0.0-next.0 + ## 2.1.2 ### Patch Changes diff --git a/packages/cloudflare-d1/package.json b/packages/cloudflare-d1/package.json index c2b2ccb7f..5d0103f2f 100644 --- a/packages/cloudflare-d1/package.json +++ b/packages/cloudflare-d1/package.json @@ -1,27 +1,22 @@ { "name": "@voltagent/cloudflare-d1", "description": "VoltAgent Cloudflare D1 - D1 Memory provider integration for VoltAgent", - "version": "2.1.2", + "version": "3.0.0-next.0", "dependencies": { "@cloudflare/workers-types": "^4.20250408.0", - "@voltagent/internal": "^1.0.2" + "@voltagent/internal": "^2.0.0-next.0" }, "devDependencies": { "@vitest/coverage-v8": "^3.2.4", - "@voltagent/core": "^2.4.4", - "@voltagent/logger": "^2.0.2", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "ai": "^7.0.0" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -29,11 +24,11 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "@voltagent/logger": "^2.0.0", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "ai": "^7.0.0" }, "publishConfig": { "access": "public" @@ -53,5 +48,6 @@ "test": "vitest --reporter=hanging-process --reporter=default --typecheck", "test:coverage": "vitest run --coverage --typecheck" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/cloudflare-d1/tsup.config.ts b/packages/cloudflare-d1/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/cloudflare-d1/tsup.config.ts +++ b/packages/cloudflare-d1/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/cloudflare-d1/vitest.config.mts b/packages/cloudflare-d1/vitest.config.mts new file mode 100644 index 000000000..b04319c17 --- /dev/null +++ b/packages/cloudflare-d1/vitest.config.mts @@ -0,0 +1,9 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["src/**/*.spec.ts"], + environment: "node", + globals: true, + }, +}); diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 5e527656d..f8707fb55 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,240 @@ # @voltagent/core +## 3.0.0-next.1 + +### Patch Changes + +- Publish the latest AI SDK v7 tool compatibility updates on the `next` channel. + + Raw AI SDK tools remain first-class, including native `contextSchema` and call-level + `toolsContext`, while VoltAgent metadata can be attached out-of-band with + `withVoltAgentMetadata`. + +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/internal@2.0.0-next.0 + - @voltagent/logger@3.0.0-next.0 + ## 2.9.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index d8bda591e..28bcb1bc9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,29 +1,27 @@ { "name": "@voltagent/core", "description": "VoltAgent Core - AI agent framework for JavaScript", - "version": "2.9.0", + "version": "3.0.0-next.1", "dependencies": { - "@ai-sdk/amazon-bedrock": "^3.0.0", - "@ai-sdk/anthropic": "^3.0.0", - "@ai-sdk/azure": "^3.0.12", - "@ai-sdk/cerebras": "^2.0.14", - "@ai-sdk/cohere": "^3.0.8", - "@ai-sdk/deepinfra": "^2.0.13", - "@ai-sdk/gateway": "^3.0.16", - "@ai-sdk/google": "^3.0.0", - "@ai-sdk/google-vertex": "^3.0.25", - "@ai-sdk/groq": "^3.0.0", - "@ai-sdk/mistral": "^3.0.0", - "@ai-sdk/openai": "^3.0.0", - "@ai-sdk/openai-compatible": "^2.0.13", - "@ai-sdk/perplexity": "^3.0.8", - "@ai-sdk/togetherai": "^2.0.13", - "@ai-sdk/vercel": "^2.0.13", - "@ai-sdk/xai": "^3.0.26", - "@aihubmix/ai-sdk-provider": "^1.0.1", - "@gitlab/gitlab-ai-provider": "^3.1.1", + "@ai-sdk/amazon-bedrock": "^5.0.0", + "@ai-sdk/anthropic": "^4.0.0", + "@ai-sdk/azure": "^4.0.0", + "@ai-sdk/cerebras": "^3.0.0", + "@ai-sdk/cohere": "^4.0.0", + "@ai-sdk/deepinfra": "^3.0.0", + "@ai-sdk/gateway": "^4.0.0", + "@ai-sdk/google": "^4.0.0", + "@ai-sdk/google-vertex": "^5.0.0", + "@ai-sdk/groq": "^4.0.0", + "@ai-sdk/mistral": "^4.0.0", + "@ai-sdk/openai": "^4.0.0", + "@ai-sdk/openai-compatible": "^3.0.0", + "@ai-sdk/perplexity": "^4.0.0", + "@ai-sdk/togetherai": "^3.0.0", + "@ai-sdk/vercel": "^3.0.0", + "@ai-sdk/xai": "^4.0.0", + "@gitlab/gitlab-ai-provider": "^4.1.0", "@modelcontextprotocol/sdk": "^1.12.1", - "@mymediset/sap-ai-provider": "^2.1.0", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.204.0", "@opentelemetry/context-async-hooks": "^2.2.0", @@ -36,37 +34,29 @@ "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.28.0", - "@voltagent/internal": "^1.0.3", + "@voltagent/internal": "^2.0.0-next.0", "fast-glob": "^3.3.3", "gray-matter": "^4.0.3", "micromatch": "^4.0.8", - "ollama-ai-provider-v2": "^1.5.3", "ts-pattern": "^5.7.1", "type-fest": "^4.41.0", "uuid": "^9.0.1", - "workers-ai-provider": "^3.0.2", - "zod-from-json-schema": "^0.5.0", - "zod-from-json-schema-v3": "npm:zod-from-json-schema@^0.0.5" + "zod-from-json-schema": "^0.5.0" }, "devDependencies": { - "@ai-sdk/provider-utils": "^4.0.0", + "@ai-sdk/provider-utils": "^5.0.0", "@types/micromatch": "^4.0.10", "@types/uuid": "^10.0.0", "@vitest/coverage-v8": "^3.2.4", - "ai": "^6.0.0", + "ai": "^7.0.0", "msw": "^2.11.5", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -75,12 +65,12 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@ai-sdk/provider-utils": "4.x", - "@voltagent/logger": "2.0.2", - "ai": "^6.0.0", - "zod": "^3.25.0 || ^4.0.0" + "@ai-sdk/provider-utils": "^5.0.0", + "@voltagent/logger": "3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.0.0" }, "peerDependenciesMeta": { "@voltagent/logger": { @@ -108,5 +98,6 @@ "test:single": "vitest run --reporter=verbose", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/core/src/agent/agent-observability.spec.ts b/packages/core/src/agent/agent-observability.spec.ts index fff3a67c7..4732cb12f 100644 --- a/packages/core/src/agent/agent-observability.spec.ts +++ b/packages/core/src/agent/agent-observability.spec.ts @@ -406,6 +406,7 @@ describe("Agent with Observability", () => { instructions: "You are a test agent", model: mockModel as any, observability, + maxRetries: 0, }); // Execute and expect error diff --git a/packages/core/src/agent/agent-semantic-search.spec.ts b/packages/core/src/agent/agent-semantic-search.spec.ts index 0195de157..ae0190960 100644 --- a/packages/core/src/agent/agent-semantic-search.spec.ts +++ b/packages/core/src/agent/agent-semantic-search.spec.ts @@ -19,7 +19,7 @@ vi.mock("ai", () => ({ generateObject: vi.fn(), streamObject: vi.fn(), convertToModelMessages: vi.fn((messages) => messages), - stepCountIs: vi.fn(() => vi.fn(() => false)), + isStepCount: vi.fn(() => vi.fn(() => false)), validateUIMessages: vi.fn(async ({ messages }) => messages), })); @@ -270,6 +270,7 @@ describe("Agent Semantic Search", () => { instructions: "Test", model: mockModel as any, memory: memoryWithVector, + maxRetries: 0, }); // Replace the memory manager's getMessages method @@ -311,6 +312,7 @@ describe("Agent Semantic Search", () => { instructions: "Test", model: mockModel as any, memory: memoryWithVector, + maxRetries: 0, }); const memoryManager = (agent as any).memoryManager; @@ -345,6 +347,7 @@ describe("Agent Semantic Search", () => { instructions: "Test", model: mockModel as any, memory: memoryWithVector, + maxRetries: 0, }); const memoryManager = (agent as any).memoryManager; diff --git a/packages/core/src/agent/agent.spec-d.ts b/packages/core/src/agent/agent.spec-d.ts index 51c0ef040..4ebdaec40 100644 --- a/packages/core/src/agent/agent.spec-d.ts +++ b/packages/core/src/agent/agent.spec-d.ts @@ -1,11 +1,17 @@ import type { ModelMessage } from "@ai-sdk/provider-utils"; -import type { FinishReason, LanguageModelUsage, UIMessage } from "ai"; +import { + type FinishReason, + type LanguageModelUsage, + Output, + type UIMessage, + tool as rawAiTool, +} from "ai"; import { MockLanguageModelV3 } from "ai/test"; import { describe, expectTypeOf, it } from "vitest"; import { z } from "zod"; import type { ModelRouterModelId } from "../registries/model-provider-types.generated"; import type { BaseRetriever } from "../retriever/retriever"; -import { Tool, type Toolkit, createTool } from "../tool"; +import { Tool, type Toolkit, tool as aiSdkTool, createTool, withVoltAgentMetadata } from "../tool"; import type { StreamEventType } from "../utils/streams"; import type { Voice } from "../voice"; import type { VoltOpsClient } from "../voltops/client"; @@ -15,6 +21,7 @@ import { Agent, type AgentHooks, type GenerateObjectResultWithContext, + type GenerateTextOptions, type GenerateTextResultWithContext, type StreamObjectResultWithContext, type StreamTextResultWithContext, @@ -38,6 +45,7 @@ import type { SupervisorConfig, ToolsDynamicValue, UserContext, + VoltAgentRuntimeOptions, } from "./types"; describe("Agent Type System", () => { @@ -213,6 +221,93 @@ describe("Agent Type System", () => { expectTypeOf(agent).toMatchTypeOf(); }); + + it("should accept AI SDK ToolSet tools", () => { + const agent = new Agent({ + name: "Test", + instructions: "Test", + model: mockModel, + tools: { + test_tool: aiSdkTool({ + description: "Test", + inputSchema: z.object({ value: z.string() }), + execute: async ({ value }) => ({ result: value }), + voltagent: { + name: "test_tool", + purpose: "Exercise AI SDK tool metadata typing", + tags: ["test"], + }, + }), + }, + }); + + expectTypeOf(agent).toMatchTypeOf(); + }); + + it("should accept AI SDK contextSchema on AI SDK-style tools", () => { + const weatherTool = aiSdkTool({ + description: "Get weather", + inputSchema: z.object({ city: z.string() }), + contextSchema: z.object({ + apiKey: z.string(), + defaultUnit: z.enum(["celsius", "fahrenheit"]), + }), + execute: async ({ city }, { context }) => { + expectTypeOf(context.apiKey).toEqualTypeOf(); + expectTypeOf(context.defaultUnit).toEqualTypeOf<"celsius" | "fahrenheit">(); + return { city, unit: context.defaultUnit }; + }, + }); + + const agent = new Agent({ + name: "Weather", + instructions: "Test", + model: mockModel, + tools: { + weather: weatherTool, + }, + }); + + expectTypeOf(agent).toMatchTypeOf(); + }); + + it("should attach VoltAgent metadata to raw AI SDK tools", () => { + const refundCustomer = withVoltAgentMetadata( + rawAiTool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + contextSchema: z.object({ + actorId: z.string(), + permissions: z.array(z.string()), + }), + execute: async ({ orderId, reason }, { context }) => { + expectTypeOf(context.actorId).toEqualTypeOf(); + expectTypeOf(context.permissions).toEqualTypeOf(); + return { orderId, reason, actorId: context.actorId }; + }, + }), + { + tags: ["billing", "dangerous"], + metadata: { + owner: "payments-team", + }, + }, + ); + + const agent = new Agent({ + name: "Support", + instructions: "Test", + model: mockModel, + tools: { + refundCustomer, + }, + }); + + expectTypeOf(agent).toMatchTypeOf(); + }); }); describe("Dynamic Value Types", () => { @@ -322,6 +417,26 @@ describe("Agent Type System", () => { // Tools with toolkit const mixedTools: ToolsDynamicValue = [tool, mockToolkit]; expectTypeOf(mixedTools).toMatchTypeOf(); + + // AI SDK ToolSet + const toolSet: ToolsDynamicValue = { + test_tool: aiSdkTool({ + description: "Test tool", + inputSchema: z.object({ value: z.string() }), + execute: async ({ value }) => ({ result: value }), + }), + }; + expectTypeOf(toolSet).toMatchTypeOf(); + + // Dynamic AI SDK ToolSet + const dynamicToolSet: ToolsDynamicValue = async () => ({ + test_tool: aiSdkTool({ + description: "Test tool", + inputSchema: z.object({ value: z.string() }), + execute: async ({ value }) => ({ result: value }), + }), + }); + expectTypeOf(dynamicToolSet).toMatchTypeOf(); }); }); @@ -359,6 +474,85 @@ describe("Agent Type System", () => { expectTypeOf(result.context).toEqualTypeOf>(); }); + it("should infer generateText structured output type with Output.object", async () => { + const agent = new Agent({ + name: "Test", + instructions: "Test", + model: mockModel, + }); + + const schema = z.object({ + answer: z.string(), + count: z.number(), + }); + + const result = await agent.generateText("Test input", { + output: Output.object({ schema }), + }); + + expectTypeOf(result.output).toEqualTypeOf<{ answer: string; count: number }>(); + expectTypeOf(result.output.answer).toEqualTypeOf(); + expectTypeOf(result.output.count).toEqualTypeOf(); + expectTypeOf(result.context).toEqualTypeOf>(); + + // @ts-expect-error - missing does not exist in schema + result.output.missing; + }); + + it("should infer object-style generateText structured output type", async () => { + const agent = new Agent({ + name: "Test", + instructions: "Test", + model: mockModel, + }); + + const schema = z.object({ + answer: z.string(), + count: z.number(), + }); + + const result = await agent.generateText({ + prompt: "Test input", + output: Output.object({ schema }), + temperature: 0.2, + }); + + expectTypeOf(result).toMatchTypeOf(); + expectTypeOf(result.output).toEqualTypeOf<{ answer: string; count: number }>(); + expectTypeOf(result.output.answer).toEqualTypeOf(); + expectTypeOf(result.output.count).toEqualTypeOf(); + + // @ts-expect-error - missing does not exist in schema + result.output.missing; + }); + + it("should accept native toolApproval options", async () => { + const agent = new Agent({ + name: "Test", + instructions: "Test", + model: mockModel, + }); + + const tools = { + dangerous_tool: aiSdkTool({ + description: "Dangerous tool", + inputSchema: z.object({ value: z.string() }), + execute: async ({ value }) => ({ value }), + }), + }; + + const result = await agent.generateText({ + prompt: "Test input", + tools, + toolApproval: { + dangerous_tool: "user-approval", + }, + experimental_toolApprovalSecret: new Uint8Array([1, 2, 3]), + }); + + expectTypeOf(result).toMatchTypeOf(); + }); + it("should infer streamText return type", async () => { const agent = new Agent({ name: "Test", @@ -372,6 +566,169 @@ describe("Agent Type System", () => { expectTypeOf(result.context).toEqualTypeOf>(); }); + it("should infer object-style streamText return type", async () => { + const agent = new Agent({ + name: "Test", + instructions: "Test", + model: mockModel, + }); + + const messages: UIMessage[] = [ + { + id: "message-1", + role: "user", + parts: [{ type: "text", text: "Test input" }], + }, + ]; + + const result = await agent.streamText({ + messages, + temperature: 0.2, + }); + + expectTypeOf(result).toMatchTypeOf(); + expectTypeOf(result.textStream).not.toBeUndefined(); + expectTypeOf(result.context).toEqualTypeOf>(); + }); + + it("should accept native toolApproval options for streamText", async () => { + const agent = new Agent({ + name: "Test", + instructions: "Test", + model: mockModel, + }); + + const result = await agent.streamText({ + prompt: "Test input", + toolApproval: { + dangerous_tool: "approved", + }, + }); + + expectTypeOf(result).toMatchTypeOf(); + }); + + it("should accept AI SDK v7 generateText passthrough options", async () => { + const agent = new Agent({ + name: "Test", + instructions: "Test", + model: mockModel, + }); + + const tools = { + lookup_order: aiSdkTool({ + description: "Lookup an order", + inputSchema: z.object({ orderId: z.string() }), + execute: async ({ orderId }) => ({ orderId }), + }), + }; + + const result = await agent.generateText({ + prompt: "Test input", + tools, + activeTools: ["lookup_order"], + toolOrder: ["lookup_order"], + timeout: { + totalMs: 10_000, + stepMs: 5_000, + toolMs: 2_000, + tools: { + lookup_orderMs: 1_000, + }, + }, + headers: { + "x-provider-header": "provider-value", + }, + include: { + requestBody: true, + requestMessages: true, + responseBody: true, + }, + experimental_download: async (downloads) => downloads.map(() => null), + toolsContext: { + lookup_order: {}, + }, + onStart: async () => {}, + onStepStart: async () => {}, + onLanguageModelCallStart: async () => {}, + onLanguageModelCallEnd: async () => {}, + onToolExecutionStart: async () => {}, + onToolExecutionEnd: async () => {}, + onStepEnd: async (step) => { + expectTypeOf(step).toMatchTypeOf(); + }, + onEnd: async (finish) => { + expectTypeOf(finish).toMatchTypeOf(); + }, + }); + + expectTypeOf(result).toMatchTypeOf(); + }); + + it("should accept toolsContext and reject VoltAgent-owned runtime/telemetry fields", () => { + const runtimeContextOptions: GenerateTextOptions = { + // @ts-expect-error - use `voltagent.context` instead + runtimeContext: { + tenantId: "tenant-1", + }, + }; + + const toolsContextOptions: GenerateTextOptions = { + toolsContext: { + lookup_order: {}, + }, + }; + + const telemetryOptions: GenerateTextOptions = { + // @ts-expect-error - use VoltAgent observability/tracing instead + telemetry: { + isEnabled: false, + }, + }; + + const experimentalTelemetryOptions: GenerateTextOptions = { + // @ts-expect-error - use VoltAgent observability/tracing instead + experimental_telemetry: { + isEnabled: false, + }, + }; + + expectTypeOf(runtimeContextOptions).toMatchTypeOf(); + expectTypeOf(toolsContextOptions).toMatchTypeOf(); + expectTypeOf(telemetryOptions).toMatchTypeOf(); + expectTypeOf(experimentalTelemetryOptions).toMatchTypeOf(); + }); + + it("should accept AI SDK v7 streamText-only passthrough options", async () => { + const agent = new Agent({ + name: "Test", + instructions: "Test", + model: mockModel, + }); + + const result = await agent.streamText({ + prompt: "Test input", + timeout: { + totalMs: 10_000, + chunkMs: 1_000, + }, + include: { + requestBody: true, + requestMessages: true, + rawChunks: true, + }, + includeRawChunks: true, + experimental_transform: [], + onChunk: async () => {}, + onAbort: async () => {}, + onError: async ({ error }) => { + expectTypeOf(error).toEqualTypeOf(); + }, + }); + + expectTypeOf(result).toMatchTypeOf(); + }); + it("should infer generateObject return type with schema", async () => { const agent = new Agent({ name: "Test", @@ -453,6 +810,39 @@ describe("Agent Type System", () => { }, }; + const runtimeOptions: VoltAgentRuntimeOptions = { + memory: { + conversationId: "namespaced-conversation", + userId: "namespaced-user", + options: { + contextLimit: 500, + semanticMemory: { + enabled: true, + }, + }, + }, + context: { + requestId: "req-1", + }, + requestHeaders: { + authorization: "Bearer token", + }, + feedback: true, + guardrails: { + input: [], + output: [], + }, + middleware: { + input: [], + output: [], + maxRetries: 0, + }, + resumableStream: true, + }; + const namespacedOptions: PublicGenerateOptions = { + voltagent: runtimeOptions, + }; + const internalOptions: InternalGenerateOptions = { ...publicOptions, parentAgentId: "parent-123", @@ -466,6 +856,8 @@ describe("Agent Type System", () => { expectTypeOf(publicOptions).toMatchTypeOf(); expectTypeOf(legacyOptions).toMatchTypeOf(); + expectTypeOf(namespacedOptions).toMatchTypeOf(); + expectTypeOf(runtimeOptions).toMatchTypeOf(); expectTypeOf(internalOptions).toMatchTypeOf(); }); @@ -479,10 +871,10 @@ describe("Agent Type System", () => { seed: 12345, stopSequences: ["END"], extraOptions: { custom: "value" }, - onStepFinish: async (_step) => { + onStepEnd: async (_step) => { // Step type varies based on provider }, - onFinish: async (result) => { + onEnd: async (result) => { expectTypeOf(result).toEqualTypeOf(); }, onError: async (error) => { @@ -657,9 +1049,9 @@ describe("Agent Type System", () => { expectTypeOf(hooks).toMatchTypeOf(); }); - it("should validate onStepFinish hook", () => { + it("should validate onStepEnd hook", () => { const hooks: AgentHooks = { - onStepFinish: async ({ step }) => { + onStepEnd: async ({ step }) => { // Step can be any type based on provider expectTypeOf(step).toBeAny(); }, @@ -848,7 +1240,7 @@ describe("Agent Type System", () => { tags: z.array(z.string()), }), }), - metadata: z.record(z.unknown()), + metadata: z.record(z.string(), z.unknown()), }); type InferredObject = z.infer; @@ -1154,7 +1546,7 @@ describe("Agent Type System", () => { // Should have AI SDK compatible stream properties expectTypeOf(result.textStream).not.toBeNever(); - expectTypeOf(result.fullStream).not.toBeNever(); + expectTypeOf(result.stream).not.toBeNever(); expectTypeOf(result.usage).not.toBeNever(); expectTypeOf(result.text).not.toBeNever(); expectTypeOf(result.finishReason).not.toBeNever(); @@ -1194,7 +1586,7 @@ describe("Agent Type System", () => { z.object({ id: z.number(), value: z.string(), - metadata: z.record(z.unknown()).optional(), + metadata: z.record(z.string(), z.unknown()).optional(), }), ), options: z.object({ @@ -1229,7 +1621,7 @@ describe("Agent Type System", () => { z.object({ id: z.number(), value: z.string(), - metadata: z.record(z.unknown()).optional(), + metadata: z.record(z.string(), z.unknown()).optional(), }), ), options: z.object({ diff --git a/packages/core/src/agent/agent.spec.ts b/packages/core/src/agent/agent.spec.ts index e2572f4fd..237a99159 100644 --- a/packages/core/src/agent/agent.spec.ts +++ b/packages/core/src/agent/agent.spec.ts @@ -4,6 +4,7 @@ */ import type { ModelMessage } from "@ai-sdk/provider-utils"; +import { safeStringify } from "@voltagent/internal/utils"; import * as ai from "ai"; import type { UIMessage } from "ai"; import { MockLanguageModelV3 } from "ai/test"; @@ -13,7 +14,7 @@ import { Memory } from "../memory"; import { InMemoryStorageAdapter } from "../memory/adapters/storage/in-memory"; import { AgentRegistry } from "../registries/agent-registry"; import { ModelProviderRegistry } from "../registries/model-provider-registry"; -import { Tool } from "../tool"; +import { Tool, tool as aiSdkTool } from "../tool"; import { Workspace } from "../workspace"; import { Agent, renameProviderOptions } from "./agent"; import { SPECULATIVE_INPUT_GUARDRAIL_CONTEXT_KEY } from "./context-keys"; @@ -31,7 +32,7 @@ vi.mock("ai", async () => { streamText: vi.fn(), generateObject: vi.fn(), streamObject: vi.fn(), - stepCountIs: vi.fn(() => vi.fn(() => false)), + isStepCount: vi.fn(() => vi.fn(() => false)), }; }); @@ -146,6 +147,51 @@ describe("Agent", () => { }); }); + const toText = (message: ModelMessage): string => { + const content = (message as { content?: unknown }).content; + if (typeof content === "string") { + return content; + } + if (!Array.isArray(content)) { + return ""; + } + + return content + .map((part) => { + if (typeof part === "string") { + return part; + } + if (part && typeof part === "object" && "text" in part && typeof part.text === "string") { + return part.text; + } + return ""; + }) + .join("\n"); + }; + + const getInstructionMessages = (callArgs?: { + instructions?: unknown; + messages?: ModelMessage[]; + }): ModelMessage[] => { + const instructions = callArgs?.instructions; + const instructionMessages = + instructions == null + ? [] + : typeof instructions === "string" + ? [{ role: "system", content: instructions }] + : Array.isArray(instructions) + ? instructions + : [instructions]; + + return [ + ...(instructionMessages as ModelMessage[]), + ...((callArgs?.messages || []).filter((message) => message.role === "system") || []), + ]; + }; + + const getSystemTexts = (callArgs?: { instructions?: unknown; messages?: ModelMessage[] }) => + getInstructionMessages(callArgs).map(toText); + describe("Workspace skills prompt injection", () => { const createWorkspaceWithSkill = () => { const timestamp = new Date().toISOString(); @@ -195,31 +241,6 @@ Use pandas and summarize findings.`.split("\n"), steps: [], }); - const toText = (message: ModelMessage): string => { - const content = (message as { content?: unknown }).content; - if (typeof content === "string") { - return content; - } - if (!Array.isArray(content)) { - return ""; - } - - return content - .map((part) => { - if (typeof part === "string") { - return part; - } - if (part && typeof part === "object" && "text" in part && typeof part.text === "string") { - return part.text; - } - return ""; - }) - .join("\n"); - }; - - const getSystemTexts = (messages: ModelMessage[] | undefined): string[] => - (messages || []).filter((message) => message.role === "system").map(toText); - it("auto-injects workspace skills prompt by default", async () => { const workspace = createWorkspaceWithSkill(); const agent = new Agent({ @@ -234,7 +255,7 @@ Use pandas and summarize findings.`.split("\n"), await agent.generateText("Analyze my data"); const callArgs = vi.mocked(ai.generateText).mock.calls[0]?.[0]; - const systemTexts = getSystemTexts(callArgs?.messages); + const systemTexts = getSystemTexts(callArgs); expect(systemTexts.some((text) => text.includes(""))).toBe(true); expect(systemTexts.some((text) => text.includes("Data Analyst (/skills/data)"))).toBe(true); @@ -259,7 +280,7 @@ Use pandas and summarize findings.`.split("\n"), await agent.generateText("Analyze my data"); const callArgs = vi.mocked(ai.generateText).mock.calls[0]?.[0]; - const systemTexts = getSystemTexts(callArgs?.messages); + const systemTexts = getSystemTexts(callArgs); expect(onPrepareMessages).toHaveBeenCalledTimes(1); expect(systemTexts.some((text) => text.includes(""))).toBe(true); @@ -283,7 +304,7 @@ Use pandas and summarize findings.`.split("\n"), await agent.generateText("Analyze my data"); const callArgs = vi.mocked(ai.generateText).mock.calls[0]?.[0]; - const systemTexts = getSystemTexts(callArgs?.messages); + const systemTexts = getSystemTexts(callArgs); expect(onPrepareMessages).toHaveBeenCalledTimes(1); expect(systemTexts.some((text) => text.includes(""))).toBe(false); @@ -308,7 +329,7 @@ Use pandas and summarize findings.`.split("\n"), await agent.generateText("Analyze my data"); const callArgs = vi.mocked(ai.generateText).mock.calls[0]?.[0]; - const systemTexts = getSystemTexts(callArgs?.messages); + const systemTexts = getSystemTexts(callArgs); expect(onPrepareMessages).toHaveBeenCalledTimes(1); expect(systemTexts.some((text) => text.includes(""))).toBe(true); @@ -356,15 +377,339 @@ Use pandas and summarize findings.`.split("\n"), expect(ai.generateText).toHaveBeenCalled(); const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; expect(callArgs.model).toBe(mockModel); - if (callArgs.messages) { - expect(callArgs.messages).toHaveLength(2); - expect(callArgs.messages[0].role).toBe("system"); - expect(callArgs.messages[1].role).toBe("user"); - } + expect(getSystemTexts(callArgs)).toContain("You are a helpful assistant"); + expect(callArgs.messages).toHaveLength(1); + expect(callArgs.messages?.[0].role).toBe("user"); expect(result.text).toBe("Generated response"); }); + it("should preserve structured output on generateText results", async () => { + const agent = new Agent({ + name: "StructuredTextAgent", + instructions: "Return structured data", + model: mockModel as any, + }); + + const output = ai.Output.object({ + schema: z.object({ + answer: z.string(), + count: z.number(), + }), + }); + const providerOptions = { + openai: { + reasoningEffort: "low", + }, + } as const; + const context = new Map([["requestId", "req-123"]]); + + const mockResponse = { + text: "Structured response", + content: [{ type: "text", text: "Structured response" }], + reasoning: [], + files: [], + sources: [], + toolCalls: [], + toolResults: [], + finishReason: "stop", + usage: { + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }, + warnings: [], + request: {}, + response: { + id: "structured-response", + modelId: "test-model", + timestamp: new Date(), + messages: [], + }, + steps: [], + output: { + answer: "ok", + count: 2, + }, + }; + + vi.mocked(ai.generateText).mockResolvedValue(mockResponse as any); + + const result = await agent.generateText("Return JSON", { + output, + providerOptions, + context, + userId: "user-1", + conversationId: "conv-1", + }); + + const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; + expect(callArgs.output).toBe(output); + expect(callArgs.providerOptions).toBe(providerOptions); + expect(callArgs.maxRetries).toBe(0); + expect(callArgs.model).toBe(mockModel); + + expect(result.text).toBe("Structured response"); + expect(result.output).toEqual({ answer: "ok", count: 2 }); + expect(result.context.get("requestId")).toBe("req-123"); + }); + + it("should preserve positional generateText options for AI SDK calls", async () => { + const agent = new Agent({ + name: "PositionalTextAgent", + instructions: "You are a helpful assistant", + model: mockModel as any, + }); + + const providerOptions = { + openai: { + reasoningEffort: "medium", + }, + } as const; + const context = new Map([["tenantId", "tenant-1"]]); + const stopWhen = vi.fn(() => false); + const toolApproval = { + get_weather: "user-approval" as const, + }; + const experimentalToolApprovalSecret = new Uint8Array([1, 2, 3]); + + const mockResponse = { + text: "Generated response", + content: [{ type: "text", text: "Generated response" }], + reasoning: [], + files: [], + sources: [], + toolCalls: [], + toolResults: [], + finishReason: "stop", + usage: { + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }, + warnings: [], + request: {}, + response: { + id: "positional-response", + modelId: "test-model", + timestamp: new Date(), + messages: [], + }, + steps: [], + }; + + vi.mocked(ai.generateText).mockResolvedValue(mockResponse as any); + + const result = await agent.generateText("Keep positional API", { + temperature: 0.2, + maxOutputTokens: 256, + topP: 0.8, + seed: 123, + stop: ["END"], + stopWhen, + toolChoice: "none", + toolApproval, + experimental_toolApprovalSecret: experimentalToolApprovalSecret, + providerOptions, + context, + userId: "user-1", + conversationId: "conv-1", + requestHeaders: { + authorization: "Bearer test", + }, + maxSteps: 7, + }); + + const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; + expect(callArgs.model).toBe(mockModel); + expect(callArgs.temperature).toBe(0.2); + expect(callArgs.maxOutputTokens).toBe(256); + expect(callArgs.topP).toBe(0.8); + expect(callArgs.seed).toBe(123); + expect(callArgs.stop).toEqual(["END"]); + expect(callArgs.stopWhen).toBe(stopWhen); + expect(callArgs.toolChoice).toBe("none"); + expect(callArgs.toolApproval).toBe(toolApproval); + expect(callArgs.experimental_toolApprovalSecret).toBe(experimentalToolApprovalSecret); + expect(callArgs.providerOptions).toBe(providerOptions); + expect(callArgs.maxRetries).toBe(0); + expect(callArgs).not.toHaveProperty("context"); + expect(callArgs).not.toHaveProperty("userId"); + expect(callArgs).not.toHaveProperty("conversationId"); + expect(callArgs).not.toHaveProperty("requestHeaders"); + expect(callArgs).not.toHaveProperty("maxSteps"); + expect(result.context.get("tenantId")).toBe("tenant-1"); + }); + + it("should normalize object-style generateText requests", async () => { + const agent = new Agent({ + name: "ObjectStyleTextAgent", + instructions: "You are a helpful assistant", + model: mockModel as any, + }); + + const output = ai.Output.object({ + schema: z.object({ + answer: z.string(), + }), + }); + const providerOptions = { + openai: { + reasoningEffort: "high", + }, + } as const; + const context = { + requestId: "req-object-1", + }; + + const mockResponse = { + text: "Object-style response", + content: [{ type: "text", text: "Object-style response" }], + reasoning: [], + files: [], + sources: [], + toolCalls: [], + toolResults: [], + finishReason: "stop", + usage: { + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }, + warnings: [], + request: {}, + response: { + id: "object-style-response", + modelId: "test-model", + timestamp: new Date(), + messages: [], + }, + steps: [], + output: { + answer: "ok", + }, + }; + + vi.mocked(ai.generateText).mockResolvedValue(mockResponse as any); + + const result = await agent.generateText({ + prompt: "Keep object-style API", + options: { + temperature: 0.2, + providerOptions, + context, + userId: "user-1", + conversationId: "conv-1", + }, + temperature: 0.6, + maxOutputTokens: 64, + output, + }); + + const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; + expect(callArgs.model).toBe(mockModel); + expect(callArgs.temperature).toBe(0.6); + expect(callArgs.maxOutputTokens).toBe(64); + expect(callArgs.providerOptions).toBe(providerOptions); + expect(callArgs.output).toBe(output); + expect(callArgs.maxRetries).toBe(0); + expect(callArgs).not.toHaveProperty("prompt"); + expect(callArgs).not.toHaveProperty("options"); + expect(callArgs).not.toHaveProperty("context"); + expect(callArgs).not.toHaveProperty("userId"); + expect(callArgs).not.toHaveProperty("conversationId"); + expect(result.text).toBe("Object-style response"); + expect(result.output).toEqual({ answer: "ok" }); + expect(result.context.get("requestId")).toBe("req-object-1"); + }); + + it("should normalize voltagent namespaced runtime options for generateText", async () => { + let startContext: any; + let capturedHeaders: Record | undefined; + const agent = new Agent({ + name: "NamespacedRuntimeTextAgent", + instructions: async ({ headers }) => { + capturedHeaders = headers; + return "You are a helpful assistant"; + }, + model: mockModel as any, + hooks: createHooks({ + onStart: ({ context }) => { + startContext = context; + }, + }), + }); + + const mockResponse = { + text: "Namespaced response", + content: [{ type: "text", text: "Namespaced response" }], + reasoning: [], + files: [], + sources: [], + toolCalls: [], + toolResults: [], + finishReason: "stop", + usage: { + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }, + warnings: [], + request: {}, + response: { + id: "namespaced-runtime-response", + modelId: "test-model", + timestamp: new Date(), + messages: [], + }, + steps: [], + }; + + vi.mocked(ai.generateText).mockResolvedValue(mockResponse as any); + + const result = await agent.generateText({ + prompt: "Use namespaced runtime options", + temperature: 0.3, + userId: "legacy-user", + conversationId: "legacy-conv", + context: { + requestId: "legacy-request", + }, + requestHeaders: { + "x-runtime-source": "legacy", + }, + voltagent: { + userId: "runtime-user", + conversationId: "runtime-conv", + context: { + requestId: "runtime-request", + tenantId: "tenant-1", + }, + requestHeaders: { + "x-runtime-source": "voltagent", + }, + maxSteps: 3, + }, + }); + + const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; + expect(callArgs.temperature).toBe(0.3); + expect(callArgs).not.toHaveProperty("voltagent"); + expect(callArgs).not.toHaveProperty("context"); + expect(callArgs).not.toHaveProperty("userId"); + expect(callArgs).not.toHaveProperty("conversationId"); + expect(callArgs).not.toHaveProperty("requestHeaders"); + expect(callArgs).not.toHaveProperty("maxSteps"); + + expect(result.context.get("requestId")).toBe("runtime-request"); + expect(result.context.get("tenantId")).toBe("tenant-1"); + expect(startContext.userId).toBe("runtime-user"); + expect(startContext.conversationId).toBe("runtime-conv"); + expect(capturedHeaders).toEqual({ + "x-runtime-source": "voltagent", + }); + }); + it("should resolve string model ids via registry", async () => { const registry = ModelProviderRegistry.getInstance(); registry.registerProvider("mock", (modelId) => { @@ -666,8 +1011,10 @@ Use pandas and summarize findings.`.split("\n"), const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; expect(Array.isArray(callArgs.messages)).toBe(true); - expect(callArgs.messages?.[0]).toMatchObject({ role: "system" }); - expect((callArgs.messages?.[0] as any).parts).toBeUndefined(); + const instructionMessage = getInstructionMessages(callArgs)[0] as any; + expect(instructionMessage).toMatchObject({ role: "system" }); + expect(instructionMessage.parts).toBeUndefined(); + expect(callArgs.messages?.some((message) => message.role === "system")).toBe(false); }); it("should retain provider options from system instructions", async () => { @@ -721,10 +1068,13 @@ Use pandas and summarize findings.`.split("\n"), await agent.generateText("test"); const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; - // Under the current constraint, we assert only the role is preserved here. - // Provider options handling is validated elsewhere and may be stripped by normalizers. - expect(callArgs.messages?.[0]).toMatchObject({ + expect(getInstructionMessages(callArgs)[0]).toMatchObject({ role: "system", + providerOptions: { + anthropic: { + cacheControl, + }, + }, }); }); @@ -798,7 +1148,7 @@ Use pandas and summarize findings.`.split("\n"), ); const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; - expect(callArgs.messages).toContain(injectedModelMessage); + expect(getInstructionMessages(callArgs)).toContain(injectedModelMessage); }); it("should throw a descriptive error when structured output is missing", async () => { @@ -951,7 +1301,434 @@ Use pandas and summarize findings.`.split("\n"), describe("Stream Text", () => { it("should stream text response", async () => { const agent = new Agent({ - name: "TestAgent", + name: "TestAgent", + instructions: "You are a helpful assistant", + model: mockModel as any, + }); + + const mockStream = { + text: Promise.resolve("Streamed response"), + textStream: (async function* () { + yield "Streamed "; + yield "response"; + })(), + get stream() { + return this.fullStream; + }, + fullStream: (async function* () { + yield { + type: "text-delta" as const, + id: "text-1", + delta: "Streamed ", + text: "Streamed ", + }; + yield { + type: "text-delta" as const, + id: "text-1", + delta: "response", + text: "response", + }; + })(), + usage: Promise.resolve({ + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }), + finishReason: Promise.resolve("stop"), + warnings: [], + // Add missing methods that agent.ts expects + toUIMessageStream: vi.fn(), + toUIMessageStreamResponse: vi.fn(), + pipeUIMessageStreamToResponse: vi.fn(), + pipeTextStreamToResponse: vi.fn(), + toTextStreamResponse: vi.fn(), + partialOutputStream: undefined, + }; + + vi.mocked(ai.streamText).mockReturnValue(mockStream as any); + + const result = await agent.streamText("Stream this"); + + expect(ai.streamText).toHaveBeenCalled(); + const callArgs = vi.mocked(ai.streamText).mock.calls[0][0]; + expect(callArgs.model).toBe(mockModel); + expect(getSystemTexts(callArgs)).toContain("You are a helpful assistant"); + expect(callArgs.messages).toHaveLength(1); + expect(callArgs.messages?.[0].role).toBe("user"); + + const text = await result.text; + expect(text).toBe("Streamed response"); + }); + + it("should preserve positional streamText options for AI SDK calls", async () => { + const agent = new Agent({ + name: "PositionalStreamAgent", + instructions: "You are a helpful assistant", + model: mockModel as any, + }); + + const providerOptions = { + anthropic: { + thinking: { + type: "enabled", + budgetTokens: 1024, + }, + }, + } as const; + const context = new Map([["requestId", "req-456"]]); + const stopWhen = vi.fn(() => false); + const toolApproval = { + get_weather: "approved" as const, + }; + const experimentalToolApprovalSecret = new Uint8Array([4, 5, 6]); + const mockStream = { + text: Promise.resolve("Streamed response"), + textStream: (async function* () { + yield "Streamed response"; + })(), + get stream() { + return this.fullStream; + }, + fullStream: (async function* () { + yield { + type: "text-delta" as const, + id: "text-1", + delta: "Streamed response", + text: "Streamed response", + }; + })(), + usage: Promise.resolve({ + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }), + finishReason: Promise.resolve("stop"), + warnings: [], + toUIMessageStream: vi.fn(), + toUIMessageStreamResponse: vi.fn(), + pipeUIMessageStreamToResponse: vi.fn(), + pipeTextStreamToResponse: vi.fn(), + toTextStreamResponse: vi.fn(), + partialOutputStream: undefined, + }; + + vi.mocked(ai.streamText).mockReturnValue(mockStream as any); + + const result = await agent.streamText("Keep positional stream API", { + temperature: 0.4, + maxOutputTokens: 128, + topK: 20, + seed: 456, + stop: "DONE", + stopWhen, + toolChoice: "none", + toolApproval, + experimental_toolApprovalSecret: experimentalToolApprovalSecret, + providerOptions, + context, + userId: "user-1", + conversationId: "conv-1", + requestHeaders: { + "x-request-id": "req-456", + }, + maxSteps: 5, + }); + + const callArgs = vi.mocked(ai.streamText).mock.calls[0][0]; + expect(callArgs.model).toBe(mockModel); + expect(callArgs.temperature).toBe(0.4); + expect(callArgs.maxOutputTokens).toBe(128); + expect(callArgs.topK).toBe(20); + expect(callArgs.seed).toBe(456); + expect(callArgs.stop).toBe("DONE"); + expect(callArgs.stopWhen).toBe(stopWhen); + expect(callArgs.toolChoice).toBe("none"); + expect(callArgs.toolApproval).toBe(toolApproval); + expect(callArgs.experimental_toolApprovalSecret).toBe(experimentalToolApprovalSecret); + expect(callArgs.providerOptions).toBe(providerOptions); + expect(callArgs.maxRetries).toBe(0); + expect(callArgs).not.toHaveProperty("context"); + expect(callArgs).not.toHaveProperty("userId"); + expect(callArgs).not.toHaveProperty("conversationId"); + expect(callArgs).not.toHaveProperty("requestHeaders"); + expect(callArgs).not.toHaveProperty("maxSteps"); + expect(result.context.get("requestId")).toBe("req-456"); + }); + + it("should normalize object-style streamText requests", async () => { + const agent = new Agent({ + name: "ObjectStyleStreamAgent", + instructions: "You are a helpful assistant", + model: mockModel as any, + }); + + const messages: UIMessage[] = [ + { + id: "msg-1", + role: "user", + parts: [{ type: "text", text: "Stream from messages" }], + }, + ]; + const providerOptions = { + openai: { + reasoningEffort: "low", + }, + } as const; + const context = new Map([["requestId", "req-stream-object"]]); + const mockStream = { + text: Promise.resolve("Streamed object-style response"), + textStream: (async function* () { + yield "Streamed object-style response"; + })(), + get stream() { + return this.fullStream; + }, + fullStream: (async function* () { + yield { + type: "text-delta" as const, + id: "text-1", + delta: "Streamed object-style response", + text: "Streamed object-style response", + }; + })(), + usage: Promise.resolve({ + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }), + finishReason: Promise.resolve("stop"), + warnings: [], + toUIMessageStream: vi.fn(), + toUIMessageStreamResponse: vi.fn(), + pipeUIMessageStreamToResponse: vi.fn(), + pipeTextStreamToResponse: vi.fn(), + toTextStreamResponse: vi.fn(), + partialOutputStream: undefined, + }; + + vi.mocked(ai.streamText).mockReturnValue(mockStream as any); + + const result = await agent.streamText({ + messages, + options: { + temperature: 0.1, + providerOptions, + context, + userId: "user-1", + conversationId: "conv-1", + }, + temperature: 0.5, + topP: 0.9, + }); + + const callArgs = vi.mocked(ai.streamText).mock.calls[0][0]; + expect(callArgs.model).toBe(mockModel); + expect(callArgs.temperature).toBe(0.5); + expect(callArgs.topP).toBe(0.9); + expect(callArgs.providerOptions).toBe(providerOptions); + expect(callArgs.maxRetries).toBe(0); + expect(callArgs).not.toHaveProperty("messagesInput"); + expect(callArgs).not.toHaveProperty("options"); + expect(callArgs).not.toHaveProperty("context"); + expect(callArgs).not.toHaveProperty("userId"); + expect(callArgs).not.toHaveProperty("conversationId"); + expect(result.context.get("requestId")).toBe("req-stream-object"); + }); + + it("should normalize voltagent namespaced runtime options for positional streamText", async () => { + let startContext: any; + const agent = new Agent({ + name: "NamespacedRuntimeStreamAgent", + instructions: "You are a helpful assistant", + model: mockModel as any, + hooks: createHooks({ + onStart: ({ context }) => { + startContext = context; + }, + }), + }); + + const mockStream = { + text: Promise.resolve("Streamed namespaced response"), + textStream: (async function* () { + yield "Streamed namespaced response"; + })(), + get stream() { + return this.fullStream; + }, + fullStream: (async function* () { + yield { + type: "text-delta" as const, + id: "text-1", + delta: "Streamed namespaced response", + text: "Streamed namespaced response", + }; + })(), + usage: Promise.resolve({ + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }), + finishReason: Promise.resolve("stop"), + warnings: [], + toUIMessageStream: vi.fn(), + toUIMessageStreamResponse: vi.fn(), + pipeUIMessageStreamToResponse: vi.fn(), + pipeTextStreamToResponse: vi.fn(), + toTextStreamResponse: vi.fn(), + partialOutputStream: undefined, + }; + + vi.mocked(ai.streamText).mockReturnValue(mockStream as any); + + const result = await agent.streamText("Stream with namespaced options", { + userId: "legacy-user", + conversationId: "legacy-conv", + context: { + requestId: "legacy-request", + }, + voltagent: { + userId: "runtime-user", + conversationId: "runtime-conv", + context: { + requestId: "runtime-request", + }, + resumableStream: true, + }, + }); + + const callArgs = vi.mocked(ai.streamText).mock.calls[0][0]; + expect(callArgs).not.toHaveProperty("voltagent"); + expect(callArgs).not.toHaveProperty("context"); + expect(callArgs).not.toHaveProperty("userId"); + expect(callArgs).not.toHaveProperty("conversationId"); + expect(callArgs).not.toHaveProperty("resumableStream"); + expect(result.context.get("requestId")).toBe("runtime-request"); + expect(startContext.userId).toBe("runtime-user"); + expect(startContext.conversationId).toBe("runtime-conv"); + }); + + it("should pass AI SDK v7 generateText options, strip VoltAgent-owned telemetry/runtime fields, and compose managed callbacks", async () => { + const hookOnStepEnd = vi.fn(); + const userOnStepEnd = vi.fn(); + const userOnEnd = vi.fn(); + const onStart = vi.fn(); + const onStepStart = vi.fn(); + const experimentalDownload = vi.fn(async (downloads: Array<{ url: URL }>) => + downloads.map(() => null), + ); + const agent = new Agent({ + name: "AISDKOptionsAgent", + instructions: "You are a helpful assistant", + model: mockModel as any, + hooks: createHooks({ + onStepEnd: hookOnStepEnd, + }), + }); + + vi.mocked(ai.generateText).mockResolvedValue({ + text: "Response", + content: [{ type: "text", text: "Response" }], + reasoning: [], + files: [], + sources: [], + toolCalls: [], + toolResults: [], + finishReason: "stop", + usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 }, + warnings: [], + request: {}, + response: { + id: "test", + modelId: "test-model", + timestamp: new Date(), + messages: [], + }, + steps: [], + } as any); + + await agent.generateText({ + prompt: "Hello", + timeout: { + totalMs: 10_000, + stepMs: 5_000, + }, + headers: { + "x-provider-header": "provider-value", + }, + include: { + requestBody: true, + requestMessages: true, + responseBody: true, + }, + experimental_download: experimentalDownload, + onStart, + onStepStart, + onStepEnd: userOnStepEnd, + onEnd: userOnEnd, + ...({ + telemetry: { + isEnabled: false, + functionId: "generateText-test", + }, + experimental_telemetry: { + isEnabled: false, + }, + runtimeContext: { + tenantId: "tenant-1", + }, + toolsContext: { + lookup_order: { + requestId: "tool-request-1", + }, + }, + } as Record), + }); + + const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; + expect(callArgs.timeout).toEqual({ totalMs: 10_000, stepMs: 5_000 }); + expect(callArgs.headers).toEqual({ "x-provider-header": "provider-value" }); + expect(callArgs.telemetry).toBeUndefined(); + expect(callArgs.experimental_telemetry).toBeUndefined(); + expect(callArgs.runtimeContext).toBeUndefined(); + expect(callArgs.toolsContext).toEqual({ + lookup_order: { + requestId: "tool-request-1", + }, + }); + expect(callArgs.include).toEqual({ + requestBody: true, + requestMessages: true, + responseBody: true, + }); + expect(callArgs.experimental_download).toBe(experimentalDownload); + expect(callArgs.onStart).toBe(onStart); + expect(callArgs.onStepStart).toBe(onStepStart); + expect(callArgs.onEnd).toBeUndefined(); + expect(callArgs.onFinish).toBeUndefined(); + expect(userOnEnd).toHaveBeenCalledTimes(1); + expect(userOnEnd.mock.calls[0][0]).toMatchObject({ + text: "Response", + context: expect.any(Map), + }); + + await callArgs.onStepEnd?.({ + content: [], + response: { + messages: [], + }, + } as any); + + expect(hookOnStepEnd).toHaveBeenCalledTimes(1); + expect(userOnStepEnd).toHaveBeenCalledTimes(1); + }); + + it("should pass AI SDK v7 streamText options and compose managed callbacks", async () => { + const onChunk = vi.fn(); + const onAbort = vi.fn(); + const userOnError = vi.fn(); + const agent = new Agent({ + name: "AISDKStreamOptionsAgent", instructions: "You are a helpful assistant", model: mockModel as any, }); @@ -959,21 +1736,104 @@ Use pandas and summarize findings.`.split("\n"), const mockStream = { text: Promise.resolve("Streamed response"), textStream: (async function* () { - yield "Streamed "; - yield "response"; + yield "Streamed response"; })(), + get stream() { + return this.fullStream; + }, fullStream: (async function* () { yield { type: "text-delta" as const, id: "text-1", - delta: "Streamed ", - text: "Streamed ", + delta: "Streamed response", + text: "Streamed response", }; + })(), + usage: Promise.resolve({ + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }), + finishReason: Promise.resolve("stop"), + warnings: [], + toUIMessageStream: vi.fn(), + toUIMessageStreamResponse: vi.fn(), + pipeUIMessageStreamToResponse: vi.fn(), + pipeTextStreamToResponse: vi.fn(), + toTextStreamResponse: vi.fn(), + partialOutputStream: undefined, + }; + + vi.mocked(ai.streamText).mockReturnValue(mockStream as any); + + await agent.streamText({ + prompt: "Hello", + timeout: { + totalMs: 10_000, + chunkMs: 1_000, + }, + include: { + requestBody: true, + requestMessages: true, + rawChunks: true, + }, + includeRawChunks: true, + experimental_transform: [], + onChunk, + onAbort, + onError: userOnError, + }); + + const callArgs = vi.mocked(ai.streamText).mock.calls[0][0]; + expect(callArgs.timeout).toEqual({ totalMs: 10_000, chunkMs: 1_000 }); + expect(callArgs.include).toEqual({ + requestBody: true, + requestMessages: true, + rawChunks: true, + }); + expect(callArgs.includeRawChunks).toBe(true); + expect(callArgs.experimental_transform).toEqual([]); + expect(callArgs.onChunk).toBe(onChunk); + expect(callArgs.onAbort).toBe(onAbort); + expect(callArgs.onError).not.toBe(userOnError); + + const abortError = new Error("client aborted"); + abortError.name = "AbortError"; + await callArgs.onError?.({ error: abortError }); + + expect(userOnError).toHaveBeenCalledTimes(1); + expect(userOnError).toHaveBeenCalledWith({ error: abortError }); + }); + + it("should use bailed delegate_task output as streamText final text", async () => { + const agent = new Agent({ + name: "SupervisorAgent", + instructions: "Delegate when useful", + model: mockModel as any, + }); + + const mockStream = { + text: Promise.resolve("Supervisor continuation"), + textStream: (async function* () { + yield "Supervisor continuation"; + })(), + get stream() { + return this.fullStream; + }, + fullStream: (async function* () { yield { - type: "text-delta" as const, - id: "text-1", - delta: "response", - text: "response", + type: "tool-result" as const, + toolCallId: "call-1", + toolName: "delegate_task", + input: {}, + output: [ + { + agentName: "Research Agent", + response: "Bailed final answer", + usage: {}, + bailed: true, + }, + ], }; })(), usage: Promise.resolve({ @@ -983,7 +1843,6 @@ Use pandas and summarize findings.`.split("\n"), }), finishReason: Promise.resolve("stop"), warnings: [], - // Add missing methods that agent.ts expects toUIMessageStream: vi.fn(), toUIMessageStreamResponse: vi.fn(), pipeUIMessageStreamToResponse: vi.fn(), @@ -994,19 +1853,33 @@ Use pandas and summarize findings.`.split("\n"), vi.mocked(ai.streamText).mockReturnValue(mockStream as any); - const result = await agent.streamText("Stream this"); - - expect(ai.streamText).toHaveBeenCalled(); + const result = await agent.streamText("Delegate this"); const callArgs = vi.mocked(ai.streamText).mock.calls[0][0]; - expect(callArgs.model).toBe(mockModel); - if (callArgs.messages) { - expect(callArgs.messages).toHaveLength(2); - expect(callArgs.messages[0].role).toBe("system"); - expect(callArgs.messages[1].role).toBe("user"); - } - const text = await result.text; - expect(text).toBe("Streamed response"); + await callArgs.onStepEnd?.({ + content: [ + { + type: "tool-result", + toolCallId: "call-1", + toolName: "delegate_task", + input: {}, + output: [ + { + agentName: "Research Agent", + response: "Bailed final answer", + usage: {}, + bailed: true, + }, + ], + }, + ], + response: { + messages: [], + }, + } as any); + + expect(callArgs.abortSignal.aborted).toBe(true); + await expect(result.text).resolves.toBe("Bailed final answer"); }); it("does not eagerly materialize lazy stream result promises", async () => { @@ -1030,6 +1903,9 @@ Use pandas and summarize findings.`.split("\n"), textStream: (async function* () { yield "Streamed response"; })(), + get stream() { + return this.fullStream; + }, fullStream: toAsyncIterableStream( convertArrayToReadableStream([ { @@ -1097,6 +1973,9 @@ Use pandas and summarize findings.`.split("\n"), textStream: (async function* () { yield "Streamed response"; })(), + get stream() { + return this.fullStream; + }, fullStream: (async function* () { yield { type: "start" as const, @@ -1153,7 +2032,7 @@ Use pandas and summarize findings.`.split("\n"), expect(callArgs?.generateMessageId()).toBe(generatedId); const parts: any[] = []; - for await (const part of result.fullStream) { + for await (const part of result.stream) { parts.push(part); } expect(parts).toHaveLength(2); @@ -1187,6 +2066,9 @@ Use pandas and summarize findings.`.split("\n"), textStream: (async function* () { yield "Streamed response"; })(), + get stream() { + return this.fullStream; + }, fullStream: (async function* () { yield { type: "finish-step" as const, @@ -1220,7 +2102,7 @@ Use pandas and summarize findings.`.split("\n"), const result = await agent.streamText("Stream this"); const parts: any[] = []; - for await (const part of result.fullStream) { + for await (const part of result.stream) { parts.push(part); } @@ -1255,6 +2137,7 @@ Use pandas and summarize findings.`.split("\n"), textStream: (async function* () { yield "Final answer"; })(), + stream: fullStream, fullStream, usage: Promise.resolve({ inputTokens: 10, @@ -1275,7 +2158,7 @@ Use pandas and summarize findings.`.split("\n"), const result = await agent.streamText("answer me"); const emittedTypes: string[] = []; - for await (const part of result.fullStream as AsyncIterable<{ type: string }>) { + for await (const part of result.stream as AsyncIterable<{ type: string }>) { emittedTypes.push(part.type); } @@ -1315,10 +2198,14 @@ Use pandas and summarize findings.`.split("\n"), return toAsyncIterableStream(probeStream); } - get fullStream(): ai.AsyncIterableStream { + get stream(): ai.AsyncIterableStream { return this.teeStream(); } + get fullStream(): ai.AsyncIterableStream { + return this.stream; + } + get text(): Promise { return this.cachedText; } @@ -1345,7 +2232,7 @@ Use pandas and summarize findings.`.split("\n"), private async consumeText(): Promise { let text = ""; - for await (const part of this.fullStream) { + for await (const part of this.stream) { if (part.type === "text-delta" && typeof part.delta === "string") { text += part.delta; } @@ -1360,7 +2247,7 @@ Use pandas and summarize findings.`.split("\n"), const result = await agent.streamText("answer me"); const emittedTypes: string[] = []; - for await (const part of result.fullStream as AsyncIterable<{ type: string }>) { + for await (const part of result.stream as AsyncIterable<{ type: string }>) { emittedTypes.push(part.type); } @@ -1437,6 +2324,36 @@ Use pandas and summarize findings.`.split("\n"), const tools = agent.getTools(); expect(tools).toHaveLength(1); // But only keeps one instance }); + + it("should expose AI SDK ToolSet tools from getTools", () => { + const agent = new Agent({ + name: "TestAgent", + instructions: "Test", + model: mockModel as any, + tools: { + get_weather: aiSdkTool({ + description: "Get weather", + inputSchema: z.object({ city: z.string() }), + execute: async ({ city }) => ({ city, temperature: 72 }), + voltagent: { + name: "Weather Lookup", + purpose: "Fetch weather observations", + tags: ["weather"], + }, + }), + }, + }); + + const tools = agent.getTools(); + expect(tools).toHaveLength(1); + expect(tools[0]).toMatchObject({ + name: "get_weather", + displayName: "Weather Lookup", + purpose: "Fetch weather observations", + description: "Get weather", + tags: ["weather"], + }); + }); }); describe("Tool Execution", () => { @@ -2578,7 +3495,7 @@ Use pandas and summarize findings.`.split("\n"), totalUsage: providerUsage, }; } finally { - await args.onFinish?.(finalResult); + await args.onEnd?.(finalResult); } })(); @@ -2587,6 +3504,7 @@ Use pandas and summarize findings.`.split("\n"), textStream: (async function* () { yield "Persisted stream response"; })(), + stream: fullStream, fullStream, usage: Promise.resolve(providerUsage), finishReason: Promise.resolve("stop"), @@ -2613,7 +3531,7 @@ Use pandas and summarize findings.`.split("\n"), }, }); - for await (const _part of result.fullStream) { + for await (const _part of result.stream) { // Consume stream to trigger mocked onFinish. } @@ -3144,6 +4062,7 @@ Use pandas and summarize findings.`.split("\n"), name: "TestAgent", instructions: "Test", model: mockModel as any, + maxRetries: 0, hooks: { onError }, }); @@ -3269,177 +4188,402 @@ Use pandas and summarize findings.`.split("\n"), warnings: [], request: {}, response: { - id: "test", + id: "test", + modelId: "test-model", + timestamp: new Date(), + messages: [], + }, + steps, + } as any); + + await agent.generateText("Test"); + + expect(onEnd).toHaveBeenCalledTimes(1); + const output = onEnd.mock.calls[0]?.[0].output; + expect(output?.usage).toEqual(stepUsages[2]); + expect(output?.totalUsage).toEqual(totalUsage); + expect(output?.steps?.map((step: any) => step.usage)).toEqual(stepUsages); + }); + + it("should call onStepEnd for multi-step generation", async () => { + const onStepEndSpy = vi.fn(); + const agent = new Agent({ + name: "TestAgent", + instructions: "Test", + model: mockModel as any, + hooks: { onStepEnd: onStepEndSpy }, + maxSteps: 2, + }); + + // Mock a multi-step response with tool calls + const mockResponse = { + text: "Final response", + content: [], + reasoning: [], + files: [], + sources: [], + toolCalls: [], + toolResults: [], + finishReason: "stop", + usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 }, + warnings: [], + request: {}, + response: { + id: "test", + modelId: "test-model", + timestamp: new Date(), + messages: [], + }, + steps: [ + { stepNumber: 1, output: "Step 1" }, + { stepNumber: 2, output: "Step 2" }, + ], + }; + + vi.mocked(ai.generateText).mockResolvedValue(mockResponse as any); + + await agent.generateText("Test with steps"); + + // onStepEnd might be called, depending on implementation + // Just verify the test doesn't throw + expect(onStepEndSpy.mock.calls.length).toBeGreaterThanOrEqual(0); + }); + }); + + describe("SubAgent Management", () => { + it("should add subagents", () => { + const agent = new Agent({ + name: "MainAgent", + instructions: "Main", + model: mockModel as any, + }); + + const subAgent = new Agent({ + name: "SubAgent", + instructions: "Sub", + model: mockModel as any, + }); + + agent.addSubAgent(subAgent); + + const subAgents = agent.getSubAgents(); + expect(subAgents).toHaveLength(1); + }); + + it("should remove subagents", () => { + const subAgent = new Agent({ + name: "SubAgent", + instructions: "Sub", + model: mockModel as any, + }); + + const agent = new Agent({ + name: "MainAgent", + instructions: "Main", + model: mockModel as any, + subAgents: [subAgent], + }); + + agent.removeSubAgent(subAgent.id); + + const subAgents = agent.getSubAgents(); + expect(subAgents).toHaveLength(0); + }); + }); + + describe("Object Generation", () => { + const streamObjectUsage = { + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }; + + const collectAsyncIterable = async (iterable: AsyncIterable): Promise => { + const items: T[] = []; + for await (const item of iterable) { + items.push(item); + } + return items; + }; + + const createMockStructuredStreamTextResult = ( + args: { onEnd?: (result: any) => Promise | void }, + finalObject: Record, + partials: Array>, + ) => { + const finalResult = { + text: safeStringify(finalObject), + output: finalObject, + finishReason: "stop", + usage: streamObjectUsage, + totalUsage: streamObjectUsage, + warnings: [], + response: { + id: "stream-object-response", + modelId: "test-model", + timestamp: new Date(), + }, + steps: [], + }; + let finishTriggered = false; + const triggerFinish = async () => { + if (!finishTriggered) { + finishTriggered = true; + await args.onEnd?.(finalResult); + } + }; + + const partialOutputStream = (async function* () { + for (const partial of partials) { + yield partial; + } + await triggerFinish(); + })(); + + return { + output: Promise.resolve(finalObject), + partialOutputStream, + textStream: (async function* () { + yield safeStringify(finalObject); + })(), + get stream() { + return this.fullStream; + }, + fullStream: (async function* () { + yield { type: "text-delta", text: safeStringify(partials.at(-1) ?? finalObject) }; + yield { type: "finish", finishReason: "stop", usage: streamObjectUsage }; + })(), + usage: Promise.resolve(streamObjectUsage), + finishReason: Promise.resolve("stop"), + warnings: [], + pipeTextStreamToResponse: vi.fn(), + toTextStreamResponse: vi.fn(() => new Response("streamed object")), + }; + }; + + it("should generate object with schema", async () => { + const agent = new Agent({ + name: "TestAgent", + instructions: "Generate structured data", + model: mockModel as any, + }); + + const schema = z.object({ + name: z.string(), + age: z.number(), + }); + + const mockResponse = { + text: '{"name":"John","age":30}', + content: [{ type: "text", text: '{"name":"John","age":30}' }], + reasoning: [], + reasoningText: undefined, + files: [], + sources: [], + toolCalls: [], + toolResults: [], + output: { name: "John", age: 30 }, + finishReason: "stop", + usage: { + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }, + totalUsage: { + inputTokens: 10, + outputTokens: 5, + totalTokens: 15, + }, + warnings: [], + request: {}, + response: { + id: "object-response", modelId: "test-model", timestamp: new Date(), messages: [], }, - steps, - } as any); + steps: [], + }; - await agent.generateText("Test"); + vi.mocked(ai.generateText).mockResolvedValue(mockResponse as any); - expect(onEnd).toHaveBeenCalledTimes(1); - const output = onEnd.mock.calls[0]?.[0].output; - expect(output?.usage).toEqual(stepUsages[2]); - expect(output?.totalUsage).toEqual(totalUsage); - expect(output?.steps?.map((step: any) => step.usage)).toEqual(stepUsages); + const result = await agent.generateObject("Generate a person", schema); + + expect(ai.generateText).toHaveBeenCalled(); + expect(ai.generateObject).not.toHaveBeenCalled(); + const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; + expect(callArgs.output).toBeDefined(); + expect(callArgs.output).toHaveProperty("parseCompleteOutput"); + expect(result.object).toEqual({ name: "John", age: 30 }); }); - it("should call onStepFinish for multi-step generation", async () => { - const onStepFinish = vi.fn(); + it("should normalize voltagent namespaced runtime options for generateObject", async () => { + let startContext: any; const agent = new Agent({ - name: "TestAgent", - instructions: "Test", + name: "NamespacedRuntimeObjectAgent", + instructions: "Generate structured data", model: mockModel as any, - hooks: { onStepFinish }, - maxSteps: 2, + hooks: createHooks({ + onStart: ({ context }) => { + startContext = context; + }, + }), + }); + + const schema = z.object({ + name: z.string(), }); - // Mock a multi-step response with tool calls const mockResponse = { - text: "Final response", - content: [], + text: '{"name":"Ada"}', + content: [{ type: "text", text: '{"name":"Ada"}' }], reasoning: [], + reasoningText: undefined, files: [], sources: [], toolCalls: [], toolResults: [], + output: { name: "Ada" }, finishReason: "stop", - usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 }, + usage: streamObjectUsage, + totalUsage: streamObjectUsage, warnings: [], request: {}, response: { - id: "test", + id: "namespaced-object-response", modelId: "test-model", timestamp: new Date(), messages: [], }, - steps: [ - { stepNumber: 1, output: "Step 1" }, - { stepNumber: 2, output: "Step 2" }, - ], + steps: [], }; vi.mocked(ai.generateText).mockResolvedValue(mockResponse as any); - await agent.generateText("Test with steps"); - - // onStepFinish might be called, depending on implementation - // Just verify the test doesn't throw - expect(onStepFinish.mock.calls.length).toBeGreaterThanOrEqual(0); - }); - }); - - describe("SubAgent Management", () => { - it("should add subagents", () => { - const agent = new Agent({ - name: "MainAgent", - instructions: "Main", - model: mockModel as any, - }); - - const subAgent = new Agent({ - name: "SubAgent", - instructions: "Sub", - model: mockModel as any, - }); - - agent.addSubAgent(subAgent); - - const subAgents = agent.getSubAgents(); - expect(subAgents).toHaveLength(1); - }); - - it("should remove subagents", () => { - const subAgent = new Agent({ - name: "SubAgent", - instructions: "Sub", - model: mockModel as any, - }); - - const agent = new Agent({ - name: "MainAgent", - instructions: "Main", - model: mockModel as any, - subAgents: [subAgent], + const result = await agent.generateObject("Generate a person", schema, { + userId: "legacy-user", + conversationId: "legacy-conv", + context: { + requestId: "legacy-request", + }, + voltagent: { + userId: "runtime-user", + conversationId: "runtime-conv", + context: { + requestId: "runtime-request", + }, + }, }); - agent.removeSubAgent(subAgent.id); - - const subAgents = agent.getSubAgents(); - expect(subAgents).toHaveLength(0); + const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; + expect(callArgs).not.toHaveProperty("voltagent"); + expect(callArgs).not.toHaveProperty("context"); + expect(callArgs).not.toHaveProperty("userId"); + expect(callArgs).not.toHaveProperty("conversationId"); + expect(result.object).toEqual({ name: "Ada" }); + expect(result.context.get("requestId")).toBe("runtime-request"); + expect(startContext.userId).toBe("runtime-user"); + expect(startContext.conversationId).toBe("runtime-conv"); }); - }); - describe("Object Generation", () => { - it("should generate object with schema", async () => { + it("should expose the streamObject public stream contract", async () => { const agent = new Agent({ name: "TestAgent", - instructions: "Generate structured data", + instructions: "Stream structured data", model: mockModel as any, }); const schema = z.object({ - name: z.string(), - age: z.number(), + message: z.string(), }); - const mockResponse = { - object: { name: "John", age: 30 }, - finishReason: "stop", - usage: { - inputTokens: 10, - outputTokens: 5, - totalTokens: 15, - }, - warnings: [], - }; + const mockStream = createMockStructuredStreamTextResult({}, { message: "Hello" }, [ + { message: "H" }, + { message: "Hello" }, + ]); - vi.mocked(ai.generateObject).mockResolvedValue(mockResponse as any); + vi.mocked(ai.streamText).mockReturnValue(mockStream as any); - const result = await agent.generateObject("Generate a person", schema); + const result = await agent.streamObject("Stream a message", schema, { + context: { + requestId: "req-1", + }, + }); - expect(ai.generateObject).toHaveBeenCalled(); - expect(result.object).toEqual({ name: "John", age: 30 }); + expect(ai.streamText).toHaveBeenCalled(); + expect(ai.streamObject).not.toHaveBeenCalled(); + const callArgs = vi.mocked(ai.streamText).mock.calls.at(-1)?.[0]; + expect(callArgs?.output).toBeDefined(); + expect(callArgs?.output).toHaveProperty("parseCompleteOutput"); + expect(result.context).toBeInstanceOf(Map); + expect(result.context.get("requestId")).toBe("req-1"); + + await expect(result.object).resolves.toEqual({ message: "Hello" }); + await expect(result.usage).resolves.toEqual(streamObjectUsage); + await expect(result.finishReason).resolves.toBe("stop"); + + await expect(collectAsyncIterable(result.partialObjectStream as any)).resolves.toEqual([ + { message: "H" }, + { message: "Hello" }, + ]); + await expect(collectAsyncIterable(result.textStream as any)).resolves.toEqual([ + safeStringify({ message: "Hello" }), + ]); + expect(await result.toTextStreamResponse().text()).toBe("streamed object"); + expect(mockStream.toTextStreamResponse).toHaveBeenCalled(); }); - it("should stream object with schema", async () => { + it("should apply streamObject output guardrails before result object and onFinish", async () => { + const outputGuardrail = vi.fn(({ output }) => ({ + pass: true, + action: "modify" as const, + modifiedOutput: { + ...(output as Record), + message: "Safe", + }, + })); + const userOnFinish = vi.fn(); const agent = new Agent({ name: "TestAgent", instructions: "Stream structured data", model: mockModel as any, + outputGuardrails: [outputGuardrail as any], }); const schema = z.object({ message: z.string(), }); - const mockStream = { - object: Promise.resolve({ message: "Hello" }), - partialObjectStream: (async function* () { - yield { message: "H" }; - yield { message: "Hello" }; - })(), - fullStream: (async function* () { - yield { type: "object-delta", delta: { message: "H" } }; - yield { type: "object-delta", delta: { message: "ello" } }; - })(), - usage: Promise.resolve({ - inputTokens: 10, - outputTokens: 5, - totalTokens: 15, - }), - warnings: [], - }; + vi.mocked(ai.streamText).mockImplementation( + (args: any) => + createMockStructuredStreamTextResult(args, { message: "Unsafe" }, [ + { message: "Un" }, + { message: "Unsafe" }, + ]) as any, + ); - vi.mocked(ai.streamObject).mockReturnValue(mockStream as any); + const result = await agent.streamObject("Stream a guarded message", schema, { + onEnd: userOnFinish, + }); - const result = await agent.streamObject("Stream a message", schema); + await collectAsyncIterable(result.partialObjectStream as any); - expect(ai.streamObject).toHaveBeenCalled(); const obj = await result.object; - expect(obj).toEqual({ message: "Hello" }); + expect(obj).toEqual({ message: "Safe" }); + expect(outputGuardrail).toHaveBeenCalledWith( + expect.objectContaining({ + output: { message: "Unsafe" }, + originalOutput: { message: "Unsafe" }, + operation: "streamObject", + }), + ); + expect(userOnFinish).toHaveBeenCalledWith( + expect.objectContaining({ + object: { message: "Safe" }, + finishReason: "stop", + usage: streamObjectUsage, + }), + ); }); it("should abort with ToolDeniedError passed to abortController", async () => { @@ -3993,6 +5137,7 @@ Use pandas and summarize findings.`.split("\n"), name: "TestAgent", instructions: "Test", model: mockModel as any, + maxRetries: 0, }); const modelError = new Error("Model unavailable"); @@ -4006,6 +5151,7 @@ Use pandas and summarize findings.`.split("\n"), name: "TestAgent", instructions: "Test", model: mockModel as any, + maxRetries: 0, }); // Test with null/undefined @@ -4074,9 +5220,7 @@ Use pandas and summarize findings.`.split("\n"), expect(dynamicInstructions).toHaveBeenCalled(); const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; - if (callArgs?.messages?.[0]) { - expect(callArgs.messages[0].role).toBe("system"); - } + expect(getInstructionMessages(callArgs)[0]?.role).toBe("system"); }); it("should handle retriever integration", async () => { @@ -4203,7 +5347,9 @@ Use pandas and summarize findings.`.split("\n"), expect(dynamicTools).toHaveBeenCalledTimes(1); const callArgs = vi.mocked(ai.generateText).mock.calls[0][0]; - const systemMessage = callArgs.messages?.find((message: any) => message.role === "system"); + const systemMessage = getInstructionMessages(callArgs).find( + (message: any) => message.role === "system", + ); expect(systemMessage?.content).toContain("Base instructions"); expect(systemMessage?.content).toContain("My test instructions"); @@ -4394,6 +5540,105 @@ Use pandas and summarize findings.`.split("\n"), expect(prepared["static-only"].description).toBe("Static only tool"); }); + it("should prepare AI SDK tool records with VoltAgent metadata hooks", async () => { + const inputSchema = z.object({ + location: z.string(), + }); + const execute = vi.fn().mockResolvedValue({ location: "SF", temp: 72 }); + const toolOnStart = vi.fn(); + const agentOnToolStart = vi.fn(); + const agentOnToolEnd = vi.fn(); + + const agent = new Agent({ + name: "TestAgent", + instructions: "Test", + model: mockModel as any, + tools: { + get_weather: aiSdkTool({ + description: "Get weather", + inputSchema, + execute, + voltagent: { + name: "Weather Lookup", + purpose: "Fetch weather observations", + tags: ["weather", "external-api"], + hooks: { + onStart: toolOnStart, + }, + }, + }), + }, + hooks: { + onToolStart: agentOnToolStart, + onToolEnd: agentOnToolEnd, + }, + }); + + const operationContext = (agent as any).createOperationContext("input message"); + const createChildSpanSpy = vi.spyOn(operationContext.traceContext, "createChildSpan"); + const prepared = await (agent as any).prepareTools([], operationContext, 3, {}); + + expect(prepared.get_weather.description).toBe("Get weather"); + expect(prepared.get_weather.inputSchema).toBe(inputSchema); + expect(prepared.get_weather.metadata?.voltagent).toMatchObject({ + name: "Weather Lookup", + purpose: "Fetch weather observations", + tags: ["weather", "external-api"], + }); + + await expect( + prepared.get_weather.execute( + { location: "SF" }, + { + toolCallId: "call-1", + messages: [], + abortSignal: new AbortController().signal, + context: undefined, + }, + ), + ).resolves.toEqual({ location: "SF", temp: 72 }); + + expect(execute).toHaveBeenCalledWith( + { location: "SF" }, + expect.objectContaining({ toolCallId: "call-1" }), + ); + const toolSpanCall = createChildSpanSpy.mock.calls.find( + ([spanName]) => spanName === "tool.execution:get_weather", + ); + expect(toolSpanCall?.[2]).toMatchObject({ + label: "get_weather", + attributes: expect.objectContaining({ + "tool.name": "get_weather", + "tool.display_name": "Weather Lookup", + "tool.purpose": "Fetch weather observations", + "tool.description": "Get weather", + }), + }); + expect(toolOnStart).toHaveBeenCalledWith( + expect.objectContaining({ + args: { location: "SF" }, + tool: expect.objectContaining({ + name: "get_weather", + tags: ["weather", "external-api"], + }), + }), + ); + expect(agentOnToolStart).toHaveBeenCalledWith( + expect.objectContaining({ + agent, + args: { location: "SF" }, + tool: expect.objectContaining({ name: "get_weather" }), + }), + ); + expect(agentOnToolEnd).toHaveBeenCalledWith( + expect.objectContaining({ + agent, + output: { location: "SF", temp: 72 }, + tool: expect.objectContaining({ name: "get_weather" }), + }), + ); + }); + it("should prefer user-defined callTool/searchTools when tool routing is enabled", async () => { const callTool = new Tool({ name: "callTool", @@ -4481,6 +5726,51 @@ Use pandas and summarize findings.`.split("\n"), ); }); + it("should apply native toolApproval to tool routing pool calls", async () => { + const execute = vi.fn().mockResolvedValue("sensitive-result"); + const sensitiveTool = new Tool({ + name: "sensitiveTool", + description: "Sensitive tool", + parameters: z.object({ + query: z.string(), + }), + execute, + }); + + const agent = new Agent({ + name: "TestAgent", + instructions: "Test", + model: mockModel as any, + toolRouting: { + enforceSearchBeforeCall: false, + }, + tools: [sensitiveTool], + }); + + const testAgent = agent as unknown as TestAgentInternals; + const operationContext = testAgent.createOperationContext("input message"); + const prepared = await testAgent.prepareTools([], operationContext, 3, { + toolApproval: { + sensitiveTool: "user-approval", + }, + }); + + await expect( + prepared.callTool.execute({ + name: "sensitiveTool", + args: { + query: "secret", + }, + }), + ).resolves.toMatchObject({ + error: true, + name: "sensitiveTool", + code: "TOOL_APPROVAL_REQUIRED", + message: "Tool sensitiveTool requires user approval.", + }); + expect(execute).not.toHaveBeenCalled(); + }); + it("should add delegate tool when subagents are present", async () => { const agent = new Agent({ name: "TestAgent", @@ -4627,6 +5917,75 @@ Use pandas and summarize findings.`.split("\n"), expect(toolNames).not.toContain("update_working_memory"); expect(toolNames).not.toContain("clear_working_memory"); }); + + it("should execute working memory tools against the resolved memory envelope", async () => { + const memory = new Memory({ + storage: new InMemoryStorageAdapter(), + workingMemory: { + enabled: true, + }, + }); + + const agent = new Agent({ + name: "TestAgent", + instructions: "Test", + model: mockModel as any, + memory, + }); + await memory.createConversation({ + id: "memory-conv", + userId: "memory-user", + title: "Memory Conversation", + metadata: {}, + }); + await memory.createConversation({ + id: "legacy-conv", + userId: "legacy-user", + title: "Legacy Conversation", + metadata: {}, + }); + + const options = { + userId: "legacy-user", + conversationId: "legacy-conv", + memory: { + userId: "memory-user", + conversationId: "memory-conv", + }, + } as any; + const operationContext = (agent as any).createOperationContext("input message", options); + const runtimeTools = (agent as any).createWorkingMemoryTools(options, operationContext); + const getWorkingMemoryTool = runtimeTools.find( + (tool: Tool) => tool.name === "get_working_memory", + ); + const updateWorkingMemoryTool = runtimeTools.find( + (tool: Tool) => tool.name === "update_working_memory", + ); + + await updateWorkingMemoryTool?.execute?.( + { + content: "Preferred language: Turkish", + mode: "replace", + }, + operationContext, + ); + + await expect( + memory.getWorkingMemory({ + userId: "memory-user", + conversationId: "memory-conv", + }), + ).resolves.toBe("Preferred language: Turkish"); + await expect( + memory.getWorkingMemory({ + userId: "legacy-user", + conversationId: "legacy-conv", + }), + ).resolves.toBeNull(); + await expect(getWorkingMemoryTool?.execute?.({}, operationContext)).resolves.toBe( + "Preferred language: Turkish", + ); + }); }); describe("Utility Methods", () => { diff --git a/packages/core/src/agent/agent.ts b/packages/core/src/agent/agent.ts index 9bc2ed8b2..4dbf3fdf6 100644 --- a/packages/core/src/agent/agent.ts +++ b/packages/core/src/agent/agent.ts @@ -14,12 +14,13 @@ import { safeStringify } from "@voltagent/internal/utils"; import type { StreamTextResult as AIStreamTextResult, Tool as AITool, - CallSettings, GenerateObjectResult, GenerateTextResult, LanguageModel, PrepareStepFunction, StepResult, + ToolApprovalConfiguration, + ToolApprovalStatus, ToolChoice, ToolSet, UIMessage, @@ -28,9 +29,10 @@ import { type AsyncIterableStream, type FinishReason, type InferGenerateOutput, + type Instructions, type LanguageModelUsage, NoOutputGeneratedError, - type Output, + Output, type Warning, consumeStream, convertToModelMessages, @@ -38,12 +40,10 @@ import { createUIMessageStream, createUIMessageStreamResponse, generateId, - generateObject, generateText, + isStepCount, pipeTextStreamToResponse, pipeUIMessageStreamToResponse, - stepCountIs, - streamObject, streamText, validateUIMessages, } from "ai"; @@ -60,8 +60,17 @@ import { type ObservabilityFlushState, flushObservability } from "../observabili import { AgentRegistry } from "../registries/agent-registry"; import { ModelProviderRegistry } from "../registries/model-provider-registry"; import type { BaseRetriever } from "../retriever/retriever"; -import type { ProviderTool, Tool, ToolExecutionResult, Toolkit, VercelTool } from "../tool"; +import type { + NamedAiSdkTool, + ProviderTool, + Tool, + ToolExecutionResult, + Toolkit, + VercelTool, + VoltAgentToolMetadata, +} from "../tool"; import { createTool } from "../tool"; +import { getRawAiSdkTool, isNamedAiSdkTool } from "../tool"; import { isProviderTool } from "../tool/manager"; import { ToolManager } from "../tool/manager"; import { createEmbeddingToolSearchStrategy } from "../tool/routing"; @@ -137,6 +146,7 @@ import { AGENT_REF_CONTEXT_KEY, FORCED_TOOL_CHOICE_CONTEXT_KEY, SPECULATIVE_INPUT_GUARDRAIL_CONTEXT_KEY, + TOOL_APPROVAL_CONTEXT_KEY, TOOL_ROUTING_CONTEXT_KEY, TOOL_ROUTING_SEARCHED_TOOLS_CONTEXT_KEY, } from "./context-keys"; @@ -202,6 +212,7 @@ import type { AgentModelValue, AgentOptions, AgentSummarizationOptions, + AgentToolInput, AgentToolRoutingState, ApiToolInfo, CommonResolvedRuntimeMemoryOptions, @@ -216,6 +227,7 @@ import type { RuntimeMemoryEnvelope, SemanticMemoryOptions, SupervisorConfig, + VoltAgentRuntimeOptions, } from "./types"; const BUFFER_CONTEXT_KEY = Symbol("conversationBuffer"); @@ -260,6 +272,7 @@ const DEFAULT_MESSAGE_METADATA_PERSISTENCE_OPTIONS: ResolvedMessageMetadataPersi }; type ResponseMessage = AssistantModelMessage | ToolModelMessage; +type ValidationIssue = Parameters[1][number]; const isRecord = (value: unknown): value is Record => typeof value === "object" && value !== null; @@ -267,6 +280,15 @@ const isRecord = (value: unknown): value is Record => const isPlainObject = (value: unknown): value is Record => isRecord(value) && !Array.isArray(value); +const getValidationIssues = (error: unknown): ValidationIssue[] => { + if (!isRecord(error)) { + return []; + } + + const issues = error.issues ?? error.errors; + return Array.isArray(issues) ? (issues as ValidationIssue[]) : []; +}; + const stringIncludesTemperature = (value: unknown): boolean => typeof value === "string" && value.toLowerCase().includes("temperature"); @@ -693,23 +715,29 @@ function sanitizeConversationTitle(text: string, maxLength: number): string { */ export type StreamTextResultWithContext< TOOLS extends ToolSet = Record, - OUTPUT = unknown, + OUTPUT extends OutputSpec = OutputSpec, > = { // All methods from AIStreamTextResult - readonly text: AIStreamTextResult["text"]; - readonly textStream: AIStreamTextResult["textStream"]; + readonly text: AIStreamTextResult["text"]; + readonly textStream: AIStreamTextResult["textStream"]; + readonly stream: AsyncIterable>; + /** @deprecated Use `stream` instead. */ readonly fullStream: AsyncIterable>; - readonly usage: AIStreamTextResult["usage"]; - readonly totalUsage: AIStreamTextResult["totalUsage"]; - readonly steps: AIStreamTextResult["steps"]; - readonly finishReason: AIStreamTextResult["finishReason"]; + readonly usage: AIStreamTextResult["usage"]; + readonly totalUsage: AIStreamTextResult["totalUsage"]; + readonly steps: AIStreamTextResult["steps"]; + readonly finishReason: AIStreamTextResult["finishReason"]; // Partial output stream for streaming structured objects - readonly partialOutputStream?: AIStreamTextResult["partialOutputStream"]; - toUIMessageStream: AIStreamTextResult["toUIMessageStream"]; - toUIMessageStreamResponse: AIStreamTextResult["toUIMessageStreamResponse"]; - pipeUIMessageStreamToResponse: AIStreamTextResult["pipeUIMessageStreamToResponse"]; - pipeTextStreamToResponse: AIStreamTextResult["pipeTextStreamToResponse"]; - toTextStreamResponse: AIStreamTextResult["toTextStreamResponse"]; + readonly partialOutputStream?: AIStreamTextResult["partialOutputStream"]; + toUIMessageStream: AIStreamTextResult["toUIMessageStream"]; + toUIMessageStreamResponse: AIStreamTextResult["toUIMessageStreamResponse"]; + pipeUIMessageStreamToResponse: AIStreamTextResult< + TOOLS, + any, + OUTPUT + >["pipeUIMessageStreamToResponse"]; + pipeTextStreamToResponse: AIStreamTextResult["pipeTextStreamToResponse"]; + toTextStreamResponse: AIStreamTextResult["toTextStreamResponse"]; // Additional context field context: Map; // Feedback metadata for the trace, if enabled @@ -737,22 +765,20 @@ export interface StreamObjectResultWithContext { /** * Extended GenerateTextResult that includes context */ -type BaseGenerateTextResult> = Omit< - GenerateTextResult, - "experimental_output" | "output" -> & { - experimental_output: unknown; +type BaseGenerateTextResult< + TOOLS extends ToolSet = Record, + OUTPUT extends OutputSpec = OutputSpec, +> = Omit, "output"> & { output: unknown; }; export interface GenerateTextResultWithContext< TOOLS extends ToolSet = Record, OUTPUT extends OutputSpec = OutputSpec, -> extends BaseGenerateTextResult { +> extends BaseGenerateTextResult { // Additional context field context: Map; // Typed structured output override if provided by callers - experimental_output: OutputValue; output: OutputValue; // Feedback metadata for the trace, if enabled feedback?: AgentFeedbackHandle | null; @@ -777,7 +803,7 @@ function cloneGenerateTextResultWithContext< TOOLS extends ToolSet = Record, OUTPUT extends OutputSpec = OutputSpec, >( - result: GenerateTextResult, + result: GenerateTextResult, overrides: Partial< Pick< GenerateTextResultWithContext, @@ -807,10 +833,76 @@ function cloneGenerateTextResultWithContext< return clone; } -type AITextCallOptions = Partial & { +type AIGenerateTextOptions = Parameters[0]; +type AIStreamTextOptions = Parameters[0]; +type AITextGenerationOptions = AIGenerateTextOptions & AIStreamTextOptions; +type VoltAgentControlledAISDKOption = + | "model" + | "prompt" + | "messages" + | "tools" + | "output" + | "providerOptions" + | "abortSignal" + | "maxRetries" + | "runtimeContext" + | "toolsContext" + | "telemetry" + | "experimental_telemetry" + | "onStepEnd" + | "onStepFinish" + | "onEnd" + | "onFinish" + | "onError" + | "_internal"; +type AISDKPassthroughOptions = Partial< + Omit +>; +type AISDKManagedCallbacks = Pick< + Partial, + "onStepEnd" | "onStepFinish" | "onEnd" | "onFinish" | "onError" +>; + +type AITextCallOptions = AISDKPassthroughOptions & { + instructions?: Instructions; + system?: Instructions; + stop?: string | string[]; toolChoice?: ToolChoice>; + toolApproval?: ToolApprovalConfiguration; + experimental_toolApprovalSecret?: string | Uint8Array; + toolsContext?: Record; prepareStep?: PrepareStepFunction>; + onStepEnd?: AISDKManagedCallbacks["onStepEnd"]; + onStepFinish?: AISDKManagedCallbacks["onStepFinish"]; + onEnd?: AISDKManagedCallbacks["onEnd"]; + onFinish?: AISDKManagedCallbacks["onFinish"]; + onError?: AISDKManagedCallbacks["onError"]; +}; + +type VoltAgentGenerateTextCallOptions = Omit & { + toolsContext?: Record; +}; +type VoltAgentStreamTextCallOptions = Omit & { + toolsContext?: Record; }; +type VoltAgentGenerateTextReturn = ReturnType>; +type VoltAgentStreamTextReturn = ReturnType>; + +function generateTextWithVoltAgentTools( + options: VoltAgentGenerateTextCallOptions, +): VoltAgentGenerateTextReturn { + // VoltAgent resolves ToolSet entries dynamically at runtime, so TypeScript + // cannot infer which tools declare AI SDK `contextSchema`. The AI SDK runtime + // supports `toolsContext`; this boundary keeps the cast localized. + return generateText(options as unknown as AIGenerateTextOptions) as VoltAgentGenerateTextReturn; +} + +function streamTextWithVoltAgentTools( + options: VoltAgentStreamTextCallOptions, +): VoltAgentStreamTextReturn { + // See `generateTextWithVoltAgentTools` for why this cast is localized here. + return streamText(options as unknown as AIStreamTextOptions) as VoltAgentStreamTextReturn; +} function applyForcedToolChoice( aiSDKOptions: AITextCallOptions, @@ -873,8 +965,11 @@ function isAsyncIterable(value: unknown): value is AsyncIterable { * Extends AI SDK's CallSettings for full compatibility */ export interface BaseGenerationOptions - extends Partial { + extends AISDKPassthroughOptions { // === VoltAgent Specific === + // New namespace for VoltAgent runtime-specific options. + voltagent?: VoltAgentRuntimeOptions; + // Context /** * Runtime memory envelope for per-call memory identity and behavior overrides. @@ -904,6 +999,12 @@ export interface BaseGenerationOptions | Toolkit)[]; + tools?: AgentToolInput; /** * Optional per-call tool routing override. */ @@ -961,10 +1074,9 @@ export interface BaseGenerationOptions>; + /** + * AI SDK native tool approval configuration. + * + * This takes precedence over tool-level `needsApproval` during AI SDK tool + * execution. VoltAgent also reads it inside tool routing so hidden pool tools + * can follow the same approval policy when called through `callTool`. + */ + toolApproval?: ToolApprovalConfiguration; + + /** + * AI SDK per-tool execution context. + * + * Use this with native AI SDK tools that declare `contextSchema`. VoltAgent + * forwards the value to the underlying AI SDK call so tool `execute` + * handlers receive it as `options.context`. + */ + toolsContext?: Record; + + /** + * Secret used by AI SDK to sign native tool approval requests. + */ + experimental_toolApprovalSecret?: string | Uint8Array; + /** * Step preparation callback (ai-sdk `prepareStep`). * Called before each step to control tool availability, tool choice, etc. * Overrides the agent-level `prepareStep` if provided. */ prepareStep?: PrepareStep; + + /** + * AI SDK step callback. VoltAgent invokes this from its managed step handler + * after internal memory/tracing work, preserving native callback access while + * keeping framework behavior intact. + */ + onStepEnd?: AISDKManagedCallbacks["onStepEnd"]; + /** + * Deprecated AI SDK alias for `onStepEnd`. + */ + onStepFinish?: AISDKManagedCallbacks["onStepFinish"]; + /** + * AI SDK completion callback. VoltAgent invokes it after guardrails, + * middleware, memory persistence, and tracing have produced the final result. + */ + onEnd?: AISDKManagedCallbacks["onEnd"]; + /** + * Deprecated AI SDK alias for `onEnd`. + */ + onFinish?: AISDKManagedCallbacks["onFinish"]; + /** + * AI SDK stream error callback. VoltAgent invokes it from its managed stream + * error handler after framework recovery/error handling has run. + */ + onError?: AISDKManagedCallbacks["onError"]; +} + +function normalizeInstructions(instructions: Instructions | undefined): SystemModelMessage[] { + if (!instructions) { + return []; + } + if (typeof instructions === "string") { + return [{ role: "system", content: instructions }]; + } + return Array.isArray(instructions) ? instructions : [instructions]; +} + +function splitInstructionsFromMessages( + messages: ModelMessage[], + existingInstructions?: Instructions, +): { instructions?: Instructions; messages: ModelMessage[] } { + const systemMessages: SystemModelMessage[] = []; + const modelMessages: ModelMessage[] = []; + + for (const message of messages) { + if (message.role === "system") { + systemMessages.push(message as SystemModelMessage); + } else { + modelMessages.push(message); + } + } + + const mergedInstructions = [...normalizeInstructions(existingInstructions), ...systemMessages]; + + return { + instructions: + mergedInstructions.length === 0 + ? undefined + : mergedInstructions.length === 1 + ? mergedInstructions[0] + : mergedInstructions, + messages: modelMessages, + }; } export type GenerateTextOptions< @@ -993,12 +1191,27 @@ export type GenerateTextOptions< export type StreamTextOptions = BaseGenerationOptions & { onFinish?: (result: any) => void | Promise; - /** - * When true, avoids wiring the HTTP abort signal into the stream so clients can resume later. - * Use with a resumable stream store to prevent orphaned streams. - */ - resumableStream?: boolean; }; +type TextGenerationInput = string | UIMessage[] | BaseMessage[]; +type TextGenerationRequest = ( + | { + prompt: string; + messages?: never; + } + | { + messages: UIMessage[] | BaseMessage[]; + prompt?: never; + } +) & + TOptions & { + options?: TOptions; + }; +export type GenerateTextRequest< + OUTPUT extends OutputSpec = OutputSpec, + TProviderOptions extends ProviderOptions = ProviderOptions, +> = TextGenerationRequest>; +export type StreamTextRequest = + TextGenerationRequest>; export type GenerateObjectOptions = BaseGenerationOptions; export type StreamObjectOptions = @@ -1006,6 +1219,218 @@ export type StreamObjectOptions void | Promise; }; +function normalizeVoltAgentRuntimeOptions( + options: TOptions, +): TOptions { + if (!options || !("voltagent" in options)) { + return options; + } + + const { voltagent, ...legacyOptions } = options; + if (!voltagent) { + return legacyOptions as TOptions; + } + + const { + guardrails, + middleware, + inputGuardrails, + outputGuardrails, + inputMiddlewares, + outputMiddlewares, + maxMiddlewareRetries, + ...runtimeOptions + } = voltagent; + const normalizedOptions = { + ...legacyOptions, + ...runtimeOptions, + ...(guardrails?.input !== undefined || inputGuardrails !== undefined + ? { inputGuardrails: guardrails?.input ?? inputGuardrails } + : {}), + ...(guardrails?.output !== undefined || outputGuardrails !== undefined + ? { outputGuardrails: guardrails?.output ?? outputGuardrails } + : {}), + ...(middleware?.input !== undefined || inputMiddlewares !== undefined + ? { inputMiddlewares: middleware?.input ?? inputMiddlewares } + : {}), + ...(middleware?.output !== undefined || outputMiddlewares !== undefined + ? { outputMiddlewares: middleware?.output ?? outputMiddlewares } + : {}), + ...(middleware?.maxRetries !== undefined || maxMiddlewareRetries !== undefined + ? { maxMiddlewareRetries: middleware?.maxRetries ?? maxMiddlewareRetries } + : {}), + }; + + return normalizedOptions as TOptions; +} + +type GenerationFinishCallback = (result: any) => void | PromiseLike; +type GenerationStepEndCallback = (event: StepResult) => void | PromiseLike; +type GenerationErrorCallback = (event: { error: unknown }) => void | PromiseLike; + +type GenerationOptionsWithManagedCallbacks< + TProviderOptions extends ProviderOptions = ProviderOptions, +> = BaseGenerationOptions & { + onFinish?: GenerationFinishCallback; + onEnd?: GenerationFinishCallback; + onStepEnd?: GenerationStepEndCallback; + onStepFinish?: GenerationStepEndCallback; + onError?: GenerationErrorCallback; +}; +type GenerationOptionsWithBlockedAISDKFields< + TProviderOptions extends ProviderOptions = ProviderOptions, +> = GenerationOptionsWithManagedCallbacks & { + runtimeContext?: unknown; + telemetry?: unknown; + experimental_telemetry?: unknown; +}; + +function extractAISDKCallOptions( + options?: GenerationOptionsWithManagedCallbacks, +): { + aiSDKOptions: AITextCallOptions; + output?: OutputSpec; + providerOptions?: TProviderOptions; + onFinish?: GenerationFinishCallback; + onStepEnd?: GenerationStepEndCallback; + onError?: GenerationErrorCallback; +} { + const { + voltagent: _voltagent, + userId: _userId, + conversationId: _conversationId, + memory: _memory, + context: _context, + requestHeaders: _requestHeaders, + elicitation: _elicitation, + parentAgentId: _parentAgentId, + parentOperationContext: _parentOperationContext, + parentSpan: _parentSpan, + inheritParentSpan: _inheritParentSpan, + hooks: _hooks, + feedback: _feedback, + maxSteps: _maxSteps, + tools: _tools, + toolRouting: _toolRouting, + contextLimit: _contextLimit, + semanticMemory: _semanticMemory, + conversationPersistence: _conversationPersistence, + messageMetadataPersistence: _messageMetadataPersistence, + inputGuardrails: _inputGuardrails, + outputGuardrails: _outputGuardrails, + inputMiddlewares: _inputMiddlewares, + outputMiddlewares: _outputMiddlewares, + maxMiddlewareRetries: _maxMiddlewareRetries, + resumableStream: _resumableStream, + output, + providerOptions, + runtimeContext: _runtimeContext, + telemetry: _telemetry, + experimental_telemetry: _experimentalTelemetry, + onFinish, + onEnd, + onStepEnd, + onStepFinish, + onError, + ...aiSDKOptions + } = (options ?? {}) as GenerationOptionsWithBlockedAISDKFields; + + return { + aiSDKOptions: aiSDKOptions as AITextCallOptions, + output, + providerOptions, + onFinish: onEnd ?? onFinish, + onStepEnd: onStepEnd ?? onStepFinish, + onError, + }; +} + +function isTextGenerationRequest( + input: TextGenerationInput | TextGenerationRequest, +): input is TextGenerationRequest { + return ( + typeof input === "object" && + input !== null && + !Array.isArray(input) && + ("prompt" in input || "messages" in input) + ); +} + +function normalizeTextGenerationArgs( + inputOrRequest: TextGenerationInput | TextGenerationRequest, + options?: TOptions, +): { input: TextGenerationInput; options?: TOptions } { + if (!isTextGenerationRequest(inputOrRequest)) { + return { + input: inputOrRequest, + options: options + ? (normalizeVoltAgentRuntimeOptions( + options as TOptions & BaseGenerationOptions, + ) as TOptions) + : undefined, + }; + } + + const { + prompt, + messages, + options: nestedOptions, + ...topLevelOptions + } = inputOrRequest as TextGenerationRequest & { + prompt?: string; + messages?: UIMessage[] | BaseMessage[]; + }; + const input = prompt ?? messages; + + if (input === undefined) { + throw new Error("Agent text request must include prompt or messages"); + } + + const mergedOptions = { + ...(nestedOptions ?? {}), + ...topLevelOptions, + ...(options ?? {}), + } as TOptions; + + return { + input, + options: + Object.keys(mergedOptions).length > 0 + ? (normalizeVoltAgentRuntimeOptions( + mergedOptions as TOptions & BaseGenerationOptions, + ) as TOptions) + : undefined, + }; +} + +type LegacyToolInputItem = Tool | Toolkit | VercelTool; +type ManagedToolInfo = BaseTool | ProviderTool | NamedAiSdkTool; + +function splitAgentToolInput(input: AgentToolInput | undefined): { + items: LegacyToolInputItem[]; + toolSet?: ToolSet; +} { + if (!input) { + return { items: [] }; + } + + if (Array.isArray(input)) { + return { items: input }; + } + + return { items: [], toolSet: input }; +} + +function addAgentToolInputToManager(manager: ToolManager, input: AgentToolInput | undefined): void { + const { items, toolSet } = splitAgentToolInput(input); + if (items.length > 0) { + manager.addItems(items); + } + if (toolSet) { + manager.addToolSet(toolSet); + } +} + // ============================================================================ // Agent Implementation // ============================================================================ @@ -1016,7 +1441,7 @@ export class Agent { readonly purpose?: string; readonly instructions: InstructionsDynamicValue; readonly model: AgentModelValue; - readonly dynamicTools?: DynamicValue<(Tool | Toolkit)[]>; + readonly dynamicTools?: DynamicValue; hooks: AgentHooks; readonly temperature?: number; readonly maxOutputTokens?: number; @@ -1168,8 +1593,9 @@ export class Agent { const workspaceToolkits = buildWorkspaceToolkits(this.workspace, options.workspaceToolkits); // Initialize tool manager with static tools - const staticTools = typeof options.tools === "function" ? [] : options.tools; - this.toolManager = new ToolManager(staticTools, this.logger); + const staticTools = typeof options.tools === "function" ? undefined : options.tools; + this.toolManager = new ToolManager([], this.logger); + addAgentToolInputToManager(this.toolManager, staticTools); if (options.toolkits) { this.toolManager.addItems(options.toolkits); } @@ -1203,7 +1629,27 @@ export class Agent { >( input: string | UIMessage[] | BaseMessage[], options?: GenerateTextOptions, + ): Promise>; + async generateText< + OUTPUT extends OutputSpec = OutputSpec, + TProviderOptions extends ProviderOptions = ProviderOptions, + >( + request: GenerateTextRequest, + ): Promise>; + async generateText< + OUTPUT extends OutputSpec = OutputSpec, + TProviderOptions extends ProviderOptions = ProviderOptions, + >( + inputOrRequest: + | string + | UIMessage[] + | BaseMessage[] + | GenerateTextRequest, + requestOptions?: GenerateTextOptions, ): Promise> { + const normalizedArgs = normalizeTextGenerationArgs(inputOrRequest, requestOptions); + const input = normalizedArgs.input; + const options = normalizedArgs.options; const startTime = Date.now(); const oc = this.createOperationContext(input, options); const methodLogger = oc.logger; @@ -1315,27 +1761,13 @@ export class Agent { tools: tools ? Object.keys(tools) : [], }); - // Extract VoltAgent-specific options const { - userId, - conversationId, - memory: _memory, - context, // Explicitly exclude to prevent collision with AI SDK's future 'context' field - requestHeaders: _requestHeaders, - parentAgentId, - parentOperationContext, - hooks, - feedback: _feedback, - maxSteps: userMaxSteps, - tools: userTools, - contextLimit: _contextLimit, - semanticMemory: _semanticMemory, - conversationPersistence: _conversationPersistence, - messageMetadataPersistence: _messageMetadataPersistence, + aiSDKOptions, output, providerOptions, - ...aiSDKOptions - } = options || {}; + onFinish: userOnFinish, + onStepEnd: userOnStepEnd, + } = extractAISDKCallOptions(options); // Apply agent-level prepareStep as default (per-call overrides) if (this.prepareStep && !aiSDKOptions.prepareStep) { @@ -1346,6 +1778,15 @@ export class Agent { | ToolChoice> | undefined; applyForcedToolChoice(aiSDKOptions, forcedToolChoice); + const { + instructions: explicitInstructions, + system: explicitSystem, + ...aiSDKCallOptions + } = aiSDKOptions; + const promptOptions = splitInstructionsFromMessages(messages, [ + ...normalizeInstructions(explicitInstructions), + ...normalizeInstructions(explicitSystem), + ]); const { result, modelName: effectiveModelName } = await this.executeWithModelFallback({ oc, @@ -1383,16 +1824,16 @@ export class Agent { try { const response = await oc.traceContext.withSpan(llmSpan, () => - generateText({ + generateTextWithVoltAgentTools({ model: resolvedModel, - messages, + ...promptOptions, tools, // Default values temperature: this.temperature, maxOutputTokens: this.maxOutputTokens, - stopWhen: options?.stopWhen ?? this.stopWhen ?? stepCountIs(maxSteps), + stopWhen: options?.stopWhen ?? this.stopWhen ?? isStepCount(maxSteps), // User overrides from AI SDK options - ...aiSDKOptions, + ...aiSDKCallOptions, maxRetries: 0, // Structured output if provided output, @@ -1400,7 +1841,7 @@ export class Agent { providerOptions, // VoltAgent controlled (these should not be overridden) abortSignal: oc.abortController.signal, - onStepFinish: this.createStepHandler(oc, options), + onStepEnd: this.createStepHandler(oc, options, userOnStepEnd), }), ); @@ -1603,13 +2044,19 @@ export class Agent { }); })(); - return cloneGenerateTextResultWithContext(result, { + const finalResult = cloneGenerateTextResultWithContext(result, { text: finalText, context: oc.context, toolCalls: aggregatedToolCalls, toolResults: aggregatedToolResults, feedback: feedbackValue, }); + + if (userOnFinish) { + await userOnFinish(finalResult); + } + + return finalResult; } catch (error) { if (this.shouldRetryMiddleware(error, middlewareRetryCount, maxMiddlewareRetries)) { const retryError = error as { @@ -1749,7 +2196,17 @@ export class Agent { async streamText( input: string | UIMessage[] | BaseMessage[], options?: StreamTextOptions, + ): Promise; + async streamText( + request: StreamTextRequest, + ): Promise; + async streamText( + inputOrRequest: string | UIMessage[] | BaseMessage[] | StreamTextRequest, + requestOptions?: StreamTextOptions, ): Promise { + const normalizedArgs = normalizeTextGenerationArgs(inputOrRequest, requestOptions); + const input = normalizedArgs.input; + const options = normalizedArgs.options; const startTime = Date.now(); const oc = this.createOperationContext(input, options); const feedbackOptions = this.resolveFeedbackOptions(options); @@ -1983,28 +2440,14 @@ export class Agent { // Setup abort signal listener this.setupAbortSignalListener(oc); - // Extract VoltAgent-specific options const { - userId, - conversationId, - memory: _memory, - context, // Explicitly exclude to prevent collision with AI SDK's future 'context' field - requestHeaders: _requestHeaders, - parentAgentId, - parentOperationContext, - hooks, - feedback: _feedback, - maxSteps: userMaxSteps, - tools: userTools, - onFinish: userOnFinish, - contextLimit: _contextLimit, - semanticMemory: _semanticMemory, - conversationPersistence: _conversationPersistence, - messageMetadataPersistence: _messageMetadataPersistence, + aiSDKOptions, output, providerOptions, - ...aiSDKOptions - } = options || {}; + onFinish: userOnFinish, + onStepEnd: userOnStepEnd, + onError: userOnError, + } = extractAISDKCallOptions(options); // Apply agent-level prepareStep as default (per-call overrides) if (this.prepareStep && !aiSDKOptions.prepareStep) { @@ -2015,6 +2458,15 @@ export class Agent { | ToolChoice> | undefined; applyForcedToolChoice(aiSDKOptions, forcedToolChoice); + const { + instructions: explicitInstructions, + system: explicitSystem, + ...aiSDKCallOptions + } = aiSDKOptions; + const promptOptions = splitInstructionsFromMessages(messages, [ + ...normalizeInstructions(explicitInstructions), + ...normalizeInstructions(explicitSystem), + ]); const responseMessageId = await this.ensureStreamingResponseMessageId(oc, buffer); const guardrailStreamingEnabled = guardrailSet.output.length > 0; @@ -2058,16 +2510,16 @@ export class Agent { }); const finalizeLLMSpan = this.createLLMSpanFinalizer(llmSpan); - const streamResult = streamText({ + const streamResult = streamTextWithVoltAgentTools({ model: resolvedModel, - messages, + ...promptOptions, tools, // Default values temperature: this.temperature, maxOutputTokens: this.maxOutputTokens, - stopWhen: options?.stopWhen ?? this.stopWhen ?? stepCountIs(maxSteps), + stopWhen: options?.stopWhen ?? this.stopWhen ?? isStepCount(maxSteps), // User overrides from AI SDK options - ...aiSDKOptions, + ...aiSDKCallOptions, maxRetries: 0, // Structured output if provided output, @@ -2075,8 +2527,8 @@ export class Agent { providerOptions, // VoltAgent controlled (these should not be overridden) abortSignal: oc.abortController.signal, - onStepFinish: this.createStepHandler(oc, options), - onError: async (errorData) => { + onStepEnd: this.createStepHandler(oc, options, userOnStepEnd), + onError: async (errorData: any) => { // Handle nested error structure from OpenAI and other providers // The error might be directly the error or wrapped in { error: ... } const actualError = (errorData as any)?.error || errorData; @@ -2156,7 +2608,7 @@ export class Agent { } // Call error hooks if they exist - this.getMergedHooks(options).onError?.({ + await this.getMergedHooks(options).onError?.({ agent: this, error: actualError as Error, context: oc, @@ -2169,14 +2621,18 @@ export class Agent { // The onError callback should return void for AI SDK compatibility // Ensure spans are flushed on error // Uses waitUntil if available to avoid blocking - await flushObservability( - this.getObservability(), - oc.logger ?? this.logger, - this.observabilityAuthWarningState, - "streamText:onError", - ); + try { + await userOnError?.(errorData as { error: unknown }); + } finally { + await flushObservability( + this.getObservability(), + oc.logger ?? this.logger, + this.observabilityAuthWarningState, + "streamText:onError", + ); + } }, - onFinish: async (finalResult) => { + onEnd: async (finalResult: any) => { latestResponseMessages = filterResponseMessages(finalResult.response?.messages); const providerUsage = finalResult.usage ? await Promise.resolve(finalResult.usage) @@ -2381,7 +2837,7 @@ export class Agent { }, }); - const originalFullStream = streamResult.fullStream; + const originalFullStream = streamResult.stream; const probeResult = await this.probeStreamStart(originalFullStream, attemptState); const streamResultForConsumption = this.withProbedFullStream( streamResult, @@ -2390,7 +2846,7 @@ export class Agent { ); if (probeResult.status === "error") { - this.discardStream(streamResultForConsumption.fullStream); + this.discardStream(streamResultForConsumption.stream); const fallbackEligible = this.shouldFallbackOnError(probeResult.error); if (!fallbackEligible || isLastModel) { throw probeResult.error; @@ -2500,7 +2956,7 @@ export class Agent { }; const parentStream = applyResponseMessageIdToStream( - normalizeFinishUsageStream(wrapWithAbortHandling(result.fullStream)), + normalizeFinishUsageStream(wrapWithAbortHandling(result.stream)), ); if (agent.subAgentManager.hasSubAgents()) { @@ -2675,13 +3131,15 @@ export class Agent { ): ToUIMessageStreamReturn => { if (!guardrailPipeline) { return applySpeculativeInputGuardrailToUIStream({ - baseStream: result.toUIMessageStream(streamOptions), + baseStream: result.toUIMessageStream(streamOptions as any), guardrail: speculativeInputGuardrail, responseMessageId: responseMessageId ?? undefined, }); } return applySpeculativeInputGuardrailToUIStream({ - baseStream: guardrailPipeline.createUIStream(streamOptions) as ToUIMessageStreamReturn, + baseStream: guardrailPipeline.createUIStream( + streamOptions as any, + ) as ToUIMessageStreamReturn, guardrail: speculativeInputGuardrail, responseMessageId: responseMessageId ?? undefined, }); @@ -2796,7 +3254,7 @@ export class Agent { const stream = toUIMessageStreamSanitized(streamOptions); const initOptions = init ? { ...init } : {}; pipeUIMessageStreamToResponse({ - response, + response: response as any, stream, ...initOptions, }); @@ -2810,6 +3268,9 @@ export class Agent { get textStream() { return getGuardrailAwareTextStream(); }, + get stream() { + return getGuardrailAwareFullStream(); + }, get fullStream() { return getGuardrailAwareFullStream(); }, @@ -2836,13 +3297,13 @@ export class Agent { pipeTextStreamToResponse: (response, init) => { pipeTextStreamToResponse({ response, - textStream: getGuardrailAwareTextStream(), + stream: getGuardrailAwareTextStream() as ReadableStream, ...(init ?? {}), }); }, toTextStreamResponse: (init) => { return createTextStreamResponse({ - textStream: getGuardrailAwareTextStream(), + stream: getGuardrailAwareTextStream() as ReadableStream, ...(init ?? {}), }); }, @@ -2879,8 +3340,9 @@ export class Agent { >( input: string | UIMessage[] | BaseMessage[], schema: T, - options?: GenerateObjectOptions, + rawOptions?: GenerateObjectOptions, ): Promise>> { + const options = normalizeVoltAgentRuntimeOptions(rawOptions); const startTime = Date.now(); const oc = this.createOperationContext(input, options); const methodLogger = oc.logger; @@ -2922,6 +3384,7 @@ export class Agent { options, ); const schemaName = schema.description || "unknown"; + const objectOutput = Output.object({ schema, description: schema.description }); // Add model attributes and all options addModelAttributesToSpan( @@ -2968,48 +3431,53 @@ export class Agent { // Event tracking now handled by OpenTelemetry spans - // Extract VoltAgent-specific options const { - userId, - conversationId, - memory: _memory, - context, // Explicitly exclude to prevent collision with AI SDK's future 'context' field - requestHeaders: _requestHeaders, - parentAgentId, - parentOperationContext, - hooks, - feedback: _feedback, - maxSteps: userMaxSteps, - tools: userTools, - contextLimit: _contextLimit, - semanticMemory: _semanticMemory, - conversationPersistence: _conversationPersistence, - messageMetadataPersistence: _messageMetadataPersistence, - output: _output, + aiSDKOptions, providerOptions, - ...aiSDKOptions - } = options || {}; + onFinish: userOnFinish, + onStepEnd: userOnStepEnd, + } = extractAISDKCallOptions(options); + const { + instructions: explicitInstructions, + system: explicitSystem, + ...aiSDKCallOptions + } = aiSDKOptions; + const promptOptions = splitInstructionsFromMessages(messages, [ + ...normalizeInstructions(explicitInstructions), + ...normalizeInstructions(explicitSystem), + ]); const { result, modelName: effectiveModelName } = await this.executeWithModelFallback({ oc, operation: "generateObject", options, run: async ({ model: resolvedModel }) => { - return await generateObject({ + const response = await generateTextWithVoltAgentTools({ model: resolvedModel, - messages, - schema, + ...promptOptions, // Default values maxOutputTokens: this.maxOutputTokens, temperature: this.temperature, // User overrides from AI SDK options - ...aiSDKOptions, + ...aiSDKCallOptions, maxRetries: 0, + // Structured output is routed through the AI SDK output API. + output: objectOutput, // Provider-specific options providerOptions, // VoltAgent controlled abortSignal: oc.abortController.signal, + onStepEnd: this.createStepHandler(oc, options, userOnStepEnd), }); + + await this.ensureStructuredOutputGenerated({ + result: response, + output: objectOutput, + tools: {}, + maxSteps: 1, + }); + + return response; }, }); @@ -3033,8 +3501,9 @@ export class Agent { (result as { providerMetadata?: unknown }).providerMetadata, ); const usageInfo = convertUsage(usageForFinish); + const generatedObject = result.output as z.infer; const middlewareObject = await runOutputMiddlewares>( - result.object, + generatedObject, oc, middlewareSet.output as NormalizedOutputMiddleware>[], "generateObject", @@ -3154,11 +3623,19 @@ export class Agent { ); // Return result with same context reference for consistency - return { + const finalResult = { ...result, + reasoning: result.reasoningText, object: finalObject, + toJsonResponse: (init?: ResponseInit) => Response.json(finalObject, init), context: oc.context, }; + + if (userOnFinish) { + await userOnFinish(finalResult); + } + + return finalResult; } catch (error) { if (this.shouldRetryMiddleware(error, middlewareRetryCount, maxMiddlewareRetries)) { const retryError = error as { @@ -3221,8 +3698,9 @@ export class Agent { >( input: string | UIMessage[] | BaseMessage[], schema: T, - options?: StreamObjectOptions, + rawOptions?: StreamObjectOptions, ): Promise>> { + const options = normalizeVoltAgentRuntimeOptions(rawOptions); const startTime = Date.now(); const oc = this.createOperationContext(input, options); @@ -3298,6 +3776,7 @@ export class Agent { options, ); const schemaName = schema.description || "unknown"; + const objectOutput = Output.object({ schema, description: schema.description }); // Add model attributes and all options addModelAttributesToSpan( @@ -3344,28 +3823,22 @@ export class Agent { // Event tracking now handled by OpenTelemetry spans - // Extract VoltAgent-specific options const { - userId, - conversationId, - memory: _memory, - context, // Explicitly exclude to prevent collision with AI SDK's future 'context' field - requestHeaders: _requestHeaders, - parentAgentId, - parentOperationContext, - hooks, - feedback: _feedback, - maxSteps: userMaxSteps, - tools: userTools, - onFinish: userOnFinish, - contextLimit: _contextLimit, - semanticMemory: _semanticMemory, - conversationPersistence: _conversationPersistence, - messageMetadataPersistence: _messageMetadataPersistence, - output: _output, + aiSDKOptions, providerOptions, - ...aiSDKOptions - } = options || {}; + onFinish: userOnFinish, + onStepEnd: userOnStepEnd, + onError: userOnError, + } = extractAISDKCallOptions(options); + const { + instructions: explicitInstructions, + system: explicitSystem, + ...aiSDKCallOptions + } = aiSDKOptions; + const promptOptions = splitInstructionsFromMessages(messages, [ + ...normalizeInstructions(explicitInstructions), + ...normalizeInstructions(explicitSystem), + ]); let guardrailObjectPromise!: Promise>; let resolveGuardrailObject: ((value: z.infer) => void) | undefined; @@ -3386,21 +3859,22 @@ export class Agent { const attemptState: { hasOutput: boolean; lastError?: unknown } = { hasOutput: false, }; - const streamResult = streamObject({ + const streamResult = streamTextWithVoltAgentTools({ model: resolvedModel, - messages, - schema, + ...promptOptions, + output: objectOutput, // Default values maxOutputTokens: this.maxOutputTokens, temperature: this.temperature, // User overrides from AI SDK options - ...aiSDKOptions, + ...aiSDKCallOptions, maxRetries: 0, // Provider-specific options providerOptions, // VoltAgent controlled abortSignal: oc.abortController.signal, - onError: async (errorData) => { + onStepEnd: this.createStepHandler(oc, options, userOnStepEnd), + onError: async (errorData: any) => { // Handle nested error structure from OpenAI and other providers // The error might be directly the error or wrapped in { error: ... } const actualError = (errorData as any)?.error || errorData; @@ -3462,7 +3936,7 @@ export class Agent { } // Call error hooks if they exist - this.getMergedHooks(options).onError?.({ + await this.getMergedHooks(options).onError?.({ agent: this, error: actualError as Error, context: oc, @@ -3476,14 +3950,18 @@ export class Agent { // The onError callback should return void for AI SDK compatibility // Ensure spans are flushed on error // Uses waitUntil if available to avoid blocking - await flushObservability( - this.getObservability(), - oc.logger ?? this.logger, - this.observabilityAuthWarningState, - "streamObject:onError", - ); + try { + await userOnError?.(errorData as { error: unknown }); + } finally { + await flushObservability( + this.getObservability(), + oc.logger ?? this.logger, + this.observabilityAuthWarningState, + "streamObject:onError", + ); + } }, - onFinish: async (finalResult: any) => { + onEnd: async (finalResult: any) => { try { const providerUsage = finalResult.usage ? await Promise.resolve(finalResult.usage) @@ -3499,10 +3977,10 @@ export class Agent { finalResult.providerMetadata, ); const usageInfo = convertUsage(usageForFinish); - let finalObject = finalResult.object as z.infer; + let finalObject = (await streamResult.output) as z.infer; if (guardrailSet.output.length > 0) { finalObject = await executeOutputGuardrails({ - output: finalResult.object as z.infer, + output: finalObject, operationContext: oc, guardrails: guardrailSet.output, operation: "streamObject", @@ -3550,7 +4028,11 @@ export class Agent { oc.traceContext.setOutput(finalObject); // Set output in operation context - oc.output = finalObject; + oc.output = + typeof finalObject === "string" || + (typeof finalObject === "object" && finalObject !== null) + ? finalObject + : safeStringify(finalObject); await this.getMergedHooks(options).onEnd?.({ conversationId: oc.conversationId || "", @@ -3570,11 +4052,10 @@ export class Agent { }); if (userOnFinish) { - const guardrailedResult = - guardrailSet.output.length > 0 - ? { ...finalResult, object: finalObject } - : finalResult; - await userOnFinish(guardrailedResult); + await userOnFinish({ + ...finalResult, + object: finalObject, + }); } const tokenInfo = usageForFinish @@ -3623,7 +4104,7 @@ export class Agent { }, }); - const originalFullStream = streamResult.fullStream; + const originalFullStream = streamResult.stream; const probeResult = await this.probeStreamStart(originalFullStream, attemptState); const streamResultForConsumption = this.withProbedFullStream( streamResult, @@ -3632,7 +4113,7 @@ export class Agent { ); if (probeResult.status === "error") { - this.discardStream(streamResultForConsumption.fullStream); + this.discardStream(streamResultForConsumption.stream); const fallbackEligible = this.shouldFallbackOnError(probeResult.error); if (!fallbackEligible || isLastModel) { throw probeResult.error; @@ -3657,8 +4138,11 @@ export class Agent { resolveGuardrailObject = resolve; rejectGuardrailObject = reject; }); + void Promise.resolve(result.output as PromiseLike>).catch((error) => { + rejectGuardrailObject?.(error); + }); } else { - guardrailObjectPromise = result.object; + guardrailObjectPromise = Promise.resolve(result.output as PromiseLike>); } // Create a wrapper that includes context and delegates to the original result @@ -3668,14 +4152,14 @@ export class Agent { object: guardrailObjectPromise, // Use getter for lazy access to avoid stream locking get partialObjectStream() { - return result.partialObjectStream; + return result.partialOutputStream; }, get textStream() { return result.textStream; }, - warnings: result.warnings, - usage: result.usage, - finishReason: result.finishReason, + warnings: Promise.resolve(result.warnings), + usage: Promise.resolve(result.usage), + finishReason: Promise.resolve(result.finishReason), // Delegate response conversion methods pipeTextStreamToResponse: (response, init) => result.pipeTextStreamToResponse(response, init), @@ -3800,11 +4284,13 @@ export class Agent { tools: Record; maxSteps: number; }> { - const dynamicToolList = (await this.resolveValue(this.dynamicTools, oc)) || []; - - // Merge agent tools with option tools - const optionToolsArray = options?.tools || []; - const adHocTools = [...dynamicToolList, ...optionToolsArray]; + const dynamicToolInput = await this.resolveValue(this.dynamicTools, oc); + const dynamicTools = splitAgentToolInput(dynamicToolInput); + const optionTools = splitAgentToolInput(options?.tools); + const adHocTools = [...dynamicTools.items, ...optionTools.items]; + const adHocToolSets = [dynamicTools.toolSet, optionTools.toolSet].filter( + (toolSet): toolSet is ToolSet => Boolean(toolSet), + ); const runtimeToolkits = this.extractToolkits(adHocTools); // Prepare messages (system + memory + input) as UIMessages @@ -3835,7 +4321,7 @@ export class Agent { const modelName = this.getModelName(); // Prepare tools with execution context - const tools = await this.prepareTools(adHocTools, oc, maxSteps, options); + const tools = await this.prepareTools(adHocTools, oc, maxSteps, options, adHocToolSets); return { messages, @@ -3847,10 +4333,10 @@ export class Agent { } private collectToolDataFromResult( - result: GenerateTextResult, + result: GenerateTextResult, ): { - toolCalls: GenerateTextResult["toolCalls"]; - toolResults: GenerateTextResult["toolResults"]; + toolCalls: GenerateTextResult["toolCalls"]; + toolResults: GenerateTextResult["toolResults"]; } { const steps = result.steps ?? []; @@ -3867,7 +4353,7 @@ export class Agent { TOOLS extends ToolSet, OUTPUT extends OutputSpec, >(params: { - result: GenerateTextResult; + result: GenerateTextResult; output: OUTPUT | undefined; tools: Record; maxSteps: number; @@ -4923,6 +5409,7 @@ export class Agent { messages.push({ role: "system", content: systemPrompt }); } messages.push({ role: "user", content: limitedInput }); + const promptOptions = splitInstructionsFromMessages(messages as ModelMessage[]); const modelName = this.getModelName(resolvedModel); const llmSpan = this.createLLMSpan(context, { operation: "generateTitle", @@ -4942,7 +5429,7 @@ export class Agent { const result = await context.traceContext.withSpan(llmSpan, () => generateText({ model: resolvedModel, - messages, + ...promptOptions, ...(temperature !== undefined ? { temperature } : {}), maxOutputTokens, abortSignal: context.abortController.signal, @@ -5625,7 +6112,7 @@ export class Agent { return content; } - private extractToolkits(items: (BaseTool | Toolkit)[]): Toolkit[] { + private extractToolkits(items: LegacyToolInputItem[]): Toolkit[] { return items.filter( (item): item is Toolkit => typeof item === "object" && @@ -6231,17 +6718,17 @@ export class Agent { : { status: "error", error, stream: passthroughStream }; } - private cloneResultWithFullStream< + private cloneResultWithStream< TResult extends { - fullStream: AsyncIterableStream; + stream: AsyncIterableStream; }, - >(result: TResult, fullStream: TResult["fullStream"]): TResult { + >(result: TResult, stream: TResult["stream"]): TResult { const prototype = Object.getPrototypeOf(result); const clone = Object.create(prototype) as TResult; const descriptors = Object.getOwnPropertyDescriptors(result); Object.defineProperties(clone, descriptors); - Object.defineProperty(clone, "fullStream", { - value: fullStream, + Object.defineProperty(clone, "stream", { + value: stream, writable: true, configurable: true, enumerable: true, @@ -6251,12 +6738,12 @@ export class Agent { private withProbedFullStream< TResult extends { - fullStream: AsyncIterableStream; + stream: AsyncIterableStream; }, >( result: TResult, - originalFullStream: TResult["fullStream"], - probedFullStream: TResult["fullStream"], + originalFullStream: TResult["stream"], + probedFullStream: TResult["stream"], ): TResult { if (probedFullStream === originalFullStream) { return result; @@ -6268,13 +6755,13 @@ export class Agent { return result; } - return this.cloneResultWithFullStream(result, probedFullStream); + return this.cloneResultWithStream(result, probedFullStream); } private usesGetterBasedTeeingFullStream(result: { - fullStream: AsyncIterableStream; + stream: AsyncIterableStream; }): boolean { - const descriptor = this.findPropertyDescriptor(result, "fullStream"); + const descriptor = this.findPropertyDescriptor(result, "stream"); return ( typeof descriptor?.get === "function" && typeof (result as { teeStream?: unknown }).teeStream === "function" @@ -6329,16 +6816,21 @@ export class Agent { * Prepare tools with execution context */ private async prepareTools( - adHocTools: (BaseTool | Toolkit)[], + adHocTools: LegacyToolInputItem[], oc: OperationContext, maxSteps: number, options?: BaseGenerationOptions, + adHocToolSets: ToolSet[] = [], ): Promise> { const resolvedMemory = this.resolveMemoryRuntimeOptions(options, oc); const hooks = this.getMergedHooks(options); const createToolExecuteFunction = this.createToolExecutionFactory(oc, hooks); + const createAiSdkToolExecuteFunction = this.createAiSdkToolExecutionFactory(oc, hooks); + if (options?.toolApproval !== undefined) { + oc.systemContext.set(TOOL_APPROVAL_CONTEXT_KEY, options.toolApproval); + } - const runtimeTools: (BaseTool | Toolkit)[] = [...adHocTools]; + const runtimeTools: LegacyToolInputItem[] = [...adHocTools]; // Add delegate tool if we have subagents if (this.subAgentManager.hasSubAgents()) { @@ -6359,10 +6851,18 @@ export class Agent { } const tempManager = new ToolManager(runtimeTools, this.logger); + for (const toolSet of adHocToolSets) { + tempManager.addToolSet(toolSet); + } - const preparedDynamicTools = tempManager.prepareToolsForExecution(createToolExecuteFunction); - const preparedStaticTools = - this.toolManager.prepareToolsForExecution(createToolExecuteFunction); + const preparedDynamicTools = tempManager.prepareToolsForExecution( + createToolExecuteFunction, + createAiSdkToolExecuteFunction, + ); + const preparedStaticTools = this.toolManager.prepareToolsForExecution( + createToolExecuteFunction, + createAiSdkToolExecuteFunction, + ); const toolRouting = this.resolveToolRouting(options); oc.systemContext.set(TOOL_ROUTING_CONTEXT_KEY, toolRouting); @@ -6411,7 +6911,7 @@ export class Agent { if (!parseResult.success) { const error = new Error(`Output validation failed: ${parseResult.error.message}`); Object.assign(error, { - validationErrors: parseResult.error.errors, + validationErrors: getValidationIssues(parseResult.error), actualOutput: result, }); @@ -6421,11 +6921,333 @@ export class Agent { return parseResult.data; } + private createAiSdkToolExecutionFactory( + oc: OperationContext, + hooks: AgentHooks, + ): ( + name: string, + tool: AITool, + metadata?: VoltAgentToolMetadata, + ) => (args: any, options?: ToolExecutionOptions) => ToolExecutionResult { + return (name, tool, metadata) => { + const execute = (tool as { execute?: unknown }).execute; + const toolDisplayName = + typeof metadata?.name === "string" && metadata.name.trim().length > 0 + ? metadata.name.trim() + : undefined; + const toolPurpose = + typeof metadata?.purpose === "string" && metadata.purpose.trim().length > 0 + ? metadata.purpose.trim() + : undefined; + const toolInfo = { + name, + displayName: toolDisplayName, + purpose: toolPurpose, + description: + typeof (tool as { description?: unknown }).description === "string" + ? (tool as { description: string }).description + : "", + parameters: + (tool as { inputSchema?: unknown; args?: unknown }).inputSchema ?? + (tool as { args?: unknown }).args, + outputSchema: (tool as { outputSchema?: unknown }).outputSchema, + tags: metadata?.tags, + needsApproval: + metadata?.needsApproval ?? + (tool as { needsApproval?: Tool["needsApproval"] }).needsApproval, + providerOptions: (tool as { providerOptions?: unknown }).providerOptions, + toModelOutput: (tool as { toModelOutput?: unknown }).toModelOutput, + hooks: metadata?.hooks, + execute, + isClientSide: () => typeof execute !== "function", + } as unknown as Tool; + + return (args: any, options?: ToolExecutionOptions) => { + const toolCallId = options?.toolCallId ?? randomUUID(); + const messages = options?.messages ?? []; + const abortSignal = options?.abortSignal; + const executionOptions: ToolExecuteOptions = { + ...oc, + toolContext: { + name, + callId: toolCallId, + messages, + abortSignal, + }, + }; + executionOptions.hooks = hooks; + + const toolTags = metadata?.tags; + const toolSpan = oc.traceContext.createChildSpan(`tool.execution:${name}`, "tool", { + label: name, + attributes: { + "tool.name": name, + ...(toolDisplayName ? { "tool.display_name": toolDisplayName } : {}), + ...(toolPurpose ? { "tool.purpose": toolPurpose } : {}), + "tool.call.id": toolCallId, + "tool.description": toolInfo.description, + ...(toolTags && toolTags.length > 0 ? { "tool.tags": safeStringify(toolTags) } : {}), + "tool.parameters": safeStringify(toolInfo.parameters), + input: args ? safeStringify(args) : undefined, + }, + kind: SpanKind.CLIENT, + }); + + oc.systemContext.set("agentId", this.id); + oc.systemContext.set("historyEntryId", oc.operationId); + executionOptions.parentToolSpan = toolSpan; + + const hasOutputOverride = ( + value: unknown, + ): value is { + output?: unknown; + } => { + if (!value || typeof value !== "object") { + return false; + } + return Object.prototype.hasOwnProperty.call(value, "output"); + }; + + const runToolStartHooks = async () => { + await metadata?.hooks?.onStart?.({ + tool: toolInfo, + args, + options: executionOptions, + }); + await hooks.onToolStart?.({ + agent: this, + tool: toolInfo, + context: oc, + args, + options: executionOptions, + }); + }; + + let spanOutcome: + | { status: "completed"; output?: unknown } + | { status: "error"; error?: Error | any } + | null = null; + + const finalizeToolSpan = () => { + const shouldEnd = + typeof toolSpan.isRecording === "function" ? toolSpan.isRecording() : true; + if (!shouldEnd) { + return; + } + const status = spanOutcome?.status ?? "completed"; + oc.traceContext.endChildSpan(toolSpan, status, { + output: spanOutcome?.status === "completed" ? spanOutcome.output : undefined, + error: spanOutcome?.status === "error" ? spanOutcome.error : undefined, + }); + }; + + const resolveToolEndOutput = async (currentOutput: any) => { + let output = currentOutput; + let overrideProvided = false; + + const toolHookResult = await metadata?.hooks?.onEnd?.({ + tool: toolInfo, + args, + output, + error: undefined, + options: executionOptions, + }); + if (hasOutputOverride(toolHookResult)) { + output = toolHookResult.output; + overrideProvided = true; + } + + const agentHookResult = await hooks.onToolEnd?.({ + agent: this, + tool: toolInfo, + output, + error: undefined, + context: oc, + options: executionOptions, + }); + if (hasOutputOverride(agentHookResult)) { + output = agentHookResult.output; + overrideProvided = true; + } + + if (overrideProvided) { + output = await this.validateToolOutput(output, toolInfo); + } + + return output; + }; + + const handleToolSuccess = async (_result: any, validatedResult: any) => { + const finalOutput = await resolveToolEndOutput(validatedResult); + spanOutcome = { status: "completed", output: finalOutput }; + return finalOutput; + }; + + const handleToolError = async (errorValue: unknown) => { + const error = errorValue instanceof Error ? errorValue : new Error(String(errorValue)); + const voltAgentError = createVoltAgentError(error, { + stage: "tool_execution", + toolError: { + toolCallId, + toolName: name, + toolExecutionError: error, + toolArguments: args, + }, + }); + let errorOutputOverride: unknown; + let hasErrorOutputOverride = false; + + spanOutcome = { status: "error", error: voltAgentError }; + + await metadata?.hooks?.onEnd?.({ + tool: toolInfo, + args, + output: undefined, + error: voltAgentError, + options: executionOptions, + }); + + const onToolErrorResult = await hooks.onToolError?.({ + agent: this, + tool: toolInfo, + args, + error: voltAgentError, + originalError: error, + context: oc, + options: executionOptions, + }); + if (hasOutputOverride(onToolErrorResult)) { + errorOutputOverride = onToolErrorResult.output; + hasErrorOutputOverride = true; + } + + await hooks.onToolEnd?.({ + agent: this, + tool: toolInfo, + output: undefined, + error: voltAgentError, + context: oc, + options: executionOptions, + }); + + if (isToolDeniedError(errorValue)) { + oc.abortController.abort(errorValue); + } + + if (hasErrorOutputOverride) { + return errorOutputOverride; + } + + return buildToolErrorResult(error, toolCallId, name); + }; + + if (typeof execute !== "function") { + return oc.traceContext.withSpan(toolSpan, async () => { + try { + throw new Error(`Tool ${name} does not have "execute" method`); + } catch (e) { + return await handleToolError(e); + } finally { + finalizeToolSpan(); + } + }); + } + + if (isAsyncGeneratorFunction(execute)) { + const agent = this; + return (async function* (): AsyncGenerator { + try { + await agent.waitForSpeculativeInputGuardrail(oc); + await oc.traceContext.withSpan(toolSpan, async () => { + await runToolStartHooks(); + }); + + const result = execute(args, options); + if (!isAsyncIterable(result)) { + const resolved = await result; + const validatedResult = await agent.validateToolOutput(resolved, toolInfo); + const finalOutput = await oc.traceContext.withSpan(toolSpan, async () => { + return await handleToolSuccess(resolved, validatedResult); + }); + yield finalOutput; + return; + } + + const iterator = result[Symbol.asyncIterator](); + let pendingOutput: any = undefined; + let validatedResult: any = undefined; + let hasOutput = false; + + while (true) { + const next = await oc.traceContext.withSpan(toolSpan, () => iterator.next()); + if (next.done) { + break; + } + + if (hasOutput) { + yield pendingOutput; + } + + pendingOutput = next.value; + hasOutput = true; + validatedResult = await agent.validateToolOutput(pendingOutput, toolInfo); + } + + if (!hasOutput) { + validatedResult = await agent.validateToolOutput(pendingOutput, toolInfo); + } + + const finalOutput = await oc.traceContext.withSpan(toolSpan, async () => { + return await handleToolSuccess(pendingOutput, validatedResult); + }); + + if (hasOutput || finalOutput !== undefined) { + yield finalOutput; + } + } catch (e) { + const errorResult = await oc.traceContext.withSpan(toolSpan, async () => { + return await handleToolError(e); + }); + yield errorResult; + } finally { + finalizeToolSpan(); + } + })(); + } + + return oc.traceContext.withSpan(toolSpan, async () => { + try { + await this.waitForSpeculativeInputGuardrail(oc); + await runToolStartHooks(); + + let result = await execute(args, options); + if (isAsyncIterable(result)) { + let lastOutput: any = undefined; + for await (const output of result) { + lastOutput = output; + } + result = lastOutput; + } + + const validatedResult = await this.validateToolOutput(result, toolInfo); + return await handleToolSuccess(result, validatedResult); + } catch (e) { + return await handleToolError(e); + } finally { + finalizeToolSpan(); + } + }); + }; + }; + } + private createToolExecutionFactory( oc: OperationContext, hooks: AgentHooks, - ): (tool: BaseTool) => (args: any, options?: ToolExecutionOptions) => ToolExecutionResult { - return (tool: BaseTool) => (args: any, options?: ToolExecutionOptions) => { + ): ( + tool: BaseTool, + ) => (args: any, options?: ToolExecutionOptions) => ToolExecutionResult { + return (tool: BaseTool) => (args: any, options?: ToolExecutionOptions) => { // AI SDK passes ToolExecutionOptions with fields: toolCallId, messages, abortSignal const toolCallId = options?.toolCallId ?? randomUUID(); const messages = options?.messages ?? []; @@ -6718,14 +7540,14 @@ export class Agent { return new Set([TOOL_ROUTING_SEARCH_TOOL_NAME, TOOL_ROUTING_CALL_TOOL_NAME]); } - private isToolRoutingSupportTool(tool: BaseTool | ProviderTool): boolean { + private isToolRoutingSupportTool(tool: ManagedToolInfo): boolean { if (!tool || typeof tool !== "object") { return false; } return Object.prototype.hasOwnProperty.call(tool, TOOL_ROUTING_INTERNAL_TOOL_SYMBOL); } - private isToolExecutableForRouting(tool: BaseTool | ProviderTool): boolean { + private isToolExecutableForRouting(tool: ManagedToolInfo): boolean { if (isProviderTool(tool)) { const callableFlag = (tool as { callable?: boolean }).callable; if (callableFlag === false) { @@ -7132,14 +7954,8 @@ export class Agent { if (schema && typeof schema.safeParse === "function") { const parsed = schema.safeParse(rawArgs); if (!parsed.success) { - const issues = - (parsed.error as { issues?: unknown; errors?: unknown }).issues ?? - (parsed.error as { issues?: unknown; errors?: unknown }).errors ?? - []; - const coercedArgs = coerceStringifiedJsonToolArgs( - rawArgs, - Array.isArray(issues) ? issues : [], - ); + const issues = getValidationIssues(parsed.error); + const coercedArgs = coerceStringifiedJsonToolArgs(rawArgs, issues); if (coercedArgs) { const reparsed = schema.safeParse(coercedArgs); @@ -7149,14 +7965,14 @@ export class Agent { const error = new Error( `Invalid arguments for tool "${name}": ${reparsed.error.message}`, ); - Object.assign(error, { validationErrors: reparsed.error.errors }); + Object.assign(error, { validationErrors: getValidationIssues(reparsed.error) }); throw error; } } else { const error = new Error( `Invalid arguments for tool "${name}": ${parsed.error.message}`, ); - Object.assign(error, { validationErrors: parsed.error.errors }); + Object.assign(error, { validationErrors: issues }); throw error; } } else { @@ -7164,6 +7980,27 @@ export class Agent { } } + if (isNamedAiSdkTool(target)) { + await this.ensureToolApproval(target as any, parsedArgs, executionOptions, toolCallId); + + const execute = this.createAiSdkToolExecutionFactory(oc, hooks)( + target.name, + getRawAiSdkTool(target), + { + tags: target.tags, + needsApproval: target.needsApproval, + hooks: target.hooks, + }, + ); + + return await execute(parsedArgs, { + toolCallId, + messages: executionOptions.toolContext?.messages ?? [], + abortSignal: executionOptions.toolContext?.abortSignal, + context: undefined, + }); + } + await this.ensureToolApproval( target as Tool, parsedArgs, @@ -7176,6 +8013,7 @@ export class Agent { toolCallId, messages: executionOptions.toolContext?.messages ?? [], abortSignal: executionOptions.toolContext?.abortSignal, + context: undefined, }); }, }); @@ -7311,12 +8149,115 @@ export class Agent { return toolResult.output; } + private getToolApprovalFromContext( + options?: ToolExecuteOptions, + ): ToolApprovalConfiguration | undefined { + const contextValue = + options?.systemContext?.get(TOOL_APPROVAL_CONTEXT_KEY) ?? + options?.context?.get(TOOL_APPROVAL_CONTEXT_KEY); + return contextValue as ToolApprovalConfiguration | undefined; + } + + private normalizeToolApprovalStatus(status: ToolApprovalStatus): { + type: "not-applicable" | "approved" | "denied" | "user-approval"; + reason?: string; + } { + if (!status) { + return { type: "not-applicable" }; + } + + if (typeof status === "string") { + return { type: status }; + } + + return { + type: status.type, + reason: "reason" in status ? status.reason : undefined, + }; + } + + private async resolveToolApprovalStatus(params: { + toolApproval: ToolApprovalConfiguration; + tool: Tool | ProviderTool | NamedAiSdkTool; + args: Record; + options: ToolExecuteOptions; + toolCallId: string; + }): Promise { + const { toolApproval, tool, args, options, toolCallId } = params; + const messages = (options.toolContext?.messages ?? []) as ModelMessage[]; + + if (typeof toolApproval === "function") { + return await (toolApproval as any)({ + toolCall: { + type: "tool-call", + toolCallId, + toolName: tool.name, + input: args, + dynamic: true, + }, + tools: undefined, + toolsContext: {}, + runtimeContext: undefined, + messages, + }); + } + + const approvalForTool = (toolApproval as Record)[tool.name]; + if (typeof approvalForTool === "function") { + return await (approvalForTool as any)(args, { + toolCallId, + messages, + toolContext: undefined, + runtimeContext: undefined, + }); + } + + return approvalForTool as ToolApprovalStatus; + } + + private throwToolApprovalError( + tool: Tool | ProviderTool | NamedAiSdkTool, + status: ReturnType, + ): never { + if (status.type === "denied") { + throw new ToolDeniedError({ + toolName: tool.name, + message: status.reason ?? `Tool ${tool.name} was denied by tool approval policy.`, + code: "TOOL_FORBIDDEN", + httpStatus: 403, + }); + } + + throw new ToolDeniedError({ + toolName: tool.name, + message: `Tool ${tool.name} requires user approval.`, + code: "TOOL_APPROVAL_REQUIRED", + httpStatus: 403, + }); + } + private async ensureToolApproval( - tool: Tool | ProviderTool, + tool: Tool | ProviderTool | NamedAiSdkTool, args: Record, options: ToolExecuteOptions, toolCallId: string, ): Promise { + const toolApproval = this.getToolApprovalFromContext(options); + if (toolApproval !== undefined) { + const approvalStatus = await this.resolveToolApprovalStatus({ + toolApproval, + tool, + args, + options, + toolCallId, + }); + const normalizedStatus = this.normalizeToolApprovalStatus(approvalStatus); + if (normalizedStatus.type === "approved" || normalizedStatus.type === "not-applicable") { + return; + } + this.throwToolApprovalError(tool, normalizedStatus); + } + const needsApproval = (tool as { needsApproval?: Tool["needsApproval"] }) .needsApproval; if (!needsApproval) { @@ -7328,7 +8269,7 @@ export class Agent { ? await needsApproval(args as any, { toolCallId, messages: (options.toolContext?.messages ?? []) as ModelMessage[], - experimental_context: undefined, + context: undefined, }) : needsApproval; @@ -7350,7 +8291,7 @@ export class Agent { output?: OutputSpec; toolChoice?: ToolChoice>; temperature?: number; - }): Promise> { + }): Promise> { const { oc, modelValue, messages, tools, output, toolChoice, temperature } = params; const model = await this.resolveModel(modelValue ?? this.model, oc); const modelName = this.getModelName(model); @@ -7366,18 +8307,19 @@ export class Agent { }, }); const finalizeLLMSpan = this.createLLMSpanFinalizer(llmSpan); + const promptOptions = splitInstructionsFromMessages(messages); try { const response = await oc.traceContext.withSpan(llmSpan, () => generateText({ model, - messages, + ...promptOptions, tools, output, toolChoice, temperature, maxRetries: 0, - stopWhen: stepCountIs(1), + stopWhen: isStepCount(1), abortSignal: oc.abortController.signal, }), ); @@ -7419,7 +8361,11 @@ export class Agent { /** * Create step handler for memory and hooks */ - private createStepHandler(oc: OperationContext, options?: BaseGenerationOptions) { + private createStepHandler( + oc: OperationContext, + options?: BaseGenerationOptions, + userOnStepEnd?: GenerationStepEndCallback, + ) { const buffer = this.getConversationBuffer(oc); const shouldPersistMemory = this.shouldPersistMemoryForContext(oc); const persistQueue = shouldPersistMemory ? this.getMemoryPersistQueue(oc) : null; @@ -7481,7 +8427,8 @@ export class Agent { // Call hooks const hooks = this.getMergedHooks(options); - await hooks.onStepFinish?.({ agent: this, step: event, context: oc }); + await hooks.onStepEnd?.({ agent: this, step: event, context: oc }); + await userOnStepEnd?.(event); }; } @@ -7842,9 +8789,9 @@ export class Agent { } return undefined; }, - onStepFinish: async (...args) => { - await options.hooks?.onStepFinish?.(...args); - await this.hooks.onStepFinish?.(...args); + onStepEnd: async (...args) => { + await options.hooks?.onStepEnd?.(...args); + await this.hooks.onStepEnd?.(...args); }, onRetry: async (...args) => { await options.hooks?.onRetry?.(...args); @@ -8197,7 +9144,7 @@ export class Agent { node_id: createNodeId(NodeType.AGENT, this.id), tools: (() => { - const merged = new Map(); + const merged = new Map(); for (const tool of [ ...this.toolManager.getAllTools(), ...this.toolPoolManager.getAllTools(), @@ -8349,8 +9296,8 @@ export class Agent { /** * Get all tools */ - public getTools() { - return this.toolManager.getAllBaseTools(); + public getTools(): Array | ProviderTool | NamedAiSdkTool> { + return this.toolManager.getAllTools(); } /** diff --git a/packages/core/src/agent/concurrent-tool-spans.spec.ts b/packages/core/src/agent/concurrent-tool-spans.spec.ts index a8a20a09a..710d293a7 100644 --- a/packages/core/src/agent/concurrent-tool-spans.spec.ts +++ b/packages/core/src/agent/concurrent-tool-spans.spec.ts @@ -17,7 +17,7 @@ vi.mock("ai", async () => { streamText: vi.fn(), generateObject: vi.fn(), streamObject: vi.fn(), - stepCountIs: vi.fn(() => vi.fn(() => false)), + isStepCount: vi.fn(() => vi.fn(() => false)), }; }); diff --git a/packages/core/src/agent/context-keys.ts b/packages/core/src/agent/context-keys.ts index 5c6c2c493..eedce86ef 100644 --- a/packages/core/src/agent/context-keys.ts +++ b/packages/core/src/agent/context-keys.ts @@ -2,4 +2,5 @@ export const FORCED_TOOL_CHOICE_CONTEXT_KEY = Symbol("forcedToolChoice"); export const AGENT_REF_CONTEXT_KEY = Symbol("agentRef"); export const TOOL_ROUTING_CONTEXT_KEY = Symbol("toolRoutingConfig"); export const TOOL_ROUTING_SEARCHED_TOOLS_CONTEXT_KEY = Symbol("toolRoutingSearchedTools"); +export const TOOL_APPROVAL_CONTEXT_KEY = Symbol("toolApprovalConfig"); export const SPECULATIVE_INPUT_GUARDRAIL_CONTEXT_KEY = Symbol("speculativeInputGuardrail"); diff --git a/packages/core/src/agent/eval.ts b/packages/core/src/agent/eval.ts index a82949cc6..caf6f46af 100644 --- a/packages/core/src/agent/eval.ts +++ b/packages/core/src/agent/eval.ts @@ -1436,6 +1436,12 @@ function extractJudgeTelemetry( } const usage = isPlainRecord(judge.usage) ? (judge.usage as Record) : undefined; + const inputTokenDetails = isPlainRecord(usage?.inputTokenDetails) + ? (usage.inputTokenDetails as Record) + : undefined; + const outputTokenDetails = isPlainRecord(usage?.outputTokenDetails) + ? (usage.outputTokenDetails as Record) + : undefined; const providerCost = isPlainRecord(judge.providerCost) ? (judge.providerCost as Record) : undefined; @@ -1445,8 +1451,8 @@ function extractJudgeTelemetry( promptTokens: readNumber(usage?.promptTokens), completionTokens: readNumber(usage?.completionTokens), totalTokens: readNumber(usage?.totalTokens), - cachedTokens: readNumber(usage?.cachedInputTokens ?? usage?.cachedTokens), - reasoningTokens: readNumber(usage?.reasoningTokens), + cachedTokens: readNumber(inputTokenDetails?.cacheReadTokens ?? usage?.cachedTokens), + reasoningTokens: readNumber(outputTokenDetails?.reasoningTokens ?? usage?.reasoningTokens), providerCost: providerCost ? { cost: readNumber(providerCost.cost), diff --git a/packages/core/src/agent/guardrail.integration.spec.ts b/packages/core/src/agent/guardrail.integration.spec.ts index 0bc47265f..a5ce910bf 100644 --- a/packages/core/src/agent/guardrail.integration.spec.ts +++ b/packages/core/src/agent/guardrail.integration.spec.ts @@ -158,9 +158,7 @@ describe("Agent guardrail integration", () => { expect(streamedText).toContain("[redacted digits]"); expect(streamedText).not.toMatch(/\d/); - const fullChunks = await collectStream>( - streamResult.fullStream, - ); + const fullChunks = await collectStream>(streamResult.stream); const emittedText = fullChunks .filter((chunk) => chunk.type === "text-delta") .map((chunk) => chunk.delta ?? chunk.text ?? "") @@ -333,7 +331,7 @@ describe("Agent guardrail integration", () => { const fullStreamResult = await agent.streamText("hello"); const fullChunks = await collectStream>( - fullStreamResult.fullStream, + fullStreamResult.stream, ); const fullStreamText = fullChunks .filter((chunk) => chunk.type === "text-delta") diff --git a/packages/core/src/agent/hooks/index.spec.ts b/packages/core/src/agent/hooks/index.spec.ts index 00ca7a048..88296a1ba 100644 --- a/packages/core/src/agent/hooks/index.spec.ts +++ b/packages/core/src/agent/hooks/index.spec.ts @@ -159,6 +159,7 @@ describe("Agent Hooks Functionality", () => { throw new Error("LLM Error"); }, }), + maxRetries: 0, hooks: createHooks({ onEnd: onEndSpy, onError: onErrorSpy }), }); @@ -517,13 +518,13 @@ describe("Agent Hooks Functionality", () => { }); }); - describe("onStepFinish", () => { - it("should call onStepFinish when a step completes", async () => { - const onStepFinishSpy = vi.fn(); + describe("onStepEnd", () => { + it("should call onStepEnd when a step completes", async () => { + const onStepEndSpy = vi.fn(); agent = createTestAgent({ name: "TestAgent", model: createMockLanguageModel(), - hooks: createHooks({ onStepFinish: onStepFinishSpy }), + hooks: createHooks({ onStepEnd: onStepEndSpy }), }); const mockStep = { @@ -533,7 +534,7 @@ describe("Agent Hooks Functionality", () => { finishReason: "stop", }; - await agent.hooks.onStepFinish?.({ + await agent.hooks.onStepEnd?.({ agent: agent as any, step: mockStep, context: { @@ -541,7 +542,7 @@ describe("Agent Hooks Functionality", () => { } as any, }); - expect(onStepFinishSpy).toHaveBeenCalledWith( + expect(onStepEndSpy).toHaveBeenCalledWith( expect.objectContaining({ agent: expect.any(Object), step: mockStep }), ); }); diff --git a/packages/core/src/agent/hooks/index.ts b/packages/core/src/agent/hooks/index.ts index 4223b6138..820cf4db7 100644 --- a/packages/core/src/agent/hooks/index.ts +++ b/packages/core/src/agent/hooks/index.ts @@ -205,7 +205,7 @@ export type AgentHookOnPrepareModelMessages = ( args: OnPrepareModelMessagesHookArgs, ) => Promise | OnPrepareModelMessagesHookResult; export type AgentHookOnError = (args: OnErrorHookArgs) => Promise | void; -export type AgentHookOnStepFinish = (args: OnStepFinishHookArgs) => Promise | void; +export type AgentHookOnStepEnd = (args: OnStepFinishHookArgs) => Promise | void; export type AgentHookOnRetry = (args: OnRetryHookArgs) => Promise | void; export type AgentHookOnFallback = (args: OnFallbackHookArgs) => Promise | void; @@ -224,7 +224,7 @@ export type AgentHooks = { onPrepareModelMessages?: AgentHookOnPrepareModelMessages; // Additional (kept for convenience) onError?: AgentHookOnError; - onStepFinish?: AgentHookOnStepFinish; + onStepEnd?: AgentHookOnStepEnd; onRetry?: AgentHookOnRetry; onFallback?: AgentHookOnFallback; }; @@ -243,7 +243,7 @@ const defaultHooks: Required = { onPrepareMessages: async (_args: OnPrepareMessagesHookArgs) => ({}), onPrepareModelMessages: async (_args: OnPrepareModelMessagesHookArgs) => ({}), onError: async (_args: OnErrorHookArgs) => {}, - onStepFinish: async (_args: OnStepFinishHookArgs) => {}, + onStepEnd: async (_args: OnStepFinishHookArgs) => {}, onRetry: async (_args: OnRetryHookArgs) => {}, onFallback: async (_args: OnFallbackHookArgs) => {}, }; @@ -263,7 +263,7 @@ export function createHooks(hooks: Partial = {}): AgentHooks { onPrepareMessages: hooks.onPrepareMessages || defaultHooks.onPrepareMessages, onPrepareModelMessages: hooks.onPrepareModelMessages || defaultHooks.onPrepareModelMessages, onError: hooks.onError || defaultHooks.onError, - onStepFinish: hooks.onStepFinish || defaultHooks.onStepFinish, + onStepEnd: hooks.onStepEnd || defaultHooks.onStepEnd, onRetry: hooks.onRetry || defaultHooks.onRetry, onFallback: hooks.onFallback || defaultHooks.onFallback, }; diff --git a/packages/core/src/agent/providers/base/types.ts b/packages/core/src/agent/providers/base/types.ts index 61439471d..21facb18e 100644 --- a/packages/core/src/agent/providers/base/types.ts +++ b/packages/core/src/agent/providers/base/types.ts @@ -322,7 +322,7 @@ export interface StepWithContent { subAgentName?: string; } -export type StepFinishCallback = (step: StepWithContent) => void | Promise; +export type StepEndCallback = (step: StepWithContent) => void | Promise; export type StepChunkCallback = (chunk: any) => void | Promise; export interface GenerateTextOptions { @@ -331,7 +331,7 @@ export interface GenerateTextOptions { tools?: BaseTool[]; maxSteps?: number; provider?: ProviderOptions; - onStepFinish?: StepFinishCallback; + onStepEnd?: StepEndCallback; signal?: AbortSignal; } @@ -341,9 +341,9 @@ export interface StreamTextOptions { tools?: BaseTool[]; maxSteps?: number; provider?: ProviderOptions; - onStepFinish?: StepFinishCallback; + onStepEnd?: StepEndCallback; onChunk?: StepChunkCallback; - onFinish?: StreamTextOnFinishCallback; + onEnd?: StreamTextOnFinishCallback; onError?: StreamOnErrorCallback; signal?: AbortSignal; } @@ -353,7 +353,7 @@ export interface GenerateObjectOptions { model: TModel; schema: TSchema; provider?: ProviderOptions; - onStepFinish?: StepFinishCallback; + onStepEnd?: StepEndCallback; signal?: AbortSignal; } @@ -362,8 +362,8 @@ export interface StreamObjectOptions { model: TModel; schema: TSchema; provider?: ProviderOptions; - onStepFinish?: StepFinishCallback; - onFinish?: StreamObjectOnFinishCallback>; + onStepEnd?: StepEndCallback; + onEnd?: StreamObjectOnFinishCallback>; onError?: StreamOnErrorCallback; signal?: AbortSignal; } diff --git a/packages/core/src/agent/streaming/guardrail-stream.spec.ts b/packages/core/src/agent/streaming/guardrail-stream.spec.ts index a9c600cbe..35e8fd1c8 100644 --- a/packages/core/src/agent/streaming/guardrail-stream.spec.ts +++ b/packages/core/src/agent/streaming/guardrail-stream.spec.ts @@ -292,7 +292,7 @@ describe("Output guardrail streaming integration", () => { ]); const emitted: VoltAgentTextStreamPart[] = []; - for await (const chunk of pipeline.fullStream) { + for await (const chunk of pipeline.stream) { emitted.push(chunk as VoltAgentTextStreamPart); } @@ -429,12 +429,15 @@ describe("Output guardrail streaming integration", () => { const pipeline = buildPipeline(parts, { id: "passthrough", name: "Passthrough", - handler: async (_ctx) => ({ pass: true }) as const, + handler: async (_ctx) => + ({ + pass: true, + }) as const, streamHandler: ({ part }) => part, }); const emitted: VoltAgentTextStreamPart[] = []; - for await (const chunk of pipeline.fullStream) { + for await (const chunk of pipeline.stream) { emitted.push(chunk as VoltAgentTextStreamPart); } @@ -481,7 +484,10 @@ describe("Output guardrail streaming integration", () => { const pipeline = buildPipeline(parts, { id: "passthrough", name: "Passthrough", - handler: async (_ctx) => ({ pass: true }) as const, + handler: async (_ctx) => + ({ + pass: true, + }) as const, streamHandler: ({ part }) => part, }); diff --git a/packages/core/src/agent/streaming/guardrail-stream.ts b/packages/core/src/agent/streaming/guardrail-stream.ts index 049d156ea..53ad61b4d 100644 --- a/packages/core/src/agent/streaming/guardrail-stream.ts +++ b/packages/core/src/agent/streaming/guardrail-stream.ts @@ -84,6 +84,7 @@ type GuardrailPipelineUIFactory = ( export interface GuardrailPipeline { runner: OutputGuardrailStreamRunner | null; + stream: AsyncIterableStream; fullStream: AsyncIterableStream; textStream: AsyncIterableStream; createUIStream: GuardrailPipelineUIFactory; @@ -97,9 +98,11 @@ export function createGuardrailPipeline( _fallbackTextId = "guardrailed-output", ): GuardrailPipeline { if (!context || context.guardrails.length === 0) { + const stream = iterableToStream(baseFullStream); return { runner: null, - fullStream: iterableToStream(baseFullStream), + stream, + fullStream: stream, textStream: _baseTextStream, createUIStream: ( _options?: UIMessageStreamOptions, @@ -211,7 +214,7 @@ export function createGuardrailPipeline( const uiStream = createUIMessageStream({ originalMessages: streamOptions.originalMessages, onError, - onFinish: streamOptions.onFinish, + onEnd: streamOptions.onFinish, generateId: streamOptions.generateMessageId, execute: async ({ writer }) => { const reader = currentReadable.getReader(); @@ -275,6 +278,7 @@ export function createGuardrailPipeline( return { runner, + stream: fullStream, fullStream, textStream, createUIStream, diff --git a/packages/core/src/agent/subagent/index.spec.ts b/packages/core/src/agent/subagent/index.spec.ts index e5a6bcc64..b64f40982 100644 --- a/packages/core/src/agent/subagent/index.spec.ts +++ b/packages/core/src/agent/subagent/index.spec.ts @@ -492,6 +492,7 @@ describe("SubAgentManager", () => { const mockToUIMessageStream = vi.fn().mockReturnValue(mockStream); vi.spyOn(mockAgent, "streamText").mockResolvedValue({ + stream: mockStream, fullStream: mockStream, toUIMessageStream: mockToUIMessageStream, text: Promise.resolve("Test"), @@ -532,6 +533,7 @@ describe("SubAgentManager", () => { const mockToUIMessageStream = vi.fn().mockReturnValue(mockStream); vi.spyOn(mockAgent, "streamText").mockResolvedValue({ + stream: mockStream, fullStream: mockStream, toUIMessageStream: mockToUIMessageStream, text: Promise.resolve("Text"), @@ -583,6 +585,7 @@ describe("SubAgentManager", () => { ]); vi.spyOn(subAgent, "streamText").mockResolvedValue({ + stream: mockStream, fullStream: mockStream, toUIMessageStream: vi.fn(), text: Promise.resolve("done"), @@ -608,6 +611,15 @@ describe("SubAgentManager", () => { expect(toolCallPart.parentAgentName).toBe("Parent Agent"); expect(toolCallPart.agentPath).toEqual(["Parent Agent", "Sub-Agent A"]); + const toolResultPart = forwarded.find((part) => part.type === "tool-result"); + expect(toolResultPart?.subAgentId).toBe("sub-agent-a"); + expect(toolResultPart?.subAgentName).toBe("Sub-Agent A"); + expect(toolResultPart?.executingAgentId).toBe("sub-agent-a"); + expect(toolResultPart?.executingAgentName).toBe("Sub-Agent A"); + expect(toolResultPart?.parentAgentId).toBe("parent-agent"); + expect(toolResultPart?.parentAgentName).toBe("Parent Agent"); + expect(toolResultPart?.agentPath).toEqual(["Parent Agent", "Sub-Agent A"]); + const guardrailPart = forwarded.find((part) => part.type === "input-guardrail-blocked"); expect(guardrailPart?.data).toMatchObject({ code: "GUARDRAIL_INPUT_BLOCKED", diff --git a/packages/core/src/agent/subagent/index.ts b/packages/core/src/agent/subagent/index.ts index 878d87653..d1519cf78 100644 --- a/packages/core/src/agent/subagent/index.ts +++ b/packages/core/src/agent/subagent/index.ts @@ -609,7 +609,7 @@ ${task}\n\nContext: ${safeStringify(contextObj, { indentation: 2 })}`; const { uiStreamWriter, fullStreamWriter } = this.getStreamWriters(parentOperationContext); // If we have a UI writer, merge the subagent's stream with metadata - if (uiStreamWriter && response.fullStream) { + if (uiStreamWriter && response.stream) { // Convert the subagent's fullStream to UI message stream // Include all messages to maintain tool call/result pairing const subagentUIStream = response.toUIMessageStream(); @@ -632,7 +632,7 @@ ${task}\n\nContext: ${safeStringify(contextObj, { indentation: 2 })}`; } // If we have a fullStream writer, also write the subagent's fullStream events - if (fullStreamWriter && response.fullStream) { + if (fullStreamWriter && response.stream) { this.writeFullStream( response, forwardingMetadata, @@ -660,7 +660,7 @@ ${task}\n\nContext: ${safeStringify(contextObj, { indentation: 2 })}`; // Write subagent's fullStream events with metadata const writeSubagentFullStream = async () => { try { - for await (const part of response.fullStream) { + for await (const part of response.stream) { // Check if this event type should be forwarded if (!shouldForwardChunk(part, allowedTypes)) { continue; // Skip this event if not in allowed types diff --git a/packages/core/src/agent/subagent/test-utils.ts b/packages/core/src/agent/subagent/test-utils.ts index 7cb1557c1..bcfeacc0a 100644 --- a/packages/core/src/agent/subagent/test-utils.ts +++ b/packages/core/src/agent/subagent/test-utils.ts @@ -26,11 +26,9 @@ import type { AgentHooks, GenerateObjectOptions, GenerateObjectResultWithContext, - GenerateTextOptions, GenerateTextResultWithContext, StreamObjectOptions, StreamObjectResultWithContext, - StreamTextOptions, StreamTextResultWithContext, } from "../agent"; import type { ToolSchema } from "../providers/base/types"; @@ -214,10 +212,7 @@ export function createMockAgentWithStubs(options: CreateMockAgentOptions = {}) { // Optionally stub individual methods if needed for specific test cases vi.spyOn(agent, "streamText").mockImplementation( - async ( - _input: string | ModelMessage[] | UIMessage[], - _options?: StreamTextOptions, - ): Promise => { + async (_input: any, _options?: any): Promise => { const textContent = `Hello from ${agent.name}`; const stream = simulateReadableStream({ chunks: [ @@ -245,6 +240,7 @@ export function createMockAgentWithStubs(options: CreateMockAgentOptions = {}) { }); const result: StreamTextResultWithContext = { + stream: stream as any, fullStream: stream as any, textStream: textStream as any, text: Promise.resolve(textContent), @@ -268,8 +264,8 @@ export function createMockAgentWithStubs(options: CreateMockAgentOptions = {}) { // Stub generateText method with proper signature vi.spyOn(agent, "generateText").mockImplementation( async = Output.Output>( - _input: string | ModelMessage[] | UIMessage[], - _options?: GenerateTextOptions, + _input: any, + _options?: any, ): Promise> => { // Use a minimal mock that satisfies the interface const outputValue = undefined as unknown as InferGenerateOutput; @@ -292,7 +288,6 @@ export function createMockAgentWithStubs(options: CreateMockAgentOptions = {}) { finishReason: "stop" as const, rawFinishReason: undefined, steps: [], - experimental_output: outputValue, output: outputValue, response: { id: "mock-response-id", @@ -311,7 +306,7 @@ export function createMockAgentWithStubs(options: CreateMockAgentOptions = {}) { toDataStream: vi.fn(), toDataStreamResponse: vi.fn(), pipeDataStreamToResponse: vi.fn(), - } as GenerateTextResultWithContext; + } as unknown as GenerateTextResultWithContext; return result; }, diff --git a/packages/core/src/agent/subagent/types.ts b/packages/core/src/agent/subagent/types.ts index cbeeaf3b6..2236cad54 100644 --- a/packages/core/src/agent/subagent/types.ts +++ b/packages/core/src/agent/subagent/types.ts @@ -1,4 +1,4 @@ -import type { StreamTextResult, TextStreamPart } from "ai"; +import type { Output, StreamTextResult, TextStreamPart } from "ai"; import type { z } from "zod"; import type { Agent } from "../agent"; import type { @@ -206,10 +206,12 @@ export type VoltAgentTextStreamPart = Record = Record, - OUTPUT = unknown, -> = Omit, "fullStream"> & { + OUTPUT extends Output.Output = Output.Output, +> = Omit, "stream"> & { /** - * Full stream with subagent metadata support + * Stream with subagent metadata support. */ + readonly stream: AsyncIterable>; + /** @deprecated Use `stream` instead. */ readonly fullStream: AsyncIterable>; } & Record; diff --git a/packages/core/src/agent/test-utils.ts b/packages/core/src/agent/test-utils.ts index 2fc0cabd9..c89f81b49 100644 --- a/packages/core/src/agent/test-utils.ts +++ b/packages/core/src/agent/test-utils.ts @@ -57,9 +57,6 @@ export const defaultMockResponse = { textTokens: 5, reasoningTokens: 0, }, - cachedInputTokens: 0, - reasoningTokens: 0, - raw: undefined, } as LanguageModelUsage, warnings: [], }; @@ -396,6 +393,22 @@ export function createMockToolCall(toolName: string, args: any, result?: any) { */ export function createMockStepResult(options?: Partial>): StepResult { return { + ...options, + callId: options?.callId || String(mockId()), + stepNumber: options?.stepNumber ?? 0, + model: options?.model || { provider: "mock-provider", modelId: "mock-model" }, + toolsContext: options?.toolsContext || {}, + runtimeContext: options?.runtimeContext || {}, + performance: options?.performance || { + effectiveOutputTokensPerSecond: 0, + outputTokensPerSecond: undefined, + inputTokensPerSecond: undefined, + effectiveTotalTokensPerSecond: 0, + stepTimeMs: 0, + responseTimeMs: 0, + toolExecutionMs: {}, + timeToFirstOutputMs: undefined, + }, text: options?.text || "", content: options?.content || [], reasoning: options?.reasoning || [], @@ -420,7 +433,6 @@ export function createMockStepResult(options?: Partial>): StepRe rawFinishReason: options?.rawFinishReason, usage: options?.usage || defaultMockResponse.usage, warnings: options?.warnings || [], - ...options, }; } @@ -498,10 +510,9 @@ export function createAutoAbortController(delay: number): AbortController { */ export function createMockStreamTextResult(overrides?: any) { const textContent = overrides?.text || "Mock streamed text"; - return { - text: Promise.resolve(textContent), - textStream: convertArrayToAsyncIterable(textContent.split(" ")), - fullStream: convertArrayToAsyncIterable([ + const stream = + overrides?.stream ?? + convertArrayToAsyncIterable([ { type: "text-delta" as const, id: "text-1", delta: "Mock ", text: "Mock " }, { type: "text-delta" as const, id: "text-1", delta: "streamed ", text: "streamed " }, { type: "text-delta" as const, id: "text-1", delta: "text", text: "text" }, @@ -511,14 +522,19 @@ export function createMockStreamTextResult(overrides?: any) { usage: overrides?.usage || defaultMockResponse.usage, totalUsage: overrides?.totalUsage || defaultMockResponse.usage, }, - ]), + ]); + return { + text: Promise.resolve(textContent), + textStream: convertArrayToAsyncIterable(textContent.split(" ")), + stream, + fullStream: stream, usage: Promise.resolve(overrides?.usage || defaultMockResponse.usage), finishReason: Promise.resolve(overrides?.finishReason || "stop"), rawResponse: overrides?.rawResponse, warnings: overrides?.warnings || [], // Include the onFinish callback if provided - onFinish: overrides?.onFinish ? Promise.resolve().then(overrides.onFinish) : undefined, + onEnd: overrides?.onFinish ? Promise.resolve().then(overrides.onFinish) : undefined, // Include any other overrides ...overrides, diff --git a/packages/core/src/agent/types.ts b/packages/core/src/agent/types.ts index 77be82be3..e58613ebf 100644 --- a/packages/core/src/agent/types.ts +++ b/packages/core/src/agent/types.ts @@ -1,5 +1,5 @@ import type { AnthropicProviderOptions } from "@ai-sdk/anthropic"; -import type { GoogleGenerativeAIProviderOptions } from "@ai-sdk/google"; +import type { GoogleLanguageModelOptions } from "@ai-sdk/google"; import type { OpenAIResponsesProviderOptions } from "@ai-sdk/openai"; import type { XaiProviderOptions, XaiResponsesProviderOptions } from "@ai-sdk/xai"; import type { Span } from "@opentelemetry/api"; @@ -16,7 +16,7 @@ import type { PrepareStep, StopWhen } from "../ai-types"; import type { LanguageModel, LanguageModelUsage, StepResult, ToolSet, UIMessage } from "ai"; import type { Memory } from "../memory"; import type { BaseRetriever } from "../retriever/retriever"; -import type { ProviderTool, Tool, Toolkit, VercelTool } from "../tool"; +import type { NamedAiSdkTool, ProviderTool, Tool, Toolkit, VercelTool } from "../tool"; import type { ToolRoutingConfig } from "../tool/routing/types"; import type { StreamEvent } from "../utils/streams"; import type { Voice } from "../voice/types"; @@ -66,8 +66,12 @@ export type { DynamicValueOptions, DynamicValue, PromptHelper, PromptContent }; */ export interface ApiToolInfo { name: string; + displayName?: string; + purpose?: string; description: string; parameters?: any; + tags?: string[]; + metadata?: Record; } export interface AgentToolRoutingState { @@ -124,7 +128,7 @@ export type AgentMarkFeedbackProvidedInput = { /** * Tool with node_id for agent state */ -export type ToolWithNodeId = (BaseTool | ProviderTool) & { +export type ToolWithNodeId = (BaseTool | ProviderTool | NamedAiSdkTool) & { node_id: string; }; @@ -264,12 +268,12 @@ export type AgentModelConfig = { */ export type AgentModelValue = ModelDynamicValue | AgentModelConfig[]; +export type AgentToolInput = (Tool | Toolkit | VercelTool)[] | ToolSet; + /** * Enhanced dynamic value for tools that supports static or dynamic values */ -export type ToolsDynamicValue = - | (Tool | Toolkit)[] - | DynamicValue<(Tool | Toolkit)[]>; +export type ToolsDynamicValue = AgentToolInput | DynamicValue; /** * Provider options type for LLM configurations @@ -292,11 +296,11 @@ type LegacyProviderCallOptions = { // Provider-specific options that don't fit the common pattern extraOptions?: Record; - // Callback when a step is finished - onStepFinish?: (step: StepWithContent) => Promise; + // Callback when a step ends + onStepEnd?: (step: StepWithContent) => Promise; - // Callback when generation completes successfully - onFinish?: (result: unknown) => Promise; + // Callback when generation ends successfully + onEnd?: (result: unknown) => Promise; // Callback when an error occurs during generation onError?: (error: unknown) => Promise; @@ -305,7 +309,7 @@ type LegacyProviderCallOptions = { export type ProviderOptions = LegacyProviderCallOptions & { // Common provider-specific option buckets with IntelliSense anthropic?: AnthropicProviderOptions & Record; - google?: GoogleGenerativeAIProviderOptions & Record; + google?: GoogleLanguageModelOptions & Record; openai?: OpenAIResponsesProviderOptions & Record; xai?: (XaiProviderOptions | XaiResponsesProviderOptions) & Record; @@ -687,7 +691,7 @@ export type AgentOptions = { instructions: InstructionsDynamicValue; // Tools & Memory - tools?: (Tool | Toolkit | VercelTool)[] | DynamicValue<(Tool | Toolkit)[]>; + tools?: AgentToolInput | DynamicValue; toolkits?: Toolkit[]; toolRouting?: ToolRoutingConfig | false; workspace?: Workspace | WorkspaceConfig | false; @@ -1022,6 +1026,76 @@ export type SemanticMemoryOptions = CommonSemanticMemoryOptions; export type RuntimeMemoryBehaviorOptions = CommonRuntimeMemoryBehaviorOptions; export type RuntimeMemoryEnvelope = CommonRuntimeMemoryEnvelope; +export interface VoltAgentRuntimeGuardrailOptions { + input?: InputGuardrail[]; + output?: OutputGuardrail[]; +} + +export interface VoltAgentRuntimeMiddlewareOptions { + input?: InputMiddleware[]; + output?: OutputMiddleware[]; + maxRetries?: number; +} + +export interface VoltAgentRuntimeOptions { + // Preferred runtime memory envelope for per-call memory identity and behavior overrides. + memory?: CommonRuntimeMemoryEnvelope; + + /** + * @deprecated Use `memory.userId` instead. + */ + userId?: string; + + /** + * @deprecated Use `memory.conversationId` instead. + */ + conversationId?: string; + + /** + * @deprecated Use `memory.options.contextLimit` instead. + */ + contextLimit?: number; + + /** + * @deprecated Use `memory.options.semanticMemory` instead. + */ + semanticMemory?: CommonSemanticMemoryOptions; + + /** + * @deprecated Use `memory.options.messageMetadataPersistence` instead. + */ + messageMetadataPersistence?: AgentMessageMetadataPersistenceConfig; + + /** + * @deprecated Use `memory.options.conversationPersistence` instead. + */ + conversationPersistence?: AgentConversationPersistenceOptions; + + context?: ContextInput; + requestHeaders?: Record; + elicitation?: (request: unknown) => Promise; + + parentAgentId?: string; + parentOperationContext?: OperationContext; + parentSpan?: Span; + inheritParentSpan?: boolean; + + maxSteps?: number; + feedback?: AgentFeedbackOptions | boolean; + toolRouting?: ToolRoutingConfig | false; + + hooks?: AgentHooks; + guardrails?: VoltAgentRuntimeGuardrailOptions; + inputGuardrails?: InputGuardrail[]; + outputGuardrails?: OutputGuardrail[]; + middleware?: VoltAgentRuntimeMiddlewareOptions; + inputMiddlewares?: InputMiddleware[]; + outputMiddlewares?: OutputMiddleware[]; + maxMiddlewareRetries?: number; + + resumableStream?: boolean; +} + export interface CommonResolvedRuntimeMemoryOptions { userId?: string; conversationId?: string; @@ -1036,6 +1110,9 @@ export interface CommonGenerateOptions { // Common LLM provider properties provider?: ProviderOptions; + // New namespace for VoltAgent runtime-specific options. + voltagent?: VoltAgentRuntimeOptions; + // Preferred runtime memory envelope for per-call memory identity and behavior overrides. memory?: CommonRuntimeMemoryEnvelope; diff --git a/packages/core/src/index.spec.ts b/packages/core/src/index.spec.ts index 484775093..bbcc69f6d 100644 --- a/packages/core/src/index.spec.ts +++ b/packages/core/src/index.spec.ts @@ -1,5 +1,6 @@ import { describe, it } from "vitest"; import { Agent as InternalAgent } from "./agent"; +import DefaultVoltAgent, { Agent, VoltAgent } from "./index"; import { VoltAgent as InternalVoltAgent } from "./voltagent"; describe("exports", () => { @@ -7,20 +8,17 @@ describe("exports", () => { // TODO: Add tests to make sure our main exports are ALWAYS available, and that we don't break them }); - it("should export the VoltAgent class as default", async () => { - const defaultExport = await import("./index"); - expect(defaultExport.default).toBeDefined(); - expect(defaultExport.default).toBe(InternalVoltAgent); + it("should export the VoltAgent class as default", () => { + expect(DefaultVoltAgent).toBeDefined(); + expect(DefaultVoltAgent).toBe(InternalVoltAgent); }); - it("should export the VoltAgent class", async () => { - const { VoltAgent } = await import("./index"); + it("should export the VoltAgent class", () => { expect(VoltAgent).toBeDefined(); expect(VoltAgent).toBe(InternalVoltAgent); }); - it("should export the Agent class", async () => { - const { Agent } = await import("./index"); + it("should export the Agent class", () => { expect(Agent).toBeDefined(); expect(Agent).toBe(InternalAgent); }); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index b22b821ee..b4195c5ea 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -309,7 +309,7 @@ export { convertUsage } from "./utils/usage-converter"; export { createAsyncIterableStream, type AsyncIterableStream } from "@voltagent/internal/utils"; // Convenience re-exports from ai-sdk so apps need only @voltagent/core -export { stepCountIs, hasToolCall } from "ai"; +export { isStepCount, hasToolCall } from "ai"; export type { LanguageModel } from "ai"; export type { PrepareStep, StopWhen } from "./ai-types"; diff --git a/packages/core/src/mcp/client/index.spec.ts b/packages/core/src/mcp/client/index.spec.ts index d99170b94..9fecb8d02 100644 --- a/packages/core/src/mcp/client/index.spec.ts +++ b/packages/core/src/mcp/client/index.spec.ts @@ -4,7 +4,6 @@ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js" import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { convertJsonSchemaToZod } from "zod-from-json-schema"; -import { convertJsonSchemaToZod as convertJsonSchemaToZodV3 } from "zod-from-json-schema-v3"; import { getGlobalLogger } from "../../logger"; import { MCPClient } from "./index"; @@ -30,10 +29,6 @@ vi.mock("zod-from-json-schema", () => ({ convertJsonSchemaToZod: vi.fn().mockReturnValue({}), })); -vi.mock("zod-from-json-schema-v3", () => ({ - convertJsonSchemaToZod: vi.fn().mockReturnValue({}), -})); - // Mock the logger const mockLoggerInstance = { trace: vi.fn(), @@ -464,7 +459,7 @@ describe("MCPClient", () => { expect(mockConnect).toHaveBeenCalled(); expect(mockListTools).toHaveBeenCalled(); - expect(convertJsonSchemaToZodV3).toHaveBeenCalledTimes(2); + expect(convertJsonSchemaToZod).toHaveBeenCalledTimes(2); expect(agentTools).toEqual( expect.objectContaining({ @@ -496,7 +491,7 @@ describe("MCPClient", () => { }); it("should skip a tool if schema conversion fails", async () => { - (convertJsonSchemaToZodV3 as vi.Mock).mockImplementationOnce(() => { + (convertJsonSchemaToZod as vi.Mock).mockImplementationOnce(() => { throw new Error("Schema conversion failed"); }); diff --git a/packages/core/src/mcp/client/index.ts b/packages/core/src/mcp/client/index.ts index 40bffeaa8..935311a3a 100644 --- a/packages/core/src/mcp/client/index.ts +++ b/packages/core/src/mcp/client/index.ts @@ -14,9 +14,8 @@ import { } from "@modelcontextprotocol/sdk/types.js"; import type { ListResourcesResult } from "@modelcontextprotocol/sdk/types.js"; import type { Logger } from "@voltagent/internal"; -import { z } from "zod"; +import type { z } from "zod"; import { convertJsonSchemaToZod } from "zod-from-json-schema"; -import { convertJsonSchemaToZod as convertJsonSchemaToZodV3 } from "zod-from-json-schema-v3"; import type { ToolExecuteOptions } from "../../agent/providers/base/types"; import { getGlobalLogger } from "../../logger"; import { type Tool, createTool } from "../../tool"; @@ -387,9 +386,7 @@ export class MCPClient extends SimpleEventEmitter { inputSchema: unknown; }[]) { try { - const zodSchema = ("toJSONSchema" in z - ? convertJsonSchemaToZod - : convertJsonSchemaToZodV3)( + const zodSchema = convertJsonSchemaToZod( toolDef.inputSchema as Record, ) as unknown as z.ZodType; const namespacedToolName = `${this.clientInfo.name}_${toolDef.name}`; @@ -405,10 +402,8 @@ export class MCPClient extends SimpleEventEmitter { name: namespacedToolName, description: toolDef.description || `Executes the remote tool: ${toolDef.name}`, parameters: zodSchema, - execute: async ( - args: Record, - execOptions?: ToolExecuteOptions, - ): Promise => { + execute: async (args: unknown, execOptions?: ToolExecuteOptions): Promise => { + const toolArgs = args as Record; // If elicitation handler is provided in options, set it temporarily const elicitationHandler = execOptions?.elicitation as UserInputHandler | undefined; const hadPreviousHandler = elicitationBridge.hasHandler; @@ -427,7 +422,7 @@ export class MCPClient extends SimpleEventEmitter { const result = await this.callTool( { name: toolDef.name, - arguments: args, + arguments: toolArgs, }, capturedOptions, ); diff --git a/packages/core/src/memory/index.ts b/packages/core/src/memory/index.ts index a63206f2f..5cafd1951 100644 --- a/packages/core/src/memory/index.ts +++ b/packages/core/src/memory/index.ts @@ -1216,8 +1216,21 @@ Remember: const schemaShape = this.workingMemoryConfig.schema.shape; schemaSummary = Object.fromEntries( Object.entries(schemaShape || {}).map(([key, value]) => { - const typeName = (value as z.ZodTypeAny)?._def?.typeName; - const friendlyName = typeName ? typeName.replace(/^Zod/, "").toLowerCase() : "unknown"; + const def = ( + value as { + _def?: { typeName?: string; type?: string }; + def?: { typeName?: string; type?: string }; + } + )._def; + const fallbackDef = ( + value as { + def?: { typeName?: string; type?: string }; + } + ).def; + const schemaDef = def ?? fallbackDef; + const typeName = schemaDef?.typeName ?? schemaDef?.type; + const friendlyName = + typeof typeName === "string" ? typeName.replace(/^Zod/, "").toLowerCase() : "unknown"; return [key, friendlyName]; }), ); diff --git a/packages/core/src/observability/types.ts b/packages/core/src/observability/types.ts index beea33eab..664b8aeac 100644 --- a/packages/core/src/observability/types.ts +++ b/packages/core/src/observability/types.ts @@ -170,6 +170,12 @@ export interface SpanAttributes { // Tool-specific attributes "tool.name"?: string; + "tool.display_name"?: string; + "tool.purpose"?: string; + "tool.description"?: string; + "tool.call.id"?: string; + "tool.tags"?: string; + "tool.parameters"?: string; // Workspace attributes "workspace.id"?: string; diff --git a/packages/core/src/planagent/plan-agent.ts b/packages/core/src/planagent/plan-agent.ts index 0298eb50b..6088b04dd 100644 --- a/packages/core/src/planagent/plan-agent.ts +++ b/packages/core/src/planagent/plan-agent.ts @@ -602,7 +602,7 @@ function composeAgentHooks(sequences: { onPrepareMessages?: AgentHooks["onPrepareMessages"][]; onPrepareModelMessages?: AgentHooks["onPrepareModelMessages"][]; onError?: AgentHooks["onError"][]; - onStepFinish?: AgentHooks["onStepFinish"][]; + onStepEnd?: AgentHooks["onStepEnd"][]; }): AgentHooks { return { onStart: chainVoidHooks(sequences.onStart ?? []), @@ -614,7 +614,7 @@ function composeAgentHooks(sequences: { onPrepareMessages: chainPrepareMessagesHooks(sequences.onPrepareMessages ?? []), onPrepareModelMessages: chainPrepareModelMessagesHooks(sequences.onPrepareModelMessages ?? []), onError: chainVoidHooks(sequences.onError ?? []), - onStepFinish: chainVoidHooks(sequences.onStepFinish ?? []), + onStepEnd: chainVoidHooks(sequences.onStepEnd ?? []), }; } @@ -856,7 +856,7 @@ function createPlanningExtension(options: { markPlanProgress(args.context); return undefined; }, - onStepFinish: async (args) => { + onStepEnd: async (args) => { const step = args.step as StepResult | undefined; if (!step) { return; @@ -1020,7 +1020,7 @@ export class PlanAgent extends Agent { ], onToolStart: [hooks?.onToolStart, ...extensionHooks.map((hook) => hook.onToolStart)], onToolEnd: [hooks?.onToolEnd, ...extensionHooks.map((hook) => hook.onToolEnd)], - onStepFinish: [hooks?.onStepFinish, ...extensionHooks.map((hook) => hook.onStepFinish)], + onStepEnd: [hooks?.onStepEnd, ...extensionHooks.map((hook) => hook.onStepEnd)], onError: [...extensionHooks.map((hook) => hook.onError), hooks?.onError], }); diff --git a/packages/core/src/tool/ai-sdk-tool.ts b/packages/core/src/tool/ai-sdk-tool.ts new file mode 100644 index 000000000..9a502be86 --- /dev/null +++ b/packages/core/src/tool/ai-sdk-tool.ts @@ -0,0 +1,221 @@ +import type { Context, ToolNeedsApprovalFunction } from "@ai-sdk/provider-utils"; +import { tool as aiTool } from "ai"; +import type { Tool as VercelTool } from "ai"; +import type { ToolHooks } from "./index"; + +const VOLTAGENT_TOOL_METADATA_SYMBOL = Symbol.for("@voltagent/core.tool.metadata"); +const VOLTAGENT_NAMED_AI_SDK_TOOL_SYMBOL = Symbol.for("@voltagent/core.tool.named-ai-sdk"); +const VOLTAGENT_RAW_AI_SDK_TOOL_SYMBOL = Symbol.for("@voltagent/core.tool.raw-ai-sdk"); + +const metadataStore = new WeakMap(); + +export type VoltAgentToolMetadata = { + /** + * Optional VoltAgent-facing tool name for display or metadata consumers. + * + * When the tool is registered in an AI SDK ToolSet, the object key remains + * the execution name used by the model and tool calls. + */ + name?: string; + /** + * Optional VoltAgent-facing purpose for display or metadata consumers. + */ + purpose?: string; + /** + * Optional user-defined tags for organizing or routing tools. + */ + tags?: string[]; + /** + * Whether the tool requires approval before execution. + */ + needsApproval?: boolean | ToolNeedsApprovalFunction; + /** + * Optional tool-specific hooks for lifecycle events. + */ + hooks?: ToolHooks; + /** + * Free-form VoltAgent-only metadata. This is not sent to the model provider. + */ + metadata?: Record; + /** + * Reserved namespace for future API exposure customizations. + */ + api?: Record; +} & Record; + +export type VoltAgentToolDefinition> = T & { + voltagent?: VoltAgentToolMetadata; +}; + +export type NamedAiSdkTool = { + [VOLTAGENT_NAMED_AI_SDK_TOOL_SYMBOL]: true; + name: string; + displayName?: string; + purpose?: string; + description: string; + parameters: unknown; + inputSchema?: unknown; + outputSchema?: unknown; + tags?: string[]; + needsApproval?: boolean | ToolNeedsApprovalFunction; + providerOptions?: unknown; + toModelOutput?: unknown; + hooks?: ToolHooks; + metadata?: Record; + execute?: unknown; + isClientSide: () => boolean; + type: "ai-sdk" | "provider"; + id?: string; + args?: Record; + isProviderExecuted?: boolean; + supportsDeferredResults?: boolean; +}; + +function setVoltAgentToolMetadata(target: object, metadata: VoltAgentToolMetadata): void { + metadataStore.set(target, metadata); + Object.defineProperty(target, VOLTAGENT_TOOL_METADATA_SYMBOL, { + value: metadata, + enumerable: false, + configurable: false, + }); +} + +export function getVoltAgentToolMetadata(tool: unknown): VoltAgentToolMetadata | undefined { + if (!tool || typeof tool !== "object") { + return undefined; + } + + const stored = metadataStore.get(tool); + if (stored) { + return stored; + } + + const symbolMetadata = (tool as { [VOLTAGENT_TOOL_METADATA_SYMBOL]?: VoltAgentToolMetadata })[ + VOLTAGENT_TOOL_METADATA_SYMBOL + ]; + if (symbolMetadata) { + return symbolMetadata; + } + + const inlineMetadata = (tool as { voltagent?: VoltAgentToolMetadata }).voltagent; + return inlineMetadata && typeof inlineMetadata === "object" ? inlineMetadata : undefined; +} + +function getToolDescription(tool: VercelTool): string { + const description = (tool as { description?: unknown }).description; + return typeof description === "string" ? description : ""; +} + +export function createNamedAiSdkTool( + name: string, + rawTool: VercelTool, +): NamedAiSdkTool { + const metadata = getVoltAgentToolMetadata(rawTool); + const rawMetadata = (rawTool as { metadata?: unknown }).metadata; + const providerType = (rawTool as { type?: unknown }).type === "provider"; + const descriptor: NamedAiSdkTool = { + [VOLTAGENT_NAMED_AI_SDK_TOOL_SYMBOL]: true, + name, + displayName: metadata?.name, + purpose: metadata?.purpose, + description: getToolDescription(rawTool), + parameters: (rawTool as { inputSchema?: unknown; args?: unknown }).inputSchema + ? (rawTool as { inputSchema?: unknown }).inputSchema + : (rawTool as { args?: unknown }).args, + inputSchema: (rawTool as { inputSchema?: unknown }).inputSchema, + outputSchema: (rawTool as { outputSchema?: unknown }).outputSchema, + tags: metadata?.tags, + needsApproval: + metadata?.needsApproval ?? + (rawTool as { needsApproval?: NamedAiSdkTool["needsApproval"] }).needsApproval, + providerOptions: (rawTool as { providerOptions?: unknown }).providerOptions, + toModelOutput: (rawTool as { toModelOutput?: unknown }).toModelOutput, + hooks: metadata?.hooks, + metadata: + rawMetadata && typeof rawMetadata === "object" + ? (rawMetadata as Record) + : undefined, + execute: (rawTool as { execute?: unknown }).execute, + isClientSide: () => typeof (rawTool as { execute?: unknown }).execute !== "function", + type: providerType ? "provider" : "ai-sdk", + id: + typeof (rawTool as { id?: unknown }).id === "string" + ? (rawTool as { id: string }).id + : undefined, + args: + (rawTool as { args?: unknown }).args && + typeof (rawTool as { args?: unknown }).args === "object" + ? (rawTool as { args: Record }).args + : undefined, + isProviderExecuted: + typeof (rawTool as { isProviderExecuted?: unknown }).isProviderExecuted === "boolean" + ? (rawTool as { isProviderExecuted: boolean }).isProviderExecuted + : undefined, + supportsDeferredResults: + typeof (rawTool as { supportsDeferredResults?: unknown }).supportsDeferredResults === + "boolean" + ? (rawTool as { supportsDeferredResults: boolean }).supportsDeferredResults + : undefined, + }; + + Object.defineProperty(descriptor, VOLTAGENT_RAW_AI_SDK_TOOL_SYMBOL, { + value: rawTool, + enumerable: false, + configurable: false, + }); + + if (metadata) { + setVoltAgentToolMetadata(descriptor, metadata); + } + + return descriptor; +} + +export function isNamedAiSdkTool(value: unknown): value is NamedAiSdkTool { + return Boolean( + value && + typeof value === "object" && + (value as { [VOLTAGENT_NAMED_AI_SDK_TOOL_SYMBOL]?: boolean })[ + VOLTAGENT_NAMED_AI_SDK_TOOL_SYMBOL + ], + ); +} + +export function getRawAiSdkTool(tool: NamedAiSdkTool): VercelTool { + return (tool as unknown as { [VOLTAGENT_RAW_AI_SDK_TOOL_SYMBOL]: VercelTool })[ + VOLTAGENT_RAW_AI_SDK_TOOL_SYMBOL + ]; +} + +/** + * Attach VoltAgent metadata to a raw AI SDK tool without changing the tool + * definition or sending the metadata to the model provider. + */ +export function withVoltAgentMetadata>( + tool: T, + metadata: VoltAgentToolMetadata, +): T { + setVoltAgentToolMetadata(tool as object, metadata); + return tool; +} + +/** + * AI SDK-compatible tool helper with a VoltAgent metadata namespace. + * + * The returned object is a regular AI SDK tool. VoltAgent metadata is stored + * out-of-band so it is not sent to the model provider. + */ +export function tool( + definition: VercelTool & { + voltagent?: VoltAgentToolMetadata; + }, +): VercelTool { + const { voltagent, ...toolDefinition } = definition as VercelTool & { + voltagent?: VoltAgentToolMetadata; + }; + const createdTool = aiTool(toolDefinition as VercelTool); + if (voltagent) { + withVoltAgentMetadata(createdTool, voltagent); + } + return createdTool; +} diff --git a/packages/core/src/tool/index.spec.ts b/packages/core/src/tool/index.spec.ts index 76d3d00f5..64f0b9c8c 100644 --- a/packages/core/src/tool/index.spec.ts +++ b/packages/core/src/tool/index.spec.ts @@ -230,7 +230,7 @@ describe("Tool", () => { // Validate the output against the schema const parseResult = tool.outputSchema?.safeParse(result); expect(parseResult?.success).toBe(false); - expect(parseResult?.error?.errors?.[0]?.message).toContain("Expected number"); + expect(parseResult?.error?.issues?.[0]?.message).toContain("expected number"); }); it("should maintain backward compatibility for tools without output schema", async () => { diff --git a/packages/core/src/tool/index.ts b/packages/core/src/tool/index.ts index 41a27e7eb..3b0226982 100644 --- a/packages/core/src/tool/index.ts +++ b/packages/core/src/tool/index.ts @@ -59,6 +59,15 @@ export type ToolResultOutput = export type { Tool as VercelTool } from "ai"; export type { ProviderOptions } from "@ai-sdk/provider-utils"; +export { + createNamedAiSdkTool, + getRawAiSdkTool, + getVoltAgentToolMetadata, + isNamedAiSdkTool, + tool, + withVoltAgentMetadata, +} from "./ai-sdk-tool"; +export type { NamedAiSdkTool, VoltAgentToolDefinition, VoltAgentToolMetadata } from "./ai-sdk-tool"; // Export ToolManager and related types export { ToolManager, ToolStatus, ToolStatusInfo } from "./manager"; @@ -135,7 +144,7 @@ export type ToolOptions< * Whether the tool requires approval before execution. * When set to a function, it can decide dynamically per call. */ - needsApproval?: boolean | ToolNeedsApprovalFunction>; + needsApproval?: boolean | ToolNeedsApprovalFunction, any>; /** * Provider-specific options for the tool. @@ -172,8 +181,10 @@ export type ToolOptions< * ``` */ toModelOutput?: (args: { + toolCallId: string; + input: z.infer; output: O extends ToolSchema ? z.infer : unknown; - }) => ToolResultOutput; + }) => ToolResultOutput | PromiseLike; /** * Function to execute when the tool is called. @@ -230,7 +241,7 @@ export class Tool>; + readonly needsApproval?: boolean | ToolNeedsApprovalFunction, any>; /** * Provider-specific options for the tool. @@ -243,8 +254,10 @@ export class Tool; output: O extends ToolSchema ? z.infer : unknown; - }) => ToolResultOutput; + }) => ToolResultOutput | PromiseLike; /** * Optional tool-specific hooks for lifecycle events. @@ -306,7 +319,10 @@ export class Tool( options: ToolOptions, @@ -319,8 +335,3 @@ export function createTool { return new Tool(options); } - -/** - * Alias for createTool function - */ -export const tool = createTool; diff --git a/packages/core/src/tool/manager/BaseToolManager.ts b/packages/core/src/tool/manager/BaseToolManager.ts index 7ddb110d7..546c6a06b 100644 --- a/packages/core/src/tool/manager/BaseToolManager.ts +++ b/packages/core/src/tool/manager/BaseToolManager.ts @@ -1,7 +1,7 @@ import type { Logger } from "@voltagent/internal"; import type { BaseTool } from "../../agent/providers/base/types"; import { getGlobalLogger } from "../../logger"; -import type { AgentTool, ProviderTool, VercelTool } from "../index"; +import type { AgentTool, NamedAiSdkTool, ProviderTool, VercelTool } from "../index"; import type { Tool } from "../index"; import type { Toolkit } from "../toolkit"; @@ -9,27 +9,33 @@ import type { Toolkit } from "../toolkit"; * Type guard to check if an object is a VoltAgent Tool instance * to reliably distinguish our Tool instances from externally defined tools. */ -function isBaseTool(tool: AgentTool | VercelTool): tool is Tool { +function isBaseTool(tool: AgentTool | VercelTool | NamedAiSdkTool): tool is Tool { return "type" in tool && tool.type === "user-defined"; } /** * Type guard for provider-defined tools * */ -export function isProviderTool(tool: AgentTool | Toolkit | VercelTool): tool is ProviderTool { +export function isProviderTool( + tool: AgentTool | Toolkit | VercelTool | NamedAiSdkTool, +): tool is ProviderTool { return "type" in tool && tool.type === "provider"; } /** * Type guard to check if an object is a Toolkit */ -function isToolkit(item: AgentTool | Toolkit | VercelTool): item is Toolkit { +function isToolkit(item: AgentTool | Toolkit | VercelTool | NamedAiSdkTool): item is Toolkit { // Check for the 'tools' array property which is specific to Toolkit return "tools" in item && Array.isArray((item as any).tools); } export abstract class BaseToolManager< - TItems extends AgentTool | VercelTool | Toolkit = AgentTool | VercelTool | Toolkit, + TItems extends AgentTool | VercelTool | NamedAiSdkTool | Toolkit = + | AgentTool + | VercelTool + | NamedAiSdkTool + | Toolkit, TToolkitManager extends BaseToolManager | never = BaseToolManager, > { /** @@ -86,7 +92,7 @@ export abstract class BaseToolManager< } } - addStandaloneTool(tool: AgentTool | VercelTool): boolean { + addStandaloneTool(tool: AgentTool | VercelTool | NamedAiSdkTool): boolean { if (isProviderTool(tool)) { if (!("name" in tool)) { this.logger.warn( @@ -190,7 +196,7 @@ export abstract class BaseToolManager< /** * Get all kinds of tools, owned by this manager and inside toolkits as a flattened list. * */ - getAllTools(): (BaseTool | ProviderTool)[] { + getAllTools(): (BaseTool | ProviderTool | NamedAiSdkTool)[] { return [ ...this.getStandaloneTools(), ...this.getToolkitManagers().flatMap((toolkit) => toolkit.getAllTools()), @@ -200,7 +206,7 @@ export abstract class BaseToolManager< /** * Get a tool by name across standalone tools and toolkits. */ - getToolByName(toolName: string): BaseTool | ProviderTool | undefined { + getToolByName(toolName: string): BaseTool | ProviderTool | NamedAiSdkTool | undefined { const standalone = this.baseTools.get(toolName) ?? this.providerTools.get(toolName); if (standalone) { return standalone; @@ -233,7 +239,7 @@ export abstract class BaseToolManager< /** * Returns tools owned directly by this manager (standalone tools), excluding tools inside toolkits. */ - protected getStandaloneTools(): (BaseTool | ProviderTool)[] { + protected getStandaloneTools(): (BaseTool | ProviderTool | NamedAiSdkTool)[] { return [...this.baseTools.values(), ...this.providerTools.values()]; } diff --git a/packages/core/src/tool/manager/ToolManager.ts b/packages/core/src/tool/manager/ToolManager.ts index ce74d37bf..4e62d7d5d 100644 --- a/packages/core/src/tool/manager/ToolManager.ts +++ b/packages/core/src/tool/manager/ToolManager.ts @@ -1,19 +1,165 @@ import type { ToolExecutionOptions } from "@ai-sdk/provider-utils"; import type { Logger } from "@voltagent/internal"; +import type { Tool as AITool, ToolSet } from "ai"; import type { ApiToolInfo } from "../../agent/types"; import { zodSchemaToJsonUI } from "../../utils/toolParser"; +import { + type NamedAiSdkTool, + type VoltAgentToolMetadata, + createNamedAiSdkTool, + getRawAiSdkTool, + getVoltAgentToolMetadata, + isNamedAiSdkTool, +} from "../ai-sdk-tool"; import type { AgentTool, ProviderTool, ToolExecutionResult, VercelTool } from "../index"; import type { Toolkit } from "../toolkit"; import { BaseToolManager } from "./BaseToolManager"; import { ToolkitManager } from "./ToolkitManager"; -export class ToolManager extends BaseToolManager { +function getStringMetadataValue(value: unknown): string | undefined { + if (typeof value !== "string") { + return undefined; + } + const trimmed = value.trim(); + return trimmed.length > 0 ? trimmed : undefined; +} + +function getStringArrayMetadataValue(value: unknown): string[] | undefined { + if (!Array.isArray(value)) { + return undefined; + } + + const normalized = value + .filter((item): item is string => typeof item === "string") + .map((item) => item.trim()) + .filter((item) => item.length > 0); + + return normalized.length > 0 ? normalized : undefined; +} + +function getExistingVoltAgentToolMetadata(tool: unknown): Record { + const existingMetadata = + tool && typeof tool === "object" + ? (tool as { metadata?: { voltagent?: unknown } }).metadata + : undefined; + const existingVoltAgentMetadata = existingMetadata?.voltagent; + return existingVoltAgentMetadata && typeof existingVoltAgentMetadata === "object" + ? (existingVoltAgentMetadata as Record) + : {}; +} + +function createVoltAgentToolMetadataPayload( + metadata: VoltAgentToolMetadata | undefined, + existingVoltAgentMetadata: Record = {}, +): Record | undefined { + const name = getStringMetadataValue(metadata?.name); + const purpose = getStringMetadataValue(metadata?.purpose); + const tags = getStringArrayMetadataValue(metadata?.tags); + const userMetadata = + metadata?.metadata && typeof metadata.metadata === "object" ? metadata.metadata : undefined; + const api = metadata?.api && typeof metadata.api === "object" ? metadata.api : undefined; + + const payload: Record = { + ...existingVoltAgentMetadata, + ...(name ? { name } : {}), + ...(purpose ? { purpose } : {}), + ...(tags ? { tags } : {}), + ...(userMetadata ? { metadata: userMetadata } : {}), + ...(api ? { api } : {}), + }; + + return Object.keys(payload).length > 0 ? payload : undefined; +} + +function getToolTags(tool: unknown, metadata?: VoltAgentToolMetadata): string[] | undefined { + return ( + getStringArrayMetadataValue(metadata?.tags) ?? + getStringArrayMetadataValue((tool as { tags?: unknown } | undefined)?.tags) + ); +} + +export class ToolManager extends BaseToolManager< + AgentTool | VercelTool | NamedAiSdkTool | Toolkit, + ToolkitManager +> { + private readonly aiSdkTools: Map> = new Map(); + /** * Creates a new ToolManager. * Accepts individual tools, provider-defined tools, and toolkits. */ - constructor(items: (AgentTool | VercelTool | Toolkit)[] = [], logger?: Logger) { - super(items, logger); + constructor(items: (AgentTool | VercelTool | NamedAiSdkTool | Toolkit)[] = [], logger?: Logger) { + super([], logger); + this.addItems(items); + } + + override addStandaloneTool(tool: AgentTool | VercelTool | NamedAiSdkTool): boolean { + if (isNamedAiSdkTool(tool)) { + return this.addAiSdkTool(tool.name, getRawAiSdkTool(tool)); + } + + return super.addStandaloneTool(tool); + } + + override removeTool(toolName: string): boolean { + const removedAiSdkTool = this.aiSdkTools.delete(toolName); + const removed = super.removeTool(toolName) || removedAiSdkTool; + if (removedAiSdkTool) { + this.logger.debug(`Removed AI SDK tool: ${toolName}`); + } + return removed; + } + + override getAllTools(): (AgentTool | ProviderTool | NamedAiSdkTool)[] { + return [ + ...super.getAllTools(), + ...Array.from(this.aiSdkTools.entries()).map(([name, tool]) => + createNamedAiSdkTool(name, tool), + ), + ]; + } + + override getToolByName(toolName: string): AgentTool | ProviderTool | NamedAiSdkTool | undefined { + const tool = super.getToolByName(toolName); + if (tool) { + return tool; + } + const aiSdkTool = this.aiSdkTools.get(toolName); + return aiSdkTool ? createNamedAiSdkTool(toolName, aiSdkTool) : undefined; + } + + override getAllToolNames(): string[] { + return Array.from(new Set([...super.getAllToolNames(), ...this.aiSdkTools.keys()])); + } + + override hasToolInAny(toolName: string): boolean { + return super.hasToolInAny(toolName) || this.aiSdkTools.has(toolName); + } + + addToolSet(toolSet: ToolSet | undefined): void { + if (!toolSet) { + return; + } + + for (const [name, tool] of Object.entries(toolSet)) { + this.addAiSdkTool(name, tool as AITool); + } + } + + private addAiSdkTool(name: string, tool: AITool): boolean { + if (!name) { + this.logger.warn("[ToolManager] AI SDK tool name is missing. Skipping invalid tool."); + return false; + } + + if (this.hasToolInAny(name)) { + this.logger.warn( + `[ToolManager] Warning: AI SDK tool name '${name}' conflicts with an existing tool.`, + ); + } + + this.aiSdkTools.set(name, tool); + return true; } /** @@ -48,19 +194,24 @@ export class ToolManager extends BaseToolManager (args: any, options?: ToolExecutionOptions) => ToolExecutionResult, + ) => (args: any, options?: ToolExecutionOptions) => ToolExecutionResult, + createAiSdkToolExecuteFunction?: ( + name: string, + tool: AITool, + metadata?: VoltAgentToolMetadata, + ) => (args: any, options?: ToolExecutionOptions) => ToolExecutionResult, ): Record { type ManagedTool = { description: string; inputSchema: AgentTool["parameters"]; - execute?: (args: any, options?: ToolExecutionOptions) => ToolExecutionResult; + execute?: (args: any, options?: ToolExecutionOptions) => ToolExecutionResult; needsApproval?: AgentTool["needsApproval"]; providerOptions?: AgentTool["providerOptions"]; toModelOutput?: AgentTool["toModelOutput"]; outputSchema?: AgentTool["outputSchema"]; }; - const tools: Record = {}; + const tools: Record = {}; for (const tool of this.getAllBaseTools()) { tools[tool.name] = { @@ -69,6 +220,7 @@ export class ToolManager extends BaseToolManager = { ...tool }; + const needsApproval = + metadata?.needsApproval ?? (tool as { needsApproval?: unknown }).needsApproval; + if (needsApproval !== undefined) { + preparedTool.needsApproval = needsApproval; + } + const voltAgentMetadata = createVoltAgentToolMetadataPayload( + metadata, + getExistingVoltAgentToolMetadata(tool), + ); + if (voltAgentMetadata) { + preparedTool.metadata = { + ...((tool as { metadata?: Record }).metadata ?? {}), + voltagent: voltAgentMetadata, + }; + } + if ( + typeof (tool as { execute?: unknown }).execute === "function" && + createAiSdkToolExecuteFunction + ) { + preparedTool.execute = createAiSdkToolExecuteFunction(name, tool, metadata); + } + tools[name] = preparedTool; + } + return tools; } @@ -96,14 +276,43 @@ export class ToolManager extends BaseToolManager ({ - name: tool.name, - description: tool.description || "", - // Use optional chaining for cleaner syntax - parameters: - "parameters" in tool && (tool as any).parameters - ? zodSchemaToJsonUI((tool as any).parameters) - : undefined, - })); + return this.getAllTools().map((tool: AgentTool | ProviderTool | NamedAiSdkTool) => { + const metadata = getVoltAgentToolMetadata(tool); + const displayName = getStringMetadataValue(metadata?.name); + const purpose = getStringMetadataValue(metadata?.purpose); + const tags = getToolTags(tool, metadata); + const voltagentMetadata = createVoltAgentToolMetadataPayload( + metadata, + getExistingVoltAgentToolMetadata(tool), + ); + + const apiTool: ApiToolInfo = { + name: tool.name, + description: tool.description || "", + // Use optional chaining for cleaner syntax + parameters: + "parameters" in tool && (tool as any).parameters + ? zodSchemaToJsonUI((tool as any).parameters) + : undefined, + }; + + if (displayName) { + apiTool.displayName = displayName; + } + if (purpose) { + apiTool.purpose = purpose; + } + if (tags) { + apiTool.tags = tags; + } + if (voltagentMetadata) { + apiTool.metadata = { + ...((tool as { metadata?: Record }).metadata ?? {}), + voltagent: voltagentMetadata, + }; + } + + return apiTool; + }); } } diff --git a/packages/core/src/tool/manager/ToolkitManager.ts b/packages/core/src/tool/manager/ToolkitManager.ts index ec92964ca..ddba2c606 100644 --- a/packages/core/src/tool/manager/ToolkitManager.ts +++ b/packages/core/src/tool/manager/ToolkitManager.ts @@ -1,15 +1,18 @@ import type { Logger } from "@voltagent/internal"; -import type { AgentTool, VercelTool } from "../index"; +import type { AgentTool, NamedAiSdkTool, VercelTool } from "../index"; import type { Toolkit } from "../toolkit"; import { BaseToolManager } from "./BaseToolManager"; -export class ToolkitManager extends BaseToolManager { +export class ToolkitManager extends BaseToolManager< + AgentTool | VercelTool | NamedAiSdkTool, + never +> { /** * Constructor does not accept toolkits - only tools * */ constructor( readonly name: string, - items: (AgentTool | VercelTool)[] = [], + items: (AgentTool | VercelTool | NamedAiSdkTool)[] = [], /** * A brief description of what the toolkit does or what tools it contains. * Optional. diff --git a/packages/core/src/tool/manager/index.spec.ts b/packages/core/src/tool/manager/index.spec.ts index 73e37c25c..4c78b8c47 100644 --- a/packages/core/src/tool/manager/index.spec.ts +++ b/packages/core/src/tool/manager/index.spec.ts @@ -6,7 +6,9 @@ import { Tool, type ToolExecutionResult, ToolManager, + tool as aiSdkTool, createTool, + withVoltAgentMetadata, } from "../index"; import { createToolkit } from "../toolkit"; import type { Toolkit } from "../toolkit"; @@ -300,6 +302,285 @@ describe("ToolManager", () => { }); expect(preparedTools[providerTool.name]).toBe(providerTool); }); + + it("should prepare AI SDK ToolSet records with VoltAgent metadata", async () => { + const inputSchema = z.object({ + location: z.string(), + }); + const execute = vi.fn().mockResolvedValue({ location: "SF", temp: 72 }); + const hooks = { + onStart: vi.fn(), + }; + const aiTool = aiSdkTool({ + description: "Get weather", + inputSchema, + execute, + voltagent: { + name: "weatherLookup", + purpose: "Fetch weather observations", + tags: ["weather"], + needsApproval: true, + hooks, + }, + }); + toolManager.addToolSet({ + get_weather: aiTool, + }); + + const wrappedExecute = vi.fn().mockResolvedValue({ location: "SF", temp: 72 }); + const createToolExecuteFunction = vi.fn(); + const createAiSdkToolExecuteFunction = vi.fn().mockReturnValue(wrappedExecute); + + const preparedTools = toolManager.prepareToolsForExecution( + createToolExecuteFunction, + createAiSdkToolExecuteFunction, + ); + const preparedTool = preparedTools.get_weather as { + description: string; + inputSchema: unknown; + execute?: (args: any, options?: ToolExecuteOptions) => ToolExecutionResult; + metadata?: { voltagent?: { name?: string; purpose?: string; tags?: string[] } }; + needsApproval?: unknown; + }; + + expect(createToolExecuteFunction).not.toHaveBeenCalled(); + expect(createAiSdkToolExecuteFunction).toHaveBeenCalledWith( + "get_weather", + aiTool, + expect.objectContaining({ + name: "weatherLookup", + purpose: "Fetch weather observations", + tags: ["weather"], + needsApproval: true, + hooks, + }), + ); + expect(preparedTool.description).toBe("Get weather"); + expect(preparedTool.inputSchema).toBe(inputSchema); + expect(preparedTool.needsApproval).toBe(true); + expect(preparedTool.metadata?.voltagent?.name).toBe("weatherLookup"); + expect(preparedTool.metadata?.voltagent?.purpose).toBe("Fetch weather observations"); + expect(preparedTool.metadata?.voltagent?.tags).toEqual(["weather"]); + await expect( + preparedTool.execute?.({ location: "SF" }, { toolCallId: "call-1" }), + ).resolves.toEqual({ + location: "SF", + temp: 72, + }); + expect(wrappedExecute).toHaveBeenCalledWith({ location: "SF" }, { toolCallId: "call-1" }); + }); + + it("should expose AI SDK tool display metadata in API tool info without changing the tool key", () => { + const inputSchema = z.object({ + location: z.string(), + }); + const aiTool = aiSdkTool({ + description: "Get weather", + inputSchema, + execute: vi.fn(), + voltagent: { + name: "Weather Lookup", + purpose: "Fetch weather observations", + tags: ["weather"], + }, + }); + + toolManager.addToolSet({ + get_weather: aiTool, + }); + + const apiTools = toolManager.getToolsForApi(); + + expect(apiTools).toEqual([ + expect.objectContaining({ + name: "get_weather", + displayName: "Weather Lookup", + purpose: "Fetch weather observations", + description: "Get weather", + parameters: expect.any(Object), + tags: ["weather"], + metadata: { + voltagent: { + name: "Weather Lookup", + purpose: "Fetch weather observations", + tags: ["weather"], + }, + }, + }), + ]); + }); + + it("should preserve native AI SDK contextSchema on AI SDK-style tools", () => { + const inputSchema = z.object({ + query: z.string(), + }); + const contextSchema = z.object({ tenantId: z.string() }); + const aiTool = aiSdkTool({ + description: "Search docs", + inputSchema, + contextSchema, + execute: vi.fn().mockResolvedValue({ result: "ok" }), + }); + + expect(aiTool).toHaveProperty("contextSchema", contextSchema); + + toolManager.addToolSet({ + search_docs: aiTool, + }); + + const preparedTools = toolManager.prepareToolsForExecution( + vi.fn(), + vi.fn().mockReturnValue(vi.fn().mockResolvedValue({ result: "ok" })), + ); + const preparedTool = preparedTools.search_docs as Record; + + expect(preparedTool).toHaveProperty("contextSchema", contextSchema); + }); + + it("should attach VoltAgent metadata to raw AI SDK tools", () => { + const inputSchema = z.object({ + orderId: z.string(), + }); + const rawTool = aiSdkTool({ + description: "Refund customer", + inputSchema, + contextSchema: z.object({ + actorId: z.string(), + }), + execute: vi.fn().mockResolvedValue({ status: "ok" }), + }); + const metadataTool = withVoltAgentMetadata(rawTool, { + name: "Refund Customer", + purpose: "Issue customer refunds", + tags: ["billing", "dangerous"], + metadata: { + owner: "payments-team", + }, + }); + + toolManager.addToolSet({ + refundCustomer: metadataTool, + }); + + const preparedTools = toolManager.prepareToolsForExecution( + vi.fn(), + vi.fn().mockReturnValue(vi.fn().mockResolvedValue({ status: "ok" })), + ); + const preparedTool = preparedTools.refundCustomer as { + inputSchema: unknown; + contextSchema?: unknown; + metadata?: { + voltagent?: { + name?: string; + purpose?: string; + tags?: string[]; + metadata?: Record; + }; + }; + }; + + expect(preparedTool.inputSchema).toBe(inputSchema); + expect(preparedTool.contextSchema).toBe(rawTool.contextSchema); + expect(preparedTool.metadata?.voltagent).toEqual({ + name: "Refund Customer", + purpose: "Issue customer refunds", + tags: ["billing", "dangerous"], + metadata: { + owner: "payments-team", + }, + }); + }); + + it("should preserve server, client, approval, output, and provider tool metadata together", () => { + const providerOptions = { + anthropic: { + cacheControl: { type: "ephemeral" }, + }, + } as const; + const serverOutputSchema = z.object({ + answer: z.string(), + }); + const clientOutputSchema = z.object({ + status: z.string(), + }); + const needsApproval = vi.fn(() => true); + const toModelOutput = vi.fn(({ output }) => ({ + type: "json" as const, + value: output as { answer: string }, + })); + const serverTool = createTool({ + name: "server-tool", + description: "Server tool", + parameters: z.object({ + query: z.string(), + }), + outputSchema: serverOutputSchema, + needsApproval, + providerOptions, + toModelOutput, + execute: vi.fn().mockResolvedValue({ answer: "ok" }), + }); + const clientTool = createTool({ + name: "client-tool", + description: "Client tool", + parameters: z.object({ + action: z.string(), + }), + outputSchema: clientOutputSchema, + needsApproval: true, + providerOptions, + toModelOutput, + }); + const providerTool = { + type: "provider", + id: "provider.search", + name: "provider-search", + description: "Provider search", + args: {}, + } as ProviderTool; + + toolManager.addStandaloneTool(serverTool); + toolManager.addStandaloneTool(clientTool); + toolManager.addStandaloneTool(providerTool); + + const wrappedExecute = vi.fn().mockResolvedValue({ answer: "wrapped" }); + const createToolExecuteFunction = vi.fn().mockReturnValue(wrappedExecute); + const preparedTools = toolManager.prepareToolsForExecution(createToolExecuteFunction); + + const preparedServerTool = preparedTools[serverTool.name] as { + inputSchema: unknown; + outputSchema?: unknown; + execute?: unknown; + needsApproval?: unknown; + providerOptions?: unknown; + toModelOutput?: unknown; + }; + expect(preparedServerTool.inputSchema).toBe(serverTool.parameters); + expect(preparedServerTool.outputSchema).toBe(serverOutputSchema); + expect(preparedServerTool.needsApproval).toBe(needsApproval); + expect(preparedServerTool.providerOptions).toBe(providerOptions); + expect(preparedServerTool.toModelOutput).toBe(toModelOutput); + expect(preparedServerTool.execute).toBe(wrappedExecute); + + const preparedClientTool = preparedTools[clientTool.name] as { + inputSchema: unknown; + outputSchema?: unknown; + execute?: unknown; + needsApproval?: unknown; + providerOptions?: unknown; + toModelOutput?: unknown; + }; + expect(preparedClientTool.inputSchema).toBe(clientTool.parameters); + expect(preparedClientTool.outputSchema).toBe(clientOutputSchema); + expect(preparedClientTool.needsApproval).toBe(true); + expect(preparedClientTool.providerOptions).toBe(providerOptions); + expect(preparedClientTool.toModelOutput).toBe(toModelOutput); + expect(preparedClientTool.execute).toBeUndefined(); + + expect(preparedTools[providerTool.name]).toBe(providerTool); + expect(createToolExecuteFunction).toHaveBeenCalledTimes(1); + expect(createToolExecuteFunction).toHaveBeenCalledWith(serverTool); + }); }); describe("hasToolInAny", () => { diff --git a/packages/core/src/tool/routing/types.ts b/packages/core/src/tool/routing/types.ts index cb72e41e8..8cfd3f25e 100644 --- a/packages/core/src/tool/routing/types.ts +++ b/packages/core/src/tool/routing/types.ts @@ -4,7 +4,7 @@ import type { EmbeddingAdapter, EmbeddingModelReference, } from "../../memory/adapters/embedding/types"; -import type { ProviderTool, Tool, VercelTool } from "../index"; +import type { NamedAiSdkTool, ProviderTool, Tool, VercelTool } from "../index"; import type { Toolkit } from "../toolkit"; export type ToolSearchSelection = { @@ -35,7 +35,7 @@ export type ToolSearchCandidate = { tags?: string[]; parameters?: unknown; outputSchema?: unknown; - tool: Tool | ProviderTool; + tool: Tool | ProviderTool | NamedAiSdkTool; }; export type ToolSearchContext = { diff --git a/packages/core/src/utils/message-converter.spec.ts b/packages/core/src/utils/message-converter.spec.ts index c878f06f0..0125239fd 100644 --- a/packages/core/src/utils/message-converter.spec.ts +++ b/packages/core/src/utils/message-converter.spec.ts @@ -634,8 +634,8 @@ describe("convertModelMessagesToUIMessages (AI SDK v5)", () => { role: "user", content: [ { - type: "image", - image: "https://example.com/image.jpg", + type: "file", + data: "https://example.com/image.jpg", mediaType: "image/jpeg", } as any, { type: "text", text: "What is in this image?" }, diff --git a/packages/core/src/utils/message-helpers.spec.ts b/packages/core/src/utils/message-helpers.spec.ts index 3c53dda8f..6586b230c 100644 --- a/packages/core/src/utils/message-helpers.spec.ts +++ b/packages/core/src/utils/message-helpers.spec.ts @@ -42,13 +42,29 @@ describe("Message Helpers", () => { it("should check for text parts", () => { expect(hasTextPart("hello")).toBe(true); expect(hasTextPart([{ type: "text", text: "hello" }])).toBe(true); - expect(hasTextPart([{ type: "image", image: "data" }])).toBe(false); + expect( + hasTextPart([ + { + type: "file", + data: "data", + mediaType: "image", + }, + ]), + ).toBe(false); expect(hasTextPart([])).toBe(false); }); it("should check for image parts", () => { expect(hasImagePart("hello")).toBe(false); - expect(hasImagePart([{ type: "image", image: "data" }])).toBe(true); + expect( + hasImagePart([ + { + type: "file", + data: "data", + mediaType: "image/*", + }, + ]), + ).toBe(true); expect(hasImagePart([{ type: "text", text: "hello" }])).toBe(false); }); @@ -68,7 +84,11 @@ describe("Message Helpers", () => { const content: MessageContent = [ { type: "text", text: "hello " }, { type: "text", text: "world" }, - { type: "image", image: "data" }, + { + type: "file", + data: "data", + mediaType: "image", + }, ]; expect(extractText(content)).toBe("hello world"); }); @@ -76,7 +96,11 @@ describe("Message Helpers", () => { it("should extract text parts", () => { const content: MessageContent = [ { type: "text", text: "hello" }, - { type: "image", image: "data" }, + { + type: "file", + data: "data", + mediaType: "image", + }, { type: "text", text: "world" }, ]; const textParts = extractTextParts(content); @@ -88,12 +112,24 @@ describe("Message Helpers", () => { it("should extract image parts", () => { const content: MessageContent = [ { type: "text", text: "hello" }, - { type: "image", image: "data1" }, - { type: "image", image: "data2" }, + { + type: "file", + data: "data1", + mediaType: "image/*", + }, + { + type: "file", + data: "data2", + mediaType: "image/*", + }, ]; const imageParts = extractImageParts(content); expect(imageParts).toHaveLength(2); - expect(imageParts[0]).toEqual({ type: "image", image: "data1" }); + expect(imageParts[0]).toEqual({ + type: "file", + data: "data1", + mediaType: "image/*", + }); }); it("should extract file parts", () => { @@ -117,13 +153,21 @@ describe("Message Helpers", () => { it("should transform text in structured content", () => { const content: MessageContent = [ { type: "text", text: "hello" }, - { type: "image", image: "data" }, + { + type: "file", + data: "data", + mediaType: "image", + }, { type: "text", text: "world" }, ]; const result = transformTextContent(content, (text) => text.toUpperCase()); expect(result).toEqual([ { type: "text", text: "HELLO" }, - { type: "image", image: "data" }, + { + type: "file", + data: "data", + mediaType: "image", + }, { type: "text", text: "WORLD" }, ]); }); @@ -134,7 +178,11 @@ describe("Message Helpers", () => { role: "user", parts: [ { type: "text", text: "hello" }, - { type: "image", image: "data" } as any, + { + type: "file", + data: "data", + mediaType: "image", + } as any, { type: "text", text: "world" }, ], metadata: {}, @@ -142,14 +190,22 @@ describe("Message Helpers", () => { const result = mapMessageContent(message, (text) => text.toUpperCase()); const parts = result.parts as any[]; expect(parts[0].text).toBe("HELLO"); - expect(parts[1]).toMatchObject({ type: "image", image: "data" }); + expect(parts[1]).toMatchObject({ + type: "file", + data: "data", + mediaType: "image", + }); expect(parts[2].text).toBe("WORLD"); }); it("should filter content parts", () => { const content: MessageContent = [ { type: "text", text: "hello" }, - { type: "image", image: "data" }, + { + type: "file", + data: "data", + mediaType: "image", + }, { type: "text", text: "world" }, ]; const result = filterContentParts(content, (part) => part.type === "text"); @@ -174,11 +230,19 @@ describe("Message Helpers", () => { expect( normalizeContent([ { type: "text", text: "hello" }, - { type: "image", image: "data" }, + { + type: "file", + data: "data", + mediaType: "image", + }, ]), ).toEqual([ { type: "text", text: "hello" }, - { type: "image", image: "data" }, + { + type: "file", + data: "data", + mediaType: "image", + }, ]); }); }); @@ -257,7 +321,11 @@ describe("Message Helpers", () => { expect( getContentLength([ { type: "text", text: "hello" }, - { type: "image", image: "data" }, + { + type: "file", + data: "data", + mediaType: "image", + }, ]), ).toBe(2); }); @@ -275,7 +343,11 @@ describe("Message Helpers", () => { const content = builder.addText("hello").addImage("imageData").addText("world").build(); expect(content).toEqual([ { type: "text", text: "hello" }, - { type: "image", image: "imageData" }, + { + type: "file", + data: "imageData", + mediaType: "image/*", + }, { type: "text", text: "world" }, ]); }); diff --git a/packages/core/src/utils/message-helpers.ts b/packages/core/src/utils/message-helpers.ts index 728ab3140..7d10cef06 100644 --- a/packages/core/src/utils/message-helpers.ts +++ b/packages/core/src/utils/message-helpers.ts @@ -62,7 +62,13 @@ export function hasImagePart(input: MessageContent | UIMessage): boolean { // Handle MessageContent if (isStructuredContent(input)) { - return input.some((part) => part.type === "image"); + return input.some( + (part) => + part.type === "image" || + (part.type === "file" && + typeof part.mediaType === "string" && + part.mediaType.startsWith("image/")), + ); } return false; } @@ -181,7 +187,13 @@ export function extractImageParts(input: MessageContent | UIMessage): Array // Handle MessageContent if (isStructuredContent(input)) { - return input.filter((part) => part.type === "image"); + return input.filter( + (part) => + part.type === "image" || + (part.type === "file" && + typeof part.mediaType === "string" && + part.mediaType.startsWith("image/")), + ); } return []; } @@ -311,7 +323,11 @@ export class MessageContentBuilder { * Add an image part */ addImage(image: string | Uint8Array): this { - this.parts.push({ type: "image", image }); + this.parts.push({ + type: "file", + data: image, + mediaType: "image/*", + }); return this; } diff --git a/packages/core/src/utils/toolParser/index.spec.ts b/packages/core/src/utils/toolParser/index.spec.ts index fabda8b0a..1f93afa94 100644 --- a/packages/core/src/utils/toolParser/index.spec.ts +++ b/packages/core/src/utils/toolParser/index.spec.ts @@ -213,8 +213,8 @@ describe("Tool Parser Utilities", () => { }); }); - it("should handle records", () => { - const schema = z.record(z.string()); + it("should handle records with explicit key and value schemas", () => { + const schema = z.record(z.string(), z.string()); const result = zodSchemaToJsonUI(schema); diff --git a/packages/core/src/utils/toolParser/index.ts b/packages/core/src/utils/toolParser/index.ts index abe8166f3..4b0d8d40f 100644 --- a/packages/core/src/utils/toolParser/index.ts +++ b/packages/core/src/utils/toolParser/index.ts @@ -26,7 +26,7 @@ export function zodSchemaToJsonUI(schema: any): any { const properties: Record = {}; const required: string[] = []; - // Zod v3 uses a shape() method, v4 exposes the object directly + // Zod 4 exposes shape as an object; keep a defensive function path for schema-like values. const shape = typeof def?.shape === "function" ? def.shape() : def?.shape; // Process each property in the object diff --git a/packages/core/src/utils/usage-converter.ts b/packages/core/src/utils/usage-converter.ts index aa3c6592d..ab17e2d6a 100644 --- a/packages/core/src/utils/usage-converter.ts +++ b/packages/core/src/utils/usage-converter.ts @@ -28,21 +28,8 @@ export function convertUsage(usage: LanguageModelUsage | undefined): UsageInfo | const totalTokens = typeof usage.totalTokens === "number" ? usage.totalTokens : inputTokens + outputTokens; - const cachedInputTokens = - usage.cachedInputTokens ?? - (usage as any).inputTokenDetails?.cacheReadTokens ?? - (typeof usage.inputTokens === "object" - ? ((usage.inputTokens as any)?.cacheRead ?? (usage.inputTokens as any)?.cacheReadTokens) - : undefined) ?? - 0; - - const reasoningTokens = - usage.reasoningTokens ?? - (usage as any).outputTokenDetails?.reasoningTokens ?? - (typeof usage.outputTokens === "object" - ? ((usage.outputTokens as any)?.reasoning ?? (usage.outputTokens as any)?.reasoningTokens) - : undefined) ?? - 0; + const cachedInputTokens = usage.inputTokenDetails?.cacheReadTokens ?? 0; + const reasoningTokens = usage.outputTokenDetails?.reasoningTokens ?? 0; return { promptTokens: inputTokens, diff --git a/packages/core/src/workflow/chain.spec-d.ts b/packages/core/src/workflow/chain.spec-d.ts index 7ff8a9c74..98c6c4960 100644 --- a/packages/core/src/workflow/chain.spec-d.ts +++ b/packages/core/src/workflow/chain.spec-d.ts @@ -338,7 +338,7 @@ describe("workflow chain - type inference", () => { suspendSchema: z.object({ taskId: z.string(), progress: z.number(), - metadata: z.record(z.string()), + metadata: z.record(z.string(), z.string()), }), execute: async ({ data, suspend }) => { // Should use step-level suspendSchema diff --git a/packages/core/src/workflow/core.ts b/packages/core/src/workflow/core.ts index 55c0199f6..e44415e6b 100644 --- a/packages/core/src/workflow/core.ts +++ b/packages/core/src/workflow/core.ts @@ -1594,9 +1594,10 @@ export function createWorkflow< result: null, }); } else { + const workflowResult = result as WorkflowResult; stateManager.update({ - data: result, - result, + data: workflowResult, + result: workflowResult, }); } @@ -1721,9 +1722,10 @@ export function createWorkflow< result: null, }); } else { + const workflowResult = finalResult as WorkflowResult; stateManager.update({ - data: finalResult, - result: finalResult, + data: workflowResult, + result: workflowResult, }); } @@ -2323,7 +2325,7 @@ export function createWorkflow< // Execute step within span context with automatic signal checking for immediate suspension const result = await traceContext.withSpan(attemptSpan, async () => { return await executeWithSignalCheck( - () => step.execute(stepContext), + () => step.execute(stepContext as Parameters[0]), options?.suspendController?.signal, options?.suspensionMode === "immediate" ? 50 : 500, // Check more frequently in immediate mode ); diff --git a/packages/core/src/workflow/types.ts b/packages/core/src/workflow/types.ts index bf61c8c73..751a6d813 100644 --- a/packages/core/src/workflow/types.ts +++ b/packages/core/src/workflow/types.ts @@ -181,7 +181,7 @@ export interface WorkflowStreamResult< cancellation: Promise; error: Promise; usage: Promise; - toUIMessageStreamResponse: StreamTextResult["toUIMessageStreamResponse"]; + toUIMessageStreamResponse: StreamTextResult["toUIMessageStreamResponse"]; /** * Resume a suspended workflow execution * @param input - Optional new input data for resuming (validated against resumeSchema if provided) diff --git a/packages/core/src/workflow/usage-tracking.spec.ts b/packages/core/src/workflow/usage-tracking.spec.ts index 5277f29eb..7074fe30f 100644 --- a/packages/core/src/workflow/usage-tracking.spec.ts +++ b/packages/core/src/workflow/usage-tracking.spec.ts @@ -29,8 +29,8 @@ function createMockAgentWithUsage( textTokens: outputTokens, reasoningTokens: 0, }, - cachedInputTokens: usage.cachedInputTokens, - reasoningTokens: usage.reasoningTokens, + cachedInputTokens: usage.inputTokenDetails?.cacheReadTokens ?? 0, + reasoningTokens: usage.outputTokenDetails?.reasoningTokens ?? 0, raw: usage.raw, }; diff --git a/packages/core/src/workspace/tool-policy.ts b/packages/core/src/workspace/tool-policy.ts index ba83bfa71..62bfb9d6e 100644 --- a/packages/core/src/workspace/tool-policy.ts +++ b/packages/core/src/workspace/tool-policy.ts @@ -2,7 +2,7 @@ import type { ToolNeedsApprovalFunction } from "@ai-sdk/provider-utils"; export type WorkspaceToolPolicy = { enabled?: boolean; - needsApproval?: boolean | ToolNeedsApprovalFunction; + needsApproval?: boolean | ToolNeedsApprovalFunction; }; export type WorkspaceToolPolicyGroup = { diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts index 44ec4bad1..40b50141f 100644 --- a/packages/core/tsup.config.ts +++ b/packages/core/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/create-voltagent-app/CHANGELOG.md b/packages/create-voltagent-app/CHANGELOG.md index 1b84ae437..f94f7008b 100644 --- a/packages/create-voltagent-app/CHANGELOG.md +++ b/packages/create-voltagent-app/CHANGELOG.md @@ -1,6 +1,223 @@ # create-voltagent-app -## 0.2.19 +## 1.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. ### Patch Changes diff --git a/packages/create-voltagent-app/package.json b/packages/create-voltagent-app/package.json index 08173a053..d6e820677 100644 --- a/packages/create-voltagent-app/package.json +++ b/packages/create-voltagent-app/package.json @@ -1,7 +1,7 @@ { "name": "create-voltagent-app", "description": "Create VoltAgent applications with one command", - "version": "0.2.19", + "version": "1.0.0-next.0", "bin": { "create-voltagent": "./dist/index.js", "create-voltagent-app": "./dist/index.js" @@ -34,7 +34,7 @@ "ts-jest": "^29.1.0" }, "engines": { - "node": ">=20" + "node": ">=22" }, "files": [ "dist", @@ -57,5 +57,6 @@ "start": "node dist/index.js", "test": "vitest", "test:coverage": "vitest run --coverage" - } + }, + "type": "module" } diff --git a/packages/create-voltagent-app/src/cli.integration.spec.ts b/packages/create-voltagent-app/src/cli.integration.spec.ts index 1e6741c36..879d9ff80 100644 --- a/packages/create-voltagent-app/src/cli.integration.spec.ts +++ b/packages/create-voltagent-app/src/cli.integration.spec.ts @@ -216,8 +216,8 @@ describe.sequential("create-voltagent-app CLI option matrix", () => { version: "0.1.0", type: "module", dependencies: { - "@voltagent/core": "^2.0.0", - "@voltagent/libsql": "^2.0.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/libsql": "^3.0.0-next.0", [SERVER_CONFIG[server].package]: SERVER_CONFIG[server].packageVersion, }, meta: { diff --git a/packages/create-voltagent-app/src/types.ts b/packages/create-voltagent-app/src/types.ts index fa7513c99..e9f190e05 100644 --- a/packages/create-voltagent-app/src/types.ts +++ b/packages/create-voltagent-app/src/types.ts @@ -70,13 +70,13 @@ export const SERVER_CONFIG = { hono: { name: "Hono", package: "@voltagent/server-hono", - packageVersion: "^2.0.0", + packageVersion: "^3.0.0-next.0", factory: "honoServer", }, elysia: { name: "Elysia", package: "@voltagent/server-elysia", - packageVersion: "^2.0.0", + packageVersion: "^3.0.0-next.0", factory: "elysiaServer", }, } as const; diff --git a/packages/create-voltagent-app/src/utils/dependency-installer.ts b/packages/create-voltagent-app/src/utils/dependency-installer.ts index 3002f2dc0..85db57849 100644 --- a/packages/create-voltagent-app/src/utils/dependency-installer.ts +++ b/packages/create-voltagent-app/src/utils/dependency-installer.ts @@ -32,13 +32,13 @@ export const createBaseDependencyInstaller = async ( const packageManagerConfig = PACKAGE_MANAGER_CONFIG[packageManager]; const baseDependencies: Record = { - "@voltagent/core": "^2.0.0", - "@voltagent/libsql": "^2.0.0", - ai: "^6.0.0", - "@voltagent/cli": "^0.1.10", - "@voltagent/logger": "^2.0.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/libsql": "^3.0.0-next.0", + ai: "^7.0.0", + "@voltagent/cli": "^1.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", dotenv: "^16.4.7", - zod: "^3.25.76", + zod: "^4.1.11", }; baseDependencies[serverConfig.package] = serverConfig.packageVersion; @@ -67,7 +67,7 @@ export const createBaseDependencyInstaller = async ( typescript: "^5.7.3", }, engines: { - node: ">=20.19.0", + node: ">=22", }, }; diff --git a/packages/create-voltagent-app/tsup.config.ts b/packages/create-voltagent-app/tsup.config.ts index 6815d2663..efc6e7dc8 100644 --- a/packages/create-voltagent-app/tsup.config.ts +++ b/packages/create-voltagent-app/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/docs-mcp/CHANGELOG.md b/packages/docs-mcp/CHANGELOG.md index e6edcd316..fb7635c9a 100644 --- a/packages/docs-mcp/CHANGELOG.md +++ b/packages/docs-mcp/CHANGELOG.md @@ -1,6 +1,223 @@ # @voltagent/docs-mcp -## 2.0.2 +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. ### Patch Changes diff --git a/packages/docs-mcp/package.json b/packages/docs-mcp/package.json index 1a9f3452d..893b8b7d5 100644 --- a/packages/docs-mcp/package.json +++ b/packages/docs-mcp/package.json @@ -1,7 +1,7 @@ { "name": "@voltagent/docs-mcp", "description": "VoltAgent docs-mcp - MCP Docs ", - "version": "2.0.2", + "version": "3.0.0-next.0", "bin": { "voltagent-docs-mcp": "dist/index.js" }, @@ -14,14 +14,9 @@ }, "exports": { ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "require": { - "types": "./dist/index.d.cts", - "default": "./dist/index.cjs" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -30,10 +25,10 @@ "examples" ], "license": "MIT", - "main": "dist/index.cjs", + "main": "dist/index.js", "module": "dist/index.js", "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" + "zod": "^4.0.0" }, "repository": { "type": "git", diff --git a/packages/docs-mcp/tsup.config.ts b/packages/docs-mcp/tsup.config.ts index 479a2489b..5355b05fc 100644 --- a/packages/docs-mcp/tsup.config.ts +++ b/packages/docs-mcp/tsup.config.ts @@ -142,7 +142,7 @@ function copyPackageChangelogs(sourcePkgPath: string, targetPkgPath: string) { export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], sourcemap: true, clean: false, target: "es2022", diff --git a/packages/e2e/package.json b/packages/e2e/package.json index 6431812a3..a8e6c3cb2 100644 --- a/packages/e2e/package.json +++ b/packages/e2e/package.json @@ -2,13 +2,14 @@ "name": "@voltagent/e2e", "dependencies": { "@libsql/client": "^0.15.0", - "@voltagent/core": "^2.9.0", - "@voltagent/internal": "^1.0.3", - "@voltagent/libsql": "^2.1.2", - "@voltagent/postgres": "^2.1.2", - "ai": "^6.0.0", + "@voltagent/core": "^3.0.0-next.1", + "@voltagent/internal": "^2.0.0-next.0", + "@voltagent/libsql": "^3.0.0-next.0", + "@voltagent/postgres": "^3.0.0-next.0", + "@voltagent/server-hono": "^3.0.0-next.0", + "ai": "^7.0.0", "pg": "^8.16.0", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "devDependencies": { "vitest": "^3.2.4" diff --git a/packages/e2e/src/agent-runtime.e2e.spec.ts b/packages/e2e/src/agent-runtime.e2e.spec.ts new file mode 100644 index 000000000..bf5ec959d --- /dev/null +++ b/packages/e2e/src/agent-runtime.e2e.spec.ts @@ -0,0 +1,1110 @@ +import { + Agent, + InMemoryStorageAdapter, + Memory, + createInputGuardrail, + createInputMiddleware, + createOutputGuardrail, + createOutputMiddleware, + createSubagent, + createTool, + tool, + withVoltAgentMetadata, +} from "@voltagent/core"; +import { safeStringify } from "@voltagent/internal"; +import { createVoltAgentApp } from "@voltagent/server-hono"; +import { Output, tool as aiTool } from "ai"; +import { MockLanguageModelV3, simulateReadableStream } from "ai/test"; +import { describe, expect, it, vi } from "vitest"; +import { z } from "zod"; + +const usage = { + inputTokens: { + total: 12, + noCache: 12, + cacheRead: 0, + cacheWrite: 0, + }, + outputTokens: { + total: 8, + text: 8, + reasoning: 0, + }, +}; + +const finishReason = (reason: "stop" | "tool-calls" = "stop") => ({ + unified: reason, + raw: reason, +}); + +const textGenerate = (text: string) => ({ + finishReason: finishReason("stop"), + usage, + content: [{ type: "text" as const, text }], + warnings: [], +}); + +const toolCallGenerate = ( + toolName: string, + input: Record, + toolCallId = `${toolName}-call`, +) => ({ + finishReason: finishReason("tool-calls"), + usage, + content: [ + { + type: "tool-call" as const, + toolCallId, + toolName, + input: safeStringify(input), + }, + ], + warnings: [], +}); + +const multiToolCallGenerate = ( + calls: Array<{ + toolName: string; + input: Record; + toolCallId: string; + }>, +) => ({ + finishReason: finishReason("tool-calls"), + usage, + content: calls.map((call) => ({ + type: "tool-call" as const, + toolCallId: call.toolCallId, + toolName: call.toolName, + input: safeStringify(call.input), + })), + warnings: [], +}); + +const textStream = (text: string) => ({ + stream: simulateReadableStream({ + chunks: [ + { type: "text-start" as const, id: "text-1" }, + { type: "text-delta" as const, id: "text-1", delta: text }, + { type: "text-end" as const, id: "text-1" }, + { + type: "finish" as const, + finishReason: finishReason("stop"), + usage, + }, + ], + }), +}); + +const toolCallStream = ( + toolName: string, + input: Record, + toolCallId = `${toolName}-call`, +) => ({ + stream: simulateReadableStream({ + chunks: [ + { + type: "tool-call" as const, + toolCallId, + toolName, + input: safeStringify(input), + }, + { + type: "finish" as const, + finishReason: finishReason("tool-calls"), + usage, + }, + ], + }), +}); + +const collectTextStream = async (stream: AsyncIterable) => { + let text = ""; + for await (const chunk of stream) { + text += chunk; + } + return text; +}; + +const createModel = ( + doGenerate: ConstructorParameters[0]["doGenerate"], + doStream?: ConstructorParameters[0]["doStream"], +) => + new MockLanguageModelV3({ + modelId: "mock-runtime-model", + doGenerate, + doStream, + }); + +const createServerDeps = (agent: Agent, overrides: Record = {}) => + ({ + agentRegistry: { + getAgent: (id: string) => (id === agent.id ? agent : undefined), + getAllAgents: () => [agent], + getAgentCount: () => 1, + removeAgent: () => false, + registerAgent: () => undefined, + getGlobalVoltOpsClient: () => undefined, + getGlobalLogger: () => undefined, + }, + workflowRegistry: { + getAll: () => [], + getWorkflow: () => undefined, + getWorkflowsForApi: () => [], + getWorkflowDetailForApi: () => undefined, + getWorkflowCount: () => 0, + getAllWorkflowIds: () => [], + on: () => undefined, + off: () => undefined, + }, + triggerRegistry: { list: () => [] }, + ...overrides, + }) as any; + +describe("Agent runtime e2e", () => { + it("runs generateText through an AI SDK native tool", async () => { + const execute = vi.fn(async ({ city }: { city: string }) => ({ city, tempC: 18 })); + const getWeather = tool({ + description: "Get current weather", + inputSchema: z.object({ + city: z.string(), + }), + execute, + }); + + let generateCalls = 0; + const model = createModel(async () => { + generateCalls += 1; + return generateCalls === 1 + ? toolCallGenerate("getWeather", { city: "Paris" }) + : textGenerate("Paris is 18C."); + }); + + const agent = new Agent({ + name: "NativeToolAgent", + instructions: "Use tools when useful.", + model, + tools: { + getWeather, + }, + }); + + const result = await agent.generateText("What is the weather in Paris?"); + + expect(result.text).toBe("Paris is 18C."); + expect(execute).toHaveBeenCalledWith( + { city: "Paris" }, + expect.objectContaining({ + toolCallId: "getWeather-call", + }), + ); + }); + + it("streams through a tool call and final text", async () => { + const execute = vi.fn(async ({ city }: { city: string }) => ({ city, tempC: 12 })); + const getWeather = tool({ + description: "Get current weather", + inputSchema: z.object({ + city: z.string(), + }), + execute, + }); + + let streamCalls = 0; + const model = createModel(textGenerate("unused"), async () => { + streamCalls += 1; + return streamCalls === 1 + ? toolCallStream("getWeather", { city: "Berlin" }) + : textStream("Berlin is 12C."); + }); + + const agent = new Agent({ + name: "StreamingToolAgent", + instructions: "Use tools and answer briefly.", + model, + tools: { + getWeather, + }, + }); + + const result = await agent.streamText("What is the weather in Berlin?"); + + await expect(result.text).resolves.toBe("Berlin is 12C."); + expect(execute).toHaveBeenCalledTimes(1); + expect(execute).toHaveBeenCalledWith( + { city: "Berlin" }, + expect.objectContaining({ + toolCallId: "getWeather-call", + }), + ); + }); + + it("combines createTool tools with runtime AI SDK tools", async () => { + const multiplyExecute = vi.fn(async ({ a, b }: { a: number; b: number }) => ({ + product: a * b, + })); + const lookupExecute = vi.fn(async ({ key }: { key: string }) => ({ key, value: "meaning" })); + + const multiply = createTool({ + name: "multiply", + description: "Multiply two numbers", + parameters: z.object({ + a: z.number(), + b: z.number(), + }), + execute: multiplyExecute, + }); + const lookup = tool({ + description: "Lookup a value", + inputSchema: z.object({ + key: z.string(), + }), + execute: lookupExecute, + }); + + let generateCalls = 0; + const model = createModel(async () => { + generateCalls += 1; + return generateCalls === 1 + ? multiToolCallGenerate([ + { + toolName: "multiply", + toolCallId: "multiply-call", + input: { a: 6, b: 7 }, + }, + { + toolName: "lookup", + toolCallId: "lookup-call", + input: { key: "answer" }, + }, + ]) + : textGenerate("Mixed tools completed."); + }); + + const agent = new Agent({ + name: "MixedToolAgent", + instructions: "Use all relevant tools.", + model, + tools: [multiply], + }); + + const result = await agent.generateText("Use both tools.", { + tools: { + lookup, + }, + }); + const multiplyOptions = multiplyExecute.mock.calls[0]?.[1] as + | { toolContext?: { callId?: string } } + | undefined; + + expect(result.text).toBe("Mixed tools completed."); + expect(multiplyExecute).toHaveBeenCalledTimes(1); + expect(multiplyExecute.mock.calls[0]?.[0]).toEqual({ a: 6, b: 7 }); + expect(multiplyOptions?.toolContext?.callId).toBe("multiply-call"); + expect(lookupExecute).toHaveBeenCalledWith( + { key: "answer" }, + expect.objectContaining({ + toolCallId: "lookup-call", + }), + ); + }); + + it("applies toolApproval before executing tools", async () => { + const refundExecute = vi.fn(async ({ orderId }: { orderId: string; reason: string }) => ({ + refunded: true, + orderId, + })); + const refundCustomer = createTool({ + name: "refundCustomer", + description: "Refund a customer order", + parameters: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: refundExecute, + }); + + let generateCalls = 0; + const model = createModel(async () => { + generateCalls += 1; + return generateCalls === 1 + ? toolCallGenerate("refundCustomer", { + orderId: "order-123", + reason: "duplicate charge", + }) + : textGenerate("Refund completed."); + }); + const approve = vi.fn(async () => "approved" as const); + + const agent = new Agent({ + name: "ApprovalAgent", + instructions: "Ask for approval before sensitive tools.", + model, + tools: [refundCustomer], + }); + + const result = await agent.generateText("Refund the customer.", { + toolApproval: approve, + }); + + expect(result.text).toBe("Refund completed."); + expect(approve).toHaveBeenCalledWith( + expect.objectContaining({ + toolCall: expect.objectContaining({ + toolCallId: "refundCustomer-call", + toolName: "refundCustomer", + input: { + orderId: "order-123", + reason: "duplicate charge", + }, + }), + }), + ); + expect(refundExecute).toHaveBeenCalledTimes(1); + }); + + it("returns a tool approval error result without executing denied tools", async () => { + const execute = vi.fn(async () => ({ deleted: true })); + const deleteAccount = createTool({ + name: "deleteAccount", + description: "Delete a customer account", + parameters: z.object({ + accountId: z.string(), + }), + execute, + }); + + let generateCalls = 0; + const model = createModel(async () => { + generateCalls += 1; + return generateCalls === 1 + ? toolCallGenerate("deleteAccount", { accountId: "acct-123" }) + : textGenerate("Deletion was not performed."); + }); + const agent = new Agent({ + name: "ApprovalDeniedAgent", + instructions: "Never execute denied tools.", + model, + tools: [deleteAccount], + }); + + const result = await agent.generateText("Delete this account.", { + toolApproval: { + deleteAccount: "user-approval", + }, + }); + + expect(result.text).toBe(""); + expect(generateCalls).toBe(1); + expect(execute).not.toHaveBeenCalled(); + expect(result.toolCalls[0]?.toolName).toBe("deleteAccount"); + expect(result.toolResults).toHaveLength(0); + }); + + it("parses structured output with Output.object", async () => { + const schema = z.object({ + answer: z.string(), + count: z.number(), + }); + const model = createModel(textGenerate(safeStringify({ answer: "ok", count: 2 }))); + const agent = new Agent({ + name: "StructuredAgent", + instructions: "Return structured data.", + model, + }); + + const result = await agent.generateText("Return a structured answer.", { + output: Output.object({ schema }), + }); + + expect(result.output).toEqual({ + answer: "ok", + count: 2, + }); + }); + + it("runs middleware before guardrails on input and output", async () => { + const inputMiddleware = createInputMiddleware({ + name: "append-input-marker", + handler: ({ input }) => (typeof input === "string" ? `${input} middleware-ok` : input), + }); + const inputGuardrail = createInputGuardrail({ + name: "assert-input-marker", + handler: vi.fn(async ({ inputText }) => { + expect(inputText).toContain("middleware-ok"); + return { pass: true }; + }), + }); + const outputMiddleware = createOutputMiddleware({ + name: "replace-output-token", + handler: ({ output }) => output.replace("secret", "token"), + }); + const outputGuardrail = createOutputGuardrail({ + name: "redact-output-token", + handler: vi.fn(async ({ outputText }) => ({ + pass: true, + action: "modify", + modifiedOutput: outputText?.replace("token", "redacted"), + })), + }); + + const model = createModel(textGenerate("base secret")); + const agent = new Agent({ + name: "MiddlewareGuardrailAgent", + instructions: "Return a guarded answer.", + model, + inputMiddlewares: [inputMiddleware], + inputGuardrails: [inputGuardrail], + outputMiddlewares: [outputMiddleware], + outputGuardrails: [outputGuardrail], + }); + + const result = await agent.generateText("hello"); + + expect(result.text).toBe("base redacted"); + expect(inputGuardrail.handler).toHaveBeenCalledTimes(1); + expect(outputGuardrail.handler).toHaveBeenCalledTimes(1); + }); + + it("blocks input and output through guardrails", async () => { + const inputBlocker = createInputGuardrail({ + name: "input-blocker", + handler: vi.fn(async () => ({ + pass: false, + action: "block", + message: "Input blocked by e2e policy.", + })), + }); + const inputBlockedAgent = new Agent({ + name: "InputBlockedAgent", + instructions: "Should not call model.", + model: createModel(textGenerate("unreachable")), + inputGuardrails: [inputBlocker], + }); + + await expect(inputBlockedAgent.generateText("blocked input")).rejects.toMatchObject({ + message: "Input blocked by e2e policy.", + code: "GUARDRAIL_INPUT_BLOCKED", + }); + expect(inputBlocker.handler).toHaveBeenCalledTimes(1); + expect(inputBlockedAgent.model.doGenerateCalls).toHaveLength(0); + + const outputBlocker = createOutputGuardrail({ + name: "output-blocker", + handler: vi.fn(async () => ({ + pass: false, + action: "block", + message: "Output blocked by e2e policy.", + })), + }); + const outputBlockedAgent = new Agent({ + name: "OutputBlockedAgent", + instructions: "Return guarded output.", + model: createModel(textGenerate("unsafe output")), + outputGuardrails: [outputBlocker], + }); + + await expect(outputBlockedAgent.generateText("hello")).rejects.toMatchObject({ + message: "Output blocked by e2e policy.", + code: "GUARDRAIL_OUTPUT_BLOCKED", + }); + expect(outputBlocker.handler).toHaveBeenCalledTimes(1); + }); + + it("replaces a blocked stream with the input guardrail message", async () => { + const inputGuardrail = createInputGuardrail({ + name: "stream-input-blocker", + execution: "parallel", + handler: vi.fn(async () => ({ + pass: false, + action: "block", + message: "Stream input blocked.", + })), + }); + const agent = new Agent({ + name: "StreamBlockedAgent", + instructions: "Stream response.", + model: createModel(textGenerate("unused"), textStream("unsafe stream output")), + inputGuardrails: [inputGuardrail], + }); + + const result = await agent.streamText("blocked stream input"); + + await expect(result.text).resolves.toBe("Stream input blocked."); + await expect(collectTextStream(result.textStream)).resolves.toBe("Stream input blocked."); + }); + + it("delegates work to a subagent through delegate_task", async () => { + const childAgent = new Agent({ + name: "Research Agent", + instructions: "Research the delegated task.", + model: createModel(textGenerate("Child answer.")), + }); + + let supervisorCalls = 0; + const supervisorModel = createModel(async () => { + supervisorCalls += 1; + return supervisorCalls === 1 + ? toolCallGenerate("delegate_task", { + task: "Research VoltAgent", + targetAgents: ["Research Agent"], + context: { topic: "voltagent" }, + }) + : textGenerate("Supervisor used Child answer."); + }); + const supervisorAgent = new Agent({ + name: "SupervisorAgent", + instructions: "Delegate research when useful.", + model: supervisorModel, + subAgents: [ + createSubagent({ + agent: childAgent, + method: "generateText", + }), + ], + }); + + const result = await supervisorAgent.generateText("Please research VoltAgent."); + + expect(result.text).toBe("Supervisor used Child answer."); + expect(childAgent.model.doGenerateCalls).toHaveLength(1); + }); + + it("delegates streaming work to a subagent through delegate_task", async () => { + const childModel = createModel(textGenerate("unused"), textStream("Child streamed answer.")); + const childAgent = new Agent({ + name: "Streaming Research Agent", + instructions: "Stream delegated answers.", + model: childModel, + }); + + let supervisorCalls = 0; + const supervisorModel = createModel(async () => { + supervisorCalls += 1; + return supervisorCalls === 1 + ? toolCallGenerate("delegate_task", { + task: "Stream research", + targetAgents: ["Streaming Research Agent"], + context: { topic: "streaming" }, + }) + : textGenerate("Supervisor used streamed child answer."); + }); + const supervisorAgent = new Agent({ + name: "StreamingSupervisorAgent", + instructions: "Delegate streaming research when useful.", + model: supervisorModel, + subAgents: [ + createSubagent({ + agent: childAgent, + method: "streamText", + }), + ], + }); + + const result = await supervisorAgent.generateText("Please stream delegated research."); + + expect(result.text).toBe("Supervisor used streamed child answer."); + expect(childModel.doStreamCalls).toHaveLength(1); + expect(result.toolResults[0]?.output).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + agentName: "Streaming Research Agent", + response: "Child streamed answer.", + }), + ]), + ); + }); + + it("falls back to the next model and reports the fallback hook", async () => { + const primaryModel = createModel(async () => { + throw new Error("Primary model failed."); + }); + const fallbackModel = createModel(textGenerate("Fallback model response.")); + const onFallback = vi.fn(); + const agent = new Agent({ + name: "FallbackAgent", + instructions: "Use fallback when needed.", + model: [ + { model: primaryModel, maxRetries: 0 }, + { model: fallbackModel, maxRetries: 0 }, + ], + hooks: { + onFallback, + }, + }); + + const result = await agent.generateText("Use a fallback."); + + expect(result.text).toBe("Fallback model response."); + expect(primaryModel.doGenerateCalls).toHaveLength(1); + expect(fallbackModel.doGenerateCalls).toHaveLength(1); + expect(onFallback).toHaveBeenCalledTimes(1); + }); + + it("runs agent and VoltAgent metadata hooks for AI SDK tools", async () => { + const toolMetadataStart = vi.fn(); + const toolMetadataEnd = vi.fn(); + const agentToolStart = vi.fn(); + const agentToolEnd = vi.fn(); + const execute = vi.fn(async ({ city }: { city: string }) => ({ city, tempC: 22 })); + const getWeather = tool({ + description: "Get current weather", + inputSchema: z.object({ + city: z.string(), + }), + execute, + voltagent: { + hooks: { + onStart: toolMetadataStart, + onEnd: toolMetadataEnd, + }, + }, + }); + + let generateCalls = 0; + const model = createModel(async () => { + generateCalls += 1; + return generateCalls === 1 + ? toolCallGenerate("getWeather", { city: "Rome" }) + : textGenerate("Rome is 22C."); + }); + const agent = new Agent({ + name: "AiSdkToolHooksAgent", + instructions: "Use tools.", + model, + tools: { + getWeather, + }, + hooks: { + onToolStart: agentToolStart, + onToolEnd: agentToolEnd, + }, + }); + + const result = await agent.generateText("Weather in Rome?"); + + expect(result.text).toBe("Rome is 22C."); + expect(execute).toHaveBeenCalledTimes(1); + expect(toolMetadataStart).toHaveBeenCalledTimes(1); + expect(toolMetadataEnd).toHaveBeenCalledTimes(1); + expect(agentToolStart).toHaveBeenCalledTimes(1); + expect(agentToolEnd).toHaveBeenCalledTimes(1); + }); + + it("passes toolsContext to raw AI SDK tools with VoltAgent metadata", async () => { + const toolMetadataStart = vi.fn(); + const toolMetadataEnd = vi.fn(); + const execute = vi.fn( + async ( + { orderId, reason }: { orderId: string; reason: string }, + { context }: { context: { actorId: string; permissions: string[] } }, + ) => { + if (!context.permissions.includes("refund:write")) { + throw new Error("Not allowed to refund orders"); + } + + return { + orderId, + reason, + actorId: context.actorId, + refunded: true, + }; + }, + ); + const refundCustomer = withVoltAgentMetadata( + aiTool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + contextSchema: z.object({ + actorId: z.string(), + permissions: z.array(z.string()), + }), + execute, + }), + { + name: "Refund Customer", + purpose: "Issue customer refunds", + tags: ["billing", "dangerous"], + metadata: { + owner: "payments-team", + }, + hooks: { + onStart: toolMetadataStart, + onEnd: toolMetadataEnd, + }, + }, + ); + + let generateCalls = 0; + const model = createModel(async () => { + generateCalls += 1; + return generateCalls === 1 + ? toolCallGenerate("refundCustomer", { + orderId: "order-123", + reason: "duplicate charge", + }) + : textGenerate("Refund completed."); + }); + const agent = new Agent({ + name: "RawAiSdkToolMetadataAgent", + instructions: "Use refund tools when allowed.", + model, + tools: { + refundCustomer, + }, + }); + + const result = await agent.generateText({ + prompt: "Refund order order-123.", + toolsContext: { + refundCustomer: { + actorId: "user-42", + permissions: ["refund:write"], + }, + }, + }); + + expect(result.text).toBe("Refund completed."); + expect(execute).toHaveBeenCalledWith( + { + orderId: "order-123", + reason: "duplicate charge", + }, + expect.objectContaining({ + toolCallId: "refundCustomer-call", + context: { + actorId: "user-42", + permissions: ["refund:write"], + }, + }), + ); + expect(toolMetadataStart).toHaveBeenCalledWith( + expect.objectContaining({ + tool: expect.objectContaining({ + name: "refundCustomer", + }), + args: { + orderId: "order-123", + reason: "duplicate charge", + }, + }), + ); + expect(toolMetadataEnd).toHaveBeenCalledWith( + expect.objectContaining({ + output: expect.objectContaining({ + actorId: "user-42", + refunded: true, + }), + }), + ); + }); + + it("serves generateText and streamText through server-hono routes", async () => { + const model = createModel(textGenerate("HTTP text response."), textStream("HTTP stream.")); + const agent = new Agent({ + id: "http-agent", + name: "HttpAgent", + instructions: "Answer HTTP requests.", + model, + }); + const { app } = await createVoltAgentApp(createServerDeps(agent), {}); + + const textResponse = await app.request("/agents/http-agent/text", { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: safeStringify({ + input: "hello", + }), + }); + const textJson = await textResponse.json(); + + expect(textResponse.status).toBe(200); + expect(textJson).toMatchObject({ + success: true, + data: { + text: "HTTP text response.", + }, + }); + + const streamResponse = await app.request("/agents/http-agent/stream", { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: safeStringify({ + input: "stream hello", + }), + }); + const streamBody = await streamResponse.text(); + + expect(streamResponse.status).toBe(200); + expect(streamResponse.headers.get("content-type")).toContain("text/event-stream"); + expect(streamBody).toContain("HTTP stream."); + }); + + it("normalizes server voltagent options and structured output", async () => { + let startContext: + | { + userId?: string; + conversationId?: string; + context: Map; + } + | undefined; + const model = createModel(textGenerate(safeStringify({ answer: "server-ok", count: 3 }))); + const agent = new Agent({ + id: "server-options-agent", + name: "ServerOptionsAgent", + instructions: "Return structured data.", + model, + hooks: { + onStart: ({ context }) => { + startContext = context; + }, + }, + }); + const { app } = await createVoltAgentApp(createServerDeps(agent), {}); + + const response = await app.request("/agents/server-options-agent/text", { + method: "POST", + headers: { + "content-type": "application/json", + "x-e2e-request": "server-options", + }, + body: safeStringify({ + input: "return structured data", + options: { + userId: "legacy-user", + conversationId: "legacy-conversation", + voltagent: { + userId: "server-user", + conversationId: "server-conversation", + context: { + requestId: "server-request", + }, + }, + output: { + type: "object", + schema: { + type: "object", + properties: { + answer: { type: "string" }, + count: { type: "number" }, + }, + required: ["answer", "count"], + additionalProperties: false, + }, + }, + }, + }), + }); + const json = await response.json(); + + expect(response.status).toBe(200); + expect(json).toMatchObject({ + success: true, + data: { + output: { + answer: "server-ok", + count: 3, + }, + }, + }); + expect(startContext?.userId).toBe("server-user"); + expect(startContext?.conversationId).toBe("server-conversation"); + expect(startContext?.context.get("requestId")).toBe("server-request"); + }); + + it("serves streamed tool calls through server-hono stream route", async () => { + const execute = vi.fn(async ({ city }: { city: string }) => ({ city, tempC: 19 })); + const getWeather = tool({ + description: "Get current weather", + inputSchema: z.object({ + city: z.string(), + }), + execute, + }); + + let streamCalls = 0; + const model = createModel(textGenerate("unused"), async () => { + streamCalls += 1; + return streamCalls === 1 + ? toolCallStream("getWeather", { city: "Madrid" }) + : textStream("Madrid is 19C."); + }); + const agent = new Agent({ + id: "server-stream-tool-agent", + name: "ServerStreamToolAgent", + instructions: "Use tools in streams.", + model, + tools: { + getWeather, + }, + }); + const { app } = await createVoltAgentApp(createServerDeps(agent), {}); + + const response = await app.request("/agents/server-stream-tool-agent/stream", { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: safeStringify({ + input: "stream weather in Madrid", + }), + }); + const body = await response.text(); + + expect(response.status).toBe(200); + expect(response.headers.get("content-type")).toContain("text/event-stream"); + expect(execute).toHaveBeenCalledTimes(1); + expect(body).toContain("getWeather"); + expect(body).toContain("Madrid is 19C."); + }); + + it("updates working memory through generated tool calls", async () => { + const memory = new Memory({ + storage: new InMemoryStorageAdapter(), + workingMemory: { + enabled: true, + }, + }); + let generateCalls = 0; + const model = createModel(async () => { + generateCalls += 1; + return generateCalls === 1 + ? toolCallGenerate("update_working_memory", { + content: "Preferred language: Turkish", + mode: "replace", + }) + : textGenerate("Remembered."); + }); + const agent = new Agent({ + name: "WorkingMemoryAgent", + instructions: "Remember useful user preferences.", + model, + memory, + }); + await memory.createConversation({ + id: "wm-conversation", + userId: "wm-user", + resourceId: agent.id, + title: "Working Memory E2E", + metadata: {}, + }); + + const result = await agent.generateText("Remember that I prefer Turkish.", { + userId: "wm-user", + conversationId: "wm-conversation", + }); + const workingMemory = await memory.getWorkingMemory({ + userId: "wm-user", + conversationId: "wm-conversation", + }); + + expect(result.text).toBe("Remembered."); + expect(workingMemory).toBe("Preferred language: Turkish"); + }); + + it("routes hidden tools through searchTools and callTool", async () => { + const hiddenExecute = vi.fn(async ({ query }: { query: string }) => ({ + answer: `found:${query}`, + })); + const hiddenLookup = createTool({ + name: "hiddenLookup", + description: "Find hidden documentation", + tags: ["docs"], + parameters: z.object({ + query: z.string(), + }), + execute: hiddenExecute, + }); + + let generateCalls = 0; + const model = createModel(async () => { + generateCalls += 1; + if (generateCalls === 1) { + return toolCallGenerate("searchTools", { query: "hidden documentation", topK: 1 }); + } + if (generateCalls === 2) { + return toolCallGenerate("callTool", { + name: "hiddenLookup", + args: { query: "docs" }, + }); + } + return textGenerate("Routed result ready."); + }); + const agent = new Agent({ + name: "ToolRoutingAgent", + instructions: "Use routed tools.", + model, + tools: [hiddenLookup], + toolRouting: { + topK: 1, + }, + }); + + const result = await agent.generateText("Find hidden docs."); + const hiddenOptions = hiddenExecute.mock.calls[0]?.[1] as + | { toolContext?: { callId?: string } } + | undefined; + + expect(result.text).toBe("Routed result ready."); + expect(hiddenExecute).toHaveBeenCalledTimes(1); + expect(hiddenExecute.mock.calls[0]?.[0]).toEqual({ query: "docs" }); + expect(hiddenOptions?.toolContext?.callId).toEqual(expect.any(String)); + }); + + it("applies toolApproval to tool routing pool calls", async () => { + const execute = vi.fn(async ({ query }: { query: string }) => ({ answer: query })); + const hiddenLookup = createTool({ + name: "approvalHiddenLookup", + description: "Find hidden data after approval", + parameters: z.object({ + query: z.string(), + }), + execute, + }); + + let generateCalls = 0; + const model = createModel(async () => { + generateCalls += 1; + if (generateCalls === 1) { + return toolCallGenerate("searchTools", { query: "hidden approval lookup", topK: 1 }); + } + if (generateCalls === 2) { + return toolCallGenerate("callTool", { + name: "approvalHiddenLookup", + args: { query: "secret" }, + }); + } + return textGenerate("Hidden tool was not executed."); + }); + const agent = new Agent({ + name: "ToolRoutingApprovalAgent", + instructions: "Use routed tools with approval.", + model, + tools: [hiddenLookup], + toolRouting: { + topK: 1, + }, + }); + + const result = await agent.generateText("Find hidden approved data.", { + toolApproval: { + approvalHiddenLookup: "user-approval", + }, + }); + + expect(result.text).toBe("Hidden tool was not executed."); + expect(execute).not.toHaveBeenCalled(); + expect(result.toolResults[1]?.toolName).toBe("callTool"); + expect(result.toolResults[1]?.output).toMatchObject({ + error: true, + code: "TOOL_APPROVAL_REQUIRED", + name: "approvalHiddenLookup", + }); + }); +}); diff --git a/packages/e2e/src/message-persistence.libsql.e2e.spec.ts b/packages/e2e/src/message-persistence.libsql.e2e.spec.ts index 514975449..0c1716328 100644 --- a/packages/e2e/src/message-persistence.libsql.e2e.spec.ts +++ b/packages/e2e/src/message-persistence.libsql.e2e.spec.ts @@ -72,4 +72,70 @@ describe.sequential("message persistence e2e (libsql)", () => { client.close(); } }); + + it("persists working memory across libsql memory instances", async () => { + libsqlTempDir = fs.mkdtempSync(path.join(os.tmpdir(), "voltagent-e2e-libsql-")); + const dbPath = path.join(libsqlTempDir, "working-memory.db"); + const dbUrl = `file:${dbPath}`; + const tablePrefix = `voltagent_e2e_libsql_wm_${randomUUID().replace(/-/g, "").slice(0, 8)}`; + const userId = `user-${randomUUID()}`; + const conversationId = `conversation-${randomUUID()}`; + + const firstMemory = new Memory({ + storage: new LibSQLMemoryAdapter({ + url: dbUrl, + tablePrefix, + }), + workingMemory: { + enabled: true, + }, + }); + + await firstMemory.createConversation({ + id: conversationId, + userId, + resourceId: "working-memory-e2e-agent", + title: "Working Memory E2E", + metadata: {}, + }); + await firstMemory.updateWorkingMemory({ + conversationId, + userId, + content: "Preferred language: Turkish", + }); + + const secondMemory = new Memory({ + storage: new LibSQLMemoryAdapter({ + url: dbUrl, + tablePrefix, + }), + workingMemory: { + enabled: true, + }, + }); + const persistedWorkingMemory = await secondMemory.getWorkingMemory({ + conversationId, + userId, + }); + + expect(persistedWorkingMemory).toBe("Preferred language: Turkish"); + + const client = createClient({ url: dbUrl }); + try { + const conversationRows = await client.execute({ + sql: `SELECT metadata FROM ${tablePrefix}_conversations WHERE id = ?`, + args: [conversationId], + }); + expect(conversationRows.rows).toHaveLength(1); + const rawMetadata = conversationRows.rows[0]?.metadata; + if (typeof rawMetadata !== "string") { + throw new Error("Expected libsql metadata to be JSON string."); + } + expect(JSON.parse(rawMetadata)).toMatchObject({ + workingMemory: "Preferred language: Turkish", + }); + } finally { + client.close(); + } + }); }); diff --git a/packages/evals/CHANGELOG.md b/packages/evals/CHANGELOG.md index c261ffc5f..02dc97528 100644 --- a/packages/evals/CHANGELOG.md +++ b/packages/evals/CHANGELOG.md @@ -1,5 +1,231 @@ # @voltagent/evals +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/internal@2.0.0-next.0 + - @voltagent/scorers@3.0.0-next.0 + - @voltagent/sdk@3.0.0-next.0 + ## 2.0.4 ### Patch Changes diff --git a/packages/evals/package.json b/packages/evals/package.json index 38834406e..7c915a965 100644 --- a/packages/evals/package.json +++ b/packages/evals/package.json @@ -1,24 +1,19 @@ { "name": "@voltagent/evals", "description": "VoltAgent evaluation orchestrator utilities", - "version": "2.0.4", + "version": "3.0.0-next.0", "author": "VoltAgent", "dependencies": { - "@voltagent/internal": "^1.0.2", - "@voltagent/scorers": "^2.0.2", - "@voltagent/sdk": "^2.0.2" + "@voltagent/internal": "^2.0.0-next.0", + "@voltagent/scorers": "^3.0.0-next.0", + "@voltagent/sdk": "^3.0.0-next.0" }, "devDependencies": {}, "exports": { ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "require": { - "types": "./dist/index.d.cts", - "default": "./dist/index.cjs" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -26,10 +21,10 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/scorers": "^2.0.0", - "@voltagent/sdk": "^2.0.0" + "@voltagent/scorers": "^3.0.0-next.0", + "@voltagent/sdk": "^3.0.0-next.0" }, "repository": { "type": "git", diff --git a/packages/evals/tsconfig.json b/packages/evals/tsconfig.json index 4e5d88fbc..d7de03eec 100644 --- a/packages/evals/tsconfig.json +++ b/packages/evals/tsconfig.json @@ -1,6 +1,8 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", "outDir": "dist", "rootDir": "src", "composite": false, diff --git a/packages/evals/tsup.config.ts b/packages/evals/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/evals/tsup.config.ts +++ b/packages/evals/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/internal/CHANGELOG.md b/packages/internal/CHANGELOG.md index 40043645c..c1dca4179 100644 --- a/packages/internal/CHANGELOG.md +++ b/packages/internal/CHANGELOG.md @@ -1,6 +1,223 @@ # @voltagent/internal -## 1.0.3 +## 2.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. ### Patch Changes diff --git a/packages/internal/package.json b/packages/internal/package.json index a8093f5d8..921119b99 100644 --- a/packages/internal/package.json +++ b/packages/internal/package.json @@ -1,7 +1,7 @@ { "name": "@voltagent/internal", "description": "VoltAgent internal - an internal set of tools for the VoltAgent packages", - "version": "1.0.3", + "version": "2.0.0-next.0", "dependencies": { "type-fest": "^4.41.0" }, @@ -10,54 +10,29 @@ }, "exports": { ".": { - "import": { - "types": "./dist/main/index.d.mts", - "default": "./dist/main/index.mjs" - }, - "require": { - "types": "./dist/main/index.d.ts", - "default": "./dist/main/index.js" - } + "types": "./dist/main/index.d.ts", + "import": "./dist/main/index.js", + "default": "./dist/main/index.js" }, "./test": { - "import": { - "types": "./dist/test/index.d.mts", - "default": "./dist/test/index.mjs" - }, - "require": { - "types": "./dist/test/index.d.ts", - "default": "./dist/test/index.js" - } + "types": "./dist/test/index.d.ts", + "import": "./dist/test/index.js", + "default": "./dist/test/index.js" }, "./utils": { - "import": { - "types": "./dist/utils/index.d.mts", - "default": "./dist/utils/index.mjs" - }, - "require": { - "types": "./dist/utils/index.d.ts", - "default": "./dist/utils/index.js" - } + "types": "./dist/utils/index.d.ts", + "import": "./dist/utils/index.js", + "default": "./dist/utils/index.js" }, "./a2a": { - "import": { - "types": "./dist/main/index.d.mts", - "default": "./dist/main/index.mjs" - }, - "require": { - "types": "./dist/main/index.d.ts", - "default": "./dist/main/index.js" - } + "types": "./dist/main/index.d.ts", + "import": "./dist/main/index.js", + "default": "./dist/main/index.js" }, "./mcp": { - "import": { - "types": "./dist/main/index.d.mts", - "default": "./dist/main/index.mjs" - }, - "require": { - "types": "./dist/main/index.d.ts", - "default": "./dist/main/index.js" - } + "types": "./dist/main/index.d.ts", + "import": "./dist/main/index.js", + "default": "./dist/main/index.js" }, "./types": { "types": "./dist/types/index.d.ts" @@ -70,7 +45,7 @@ ], "license": "MIT", "main": "dist/main/index.js", - "module": "dist/main/index.mjs", + "module": "dist/main/index.js", "repository": { "type": "git", "url": "https://github.com/VoltAgent/voltagent.git", @@ -86,6 +61,7 @@ "test": "vitest", "test:coverage": "vitest run --coverage" }, + "type": "module", "types": "dist/main/index.d.ts", "typesVersions": { "*": { diff --git a/packages/internal/tsup.config.ts b/packages/internal/tsup.config.ts index 8773b5658..e73159433 100644 --- a/packages/internal/tsup.config.ts +++ b/packages/internal/tsup.config.ts @@ -2,7 +2,7 @@ import { type Options as TsupConfigOptions, defineConfig } from "tsup"; import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; const baseConfig = { - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/langfuse-exporter/CHANGELOG.md b/packages/langfuse-exporter/CHANGELOG.md index 4cbb12ab4..f75726627 100644 --- a/packages/langfuse-exporter/CHANGELOG.md +++ b/packages/langfuse-exporter/CHANGELOG.md @@ -1,5 +1,229 @@ # @voltagent/langfuse-exporter +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + ## 2.0.3 ### Patch Changes diff --git a/packages/langfuse-exporter/package.json b/packages/langfuse-exporter/package.json index 3b237f36f..340d914bd 100644 --- a/packages/langfuse-exporter/package.json +++ b/packages/langfuse-exporter/package.json @@ -1,7 +1,7 @@ { "name": "@voltagent/langfuse-exporter", "description": "OpenTelemetry SpanExporter for sending VoltAgent traces to Langfuse.", - "version": "2.0.3", + "version": "3.0.0-next.0", "dependencies": { "@opentelemetry/core": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", @@ -9,18 +9,13 @@ }, "devDependencies": { "@vitest/coverage-v8": "^3.2.4", - "@voltagent/core": "^2.0.2" + "@voltagent/core": "^3.0.0-next.0" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -28,12 +23,12 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@opentelemetry/core": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", - "@voltagent/core": "^2.0.0" + "@voltagent/core": "^3.0.0-next.0" }, "repository": { "type": "git", @@ -50,5 +45,6 @@ "test": "vitest", "test:coverage": "vitest run --coverage" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/langfuse-exporter/tsup.config.ts b/packages/langfuse-exporter/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/langfuse-exporter/tsup.config.ts +++ b/packages/langfuse-exporter/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/libsql/CHANGELOG.md b/packages/libsql/CHANGELOG.md index e446821cc..d0880db57 100644 --- a/packages/libsql/CHANGELOG.md +++ b/packages/libsql/CHANGELOG.md @@ -1,5 +1,231 @@ # @voltagent/libsql +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + - @voltagent/logger@3.0.0-next.0 + ## 2.1.2 ### Patch Changes diff --git a/packages/libsql/package.json b/packages/libsql/package.json index 0e2e1bf37..8059592f2 100644 --- a/packages/libsql/package.json +++ b/packages/libsql/package.json @@ -1,37 +1,27 @@ { "name": "@voltagent/libsql", "description": "VoltAgent LibSQL - LibSQL/Turso Memory provider integration for VoltAgent", - "version": "2.1.2", + "version": "3.0.0-next.0", "dependencies": { "@libsql/client": "^0.15.0", - "@voltagent/internal": "^1.0.2" + "@voltagent/internal": "^2.0.0-next.0" }, "devDependencies": { "@vitest/coverage-v8": "^3.2.4", - "@voltagent/core": "^2.4.4", - "@voltagent/logger": "^2.0.2", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "ai": "^7.0.0" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" }, "./edge": { - "import": { - "types": "./dist/edge.d.mts", - "default": "./dist/edge.mjs" - }, - "require": { - "types": "./dist/edge.d.ts", - "default": "./dist/edge.js" - } + "types": "./dist/edge.d.ts", + "import": "./dist/edge.js", + "default": "./dist/edge.js" } }, "files": [ @@ -39,11 +29,11 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "@voltagent/logger": "^2.0.0", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "ai": "^7.0.0" }, "publishConfig": { "access": "public" @@ -63,5 +53,6 @@ "test": "vitest --reporter=hanging-process --reporter=default --typecheck", "test:coverage": "vitest run --coverage --typecheck" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/libsql/tsconfig.json b/packages/libsql/tsconfig.json index ed464a96b..2fc8e09c4 100644 --- a/packages/libsql/tsconfig.json +++ b/packages/libsql/tsconfig.json @@ -1,6 +1,8 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", "outDir": "./dist", "rootDir": "./src" }, diff --git a/packages/libsql/tsup.config.ts b/packages/libsql/tsup.config.ts index 52ba7850f..ae407acbe 100644 --- a/packages/libsql/tsup.config.ts +++ b/packages/libsql/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts", "src/edge.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/logger/CHANGELOG.md b/packages/logger/CHANGELOG.md index e5579b684..ddb16781d 100644 --- a/packages/logger/CHANGELOG.md +++ b/packages/logger/CHANGELOG.md @@ -1,5 +1,229 @@ # @voltagent/logger +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/internal@2.0.0-next.0 + ## 2.0.2 ### Patch Changes diff --git a/packages/logger/package.json b/packages/logger/package.json index eaf759f8b..f6894649c 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,13 +1,13 @@ { "name": "@voltagent/logger", "description": "VoltAgent logger - @voltagent/logger", - "version": "2.0.2", + "version": "3.0.0-next.0", "dependencies": { "@opentelemetry/api-logs": "^0.204.0", "@opentelemetry/instrumentation": "^0.204.0", "@opentelemetry/instrumentation-pino": "^0.50.1", "@opentelemetry/sdk-logs": "^0.204.0", - "@voltagent/internal": "^1.0.2", + "@voltagent/internal": "^2.0.0-next.0", "pino": "^9.7.0", "pino-pretty": "^13.0.0" }, @@ -16,14 +16,9 @@ }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -31,7 +26,7 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "repository": { "type": "git", "url": "https://github.com/VoltAgent/voltagent.git", @@ -47,5 +42,6 @@ "test": "vitest", "test:coverage": "vitest run --coverage" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/logger/tsup.config.ts b/packages/logger/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/logger/tsup.config.ts +++ b/packages/logger/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/mcp-server/CHANGELOG.md b/packages/mcp-server/CHANGELOG.md index fc05b706a..50a00861d 100644 --- a/packages/mcp-server/CHANGELOG.md +++ b/packages/mcp-server/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/mcp-server +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + ## 2.0.2 ### Patch Changes diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 7a2e66c93..01464e95d 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,25 +1,20 @@ { "name": "@voltagent/mcp-server", "description": "VoltAgent MCP server implementation for exposing agents, tools, and workflows via the Model Context Protocol.", - "version": "2.0.2", + "version": "3.0.0-next.0", "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", - "@voltagent/internal": "^1.0.2" + "@voltagent/internal": "^2.0.0-next.0" }, "devDependencies": { - "@voltagent/core": "^2.0.2", - "zod": "^3.25.76" + "@voltagent/core": "^3.0.0-next.0", + "zod": "^4.1.11" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -27,10 +22,10 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "zod": "^3.25.0 || ^4.0.0" + "@voltagent/core": "^3.0.0-next.0", + "zod": "^4.0.0" }, "repository": { "type": "git", @@ -43,5 +38,6 @@ "test": "vitest", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/mcp-server/src/adapters/agent.spec.ts b/packages/mcp-server/src/adapters/agent.spec.ts new file mode 100644 index 000000000..8f42d688f --- /dev/null +++ b/packages/mcp-server/src/adapters/agent.spec.ts @@ -0,0 +1,81 @@ +import type { Agent } from "@voltagent/core"; +import { describe, expect, it, vi } from "vitest"; +import { AgentAdapter } from "./agent"; + +function createAgent(generateText: ReturnType): Agent { + return { + id: "support-agent", + name: "Support Agent", + purpose: "Answer support questions", + instructions: "Be concise", + generateText, + } as unknown as Agent; +} + +describe("AgentAdapter", () => { + it("executes agents through positional generateText prompt and options", async () => { + const generateText = vi.fn(async () => ({ + text: "Agent response", + finishReason: "stop", + usage: { inputTokens: 1, outputTokens: 2, totalTokens: 3 }, + })); + + const result = await AgentAdapter.executeAgent(createAgent(generateText), { + prompt: "Hello", + context: { tenant: "acme" }, + conversationId: "conv-1", + userId: "user-1", + maxSteps: 3, + }); + + expect(generateText).toHaveBeenCalledTimes(1); + const [prompt, options] = generateText.mock.calls[0]; + expect(prompt).toBe("Hello"); + expect(options).toEqual( + expect.objectContaining({ + conversationId: "conv-1", + userId: "user-1", + maxSteps: 3, + context: { tenant: "acme" }, + }), + ); + expect(options).not.toHaveProperty("prompt"); + expect(options).not.toHaveProperty("messages"); + + expect(result.content[0]).toEqual(expect.objectContaining({ type: "text" })); + const text = (result.content[0] as { text: string }).text; + expect(text).toContain("Agent response"); + expect(text).toContain("finishReason"); + }); + + it("bridges elicitation through generateText options without changing the prompt shape", async () => { + const generateText = vi.fn(async () => ({ + text: "Needs approval", + finishReason: "stop", + usage: undefined, + })); + const elicitationResult = { action: "accept", content: { approved: true } }; + const requestElicitation = vi.fn(async () => elicitationResult); + + await AgentAdapter.executeAgent( + createAgent(generateText), + { + prompt: "Approve this?", + conversationId: "conv-2", + }, + requestElicitation, + ); + + const [prompt, options] = generateText.mock.calls[0]; + expect(prompt).toBe("Approve this?"); + expect(options).not.toHaveProperty("prompt"); + expect(options.elicitation).toEqual(expect.any(Function)); + + const request = { + message: "Can I continue?", + requestedSchema: { type: "object", properties: {} }, + }; + await expect(options.elicitation(request)).resolves.toBe(elicitationResult); + expect(requestElicitation).toHaveBeenCalledWith(request); + }); +}); diff --git a/packages/mcp-server/tsup.config.ts b/packages/mcp-server/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/mcp-server/tsup.config.ts +++ b/packages/mcp-server/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/postgres/CHANGELOG.md b/packages/postgres/CHANGELOG.md index 74e8f96e3..e3bc2ffe4 100644 --- a/packages/postgres/CHANGELOG.md +++ b/packages/postgres/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/postgres +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + ## 2.1.2 ### Patch Changes diff --git a/packages/postgres/package.json b/packages/postgres/package.json index a17bc179c..fe525696e 100644 --- a/packages/postgres/package.json +++ b/packages/postgres/package.json @@ -1,27 +1,22 @@ { "name": "@voltagent/postgres", "description": "VoltAgent PostgreSQL - PostgreSQL Memory provider integration for VoltAgent", - "version": "2.1.2", + "version": "3.0.0-next.0", "dependencies": { - "@voltagent/internal": "^1.0.2", + "@voltagent/internal": "^2.0.0-next.0", "pg": "^8.16.0" }, "devDependencies": { "@types/pg": "^8.15.2", "@vitest/coverage-v8": "^3.2.4", - "@voltagent/core": "^2.4.4", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "ai": "^7.0.0" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -29,10 +24,10 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "ai": "^7.0.0" }, "repository": { "type": "git", @@ -53,5 +48,6 @@ "test:integration:setup": "docker compose -f docker-compose.test.yaml up -d && sleep 10", "test:integration:teardown": "docker compose -f docker-compose.test.yaml down -v" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/postgres/tsup.config.ts b/packages/postgres/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/postgres/tsup.config.ts +++ b/packages/postgres/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/rag/CHANGELOG.md b/packages/rag/CHANGELOG.md index a3912ba3a..153be7b89 100644 --- a/packages/rag/CHANGELOG.md +++ b/packages/rag/CHANGELOG.md @@ -1,6 +1,223 @@ # @voltagent/rag -## 1.0.2 +## 2.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. ### Patch Changes diff --git a/packages/rag/package.json b/packages/rag/package.json index 43942382b..2d3f3db06 100644 --- a/packages/rag/package.json +++ b/packages/rag/package.json @@ -1,7 +1,7 @@ { "name": "@voltagent/rag", "description": "Chunking and RAG utilities for VoltAgent", - "version": "1.0.2", + "version": "2.0.0-next.0", "dependencies": { "js-tiktoken": "^1.0.14" }, @@ -10,14 +10,9 @@ }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -25,7 +20,7 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "repository": { "type": "git", "url": "https://github.com/VoltAgent/voltagent.git", @@ -37,5 +32,6 @@ "test": "vitest --reporter=hanging-process --reporter=default --typecheck", "test:coverage": "vitest run --coverage --typecheck" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/rag/tsconfig.json b/packages/rag/tsconfig.json index ed464a96b..2fc8e09c4 100644 --- a/packages/rag/tsconfig.json +++ b/packages/rag/tsconfig.json @@ -1,6 +1,8 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", "outDir": "./dist", "rootDir": "./src" }, diff --git a/packages/rag/tsup.config.ts b/packages/rag/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/rag/tsup.config.ts +++ b/packages/rag/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/resumable-streams/CHANGELOG.md b/packages/resumable-streams/CHANGELOG.md index ef5d646d6..605d1136d 100644 --- a/packages/resumable-streams/CHANGELOG.md +++ b/packages/resumable-streams/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/resumable-streams +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + ## 2.0.2 ### Patch Changes diff --git a/packages/resumable-streams/package.json b/packages/resumable-streams/package.json index 8c2c03a27..ab834e712 100644 --- a/packages/resumable-streams/package.json +++ b/packages/resumable-streams/package.json @@ -1,25 +1,20 @@ { "name": "@voltagent/resumable-streams", "description": "Resumable stream utilities for VoltAgent", - "version": "2.0.2", + "version": "3.0.0-next.0", "author": "VoltAgent Team", "dependencies": { - "@voltagent/core": "^2.6.6", - "@voltagent/internal": "^1.0.2", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/internal": "^2.0.0-next.0", "redis": "^4.7.0", "resumable-stream": "^2.2.10" }, "devDependencies": {}, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -33,10 +28,10 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "ai": "^7.0.0" }, "publishConfig": { "access": "public" @@ -52,5 +47,6 @@ "test": "vitest", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/resumable-streams/src/chat-handlers.ts b/packages/resumable-streams/src/chat-handlers.ts index 5ef441082..a8fe36b24 100644 --- a/packages/resumable-streams/src/chat-handlers.ts +++ b/packages/resumable-streams/src/chat-handlers.ts @@ -1,10 +1,14 @@ -import type { Agent, ResumableStreamAdapter } from "@voltagent/core"; +import type { + Agent, + BaseMessage, + ResumableStreamAdapter, + StreamTextOptions, +} from "@voltagent/core"; import { getGlobalLogger, setWaitUntil } from "@voltagent/core"; import { type Logger, safeStringify } from "@voltagent/internal"; -import { UI_MESSAGE_STREAM_HEADERS } from "ai"; +import { type UIMessage, UI_MESSAGE_STREAM_HEADERS } from "ai"; -type StreamTextInput = Parameters[0]; -type StreamTextOptions = Parameters[1]; +type StreamTextInput = string | UIMessage[] | BaseMessage[]; type RouteParams = Record; type HandlerContext = { @@ -114,7 +118,7 @@ export function createResumableChatHandlers< logger.error("Failed to persist resumable chat stream", { error }); } }, - onFinish: async () => { + onEnd: async () => { try { await adapter.clearActiveStream({ conversationId, diff --git a/packages/resumable-streams/src/chat-session.ts b/packages/resumable-streams/src/chat-session.ts index 1ebbf6877..40da15516 100644 --- a/packages/resumable-streams/src/chat-session.ts +++ b/packages/resumable-streams/src/chat-session.ts @@ -10,7 +10,7 @@ type ResumableChatSessionOptions = ResumableStreamContext & { export type ResumableChatSession = { consumeSseStream: (args: { stream: ReadableStream }) => Promise; - onFinish: () => Promise; + onEnd: () => Promise; resumeResponse: () => Promise; getActiveStreamId: () => Promise; clearActiveStream: (streamId?: string) => Promise; @@ -66,7 +66,7 @@ export function createResumableChatSession({ } }; - const onFinish = async () => { + const onEnd = async () => { try { const streamId = activeStreamId ?? (await getActiveStreamId()); if (!streamId) { @@ -104,7 +104,7 @@ export function createResumableChatSession({ return { consumeSseStream, - onFinish, + onEnd, resumeResponse, getActiveStreamId, clearActiveStream, diff --git a/packages/resumable-streams/tsup.config.ts b/packages/resumable-streams/tsup.config.ts index e019584d6..032b5345b 100644 --- a/packages/resumable-streams/tsup.config.ts +++ b/packages/resumable-streams/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/resumable-streams/vitest.config.ts b/packages/resumable-streams/vitest.config.ts new file mode 100644 index 000000000..06ca89f12 --- /dev/null +++ b/packages/resumable-streams/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["src/**/*.spec.ts"], + environment: "node", + globals: true, + passWithNoTests: true, + }, +}); diff --git a/packages/sandbox-blaxel/CHANGELOG.md b/packages/sandbox-blaxel/CHANGELOG.md index 0447ef8e3..3167111b0 100644 --- a/packages/sandbox-blaxel/CHANGELOG.md +++ b/packages/sandbox-blaxel/CHANGELOG.md @@ -1,5 +1,229 @@ # @voltagent/sandbox-blaxel +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + ## 2.1.1 ### Patch Changes diff --git a/packages/sandbox-blaxel/package.json b/packages/sandbox-blaxel/package.json index 1d9bb13ea..3bcb2860b 100644 --- a/packages/sandbox-blaxel/package.json +++ b/packages/sandbox-blaxel/package.json @@ -1,7 +1,7 @@ { "name": "@voltagent/sandbox-blaxel", "description": "VoltAgent Blaxel sandbox provider", - "version": "2.1.1", + "version": "3.0.0-next.0", "dependencies": { "@blaxel/core": "^0.2.0", "es-toolkit": "^1.46.1" @@ -9,21 +9,16 @@ "devDependencies": { "@types/node": "^24.2.1", "@vitest/coverage-v8": "^3.2.4", - "@voltagent/core": "^2.8.1", + "@voltagent/core": "^3.0.0-next.0", "tsup": "^8.5.0", "typescript": "^5.8.2", "vitest": "^3.2.4" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -31,9 +26,9 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0" + "@voltagent/core": "^3.0.0-next.0" }, "repository": { "type": "git", @@ -48,5 +43,6 @@ "test:watch": "vitest", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/sandbox-blaxel/tsup.config.ts b/packages/sandbox-blaxel/tsup.config.ts index 7dcbd0624..28708f1ef 100644 --- a/packages/sandbox-blaxel/tsup.config.ts +++ b/packages/sandbox-blaxel/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/sandbox-daytona/CHANGELOG.md b/packages/sandbox-daytona/CHANGELOG.md index d7e508ea0..77ac66b05 100644 --- a/packages/sandbox-daytona/CHANGELOG.md +++ b/packages/sandbox-daytona/CHANGELOG.md @@ -1,5 +1,229 @@ # @voltagent/sandbox-daytona +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + ## 2.0.3 ### Patch Changes diff --git a/packages/sandbox-daytona/package.json b/packages/sandbox-daytona/package.json index 561f31efc..a7c0c2b59 100644 --- a/packages/sandbox-daytona/package.json +++ b/packages/sandbox-daytona/package.json @@ -1,26 +1,21 @@ { "name": "@voltagent/sandbox-daytona", "description": "VoltAgent Daytona sandbox provider", - "version": "2.0.3", + "version": "3.0.0-next.0", "dependencies": { "@daytonaio/sdk": "^0.139.0" }, "devDependencies": { "@types/node": "^24.2.1", - "@voltagent/core": "^2.8.1", + "@voltagent/core": "^3.0.0-next.0", "tsup": "^8.5.0", "typescript": "^5.8.2" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -28,9 +23,9 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0" + "@voltagent/core": "^3.0.0-next.0" }, "repository": { "type": "git", @@ -42,5 +37,6 @@ "dev": "tsup --watch", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/sandbox-daytona/tsup.config.ts b/packages/sandbox-daytona/tsup.config.ts index e019584d6..032b5345b 100644 --- a/packages/sandbox-daytona/tsup.config.ts +++ b/packages/sandbox-daytona/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/sandbox-e2b/CHANGELOG.md b/packages/sandbox-e2b/CHANGELOG.md index 060847429..de5f8b5bc 100644 --- a/packages/sandbox-e2b/CHANGELOG.md +++ b/packages/sandbox-e2b/CHANGELOG.md @@ -1,5 +1,229 @@ # @voltagent/sandbox-e2b +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + ## 2.0.3 ### Patch Changes diff --git a/packages/sandbox-e2b/package.json b/packages/sandbox-e2b/package.json index 031afdcdc..c8086e54c 100644 --- a/packages/sandbox-e2b/package.json +++ b/packages/sandbox-e2b/package.json @@ -1,26 +1,21 @@ { "name": "@voltagent/sandbox-e2b", "description": "VoltAgent E2B sandbox provider", - "version": "2.0.3", + "version": "3.0.0-next.0", "dependencies": { "e2b": "^2.12.0" }, "devDependencies": { "@types/node": "^24.2.1", - "@voltagent/core": "^2.8.1", + "@voltagent/core": "^3.0.0-next.0", "tsup": "^8.5.0", "typescript": "^5.8.2" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -28,9 +23,9 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0" + "@voltagent/core": "^3.0.0-next.0" }, "repository": { "type": "git", @@ -42,5 +37,6 @@ "dev": "tsup --watch", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/sandbox-e2b/tsup.config.ts b/packages/sandbox-e2b/tsup.config.ts index e019584d6..032b5345b 100644 --- a/packages/sandbox-e2b/tsup.config.ts +++ b/packages/sandbox-e2b/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/scorers/CHANGELOG.md b/packages/scorers/CHANGELOG.md index e7409f00d..0dbb92878 100644 --- a/packages/scorers/CHANGELOG.md +++ b/packages/scorers/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/scorers +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + ## 2.1.0 ### Minor Changes diff --git a/packages/scorers/package.json b/packages/scorers/package.json index 8392e4673..c5c90421e 100644 --- a/packages/scorers/package.json +++ b/packages/scorers/package.json @@ -1,27 +1,22 @@ { "name": "@voltagent/scorers", "description": "VoltAgent scorers re-export sourced from Viteval's prebuilt scorer set", - "version": "2.1.0", + "version": "3.0.0-next.0", "author": "VoltAgent", "dependencies": { - "@voltagent/core": "^2.4.0", - "@voltagent/internal": "^1.0.2", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/internal": "^2.0.0-next.0", "autoevals": "^0.0.131" }, "devDependencies": { - "ai": "^6.0.0", - "zod": "^3.25.76" + "ai": "^7.0.0", + "zod": "^4.1.11" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "require": { - "types": "./dist/index.d.cts", - "default": "./dist/index.cjs" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -29,11 +24,11 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "ai": "^6.0.0", - "zod": "^3.25.0 || ^4.0.0" + "@voltagent/core": "^3.0.0-next.0", + "ai": "^7.0.0", + "zod": "^4.0.0" }, "peerDependenciesMeta": { "ai": { diff --git a/packages/scorers/src/llm/answer-correctness.ts b/packages/scorers/src/llm/answer-correctness.ts index 06ada87e0..fac233aa8 100644 --- a/packages/scorers/src/llm/answer-correctness.ts +++ b/packages/scorers/src/llm/answer-correctness.ts @@ -7,6 +7,7 @@ import { } from "@voltagent/core"; import { safeStringify } from "@voltagent/internal/utils"; import { z } from "zod"; +import { generateStructuredObject } from "./structured-output"; const ANSWER_CORRECTNESS_PROMPT = `Given a ground truth and an answer, analyze each statement in the answer and classify them in one of the following categories: @@ -92,8 +93,8 @@ export function createAnswerCorrectnessScorer< .replace("{{answer}}", payload.output) .replace("{{ground_truth}}", payload.expected); - const response = await agent.generateObject(prompt, CLASSIFICATION_SCHEMA); - const normalized = normalizeClassification(response.object); + const response = await generateStructuredObject(agent, prompt, CLASSIFICATION_SCHEMA); + const normalized = normalizeClassification(response); return { ...normalized, diff --git a/packages/scorers/src/llm/answer-relevancy.ts b/packages/scorers/src/llm/answer-relevancy.ts index b3ceedfe6..23ca9e3b7 100644 --- a/packages/scorers/src/llm/answer-relevancy.ts +++ b/packages/scorers/src/llm/answer-relevancy.ts @@ -8,6 +8,7 @@ import { } from "@voltagent/core"; import { safeStringify } from "@voltagent/internal/utils"; import { z } from "zod"; +import { generateStructuredObject } from "./structured-output"; const QUESTION_GEN_PROMPT = `Generate a question for the given answer and Identify if answer is noncommittal. Give noncommittal as 1 if the answer is noncommittal and 0 if the answer is committal. A noncommittal answer is one that is evasive, vague, or ambiguous. For example, "I don't know" or "I'm not sure" are noncommittal answers @@ -131,10 +132,10 @@ export function createAnswerRelevancyScorer< payload.context, ); - const response = await agent.generateObject(prompt, QUESTION_SCHEMA); + const question = await generateStructuredObject(agent, prompt, QUESTION_SCHEMA); questions.push({ - question: response.object.question, - noncommittal: response.object.noncommittal === 1, + question: question.question, + noncommittal: question.noncommittal === 1, }); } diff --git a/packages/scorers/src/llm/classifiers.ts b/packages/scorers/src/llm/classifiers.ts index 55daf7346..0f7d37dcf 100644 --- a/packages/scorers/src/llm/classifiers.ts +++ b/packages/scorers/src/llm/classifiers.ts @@ -7,6 +7,7 @@ import { } from "@voltagent/core"; import { safeStringify } from "@voltagent/internal/utils"; import { z } from "zod"; +import { generateStructuredObject } from "./structured-output"; type ChoiceId = string; @@ -96,17 +97,17 @@ async function evaluateChoice(args: EvaluateChoiceArgs): Promise instructions: judgeInstructions ?? buildDefaultChoiceInstructions(Object.keys(choices)), }); - const response = await agent.generateObject(prompt, CHOICE_RESPONSE_SCHEMA, { + const response = await generateStructuredObject(agent, prompt, CHOICE_RESPONSE_SCHEMA, { maxOutputTokens, }); - const { choice, reason } = extractChoiceFromResponse(response.object, choices, scorerId); + const { choice, reason } = extractChoiceFromResponse(response, choices, scorerId); const definition = choices[choice]; return { choice, reason, - raw: response.object, + raw: response, score: definition.score, definition, } satisfies ChoiceAnalysis; diff --git a/packages/scorers/src/llm/context-precision.ts b/packages/scorers/src/llm/context-precision.ts index dcfa38cdc..715b1b96d 100644 --- a/packages/scorers/src/llm/context-precision.ts +++ b/packages/scorers/src/llm/context-precision.ts @@ -7,6 +7,7 @@ import { } from "@voltagent/core"; import { safeStringify } from "@voltagent/internal/utils"; import { z } from "zod"; +import { generateStructuredObject } from "./structured-output"; const CONTEXT_PRECISION_PROMPT = `Given question, answer and context verify if the context was useful in arriving at the given answer. Give verdict as "1" if useful and "0" if not with json output. @@ -121,18 +122,18 @@ export function createContextPrecisionScorer< .replace("{{context}}", contextText) .replace("{{answer}}", payload.output); - const response = await agent.generateObject(prompt, CONTEXT_PRECISION_SCHEMA); + const verdict = await generateStructuredObject(agent, prompt, CONTEXT_PRECISION_SCHEMA); - context.results.raw.contextPrecisionVerdict = response.object; + context.results.raw.contextPrecisionVerdict = verdict; - if (mergedOptions.weighted && response.object.verdict === 1) { + if (mergedOptions.weighted && verdict.verdict === 1) { // For weighted scoring, we could use confidence if available // For now, return the verdict as is - return response.object.verdict; + return verdict.verdict; } // Binary scoring based on threshold - return response.object.verdict >= mergedOptions.binaryThreshold ? 1 : 0; + return verdict.verdict >= mergedOptions.binaryThreshold ? 1 : 0; }) .reason(({ results }) => { const verdict = results.raw.contextPrecisionVerdict as z.infer< diff --git a/packages/scorers/src/llm/context-recall.ts b/packages/scorers/src/llm/context-recall.ts index b64a57867..09667fd90 100644 --- a/packages/scorers/src/llm/context-recall.ts +++ b/packages/scorers/src/llm/context-recall.ts @@ -7,6 +7,7 @@ import { } from "@voltagent/core"; import { safeStringify } from "@voltagent/internal/utils"; import { z } from "zod"; +import { generateStructuredObject } from "./structured-output"; const CONTEXT_RECALL_EXTRACT_PROMPT = `Given the context and ground truth (expected output), extract all factual statements from the ground truth. @@ -134,8 +135,8 @@ export function createContextRecallScorer< contextText, ).replace("{{expected}}", payload.expected); - const extractResponse = await agent.generateObject(extractPrompt, EXTRACT_SCHEMA); - const statements = extractResponse.object.statements; + const extractResponse = await generateStructuredObject(agent, extractPrompt, EXTRACT_SCHEMA); + const statements = extractResponse.statements; if (statements.length === 0) { context.results.raw.contextRecallStatements = []; @@ -152,11 +153,11 @@ export function createContextRecallScorer< contextText, ).replace("{{statement}}", statement); - const verifyResponse = await agent.generateObject(verifyPrompt, VERIFY_SCHEMA); + const verifyResponse = await generateStructuredObject(agent, verifyPrompt, VERIFY_SCHEMA); verdicts.push({ statement, - verdict: verifyResponse.object.verdict, - reasoning: verifyResponse.object.reasoning, + verdict: verifyResponse.verdict, + reasoning: verifyResponse.reasoning, }); } diff --git a/packages/scorers/src/llm/context-relevancy.ts b/packages/scorers/src/llm/context-relevancy.ts index bc5fc45d1..e0cc2993e 100644 --- a/packages/scorers/src/llm/context-relevancy.ts +++ b/packages/scorers/src/llm/context-relevancy.ts @@ -7,6 +7,7 @@ import { } from "@voltagent/core"; import { safeStringify } from "@voltagent/internal/utils"; import { z } from "zod"; +import { generateStructuredObject } from "./structured-output"; const CONTEXT_RELEVANCY_PROMPT = `Analyze the provided context and identify which parts are relevant to answering the given question. For each context sentence or passage, determine its relevance level. @@ -157,8 +158,8 @@ export function createContextRelevancyScorer< contextText, ); - const response = await agent.generateObject(prompt, CONTEXT_RELEVANCY_SCHEMA); - const evaluations = response.object.evaluations; + const response = await generateStructuredObject(agent, prompt, CONTEXT_RELEVANCY_SCHEMA); + const evaluations = response.evaluations; context.results.raw.contextRelevancyEvaluations = evaluations; diff --git a/packages/scorers/src/llm/moderation.ts b/packages/scorers/src/llm/moderation.ts index 7c801b36f..7b4c45d67 100644 --- a/packages/scorers/src/llm/moderation.ts +++ b/packages/scorers/src/llm/moderation.ts @@ -7,6 +7,7 @@ import { } from "@voltagent/core"; import { safeStringify } from "@voltagent/internal/utils"; import { z } from "zod"; +import { generateStructuredObject } from "./structured-output"; export interface ModerationScorerOptions { id?: string; @@ -30,6 +31,11 @@ type ModerationPayload = Record; type ModerationRawScores = Record; type ModerationScores = Record; +type ModerationSchemaOutput = { + flagged: boolean; + scores: ModerationRawScores; + reason: string | null; +}; type ModerationResult = { flagged: boolean; @@ -54,19 +60,15 @@ const DEFAULT_CATEGORIES: readonly string[] = [ "violence/graphic", ]; -function buildScoresSchema(categories: readonly string[]): z.ZodObject { - const shape: Record = {}; +function buildScoresSchema(categories: readonly string[]): z.ZodType { + const shape: Record> = {}; for (const category of categories) { shape[category] = z.number().min(0).max(1).nullable(); } - return z.object(shape); + return z.object(shape) as z.ZodType; } -function createModerationSchema(categories: readonly string[]): z.ZodObject<{ - flagged: z.ZodBoolean; - scores: z.ZodObject; - reason: z.ZodNullable; -}> { +function createModerationSchema(categories: readonly string[]): z.ZodType { return z.object({ flagged: z.boolean(), scores: buildScoresSchema(categories), @@ -261,11 +263,11 @@ async function runModerationJudge(args: { "You are a safety classifier. Respond with JSON that matches the provided schema containing flagged, scores, and reason.", }); - const response = await agent.generateObject(prompt, schema, { + const response = await generateStructuredObject(agent, prompt, schema, { maxOutputTokens, }); - const parsed = mapModerationResponse(response.object, threshold, schema); + const parsed = mapModerationResponse(response, threshold, schema); return { ...parsed, diff --git a/packages/scorers/src/llm/structured-output.ts b/packages/scorers/src/llm/structured-output.ts new file mode 100644 index 000000000..eadf89a37 --- /dev/null +++ b/packages/scorers/src/llm/structured-output.ts @@ -0,0 +1,22 @@ +import type { Agent } from "@voltagent/core"; +import { Output } from "ai"; +import type { z } from "zod"; + +type StructuredObjectOptions = { + maxOutputTokens?: number; +}; + +export async function generateStructuredObject( + agent: Agent, + prompt: string, + schema: TSchema, + options?: StructuredObjectOptions, +): Promise> { + const response = await agent.generateText({ + prompt, + ...(options ?? {}), + output: Output.object({ schema }), + }); + + return response.output as z.infer; +} diff --git a/packages/scorers/src/test-utils.ts b/packages/scorers/src/test-utils.ts index bc26142f0..136ef9ebd 100644 --- a/packages/scorers/src/test-utils.ts +++ b/packages/scorers/src/test-utils.ts @@ -2,7 +2,7 @@ * Test utilities for Scorers package */ -import type { LanguageModel } from "ai"; +import type { FinishReason, LanguageModel, LanguageModelUsage } from "ai"; /** * Default mock response values @@ -19,6 +19,131 @@ export const defaultMockResponse = { rawSettings: {}, }; +const finishReasonValues: FinishReason[] = [ + "stop", + "length", + "content-filter", + "tool-calls", + "error", + "other", +]; + +const finishReasonSet = new Set(finishReasonValues); + +type ProviderFinishReason = { + unified: FinishReason; + raw: string | undefined; +}; + +type ProviderUsage = { + inputTokens: { + total: number | undefined; + noCache: number | undefined; + cacheRead: number | undefined; + cacheWrite: number | undefined; + }; + outputTokens: { + total: number | undefined; + text: number | undefined; + reasoning: number | undefined; + }; + raw?: Record; +}; + +const defaultProviderUsage: ProviderUsage = { + inputTokens: { + total: 10, + noCache: 10, + cacheRead: 0, + cacheWrite: 0, + }, + outputTokens: { + total: 5, + text: 5, + reasoning: 0, + }, +}; + +const defaultProviderFinishReason: ProviderFinishReason = { + unified: "stop", + raw: "stop", +}; + +const isProviderUsage = (usage: unknown): usage is ProviderUsage => { + if (!usage || typeof usage !== "object") return false; + const candidate = usage as ProviderUsage; + return ( + typeof candidate.inputTokens === "object" && + candidate.inputTokens !== null && + "total" in candidate.inputTokens && + typeof candidate.outputTokens === "object" && + candidate.outputTokens !== null && + "total" in candidate.outputTokens + ); +}; + +const normalizeFinishReason = (finishReason: unknown): ProviderFinishReason => { + if (finishReason && typeof finishReason === "object" && "unified" in finishReason) { + const candidate = finishReason as ProviderFinishReason; + return { + unified: finishReasonSet.has(candidate.unified) ? candidate.unified : "other", + raw: + typeof candidate.raw === "string" + ? candidate.raw + : candidate.raw == null + ? undefined + : String(candidate.raw), + }; + } + + if (typeof finishReason === "string") { + return { + unified: finishReasonSet.has(finishReason as FinishReason) + ? (finishReason as FinishReason) + : "other", + raw: finishReason, + }; + } + + return defaultProviderFinishReason; +}; + +const normalizeProviderUsage = ( + usage: LanguageModelUsage | ProviderUsage | undefined, +): ProviderUsage | undefined => { + if (!usage) return undefined; + if (isProviderUsage(usage)) return usage; + + const inputTokens = usage.inputTokens ?? usage.inputTokenDetails?.noCacheTokens; + const outputTokens = usage.outputTokens ?? usage.outputTokenDetails?.textTokens; + const hasInput = inputTokens != null || usage.inputTokenDetails != null; + const hasOutput = outputTokens != null || usage.outputTokenDetails != null; + + return { + inputTokens: { + total: typeof inputTokens === "number" ? inputTokens : undefined, + noCache: usage.inputTokenDetails?.noCacheTokens ?? inputTokens, + cacheRead: usage.inputTokenDetails?.cacheReadTokens ?? (hasInput ? 0 : undefined), + cacheWrite: usage.inputTokenDetails?.cacheWriteTokens ?? (hasInput ? 0 : undefined), + }, + outputTokens: { + total: typeof outputTokens === "number" ? outputTokens : undefined, + text: usage.outputTokenDetails?.textTokens ?? outputTokens, + reasoning: usage.outputTokenDetails?.reasoningTokens ?? (hasOutput ? 0 : undefined), + }, + raw: usage.raw as Record | undefined, + }; +}; + +const normalizeGenerateResult = (result: any) => { + if (!result || typeof result !== "object") return result; + return { + ...result, + finishReason: normalizeFinishReason(result.finishReason), + usage: normalizeProviderUsage(result.usage) ?? defaultProviderUsage, + }; +}; + /** * Simple MockLanguageModelV3 implementation * Based on AI SDK's MockLanguageModelV3 but without MSW dependency @@ -45,12 +170,12 @@ class MockLanguageModelV3 { this.doGenerate = async (options: any) => { this.doGenerateCalls.push(options); if (typeof doGenerate === "function") { - return doGenerate(options); + return normalizeGenerateResult(await doGenerate(options)); } if (Array.isArray(doGenerate)) { - return doGenerate[this.doGenerateCalls.length - 1]; + return normalizeGenerateResult(doGenerate[this.doGenerateCalls.length - 1]); } - return doGenerate; + return normalizeGenerateResult(doGenerate); }; const doStream = config?.doStream; diff --git a/packages/scorers/tsup.config.ts b/packages/scorers/tsup.config.ts index ee8a4c58c..70a8b7e1a 100644 --- a/packages/scorers/tsup.config.ts +++ b/packages/scorers/tsup.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from "tsup"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], dts: true, sourcemap: true, clean: true, diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 657248282..2da99654a 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/sdk +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + ## 2.0.3 ### Patch Changes diff --git a/packages/sdk/package.json b/packages/sdk/package.json index de6ae426e..13d6af40f 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,24 +1,19 @@ { "name": "@voltagent/sdk", "description": "VoltAgent SDK - Client SDK for interacting with VoltAgent API", - "version": "2.0.3", + "version": "3.0.0-next.0", "dependencies": { - "@voltagent/core": "^2.7.4", - "@voltagent/internal": "^1.0.2" + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/internal": "^2.0.0-next.0" }, "devDependencies": { "@vitest/coverage-v8": "^3.2.4" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -26,7 +21,7 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "repository": { "type": "git", "url": "https://github.com/VoltAgent/voltagent.git", @@ -42,5 +37,6 @@ "test": "vitest", "test:coverage": "vitest run --coverage" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/sdk/tsup.config.ts b/packages/sdk/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/sdk/tsup.config.ts +++ b/packages/sdk/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/server-core/CHANGELOG.md b/packages/server-core/CHANGELOG.md index 1a5925f53..10db82150 100644 --- a/packages/server-core/CHANGELOG.md +++ b/packages/server-core/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/server-core +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + ## 2.1.19 ### Patch Changes diff --git a/packages/server-core/package.json b/packages/server-core/package.json index a6e0f4d68..ad3b856af 100644 --- a/packages/server-core/package.json +++ b/packages/server-core/package.json @@ -1,42 +1,31 @@ { "name": "@voltagent/server-core", "description": "Framework-agnostic server core for VoltAgent", - "version": "2.1.19", + "version": "3.0.0-next.0", "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", - "@voltagent/core": "^2.8.1", - "@voltagent/internal": "^1.0.2", - "ai": "^6.0.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/internal": "^2.0.0-next.0", + "ai": "^7.0.0", "jsonwebtoken": "^9.0.2", "ws": "^8.18.1", - "zod-from-json-schema": "^0.5.0", - "zod-from-json-schema-v3": "npm:zod-from-json-schema@^0.0.5" + "zod-from-json-schema": "^0.5.0" }, "devDependencies": { "@types/jsonwebtoken": "^9.0.10", "@types/ws": "^8.18.1", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" }, "./edge": { - "import": { - "types": "./dist/edge.d.mts", - "default": "./dist/edge.mjs" - }, - "require": { - "types": "./dist/edge.d.ts", - "default": "./dist/edge.js" - } + "types": "./dist/edge.d.ts", + "import": "./dist/edge.js", + "default": "./dist/edge.js" } }, "files": [ @@ -44,10 +33,10 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "zod": "^3.25.0 || ^4.0.0" + "@voltagent/core": "^3.0.0-next.0", + "zod": "^4.0.0" }, "repository": { "type": "git", @@ -60,5 +49,6 @@ "test": "vitest", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/server-core/src/handlers/agent.handlers.spec.ts b/packages/server-core/src/handlers/agent.handlers.spec.ts index 0c8a09084..8e284f1dd 100644 --- a/packages/server-core/src/handlers/agent.handlers.spec.ts +++ b/packages/server-core/src/handlers/agent.handlers.spec.ts @@ -1,7 +1,13 @@ import { ToolDeniedError } from "@voltagent/core"; import { describe, expect, it, vi } from "vitest"; import { processAgentOptions } from "../utils/options"; -import { handleChatStream, handleGenerateText } from "./agent.handlers"; +import { + handleChatStream, + handleGenerateObject, + handleGenerateText, + handleStreamObject, + handleStreamText, +} from "./agent.handlers"; describe("server-core: agent.handlers ClientHTTPError mapping", () => { it("handleGenerateText should map ClientHTTPError (ToolDeniedError) to ApiResponse error fields", async () => { @@ -122,6 +128,309 @@ describe("server-core: processAgentOptions", () => { "x-tenant-id": "tenant-1", }); }); + + it("processAgentOptions should normalize voltagent namespaced runtime options", () => { + const headers = new Headers(); + vi.spyOn(headers, "entries").mockReturnValue( + [["Authorization", "Bearer real-token"]][Symbol.iterator]() as HeadersIterator< + [string, string] + >, + ); + + const options = processAgentOptions( + { + options: { + userId: "legacy-user", + conversationId: "legacy-conv", + context: { + requestId: "legacy-request", + }, + requestHeaders: { + authorization: "Bearer body-token", + }, + voltagent: { + userId: "runtime-user", + conversationId: "runtime-conv", + context: { + requestId: "runtime-request", + }, + requestHeaders: { + authorization: "Bearer namespaced-token", + }, + resumableStream: true, + middleware: { + maxRetries: 0, + }, + }, + }, + }, + undefined, + headers, + ); + + expect(options).not.toHaveProperty("voltagent"); + expect(options.userId).toBe("runtime-user"); + expect(options.conversationId).toBe("runtime-conv"); + expect(options.context).toBeInstanceOf(Map); + expect(options.context?.get("requestId")).toBe("runtime-request"); + expect(options.resumableStream).toBe(true); + expect(options.maxMiddlewareRetries).toBe(0); + expect(options.requestHeaders).toEqual({ + authorization: "Bearer real-token", + }); + }); +}); + +describe("server-core: agent.handlers stream contracts", () => { + it("handleGenerateObject should route through generateText with an output schema", async () => { + const logger = { + error: vi.fn(), + } as any; + const generateText = vi.fn(async () => ({ + output: { + name: "Ada", + age: 37, + }, + })); + const generateObject = vi.fn(); + const deps = { + agentRegistry: { + getAgent: vi.fn(() => ({ generateText, generateObject })), + }, + } as any; + + const res = await handleGenerateObject( + "agent-1", + { + input: "Generate a person", + schema: { + type: "object", + properties: { + name: { type: "string" }, + age: { type: "number" }, + }, + required: ["name", "age"], + }, + options: { + context: { + requestId: "req-1", + }, + output: { + type: "text", + }, + }, + }, + deps, + logger, + undefined, + { + "x-tenant-id": "tenant-1", + }, + ); + + expect(res).toEqual({ + success: true, + data: { + name: "Ada", + age: 37, + }, + }); + expect(generateObject).not.toHaveBeenCalled(); + expect(generateText).toHaveBeenCalledTimes(1); + expect(generateText).toHaveBeenCalledWith( + "Generate a person", + expect.objectContaining({ + context: expect.any(Map), + requestHeaders: { + "x-tenant-id": "tenant-1", + }, + output: expect.objectContaining({ + parseCompleteOutput: expect.any(Function), + }), + }), + ); + const requestOptions = generateText.mock.calls[0][1]; + expect(requestOptions.context.get("requestId")).toBe("req-1"); + }); + + it("handleStreamText should convert agent stream parts to SSE data events", async () => { + const logger = { + error: vi.fn(), + } as any; + const streamText = vi.fn(async () => ({ + stream: (async function* () { + yield { + type: "text-delta", + id: "text-1", + delta: "Hello", + text: "Hello", + }; + yield { + type: "finish", + finishReason: "stop", + }; + })(), + })); + const deps = { + agentRegistry: { + getAgent: vi.fn(() => ({ streamText })), + }, + } as any; + + const res = await handleStreamText( + "agent-1", + { + input: "hello", + options: { + context: { + requestId: "req-1", + }, + }, + }, + deps, + logger, + undefined, + { + "x-tenant-id": "tenant-1", + }, + ); + + expect(res.status).toBe(200); + expect(res.headers.get("content-type")).toBe("text/event-stream"); + expect(streamText).toHaveBeenCalledWith( + "hello", + expect.objectContaining({ + context: expect.any(Map), + requestHeaders: { + "x-tenant-id": "tenant-1", + }, + }), + ); + const context = streamText.mock.calls[0][1].context as Map; + expect(context.get("requestId")).toBe("req-1"); + + const body = await res.text(); + expect(body).toContain("data: "); + expect(body).toContain('"type":"text-delta"'); + expect(body).toContain('"delta":"Hello"'); + expect(body).toContain('"type":"finish"'); + expect(body.endsWith("\n\n")).toBe(true); + }); + + it("handleStreamObject should forward schema and options to agent streamObject", async () => { + const logger = { + error: vi.fn(), + } as any; + const toTextStreamResponse = vi.fn(() => new Response("object stream", { status: 200 })); + const streamObject = vi.fn(async () => ({ + toTextStreamResponse, + })); + const deps = { + agentRegistry: { + getAgent: vi.fn(() => ({ streamObject })), + }, + } as any; + + const res = await handleStreamObject( + "agent-1", + { + input: "Stream a person", + schema: { + type: "object", + properties: { + name: { type: "string" }, + }, + required: ["name"], + }, + options: { + context: { + requestId: "req-1", + }, + }, + }, + deps, + logger, + undefined, + { + "x-tenant-id": "tenant-1", + }, + ); + + expect(res.status).toBe(200); + expect(await res.text()).toBe("object stream"); + expect(streamObject).toHaveBeenCalledWith( + "Stream a person", + expect.objectContaining({ + safeParse: expect.any(Function), + }), + expect.objectContaining({ + context: expect.any(Map), + requestHeaders: { + "x-tenant-id": "tenant-1", + }, + }), + ); + const options = streamObject.mock.calls[0][2]; + expect(options.context.get("requestId")).toBe("req-1"); + expect(toTextStreamResponse).toHaveBeenCalled(); + }); + + it("handleChatStream should preserve UI stream response contract options", async () => { + const logger = { + error: vi.fn(), + warn: vi.fn(), + } as any; + const toUIMessageStreamResponse = vi.fn(() => new Response("ok", { status: 200 })); + const streamText = vi.fn(async () => ({ + toUIMessageStreamResponse, + })); + const deps = { + agentRegistry: { + getAgent: vi.fn(() => ({ streamText })), + }, + resumableStreamDefault: false, + } as any; + const input = [ + { + id: "msg-1", + role: "user", + parts: [{ type: "text", text: "hello" }], + }, + ]; + + const res = await handleChatStream( + "agent-1", + { + input, + options: { + context: { + requestId: "req-1", + }, + }, + }, + deps, + logger, + ); + + expect(res.status).toBe(200); + expect(streamText).toHaveBeenCalledWith( + input, + expect.objectContaining({ + context: expect.any(Map), + resumableStream: false, + }), + ); + expect(toUIMessageStreamResponse).toHaveBeenCalledWith( + expect.objectContaining({ + originalMessages: input, + generateMessageId: expect.any(Function), + sendReasoning: true, + sendSources: true, + consumeSseStream: expect.any(Function), + onEnd: expect.any(Function), + }), + ); + }); }); describe("server-core: agent.handlers resumable memory envelope", () => { diff --git a/packages/server-core/src/handlers/agent.handlers.ts b/packages/server-core/src/handlers/agent.handlers.ts index 61d28e78f..8700f5e9b 100644 --- a/packages/server-core/src/handlers/agent.handlers.ts +++ b/packages/server-core/src/handlers/agent.handlers.ts @@ -1,10 +1,8 @@ import { ClientHTTPError, type ServerProviderDeps } from "@voltagent/core"; import { convertUsage } from "@voltagent/core"; import { type Logger, safeStringify } from "@voltagent/internal"; -import { type UIMessage, UI_MESSAGE_STREAM_HEADERS, generateId } from "ai"; -import { z } from "zod"; +import { Output, type UIMessage, UI_MESSAGE_STREAM_HEADERS, generateId } from "ai"; import { convertJsonSchemaToZod } from "zod-from-json-schema"; -import { convertJsonSchemaToZod as convertJsonSchemaToZodV3 } from "zod-from-json-schema-v3"; import type { ApiResponse } from "../types"; import { processAgentOptions } from "../utils/options"; @@ -156,21 +154,20 @@ export async function handleStreamText( const result = await agent.streamText(input, options); - // Access the fullStream property - const { fullStream } = result; + const { stream: agentStream } = result; - // Convert fullStream to SSE format + // Convert the agent stream to SSE format. const encoder = new TextEncoder(); const stream = new ReadableStream({ async start(controller) { try { - for await (const part of fullStream) { + for await (const part of agentStream) { // Send each part as a JSON-encoded SSE event const data = `data: ${safeStringify(part)}\n\n`; controller.enqueue(encoder.encode(data)); } } catch (error) { - logger.error("Error in fullStream iteration", { error }); + logger.error("Error in stream iteration", { error }); // Send error event const errorData = `data: ${safeStringify({ type: "error", error: error instanceof Error ? error.message : "Unknown error" })}\n\n`; controller.enqueue(encoder.encode(errorData)); @@ -244,11 +241,11 @@ export async function handleChatStream( input.every((message) => Array.isArray((message as { parts?: unknown }).parts)) ? (input as UIMessage[]) : undefined; + const options = processAgentOptions(body, signal, requestHeaders); let resumableStreamRequested = - typeof body?.options?.resumableStream === "boolean" - ? body.options.resumableStream + typeof options.resumableStream === "boolean" + ? options.resumableStream : (deps.resumableStreamDefault ?? false); - const options = processAgentOptions(body, signal, requestHeaders); const memory = options.memory && typeof options.memory === "object" ? options.memory : undefined; const memoryConversationId = @@ -354,7 +351,7 @@ export async function handleChatStream( logger.error("Failed to persist resumable chat stream", { error }); } }, - onFinish: async () => { + onEnd: async () => { if (!resumableStreamEnabled || !resumableStreamAdapter || !conversationId || !userId) { return; } @@ -495,16 +492,17 @@ export async function handleGenerateObject( const { input, schema: jsonSchema } = body; const options = processAgentOptions(body, signal, requestHeaders); - // Convert JSON schema to Zod schema (supports zod v3 and v4) - const zodSchema = ("toJSONSchema" in z ? convertJsonSchemaToZod : convertJsonSchemaToZodV3)( - jsonSchema, - ) as any; + const zodSchema = convertJsonSchemaToZod(jsonSchema) as any; - const result = await agent.generateObject(input, zodSchema, options); + const output = Output.object({ schema: zodSchema }); + const result = await agent.generateText(input, { + ...options, + output, + }); return { success: true, - data: result.object, + data: result.output, }; } catch (error) { logger.error("Failed to generate object", { error }); @@ -547,10 +545,7 @@ export async function handleStreamObject( const { input, schema: jsonSchema } = body; const options = processAgentOptions(body, signal, requestHeaders); - // Convert JSON schema to Zod schema (supports zod v3 and v4) - const zodSchema = ("toJSONSchema" in z ? convertJsonSchemaToZod : convertJsonSchemaToZodV3)( - jsonSchema, - ) as any; + const zodSchema = convertJsonSchemaToZod(jsonSchema) as any; const result = await agent.streamObject(input, zodSchema, options); diff --git a/packages/server-core/src/handlers/tool.handlers.ts b/packages/server-core/src/handlers/tool.handlers.ts index 6d11407fe..0d5f9d929 100644 --- a/packages/server-core/src/handlers/tool.handlers.ts +++ b/packages/server-core/src/handlers/tool.handlers.ts @@ -1,4 +1,10 @@ -import { type Tool, zodSchemaToJsonUI } from "@voltagent/core"; +import { + type NamedAiSdkTool, + type ProviderTool, + type Tool, + getVoltAgentToolMetadata, + zodSchemaToJsonUI, +} from "@voltagent/core"; import type { ServerProviderDeps } from "@voltagent/core"; import { type Logger, safeStringify } from "@voltagent/internal"; import type { ApiResponse } from "../types"; @@ -6,9 +12,12 @@ import type { ApiResponse } from "../types"; type ToolMetadata = { id?: string; name: string; + displayName?: string; + purpose?: string; description?: string; parameters?: any; status?: string; + metadata?: Record; agents?: Array<{ id: string; name?: string; @@ -16,16 +25,19 @@ type ToolMetadata = { tags?: string[]; }; +type ToolAgentEntry = NonNullable[number]; +type ListableTool = Tool | NamedAiSdkTool | ProviderTool; + type AgentWithTools = { id: string; name?: string; - getTools: () => Tool[]; + getTools: () => ListableTool[]; }; function findTool( deps: ServerProviderDeps, toolName: string, -): { tool: Tool; agent: AgentWithTools } | undefined { +): { tool: ListableTool; agent: AgentWithTools } | undefined { const agents = deps.agentRegistry.getAllAgents(); for (const agent of agents) { @@ -62,12 +74,15 @@ const isZodLikeSchema = ( ); const extractToolTags = (tool: unknown): string[] | undefined => { - const candidate = tool as { tags?: unknown }; - if (!candidate || !Array.isArray(candidate.tags)) { + const metadata = getVoltAgentToolMetadata(tool); + const rawTags = Array.isArray(metadata?.tags) + ? metadata.tags + : (tool as { tags?: unknown } | undefined)?.tags; + if (!Array.isArray(rawTags)) { return undefined; } - const normalized = candidate.tags + const normalized = rawTags .filter((tag): tag is string => typeof tag === "string") .map((tag) => tag.trim()) .filter((tag) => tag.length > 0); @@ -75,6 +90,119 @@ const extractToolTags = (tool: unknown): string[] | undefined => { return normalized.length > 0 ? normalized : undefined; }; +const getMetadataString = (value: unknown): string | undefined => { + if (typeof value !== "string") { + return undefined; + } + const trimmed = value.trim(); + return trimmed.length > 0 ? trimmed : undefined; +}; + +const getExistingVoltAgentMetadata = (tool: unknown): Record => { + const existingMetadata = + tool && typeof tool === "object" + ? (tool as { metadata?: { voltagent?: unknown } }).metadata + : undefined; + const existingVoltAgentMetadata = existingMetadata?.voltagent; + return existingVoltAgentMetadata && typeof existingVoltAgentMetadata === "object" + ? (existingVoltAgentMetadata as Record) + : {}; +}; + +const createToolMetadataPayload = (tool: unknown): Record | undefined => { + const metadata = getVoltAgentToolMetadata(tool); + const displayName = getMetadataString(metadata?.name); + const purpose = getMetadataString(metadata?.purpose); + const tags = extractToolTags(tool); + const userMetadata = + metadata?.metadata && typeof metadata.metadata === "object" ? metadata.metadata : undefined; + const api = metadata?.api && typeof metadata.api === "object" ? metadata.api : undefined; + const voltagent = { + ...getExistingVoltAgentMetadata(tool), + ...(displayName ? { name: displayName } : {}), + ...(purpose ? { purpose } : {}), + ...(tags ? { tags } : {}), + ...(userMetadata ? { metadata: userMetadata } : {}), + ...(api ? { api } : {}), + }; + + if (Object.keys(voltagent).length === 0) { + return undefined; + } + + return { + ...((tool as { metadata?: Record } | undefined)?.metadata ?? {}), + voltagent, + }; +}; + +const mergeToolMetadata = ( + existing: ToolMetadata, + update: { + agent: ToolAgentEntry; + displayName?: string; + purpose?: string; + metadata?: Record; + tags?: string[]; + }, +): void => { + const alreadyAdded = existing.agents?.some((agent) => agent.id === update.agent.id); + if (!alreadyAdded) { + existing.agents = [...(existing.agents ?? []), update.agent]; + } + + if (update.tags && update.tags.length > 0) { + const merged = new Set([...(existing.tags ?? []), ...update.tags]); + existing.tags = Array.from(merged); + } + + existing.displayName ??= update.displayName; + existing.purpose ??= update.purpose; + existing.metadata ??= update.metadata; +}; + +const createToolListEntry = ( + tool: ListableTool, + agent: ToolAgentEntry, + parameters: unknown, +): ToolMetadata => { + const tags = extractToolTags(tool); + const metadata = getVoltAgentToolMetadata(tool); + const displayName = getMetadataString(metadata?.name); + const purpose = getMetadataString(metadata?.purpose); + const toolMetadata = createToolMetadataPayload(tool); + + return { + id: tool.id, + name: tool.name, + ...(displayName ? { displayName } : {}), + ...(purpose ? { purpose } : {}), + description: tool.description, + parameters, + status: "ready", + ...(toolMetadata ? { metadata: toolMetadata } : {}), + agents: [agent], + tags, + }; +}; + +const getToolParameters = (tool: ListableTool): unknown => { + return "parameters" in tool ? tool.parameters : undefined; +}; + +const getToolExecute = ( + tool: ListableTool, +): + | ((input: unknown, options: Record) => Promise | unknown) + | undefined => { + return "execute" in tool && typeof tool.execute === "function" + ? (tool.execute as ( + input: unknown, + options: Record, + ) => Promise | unknown) + : undefined; +}; + export async function handleListTools( deps: ServerProviderDeps, logger: Logger, @@ -88,39 +216,30 @@ export async function handleListTools( for (const tool of agentTools) { // Only expose tools that can run server-side - if (!tool?.execute) { + if (!getToolExecute(tool)) { continue; } + const toolParameters = getToolParameters(tool); const parameters = - tool.parameters && typeof tool.parameters === "object" - ? zodSchemaToJsonUI(tool.parameters) + toolParameters && typeof toolParameters === "object" + ? zodSchemaToJsonUI(toolParameters) : undefined; - const tags = extractToolTags(tool); - const existing = toolsByName.get(tool.name); const agentEntry = { id: agent.id, name: agent.name }; if (existing) { - const alreadyAdded = existing.agents?.some((a) => a.id === agentEntry.id); - if (!alreadyAdded) { - existing.agents = [...(existing.agents ?? []), agentEntry]; - } - if (tags && tags.length > 0) { - const merged = new Set([...(existing.tags ?? []), ...tags]); - existing.tags = Array.from(merged); - } - } else { - toolsByName.set(tool.name, { - id: tool.id, - name: tool.name, - description: tool.description, - parameters, - status: "ready", - agents: [agentEntry], - tags, + const metadata = getVoltAgentToolMetadata(tool); + mergeToolMetadata(existing, { + agent: agentEntry, + displayName: getMetadataString(metadata?.name), + purpose: getMetadataString(metadata?.purpose), + metadata: createToolMetadataPayload(tool), + tags: extractToolTags(tool), }); + } else { + toolsByName.set(tool.name, createToolListEntry(tool, agentEntry, parameters)); } } } @@ -164,7 +283,8 @@ export async function handleExecuteTool( const { tool, agent } = lookup; - if (!tool.execute) { + const execute = getToolExecute(tool); + if (!execute) { return { success: false, error: `Tool ${toolName} cannot be executed on the server`, @@ -174,12 +294,14 @@ export async function handleExecuteTool( // Validate input using Zod if available let parsedInput = input; - if (tool.parameters && isZodLikeSchema(tool.parameters)) { - const parsed = tool.parameters.safeParse(input ?? {}); + const toolParameters = getToolParameters(tool); + if (toolParameters && isZodLikeSchema(toolParameters)) { + const parsed = toolParameters.safeParse(input ?? {}); if (!parsed.success) { + const parseError = parsed.error as { format?: () => unknown; issues?: unknown }; return { success: false, - error: `Invalid tool input: ${safeStringify(parsed.error.format ? parsed.error.format() : (parsed.error.issues ?? parsed.error))}`, + error: `Invalid tool input: ${safeStringify(parseError.format ? parseError.format() : (parseError.issues ?? parseError))}`, httpStatus: 400, }; } @@ -197,7 +319,7 @@ export async function handleExecuteTool( body?.conversationId; // Build a minimal execution context for tools - const result = await tool.execute(parsedInput, { + const result = await execute(parsedInput, { userId, conversationId, context: contextMap, diff --git a/packages/server-core/src/schemas/agent.schemas.ts b/packages/server-core/src/schemas/agent.schemas.ts index 100b70288..2dea8a913 100644 --- a/packages/server-core/src/schemas/agent.schemas.ts +++ b/packages/server-core/src/schemas/agent.schemas.ts @@ -171,6 +171,16 @@ export function createServerCoreSchemas(zod: ZodNamespace = defaultZ) { .passthrough() .describe("Feedback options for the generated trace"); + const ToolApprovalStatusSchema = z.union([ + z.enum(["not-applicable", "approved", "denied", "user-approval"]), + z + .object({ + type: z.enum(["not-applicable", "approved", "denied", "user-approval"]), + reason: z.string().optional(), + }) + .passthrough(), + ]); + const SemanticMemoryOptionsSchema = z .object({ enabled: z @@ -268,9 +278,78 @@ export function createServerCoreSchemas(zod: ZodNamespace = defaultZ) { }) .passthrough(); + const VoltAgentRuntimeOptionsSchema: defaultZ.ZodTypeAny = z + .object({ + memory: RuntimeMemoryEnvelopeSchema.optional().describe( + "Runtime memory envelope for this call", + ), + userId: z.string().optional().describe("Deprecated: use voltagent.memory.userId"), + conversationId: z + .string() + .optional() + .describe("Deprecated: use voltagent.memory.conversationId"), + context: z + .record(z.string(), z.unknown()) + .nullish() + .describe("User context for dynamic agent behavior"), + requestHeaders: z + .record(z.string(), z.string()) + .optional() + .describe("Request headers for runtime callbacks; server request headers take precedence"), + contextLimit: z + .number() + .int() + .positive() + .optional() + .describe("Deprecated: use voltagent.memory.options.contextLimit"), + semanticMemory: SemanticMemoryOptionsSchema.optional().describe( + "Deprecated: use voltagent.memory.options.semanticMemory", + ), + conversationPersistence: ConversationPersistenceOptionsSchema.optional().describe( + "Deprecated: use voltagent.memory.options.conversationPersistence", + ), + messageMetadataPersistence: MessageMetadataPersistenceConfigSchema.optional().describe( + "Deprecated: use voltagent.memory.options.messageMetadataPersistence", + ), + maxSteps: z.number().int().positive().optional().describe("Maximum steps for this request"), + feedback: z + .union([z.boolean(), FeedbackOptionsSchema]) + .optional() + .describe("Enable or configure feedback tokens for the trace"), + resumableStream: z + .boolean() + .optional() + .describe("When true, avoids wiring the HTTP abort signal into resumable streams"), + toolRouting: z + .union([z.literal(false), z.record(z.string(), z.unknown())]) + .optional() + .describe("Per-call tool routing override"), + guardrails: z + .object({ + input: z.array(z.unknown()).optional(), + output: z.array(z.unknown()).optional(), + }) + .passthrough() + .optional() + .describe("Per-call guardrail overrides"), + middleware: z + .object({ + input: z.array(z.unknown()).optional(), + output: z.array(z.unknown()).optional(), + maxRetries: z.number().int().min(0).optional(), + }) + .passthrough() + .optional() + .describe("Per-call middleware overrides"), + }) + .passthrough(); + // Generation options schema - const GenerateOptionsSchema = z + const GenerateOptionsSchema: defaultZ.ZodTypeAny = z .object({ + voltagent: VoltAgentRuntimeOptionsSchema.optional().describe( + "VoltAgent runtime-specific options. Values here override legacy top-level runtime options during the transition.", + ), memory: RuntimeMemoryEnvelopeSchema.optional().describe( "Runtime memory envelope (preferred): memory.userId/memory.conversationId + memory.options.*", ), @@ -348,6 +427,16 @@ export function createServerCoreSchemas(zod: ZodNamespace = defaultZ) { .describe( "Provider-specific options for AI SDK providers (e.g., OpenAI's reasoningEffort)", ), + toolApproval: z + .record(z.string(), ToolApprovalStatusSchema) + .optional() + .describe( + "AI SDK native per-tool approval status map. Use 'user-approval', 'approved', 'denied', or 'not-applicable'. Function approvals are only available when calling the Agent directly in code.", + ), + experimental_toolApprovalSecret: z + .string() + .optional() + .describe("Secret used by AI SDK to sign native tool approval requests"), resumableStream: z .boolean() .optional() diff --git a/packages/server-core/src/utils/options.ts b/packages/server-core/src/utils/options.ts index 2582d59c6..2ebfef501 100644 --- a/packages/server-core/src/utils/options.ts +++ b/packages/server-core/src/utils/options.ts @@ -1,9 +1,27 @@ import { Output } from "ai"; -import { z } from "zod"; import { convertJsonSchemaToZod } from "zod-from-json-schema"; -import { convertJsonSchemaToZod as convertJsonSchemaToZodV3 } from "zod-from-json-schema-v3"; type RequestHeadersInput = Headers | Record; +type RuntimeOptionsInput = Record & { + voltagent?: + | (Record & { + guardrails?: { + input?: unknown; + output?: unknown; + }; + middleware?: { + input?: unknown; + output?: unknown; + maxRetries?: number; + }; + inputGuardrails?: unknown; + outputGuardrails?: unknown; + inputMiddlewares?: unknown; + outputMiddlewares?: unknown; + maxMiddlewareRetries?: number; + }) + | null; +}; function normalizeRequestHeaders( headers?: RequestHeadersInput, @@ -31,6 +49,48 @@ function normalizeRequestHeaders( return Object.keys(normalized).length > 0 ? normalized : undefined; } +function normalizeVoltAgentRuntimeOptions(options: RuntimeOptionsInput): Record { + if (!("voltagent" in options)) { + return options; + } + + const { voltagent, ...legacyOptions } = options; + if (!voltagent) { + return legacyOptions; + } + + const { + guardrails, + middleware, + inputGuardrails, + outputGuardrails, + inputMiddlewares, + outputMiddlewares, + maxMiddlewareRetries, + ...runtimeOptions + } = voltagent; + + return { + ...legacyOptions, + ...runtimeOptions, + ...(guardrails?.input !== undefined || inputGuardrails !== undefined + ? { inputGuardrails: guardrails?.input ?? inputGuardrails } + : {}), + ...(guardrails?.output !== undefined || outputGuardrails !== undefined + ? { outputGuardrails: guardrails?.output ?? outputGuardrails } + : {}), + ...(middleware?.input !== undefined || inputMiddlewares !== undefined + ? { inputMiddlewares: middleware?.input ?? inputMiddlewares } + : {}), + ...(middleware?.output !== undefined || outputMiddlewares !== undefined + ? { outputMiddlewares: middleware?.output ?? outputMiddlewares } + : {}), + ...(middleware?.maxRetries !== undefined || maxMiddlewareRetries !== undefined + ? { maxMiddlewareRetries: middleware?.maxRetries ?? maxMiddlewareRetries } + : {}), + }; +} + /** * Process agent options from request body */ @@ -96,7 +156,7 @@ export function processAgentOptions( requestHeaders?: RequestHeadersInput, ): ProcessedAgentOptions { // Now all options should be in body.options, no need to merge from root - const options = body.options || {}; + const options = normalizeVoltAgentRuntimeOptions(body.options || {}); const normalizedRequestHeaders = normalizeRequestHeaders(requestHeaders); const processedOptions: ProcessedAgentOptions = { @@ -117,10 +177,7 @@ export function processAgentOptions( const { type, schema: jsonSchema } = options.output; if (type === "object" && jsonSchema) { - // Convert JSON schema to Zod schema (supports zod v3 and v4) - const zodSchema = ("toJSONSchema" in z ? convertJsonSchemaToZod : convertJsonSchemaToZodV3)( - jsonSchema, - ) as any; + const zodSchema = convertJsonSchemaToZod(jsonSchema) as any; processedOptions.output = Output.object({ schema: zodSchema }); } else if (type === "text") { diff --git a/packages/server-core/tsup.config.ts b/packages/server-core/tsup.config.ts index 52ba7850f..ae407acbe 100644 --- a/packages/server-core/tsup.config.ts +++ b/packages/server-core/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts", "src/edge.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/server-elysia/CHANGELOG.md b/packages/server-elysia/CHANGELOG.md index ce6cbe4be..e77855724 100644 --- a/packages/server-elysia/CHANGELOG.md +++ b/packages/server-elysia/CHANGELOG.md @@ -1,5 +1,234 @@ # @voltagent/server-elysia +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/a2a-server@3.0.0-next.0 + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + - @voltagent/mcp-server@3.0.0-next.0 + - @voltagent/resumable-streams@3.0.0-next.0 + - @voltagent/server-core@3.0.0-next.0 + ## 2.0.9 ### Patch Changes diff --git a/packages/server-elysia/THIRD_PARTY_NOTICES.md b/packages/server-elysia/THIRD_PARTY_NOTICES.md index e37cba626..4738d28e4 100644 --- a/packages/server-elysia/THIRD_PARTY_NOTICES.md +++ b/packages/server-elysia/THIRD_PARTY_NOTICES.md @@ -29,12 +29,6 @@ This package includes or depends upon third-party code. The following is a list - **License**: MIT - **Repository**: https://github.com/colinhacks/zod -## zod-to-json-schema - -- **License**: MIT -- **Repository**: https://github.com/StefanTerdell/zod-to-json-schema -- **Copyright**: Copyright (c) 2023 Stefan Terdell - ## VoltAgent Core Packages - **License**: MIT diff --git a/packages/server-elysia/example/package.json b/packages/server-elysia/example/package.json index ce0666154..411b56b19 100644 --- a/packages/server-elysia/example/package.json +++ b/packages/server-elysia/example/package.json @@ -9,7 +9,7 @@ "@voltagent/core": "file:../../core", "@voltagent/server-elysia": "file:..", "elysia": "^1.1.29", - "zod": "^3.24.1" + "zod": "^4.1.11" }, "devDependencies": { "tsx": "^4.7.1", diff --git a/packages/server-elysia/package.json b/packages/server-elysia/package.json index d7e2f3dca..0ad15f8bc 100644 --- a/packages/server-elysia/package.json +++ b/packages/server-elysia/package.json @@ -1,34 +1,28 @@ { "name": "@voltagent/server-elysia", "description": "Elysia server implementation for VoltAgent", - "version": "2.0.9", + "version": "3.0.0-next.0", "dependencies": { "@elysiajs/cors": "^1.2.2", "@elysiajs/swagger": "^1.2.4", "@sinclair/typebox": "^0.34.45", - "@voltagent/a2a-server": "^2.0.3", - "@voltagent/core": "^2.7.6", - "@voltagent/internal": "^1.0.2", - "@voltagent/mcp-server": "^2.0.2", - "@voltagent/resumable-streams": "^2.0.1", - "@voltagent/server-core": "^2.1.18", + "@voltagent/a2a-server": "^3.0.0-next.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/internal": "^2.0.0-next.0", + "@voltagent/mcp-server": "^3.0.0-next.0", + "@voltagent/resumable-streams": "^3.0.0-next.0", + "@voltagent/server-core": "^3.0.0-next.0", "elysia": "^1.1.29", - "zod": "^3.25.76", - "zod-to-json-schema": "^3.25.1" + "zod": "^4.1.11" }, "devDependencies": { "@types/ws": "^8.18.1" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -36,9 +30,9 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", + "@voltagent/core": "^3.0.0-next.0", "elysia": "^1.x" }, "scripts": { @@ -47,5 +41,6 @@ "test": "vitest", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/server-elysia/src/elysia-server-provider.spec.ts b/packages/server-elysia/src/elysia-server-provider.spec.ts index 3355ed96c..157717c4b 100644 --- a/packages/server-elysia/src/elysia-server-provider.spec.ts +++ b/packages/server-elysia/src/elysia-server-provider.spec.ts @@ -3,6 +3,25 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import * as appFactory from "./app-factory"; import { ElysiaServerProvider } from "./elysia-server-provider"; +const { mockCreateServer, mockHttpServer } = vi.hoisted(() => { + const server = { + once: vi.fn(), + listen: vi.fn((_port: number, _hostname: string, callback?: () => void) => { + callback?.(); + return server; + }), + close: vi.fn((callback?: (error?: Error) => void) => { + callback?.(); + }), + listening: true, + }; + + return { + mockCreateServer: vi.fn(() => server), + mockHttpServer: server, + }; +}); + // Mock dependencies vi.mock("@voltagent/server-core", async () => { const actual = await vi.importActual("@voltagent/server-core"); @@ -19,10 +38,13 @@ vi.mock("@voltagent/server-core", async () => { }; }); +vi.mock("node:http", () => ({ + createServer: mockCreateServer, +})); + describe("ElysiaServerProvider", () => { let provider: ElysiaServerProvider; const mockApp = { - listen: vi.fn().mockReturnValue({}), stop: vi.fn(), routes: [], // For extractCustomEndpoints get: vi.fn(), // For configureApp test @@ -44,6 +66,18 @@ describe("ElysiaServerProvider", () => { beforeEach(() => { vi.spyOn(appFactory, "createApp").mockResolvedValue({ app: mockApp } as any); + mockCreateServer.mockReturnValue(mockHttpServer); + mockHttpServer.once.mockReturnValue(mockHttpServer); + mockHttpServer.listen.mockImplementation( + (_port: number, _hostname: string, callback?: () => void) => { + callback?.(); + return mockHttpServer; + }, + ); + mockHttpServer.close.mockImplementation((callback?: (error?: Error) => void) => { + callback?.(); + }); + mockHttpServer.listening = true; provider = new ElysiaServerProvider(mockDeps, { port: 3000 }); }); @@ -55,16 +89,16 @@ describe("ElysiaServerProvider", () => { it("should start the server", async () => { await provider.start(); expect(appFactory.createApp).toHaveBeenCalled(); - expect(mockApp.listen).toHaveBeenCalledWith({ - port: 3000, - hostname: "0.0.0.0", - }); + expect(mockCreateServer).toHaveBeenCalledWith(expect.any(Function)); + expect(mockHttpServer.once).toHaveBeenCalledWith("error", expect.any(Function)); + expect(mockHttpServer.listen).toHaveBeenCalledWith(3000, "0.0.0.0", expect.any(Function)); }); it("should stop the server", async () => { await provider.start(); await provider.stop(); expect(mockApp.stop).toHaveBeenCalled(); + expect(mockHttpServer.close).toHaveBeenCalledWith(expect.any(Function)); }); it("should throw if already running", async () => { @@ -84,7 +118,6 @@ describe("ElysiaServerProvider", () => { // Create a fresh mock app for this test to avoid pollution const localMockApp = { - listen: vi.fn().mockReturnValue({}), stop: vi.fn(), routes: [{ method: "GET", path: "/custom-test" }], get: vi.fn(), @@ -112,8 +145,7 @@ describe("ElysiaServerProvider", () => { }); it("should handle startup errors and release port", async () => { - // Mock app.listen to throw - mockApp.listen.mockImplementationOnce(() => { + mockHttpServer.listen.mockImplementationOnce(() => { throw new Error("Startup failed"); }); diff --git a/packages/server-elysia/src/elysia-server-provider.ts b/packages/server-elysia/src/elysia-server-provider.ts index 50e05169c..bc736c286 100644 --- a/packages/server-elysia/src/elysia-server-provider.ts +++ b/packages/server-elysia/src/elysia-server-provider.ts @@ -59,7 +59,7 @@ export class ElysiaServerProvider extends BaseServerProvider { } as RequestInit); const response = await app.fetch(request); res.statusCode = response.status; - response.headers.forEach((value, key) => { + response.headers.forEach((value: string, key: string) => { res.setHeader(key, value); }); if (response.body) { diff --git a/packages/server-elysia/src/utils/zod-adapter.ts b/packages/server-elysia/src/utils/zod-adapter.ts index 5e2785774..a1f89f38f 100644 --- a/packages/server-elysia/src/utils/zod-adapter.ts +++ b/packages/server-elysia/src/utils/zod-adapter.ts @@ -1,6 +1,5 @@ import { type TSchema, Type } from "@sinclair/typebox"; -import type { ZodType, ZodTypeDef } from "zod"; -import { zodToJsonSchema } from "zod-to-json-schema"; +import { type ZodType, z } from "zod"; function getOptions(schema: any) { const options = { ...schema }; @@ -55,7 +54,11 @@ function mapJsonSchemaToTypeBox(schema: any): TSchema { switch (schema.type) { case "object": { const properties: Record = {}; - const required = new Set(schema.required || []); + const required = new Set( + (schema.required || []).filter( + (key: string) => schema.properties?.[key]?.default === undefined, + ), + ); if (schema.properties) { for (const [key, value] of Object.entries(schema.properties)) { @@ -114,10 +117,12 @@ function mapJsonSchemaToTypeBox(schema: any): TSchema { * This allows us to reuse Zod schemas from @voltagent/server-core * while maintaining Elysia's TypeBox-based validation pipeline. */ -export function zodToTypeBox>(zodSchema: T): TSchema { - const jsonSchema = zodToJsonSchema(zodSchema, { - target: "jsonSchema7", - $refStrategy: "none", +export function zodToTypeBox(zodSchema: T): TSchema { + const jsonSchema = z.toJSONSchema(zodSchema, { + target: "draft-7", + unrepresentable: "any", + reused: "inline", + cycles: "throw", }); return mapJsonSchemaToTypeBox(jsonSchema); diff --git a/packages/server-elysia/tsup.config.ts b/packages/server-elysia/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/server-elysia/tsup.config.ts +++ b/packages/server-elysia/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/server-hono/CHANGELOG.md b/packages/server-hono/CHANGELOG.md index 2fa119c0f..4da3f51e7 100644 --- a/packages/server-hono/CHANGELOG.md +++ b/packages/server-hono/CHANGELOG.md @@ -1,5 +1,234 @@ # @voltagent/server-hono +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/a2a-server@3.0.0-next.0 + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + - @voltagent/mcp-server@3.0.0-next.0 + - @voltagent/resumable-streams@3.0.0-next.0 + - @voltagent/server-core@3.0.0-next.0 + ## 2.0.14 ### Patch Changes diff --git a/packages/server-hono/package.json b/packages/server-hono/package.json index bd4cd9797..5ea515ac0 100644 --- a/packages/server-hono/package.json +++ b/packages/server-hono/package.json @@ -1,34 +1,29 @@ { "name": "@voltagent/server-hono", "description": "Hono server implementation for VoltAgent", - "version": "2.0.14", + "version": "3.0.0-next.0", "dependencies": { "@hono/node-server": "^1.14.0", "@hono/swagger-ui": "^0.5.1", - "@voltagent/a2a-server": "^2.0.3", - "@voltagent/core": "^2.7.6", - "@voltagent/internal": "^1.0.2", - "@voltagent/mcp-server": "^2.0.2", - "@voltagent/resumable-streams": "^2.0.1", - "@voltagent/server-core": "^2.1.18", + "@voltagent/a2a-server": "^3.0.0-next.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/internal": "^2.0.0-next.0", + "@voltagent/mcp-server": "^3.0.0-next.0", + "@voltagent/resumable-streams": "^3.0.0-next.0", + "@voltagent/server-core": "^3.0.0-next.0", "fetch-to-node": "^2.1.0", "hono": "^4.7.7", "openapi3-ts": "^4.5.0" }, "devDependencies": { "@types/ws": "^8.18.1", - "zod": "^3.25.76" + "zod": "^4.1.11" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -36,10 +31,10 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "zod": "^3.25.0 || ^4.0.0" + "@voltagent/core": "^3.0.0-next.0", + "zod": "^4.0.0" }, "repository": { "type": "git", @@ -52,5 +47,6 @@ "test": "vitest", "typecheck": "tsc --noEmit" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/server-hono/src/routes/agent.routes.ts b/packages/server-hono/src/routes/agent.routes.ts index 47e846c5a..727e432df 100644 --- a/packages/server-hono/src/routes/agent.routes.ts +++ b/packages/server-hono/src/routes/agent.routes.ts @@ -554,8 +554,8 @@ export const workspaceReadFileRoute = createRoute({ }), query: z.object({ path: z.string().describe("File path to read"), - offset: z.number({ coerce: true }).optional().describe("Line offset (0-indexed)"), - limit: z.number({ coerce: true }).optional().describe("Max lines to read"), + offset: z.coerce.number().optional().describe("Line offset (0-indexed)"), + limit: z.coerce.number().optional().describe("Max lines to read"), }), }, responses: { @@ -616,7 +616,7 @@ export const workspaceListSkillsRoute = createRoute({ id: agentIdParam(), }), query: z.object({ - refresh: z.boolean({ coerce: true }).optional().describe("Refresh skill discovery"), + refresh: z.coerce.boolean().optional().describe("Refresh skill discovery"), }), }, responses: { diff --git a/packages/server-hono/src/routes/index.ts b/packages/server-hono/src/routes/index.ts index e40bb60d1..41cbdfa46 100644 --- a/packages/server-hono/src/routes/index.ts +++ b/packages/server-hono/src/routes/index.ts @@ -58,7 +58,6 @@ import { workspaceReadFileRoute, } from "./agent.routes"; import { getLogsRoute } from "./log.routes"; -import { registerTriggerRoutes } from "./trigger.routes"; export { registerMcpRoutes } from "./mcp.routes"; export { registerA2ARoutes } from "./a2a.routes"; export { registerToolRoutes } from "./tool.routes"; diff --git a/packages/server-hono/src/routes/memory.routes.ts b/packages/server-hono/src/routes/memory.routes.ts index 44e4ff58e..5ede11464 100644 --- a/packages/server-hono/src/routes/memory.routes.ts +++ b/packages/server-hono/src/routes/memory.routes.ts @@ -41,6 +41,14 @@ function parseDate(value?: string): Date | undefined { return Number.isNaN(parsed.getTime()) ? undefined : parsed; } +type JsonResponder = { + json: (data: any, status?: any, headers?: any) => any; +}; + +function jsonResponse(c: JsonResponder, response: unknown, status: number) { + return c.json(response, status); +} + const orderByAllowlist = new Set(["created_at", "updated_at", "title"]); function parseOrderBy(value?: string): "created_at" | "updated_at" | "title" | undefined { @@ -91,7 +99,7 @@ export function registerMemoryRoutes( orderDirection: parseOrderDirection(query.orderDirection), }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.get(MEMORY_ROUTES.getConversation.path, async (c) => { @@ -101,7 +109,7 @@ export function registerMemoryRoutes( const response = await handleGetMemoryConversation(deps, conversationId, { agentId: query.agentId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.get(MEMORY_ROUTES.listMessages.path, async (c) => { @@ -118,7 +126,7 @@ export function registerMemoryRoutes( roles: query.roles ? query.roles.split(",") : undefined, userId: query.userId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.get(memoryWorkingMemoryPath, async (c) => { @@ -133,7 +141,7 @@ export function registerMemoryRoutes( scope: query.scope === "user" ? "user" : "conversation", userId: query.userId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.post(MEMORY_ROUTES.saveMessages.path, async (c) => { @@ -143,7 +151,7 @@ export function registerMemoryRoutes( body = await c.req.json(); } catch (error) { logger.warn("Invalid JSON body for save messages", { error }); - return c.json({ success: false, error: "Invalid JSON body" }, 400); + return jsonResponse(c, { success: false, error: "Invalid JSON body" }, 400); } logger.trace("POST /api/memory/save-messages - saving messages", { messageCount: Array.isArray(body?.messages) ? body.messages.length : 0, @@ -152,7 +160,7 @@ export function registerMemoryRoutes( ...body, agentId: body?.agentId ?? query.agentId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.post(MEMORY_ROUTES.createConversation.path, async (c) => { @@ -162,14 +170,14 @@ export function registerMemoryRoutes( body = await c.req.json(); } catch (error) { logger.warn("Invalid JSON body for create conversation", { error }); - return c.json({ success: false, error: "Invalid JSON body" }, 400); + return jsonResponse(c, { success: false, error: "Invalid JSON body" }, 400); } logger.trace("POST /api/memory/conversations - creating conversation"); const response = await handleCreateMemoryConversation(deps, { ...body, agentId: body?.agentId ?? query.agentId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.patch(MEMORY_ROUTES.updateConversation.path, async (c) => { @@ -180,14 +188,14 @@ export function registerMemoryRoutes( body = await c.req.json(); } catch (error) { logger.warn("Invalid JSON body for update conversation", { error, conversationId }); - return c.json({ success: false, error: "Invalid JSON body" }, 400); + return jsonResponse(c, { success: false, error: "Invalid JSON body" }, 400); } logger.trace(`PATCH /api/memory/conversations/${conversationId} - updating conversation`); const response = await handleUpdateMemoryConversation(deps, conversationId, { ...body, agentId: body?.agentId ?? query.agentId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.delete(MEMORY_ROUTES.deleteConversation.path, async (c) => { @@ -197,7 +205,7 @@ export function registerMemoryRoutes( const response = await handleDeleteMemoryConversation(deps, conversationId, { agentId: query.agentId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.post(MEMORY_ROUTES.cloneConversation.path, async (c) => { @@ -208,14 +216,14 @@ export function registerMemoryRoutes( body = await c.req.json(); } catch (error) { logger.warn("Invalid JSON body for clone conversation", { error, conversationId }); - return c.json({ success: false, error: "Invalid JSON body" }, 400); + return jsonResponse(c, { success: false, error: "Invalid JSON body" }, 400); } logger.trace(`POST /api/memory/conversations/${conversationId}/clone - cloning conversation`); const response = await handleCloneMemoryConversation(deps, conversationId, { ...body, agentId: body?.agentId ?? query.agentId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.post(MEMORY_ROUTES.updateWorkingMemory.path, async (c) => { @@ -226,7 +234,7 @@ export function registerMemoryRoutes( body = await c.req.json(); } catch (error) { logger.warn("Invalid JSON body for update working memory", { error, conversationId }); - return c.json({ success: false, error: "Invalid JSON body" }, 400); + return jsonResponse(c, { success: false, error: "Invalid JSON body" }, 400); } logger.trace( `POST /api/memory/conversations/${conversationId}/working-memory - updating working memory`, @@ -235,7 +243,7 @@ export function registerMemoryRoutes( ...body, agentId: body?.agentId ?? query.agentId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.post(MEMORY_ROUTES.deleteMessages.path, async (c) => { @@ -245,14 +253,14 @@ export function registerMemoryRoutes( body = await c.req.json(); } catch (error) { logger.warn("Invalid JSON body for delete messages", { error }); - return c.json({ success: false, error: "Invalid JSON body" }, 400); + return jsonResponse(c, { success: false, error: "Invalid JSON body" }, 400); } logger.trace("POST /api/memory/messages/delete - deleting messages"); const response = await handleDeleteMemoryMessages(deps, { ...body, agentId: body?.agentId ?? query.agentId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); app.get(MEMORY_ROUTES.searchMemory.path, async (c) => { @@ -266,6 +274,6 @@ export function registerMemoryRoutes( conversationId: query.conversationId, userId: query.userId, }); - return c.json(response, response.success ? 200 : (response.httpStatus ?? 500)); + return jsonResponse(c, response, response.success ? 200 : (response.httpStatus ?? 500)); }); } diff --git a/packages/server-hono/src/routes/path-params.ts b/packages/server-hono/src/routes/path-params.ts index 8d07a903d..48cb6b3b3 100644 --- a/packages/server-hono/src/routes/path-params.ts +++ b/packages/server-hono/src/routes/path-params.ts @@ -12,8 +12,11 @@ export const createPathParam = (name: string, description: string, example?: str const baseSchema = z.string().min(1); const schemaWithMetadata = baseSchema.openapi(`PathParam.${name}`, metadata); - if (typeof schemaWithMetadata.meta === "function") { - return schemaWithMetadata.meta(metadata); + const schemaWithOptionalMeta = schemaWithMetadata as typeof schemaWithMetadata & { + meta?: (metadata: Record) => typeof schemaWithMetadata; + }; + if (typeof schemaWithOptionalMeta.meta === "function") { + return schemaWithOptionalMeta.meta(metadata); } return schemaWithMetadata; }; diff --git a/packages/server-hono/src/routes/tool.routes.ts b/packages/server-hono/src/routes/tool.routes.ts index fc2c32a41..ee268f67f 100644 --- a/packages/server-hono/src/routes/tool.routes.ts +++ b/packages/server-hono/src/routes/tool.routes.ts @@ -15,9 +15,12 @@ const toolNameParam = () => createPathParam("name", "The name of the tool", "web const ToolDefinitionSchema = z.object({ id: z.string().optional(), name: z.string(), + displayName: z.string().optional(), + purpose: z.string().optional(), description: z.string().optional(), parameters: z.record(z.string(), z.any()).optional(), status: z.string().optional(), + metadata: z.record(z.string(), z.any()).optional(), agents: z .array( z.object({ diff --git a/packages/server-hono/src/zod-openapi-compat.ts b/packages/server-hono/src/zod-openapi-compat.ts index 28dc8c3ba..bfbd901cd 100644 --- a/packages/server-hono/src/zod-openapi-compat.ts +++ b/packages/server-hono/src/zod-openapi-compat.ts @@ -1,66 +1,38 @@ /** - * Compatibility layer for the vendored @hono/zod-openapi implementations to support both Zod v3 and v4 + * Compatibility layer for the vendored @hono/zod-openapi implementation. * - * This module provides a unified interface that works with both Zod versions. - * It will automatically select the appropriate upstream implementation - * based on the installed Zod version in the project. - * - * - Zod v3: Uses vendored @hono/zod-openapi 0.19.10 - * - Zod v4: Uses vendored @hono/zod-openapi 1.1.0+ + * VoltAgent 3 is Zod 4-only, so this module always exposes the vendored + * @hono/zod-openapi implementation that targets Zod 4. */ -import { z as zodBase } from "zod"; -import * as zodOpenApiV3 from "./vendor/zod-openapi/v3"; -import * as zodOpenApiV4 from "./vendor/zod-openapi/v4"; - -const isZodV4 = (() => { - const testSchema = zodBase.string(); - const candidate = testSchema as unknown as { - toJSON?: (() => unknown) | undefined; - toJSONSchema?: (() => unknown) | undefined; - }; - if (typeof candidate.toJSON === "function" || typeof candidate.toJSONSchema === "function") { - return true; - } - return "toJSONSchema" in zodBase; -})(); +import * as zodOpenApi from "./vendor/zod-openapi/v4"; -export const __isZodV4 = isZodV4; +export const __isZodV4 = true; // Expose detection result for debugging/testing scenarios if (typeof globalThis !== "undefined") { try { // eslint-disable-next-line @typescript-eslint/no-explicit-any - (globalThis as any).__VOLT_ZOD_IS_V4 = isZodV4; + (globalThis as any).__VOLT_ZOD_IS_V4 = true; } catch { // ignore errors when globalThis is not writable (e.g., strict sandbox) } } -type ModuleExportsV3 = typeof import("./vendor/zod-openapi/v3"); -type CompatibleModule = Pick; +type OpenAPIHonoCtor = typeof zodOpenApi.OpenAPIHono; -const selectedModule = ( - isZodV4 ? (zodOpenApiV4 as unknown as ModuleExportsV3) : zodOpenApiV3 -) as CompatibleModule; - -type OpenAPIHonoCtor = CompatibleModule["OpenAPIHono"]; +const openApiZ = zodOpenApi.z; // Ensure metadata added via .openapi is also mirrored into Zod's meta storage so that // environments loading multiple module formats (ESM/CJS) can still retrieve parameter // information without relying solely on the internal registry instance. -const originalOpenApi = selectedModule.z.ZodType.prototype.openapi; -selectedModule.z.ZodType.prototype.openapi = function proxyOpenApi( +const originalOpenApi = openApiZ.ZodType.prototype.openapi as (...args: unknown[]) => unknown; +openApiZ.ZodType.prototype.openapi = function proxyOpenApi( refOrMetadata: unknown, metadataOrOptions?: unknown, maybeOptions?: unknown, ) { - const result = originalOpenApi.call( - this, - refOrMetadata as never, - metadataOrOptions as never, - maybeOptions as never, - ); + const result = originalOpenApi.apply(this, [refOrMetadata, metadataOrOptions, maybeOptions]); const metadata = typeof refOrMetadata === "string" @@ -86,7 +58,10 @@ selectedModule.z.ZodType.prototype.openapi = function proxyOpenApi( return result; }; -export const OpenAPIHono = selectedModule.OpenAPIHono; -export const createRoute = selectedModule.createRoute; -export const z = selectedModule.z; -export type OpenAPIHonoType = InstanceType; +export const OpenAPIHono = zodOpenApi.OpenAPIHono; +export const createRoute = zodOpenApi.createRoute; +export const z = openApiZ; +type OpenAPIHonoInstance = InstanceType; +export type OpenAPIHonoType = Omit & { + openapi: (route: any, handler: (c: any) => any) => any; +}; diff --git a/packages/server-hono/tsup.config.ts b/packages/server-hono/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/server-hono/tsup.config.ts +++ b/packages/server-hono/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/serverless-hono/CHANGELOG.md b/packages/serverless-hono/CHANGELOG.md index e06d66a06..cb410d425 100644 --- a/packages/serverless-hono/CHANGELOG.md +++ b/packages/serverless-hono/CHANGELOG.md @@ -1,5 +1,232 @@ # @voltagent/serverless-hono +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + - @voltagent/resumable-streams@3.0.0-next.0 + - @voltagent/server-core@3.0.0-next.0 + ## 2.0.12 ### Patch Changes diff --git a/packages/serverless-hono/package.json b/packages/serverless-hono/package.json index 2188c9767..9aa6bf193 100644 --- a/packages/serverless-hono/package.json +++ b/packages/serverless-hono/package.json @@ -1,11 +1,11 @@ { "name": "@voltagent/serverless-hono", "description": "Serverless (fetch-based) runtime provider for VoltAgent using Hono", - "version": "2.0.12", + "version": "3.0.0-next.0", "dependencies": { - "@voltagent/internal": "^1.0.2", - "@voltagent/resumable-streams": "^2.0.1", - "@voltagent/server-core": "^2.1.18", + "@voltagent/internal": "^2.0.0-next.0", + "@voltagent/resumable-streams": "^3.0.0-next.0", + "@voltagent/server-core": "^3.0.0-next.0", "hono": "^4.7.7" }, "devDependencies": {}, @@ -23,8 +23,8 @@ "main": "dist/index.js", "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "@voltagent/server-core": "^2.0.0", + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/server-core": "^3.0.0-next.0", "hono": "^4.0.0" }, "repository": { diff --git a/packages/supabase/CHANGELOG.md b/packages/supabase/CHANGELOG.md index 146f695c6..9761dd490 100644 --- a/packages/supabase/CHANGELOG.md +++ b/packages/supabase/CHANGELOG.md @@ -1,5 +1,231 @@ # @voltagent/supabase +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + - @voltagent/logger@3.0.0-next.0 + ## 2.1.3 ### Patch Changes diff --git a/packages/supabase/package.json b/packages/supabase/package.json index bb9f3fb25..3328f5b12 100644 --- a/packages/supabase/package.json +++ b/packages/supabase/package.json @@ -1,28 +1,23 @@ { "name": "@voltagent/supabase", "description": "VoltAgent Supabase - Supabase Memory provider integration for VoltAgent", - "version": "2.1.3", + "version": "3.0.0-next.0", "dependencies": { "@supabase/supabase-js": "^2.49.4", - "@voltagent/internal": "^1.0.2", + "@voltagent/internal": "^2.0.0-next.0", "ts-pattern": "^5.7.1" }, "devDependencies": { "@vitest/coverage-v8": "^3.2.4", - "@voltagent/core": "^2.4.4", - "@voltagent/logger": "^2.0.2", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "ai": "^7.0.0" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -30,11 +25,11 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "@voltagent/logger": "^2.0.0", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "@voltagent/logger": "^3.0.0-next.0", + "ai": "^7.0.0" }, "repository": { "type": "git", @@ -51,5 +46,6 @@ "test": "vitest --reporter=hanging-process --reporter=default --typecheck", "test:coverage": "vitest run --coverage --typecheck" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/supabase/src/memory-adapter.ts b/packages/supabase/src/memory-adapter.ts index 7ce94542f..71c1974e5 100644 --- a/packages/supabase/src/memory-adapter.ts +++ b/packages/supabase/src/memory-adapter.ts @@ -693,7 +693,13 @@ END OF MIGRATION SQL } if (row.type === "image") { - parts = [{ type: "image", image: content }]; + parts = [ + { + type: "file", + data: content, + mediaType: "image", + }, + ]; } else { parts = [{ type: "text", text: content }]; } diff --git a/packages/supabase/tsup.config.ts b/packages/supabase/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/supabase/tsup.config.ts +++ b/packages/supabase/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/vercel-ai-exporter/CHANGELOG.md b/packages/vercel-ai-exporter/CHANGELOG.md index 7cb19c137..18c48758a 100644 --- a/packages/vercel-ai-exporter/CHANGELOG.md +++ b/packages/vercel-ai-exporter/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/vercel-ai-exporter +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/sdk@3.0.0-next.0 + ## 2.0.2 ### Patch Changes diff --git a/packages/vercel-ai-exporter/package.json b/packages/vercel-ai-exporter/package.json index a5e5fad31..5c1e80463 100644 --- a/packages/vercel-ai-exporter/package.json +++ b/packages/vercel-ai-exporter/package.json @@ -1,26 +1,21 @@ { "name": "@voltagent/vercel-ai-exporter", "description": "OpenTelemetry exporter for VoltAgent observability with Vercel AI SDK", - "version": "2.0.2", + "version": "3.0.0-next.0", "author": "VoltAgent Team", "dependencies": { "@opentelemetry/core": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", - "@voltagent/sdk": "^2.0.2" + "@voltagent/sdk": "^3.0.0-next.0" }, "devDependencies": { - "@voltagent/core": "^2.0.2" + "@voltagent/core": "^3.0.0-next.0" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -36,10 +31,10 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "ai": "^7.0.0" }, "publishConfig": { "access": "public" @@ -59,5 +54,6 @@ "test": "vitest", "test:coverage": "vitest run --coverage" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/vercel-ai-exporter/src/exporter.ts b/packages/vercel-ai-exporter/src/exporter.ts index 6d3a00721..ea2f65f87 100644 --- a/packages/vercel-ai-exporter/src/exporter.ts +++ b/packages/vercel-ai-exporter/src/exporter.ts @@ -1129,7 +1129,7 @@ export class VoltAgentExporter implements SpanExporter { : "gen_ai.finishReason" in attributes // Legacy support for ai SDK versions < 4.0.0 ? (attributes["gen_ai.finishReason"]?.toString() ?? null) : null, - system: + instructions: "gen_ai.system" in attributes ? (attributes["gen_ai.system"]?.toString() ?? null) : "ai.model.provider" in attributes diff --git a/packages/vercel-ai-exporter/tsup.config.ts b/packages/vercel-ai-exporter/tsup.config.ts index e019584d6..032b5345b 100644 --- a/packages/vercel-ai-exporter/tsup.config.ts +++ b/packages/vercel-ai-exporter/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/voice/CHANGELOG.md b/packages/voice/CHANGELOG.md index 4f21cbaa2..30824f864 100644 --- a/packages/voice/CHANGELOG.md +++ b/packages/voice/CHANGELOG.md @@ -1,5 +1,229 @@ # @voltagent/voice +## 3.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + ## 2.1.0 ### Minor Changes diff --git a/packages/voice/package.json b/packages/voice/package.json index a7e14f264..d7893a87d 100644 --- a/packages/voice/package.json +++ b/packages/voice/package.json @@ -1,7 +1,7 @@ { "name": "@voltagent/voice", "description": "VoltAgent Voice - Voice capabilities for AI agents", - "version": "2.1.0", + "version": "3.0.0-next.0", "dependencies": { "@xsai/generate-speech": "0.4.0-beta.1", "@xsai/generate-transcription": "0.4.0-beta.1", @@ -11,21 +11,16 @@ "devDependencies": { "@types/node": "^24.2.1", "@vitest/coverage-v8": "^3.2.4", - "@voltagent/core": "^2.0.2", + "@voltagent/core": "^3.0.0-next.0", "tsup": "^8.5.0", "typescript": "^5.8.2", "vitest": "^3.2.4" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -33,9 +28,9 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0" + "@voltagent/core": "^3.0.0-next.0" }, "repository": { "type": "git", @@ -52,5 +47,6 @@ "test": "vitest", "test:coverage": "vitest run" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/voice/tsup.config.ts b/packages/voice/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/voice/tsup.config.ts +++ b/packages/voice/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/voltagent-memory/CHANGELOG.md b/packages/voltagent-memory/CHANGELOG.md index 781cf826b..9bfe77a80 100644 --- a/packages/voltagent-memory/CHANGELOG.md +++ b/packages/voltagent-memory/CHANGELOG.md @@ -1,5 +1,230 @@ # @voltagent/voltagent-memory +## 2.0.0-next.0 + +### Major Changes + +- Release the first VoltAgent 3 prerelease on the `next` channel. + + VoltAgent 3 aligns the framework with AI SDK v7, moves the published packages to an ESM-only runtime boundary, and requires Node.js 22 or later. This release keeps the core agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and storage features available, while tightening the public API around AI SDK-compatible names and call shapes. + + ### Install from the next channel + + ```bash + pnpm add @voltagent/core@next @voltagent/server-hono@next @voltagent/logger@next + pnpm add ai@^7 @ai-sdk/openai@^4 zod@^4 + ``` + + If your app uses additional VoltAgent packages, keep all `@voltagent/*` packages on the same major/prerelease line: + + ```bash + pnpm add @voltagent/postgres@next @voltagent/supabase@next @voltagent/voice@next + ``` + + ### Runtime requirements + + VoltAgent 3 requires Node.js 22+ and ESM imports. + + ```json + { + "type": "module", + "engines": { + "node": ">=22" + } + } + ``` + + Before: + + ```js + const { Agent } = require("@voltagent/core"); + const { openai } = require("@ai-sdk/openai"); + ``` + + After: + + ```ts + import { Agent } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + ``` + + ### AI SDK v7 alignment + + Upgrade `ai` and provider packages to AI SDK v7-compatible versions: + + ```bash + pnpm add ai@^7 @ai-sdk/provider-utils@^5 + pnpm add @ai-sdk/openai@^4 + ``` + + Common provider package upgrades: + + | Package | Version for AI SDK v7 | + | --------------------------- | --------------------- | + | `@ai-sdk/openai` | `^4` | + | `@ai-sdk/anthropic` | `^4` | + | `@ai-sdk/google` | `^4` | + | `@ai-sdk/azure` | `^4` | + | `@ai-sdk/groq` | `^4` | + | `@ai-sdk/mistral` | `^4` | + | `@ai-sdk/openai-compatible` | `^3` | + | `@ai-sdk/amazon-bedrock` | `^5` | + | `@ai-sdk/google-vertex` | `^5` | + + ### Zod 4-only + + VoltAgent 3 requires Zod 4. The framework packages now use `zod@^4` peer ranges, examples and templates install Zod 4, and the old Zod 3 JSON Schema/OpenAPI compatibility fallback has been removed. + + ```bash + pnpm add zod@^4 + ``` + + ### Agent usage + + The object-style call shape is the preferred API. AI SDK generation options stay at the top level, while VoltAgent runtime concerns live under `voltagent`. + + ```ts + const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, + }); + ``` + + The same shape works for streaming: + + ```ts + const result = await agent.streamText({ + prompt: "Write a short release note", + stopWhen: isStepCount(5), + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, + }); + + for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } + } + ``` + + `fullStream` remains as a deprecated compatibility alias during the transition, but new code should use `stream`. + + ### Tool usage + + VoltAgent now accepts AI SDK-style tool sets directly, so projects can use `tool()` without wrapping every tool in `createTool`. + + ```ts + import { Agent, tool } from "@voltagent/core"; + import { openai } from "@ai-sdk/openai"; + import { z } from "zod"; + + const agent = new Agent({ + name: "Weather Agent", + model: openai("gpt-4o-mini"), + tools: { + getWeather: tool({ + description: "Get the weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, forecast: "Sunny", temperature: 72 }; + }, + }), + }, + }); + ``` + + VoltAgent-specific tool metadata is available through the `voltagent` namespace, so existing framework features can be used with AI SDK-style tools: + + ```ts + const refundCustomer = tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + execute: async ({ orderId, reason }) => { + return issueRefund(orderId, reason); + }, + voltagent: { + name: "refundCustomer", + purpose: "Issue customer refunds", + }, + }); + ``` + + `createTool` remains available for existing tools and for codebases that prefer the VoltAgent-native helper. + + ### Tool approval + + AI SDK native `toolApproval` is forwarded through VoltAgent agent calls. + + ```ts + const result = await agent.streamText({ + prompt: "Refund order order_123 if it is eligible", + toolApproval: { + refundCustomer: "user-approval", + }, + }); + ``` + + Use call-level `toolApproval` for new per-request approval flows. Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent approval/tool-policy flow. If both are provided, call-level `toolApproval` takes precedence. + + ### Structured output + + Prefer AI SDK v7-style `output` over `experimental_output`. + + ```ts + import { Output } from "ai"; + import { z } from "zod"; + + const result = await agent.generateText({ + prompt: "Extract the customer profile", + output: Output.object({ + schema: z.object({ + name: z.string(), + plan: z.enum(["free", "pro", "enterprise"]), + }), + }), + }); + + console.log(result.output); + ``` + + `generateObject` and `streamObject` remain as deprecated compatibility wrappers. For new code, use `generateText` or `streamText` with `output`. + + ### Migration checklist + 1. Upgrade local development, CI, and production to Node.js 22 or later. + 2. Set `"type": "module"` and replace CommonJS `require()` calls with ESM imports. + 3. Upgrade all `@voltagent/*` packages together from the `next` channel. + 4. Upgrade `ai` to `^7` and AI SDK provider packages to their v7-compatible majors. + 5. Upgrade `zod` to `^4`. + 6. Replace `stepCountIs` with `isStepCount`. + 7. Prefer `result.stream` over `result.fullStream`. + 8. Prefer `output` over `experimental_output`. + 9. Prefer object-style agent calls for new code, with VoltAgent runtime options under `voltagent`. + +### Patch Changes + +- Updated dependencies []: + - @voltagent/core@3.0.0-next.0 + - @voltagent/internal@2.0.0-next.0 + ## 1.0.4 ### Patch Changes diff --git a/packages/voltagent-memory/package.json b/packages/voltagent-memory/package.json index 1a87d6e7a..ad6996c1a 100644 --- a/packages/voltagent-memory/package.json +++ b/packages/voltagent-memory/package.json @@ -1,25 +1,20 @@ { "name": "@voltagent/voltagent-memory", "description": "VoltAgent managed memory adapter backed by VoltOps", - "version": "1.0.4", + "version": "2.0.0-next.0", "dependencies": { - "@voltagent/internal": "^1.0.2" + "@voltagent/internal": "^2.0.0-next.0" }, "devDependencies": { "@vitest/coverage-v8": "^3.2.4", - "@voltagent/core": "^2.3.7", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "ai": "^7.0.0" }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "files": [ @@ -27,10 +22,10 @@ ], "license": "MIT", "main": "dist/index.js", - "module": "dist/index.mjs", + "module": "dist/index.js", "peerDependencies": { - "@voltagent/core": "^2.0.0", - "ai": "^6.0.0" + "@voltagent/core": "^3.0.0-next.0", + "ai": "^7.0.0" }, "repository": { "type": "git", @@ -46,5 +41,6 @@ "publint": "publint --strict", "test": "vitest" }, + "type": "module", "types": "dist/index.d.ts" } diff --git a/packages/voltagent-memory/tsup.config.ts b/packages/voltagent-memory/tsup.config.ts index 0819104fd..efc6e7dc8 100644 --- a/packages/voltagent-memory/tsup.config.ts +++ b/packages/voltagent-memory/tsup.config.ts @@ -3,7 +3,7 @@ import { markAsExternalPlugin } from "../shared/tsup-plugins/mark-as-external"; export default defineConfig({ entry: ["src/index.ts"], - format: ["cjs", "esm"], + format: ["esm"], splitting: false, sourcemap: true, clean: false, diff --git a/packages/voltagent-memory/vitest.config.mts b/packages/voltagent-memory/vitest.config.mts new file mode 100644 index 000000000..06ca89f12 --- /dev/null +++ b/packages/voltagent-memory/vitest.config.mts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["src/**/*.spec.ts"], + environment: "node", + globals: true, + passWithNoTests: true, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b49d84d70..356590e13 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -111,29 +111,29 @@ importers: examples/base: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -148,35 +148,35 @@ importers: examples/github-repo-analyzer: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@octokit/rest': specifier: ^21.0.0 version: 21.1.1 '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 version: 24.2.1 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli tsx: specifier: ^4.21.0 @@ -188,19 +188,19 @@ importers: examples/github-star-stories: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono '@voltagent/serverless-hono': - specifier: ^2.0.12 + specifier: ^3.0.0-next.0 version: link:../../packages/serverless-hono dotenv: specifier: ^16.4.5 @@ -209,8 +209,8 @@ importers: specifier: ^3.38.0 version: 3.114.14(@cloudflare/workers-types@4.20250813.0) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -225,8 +225,8 @@ importers: examples/next-js-chatbot-starter-template: dependencies: '@ai-sdk/react': - specifier: ^3.0.0 - version: 3.0.3(react@19.2.3)(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.19(react@19.2.3)(zod@4.3.5) '@libsql/client': specifier: ^0.15.0 version: 0.15.10 @@ -264,23 +264,23 @@ importers: specifier: ^1.2.2 version: 1.2.2(@types/react@19.1.10)(react@19.2.3) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono '@xyflow/react': specifier: ^12.9.2 version: 12.9.2(@types/react@19.1.10)(react-dom@19.2.3)(react@19.2.3) ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -354,8 +354,8 @@ importers: specifier: ^1.1.1 version: 1.1.1(react@19.2.3) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@tailwindcss/postcss': specifier: ^4.1.4 @@ -385,26 +385,26 @@ importers: examples/with-a2a-server: dependencies: '@voltagent/a2a-server': - specifier: ^2.0.3 + specifier: ^3.0.0-next.0 version: link:../../packages/a2a-server '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/internal': - specifier: ^1.0.3 + specifier: ^2.0.0-next.0 version: link:../../packages/internal '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -423,7 +423,7 @@ importers: version: 2.6.0 '@browserbasehq/stagehand': specifier: ^2.5.0 - version: 2.5.0(deepmerge@4.3.1)(dotenv@16.6.1)(react@19.2.3)(zod@3.25.76) + version: 2.5.0(deepmerge@4.3.1)(dotenv@16.6.1)(react@19.2.3)(zod@4.3.5) '@google-cloud/aiplatform': specifier: ^5.7.0 version: 5.7.0 @@ -431,23 +431,23 @@ importers: specifier: ^0.24.1 version: 0.24.1 '@voltagent/cli': - specifier: ^0.1.18 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.0.0 + specifier: ^3.0.0-next.0 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.0.0 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.0 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.0 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) dotenv: specifier: ^16.4.5 version: 16.6.1 @@ -455,8 +455,8 @@ importers: specifier: ^0.34.4 version: 0.34.4 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@biomejs/biome': specifier: ^1.9.4 @@ -477,14 +477,14 @@ importers: examples/with-agent-tool: dependencies: '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -499,29 +499,29 @@ importers: examples/with-airtable: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/internal': - specifier: ^1.0.3 + specifier: ^2.0.0-next.0 version: link:../../packages/internal '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/sdk': - specifier: ^2.0.3 + specifier: ^3.0.0-next.0 version: link:../../packages/sdk '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -536,26 +536,26 @@ importers: examples/with-amazon-bedrock: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -570,26 +570,26 @@ importers: examples/with-anthropic: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -634,17 +634,17 @@ importers: specifier: ^1.2.8 version: 1.2.8(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.3)(react@19.2.3) '@voltagent/core': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/server-hono': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -679,8 +679,8 @@ importers: specifier: ^1.4.0 version: 1.4.0 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 zustand: specifier: ^5.0.9 version: 5.0.9(@types/react@19.2.7)(react@19.2.3) @@ -710,29 +710,29 @@ importers: examples/with-auth: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -751,25 +751,25 @@ importers: version: 0.23.7(@bufbuild/protobuf@2.10.1)(@cerbos/api@0.4.0) '@modelcontextprotocol/sdk': specifier: ^1.12.1 - version: 1.24.3(zod@3.25.76) + version: 1.24.3(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) express: specifier: ^5.1.0 version: 5.1.0 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -790,14 +790,14 @@ importers: specifier: ^4.14.0 version: 4.14.0 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) chat: specifier: ^4.14.0 version: 4.14.0 @@ -811,8 +811,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(react@19.2.3) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -837,31 +837,31 @@ importers: version: 0.1.7(chromadb@3.0.12) '@chroma-core/openai': specifier: ^0.1.7 - version: 0.1.7(chromadb@3.0.12)(zod@3.25.76) + version: 0.1.7(chromadb@3.0.12)(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) chromadb: specifier: ^3.0.4 version: 3.0.12 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -876,26 +876,20 @@ importers: examples/with-client-side-tools: dependencies: '@ai-sdk/react': - specifier: ^3.0.0 - version: 3.0.3(react@19.2.3)(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.19(react@19.2.3)(zod@4.3.5) '@libsql/client': specifier: ^0.15.0 version: 0.15.10 '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono - '@voltagent/vercel-ai': - specifier: ^1.0.0 - version: 1.0.0(@voltagent/core@packages+core)(zod@3.25.76) - '@voltagent/vercel-ui': - specifier: ^1.0.1 - version: 1.0.1(@voltagent/core@packages+core)(zod@3.25.76) ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) next: specifier: ^16.0.7 version: 16.0.7(@babel/core@7.28.5)(react-dom@19.2.3)(react@19.2.3) @@ -906,8 +900,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(react@19.2.3) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -928,20 +922,20 @@ importers: examples/with-cloudflare-workers: dependencies: '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/serverless-hono': - specifier: ^2.0.12 + specifier: ^3.0.0-next.0 version: link:../../packages/serverless-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) hono: specifier: ^4.7.7 version: 4.9.1 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@cloudflare/workers-types': specifier: ^4.20250408.0 @@ -959,26 +953,26 @@ importers: examples/with-composio-mcp: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1027,23 +1021,23 @@ importers: specifier: ^1.50.0 version: 1.50.0(@langchain/core@0.3.70)(openai@5.23.2) '@voltagent/ag-ui': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../../../packages/ag-ui '@voltagent/cli': - specifier: ^0.1.20 + specifier: ^1.0.0-next.0 version: link:../../../packages/cli '@voltagent/core': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../../packages/core '@voltagent/server-hono': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: tsx: specifier: ^4.21.0 @@ -1055,26 +1049,26 @@ importers: examples/with-custom-endpoints: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1089,26 +1083,26 @@ importers: examples/with-dynamic-parameters: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1123,26 +1117,26 @@ importers: examples/with-dynamic-prompts: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1157,20 +1151,20 @@ importers: examples/with-feedback: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) devDependencies: '@types/node': specifier: ^24.2.1 @@ -1185,26 +1179,26 @@ importers: examples/with-google-ai: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1268,29 +1262,29 @@ importers: specifier: ^0.15.0 version: 0.15.10 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../../packages/server-hono composio-core: specifier: ^0.5.33 - version: 0.5.39(@ai-sdk/openai@3.0.12)(@cloudflare/workers-types@4.20250813.0)(@langchain/core@0.3.70)(@langchain/openai@0.6.7)(ai@6.0.3)(langchain@0.3.30)(openai@4.104.0) + version: 0.5.39(@ai-sdk/openai@4.0.9)(@cloudflare/workers-types@4.20250813.0)(@langchain/core@0.3.70)(@langchain/openai@0.6.7)(ai@7.0.18)(langchain@0.3.30)(openai@4.104.0) hono: specifier: ^4.7.7 version: 4.9.1 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 zod-from-json-schema: specifier: ^0.5.0 version: 0.5.0 @@ -1308,26 +1302,26 @@ importers: examples/with-google-vertex-ai: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1342,26 +1336,26 @@ importers: examples/with-groq-ai: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1376,20 +1370,20 @@ importers: examples/with-guardrails: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) devDependencies: '@types/node': specifier: ^24.2.1 @@ -1404,26 +1398,26 @@ importers: examples/with-hooks: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1438,26 +1432,26 @@ importers: examples/with-hugging-face-mcp: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1472,26 +1466,26 @@ importers: examples/with-jwt-auth: dependencies: '@voltagent/core': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) jsonwebtoken: specifier: ^9.0.2 version: 9.0.2 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/jsonwebtoken': specifier: ^9.0.10 @@ -1509,8 +1503,8 @@ importers: examples/with-lancedb: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@lancedb/lancedb': specifier: ^0.23.0 version: 0.23.0(apache-arrow@18.1.0) @@ -1527,11 +1521,11 @@ importers: specifier: workspace:^ version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1546,29 +1540,29 @@ importers: examples/with-langfuse: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/langfuse-exporter': - specifier: ^2.0.3 + specifier: ^3.0.0-next.0 version: link:../../packages/langfuse-exporter '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1583,17 +1577,17 @@ importers: examples/with-live-evals: dependencies: '@voltagent/core': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/core '@voltagent/scorers': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/scorers '@voltagent/server-hono': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1608,26 +1602,26 @@ importers: examples/with-mcp: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1642,26 +1636,26 @@ importers: examples/with-mcp-elicitation: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/mcp-server': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/mcp-server '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1676,23 +1670,23 @@ importers: examples/with-mcp-server: dependencies: '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/mcp-server': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/mcp-server '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1707,19 +1701,19 @@ importers: examples/with-memory-rest-api: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/postgres': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/postgres '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono devDependencies: '@types/node': @@ -1735,29 +1729,29 @@ importers: examples/with-middleware: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.12(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1781,13 +1775,13 @@ importers: specifier: ^11.0.0 version: 11.1.7(@nestjs/common@11.1.7)(@nestjs/core@11.1.7) '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/server-core': - specifier: ^2.1.19 + specifier: ^3.0.0-next.0 version: link:../../packages/server-core '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono hono: specifier: ^4.7.7 @@ -1802,8 +1796,8 @@ importers: specifier: ^8.18.1 version: 8.18.3 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@nestjs/cli': specifier: ^11.0.0 @@ -1827,20 +1821,20 @@ importers: examples/with-netlify-functions: dependencies: '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/serverless-hono': - specifier: ^2.0.12 + specifier: ^3.0.0-next.0 version: link:../../packages/serverless-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) hono: specifier: ^4.7.7 version: 4.9.1 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1855,8 +1849,8 @@ importers: examples/with-nextjs: dependencies: '@ai-sdk/react': - specifier: ^3.0.0 - version: 3.0.3(react@19.2.3)(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.19(react@19.2.3)(zod@4.3.5) '@libsql/client': specifier: ^0.15.0 version: 0.15.10 @@ -1864,23 +1858,23 @@ importers: specifier: ^4.1.4 version: 4.1.11 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) import-in-the-middle: specifier: ^1.14.2 version: 1.14.2 @@ -1906,8 +1900,8 @@ importers: specifier: ^4.1.4 version: 4.1.11 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -1928,8 +1922,8 @@ importers: examples/with-nextjs-resumable-stream: dependencies: '@ai-sdk/react': - specifier: ^3.0.0 - version: 3.0.3(react@19.2.3)(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.19(react@19.2.3)(zod@4.3.5) '@libsql/client': specifier: ^0.15.0 version: 0.15.10 @@ -1970,29 +1964,29 @@ importers: specifier: ^0.6.3 version: 0.6.3 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/internal': - specifier: ^1.0.3 + specifier: ^2.0.0-next.0 version: link:../../packages/internal '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/resumable-streams': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/resumable-streams '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono '@xyflow/react': specifier: ^12.9.2 version: 12.9.2(@types/react@19.2.7)(react-dom@19.2.3)(react@19.2.3) ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -2054,8 +2048,8 @@ importers: specifier: ^1.1.1 version: 1.1.1(react@19.2.3) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@tailwindcss/postcss': specifier: ^4.1.4 @@ -2089,19 +2083,19 @@ importers: version: 1.9.0(@vue/compiler-sfc@3.5.22)(eslint@9.33.0)(typescript@5.9.3)(vite@7.2.7) '@nuxt/ui': specifier: ^4.0.0 - version: 4.0.1(embla-carousel@8.6.0)(typescript@5.9.3)(vite@7.2.7)(vue-router@4.5.1)(vue@3.5.22)(zod@3.25.76) + version: 4.0.1(embla-carousel@8.6.0)(typescript@5.9.3)(vite@7.2.7)(vue-router@4.5.1)(vue@3.5.22)(zod@4.3.5) '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) nuxt: specifier: ^4.1.2 version: 4.1.3(@biomejs/biome@1.9.4)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.2.1)(@vue/compiler-sfc@3.5.22)(eslint@9.33.0)(typescript@5.9.3)(vite@7.2.7) @@ -2112,8 +2106,8 @@ importers: specifier: ^4.5.1 version: 4.5.1(vue@3.5.22) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: prettier: specifier: ^3.5.3 @@ -2122,26 +2116,26 @@ importers: examples/with-offline-evals: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/evals': - specifier: ^2.0.4 + specifier: ^3.0.0-next.0 version: link:../../packages/evals '@voltagent/scorers': - specifier: ^2.1.0 + specifier: ^3.0.0-next.0 version: link:../../packages/scorers '@voltagent/sdk': - specifier: ^2.0.3 + specifier: ^3.0.0-next.0 version: link:../../packages/sdk ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2156,26 +2150,26 @@ importers: examples/with-ollama: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) ollama-ai-provider-v2: - specifier: ^1.5.3 - version: 1.5.3(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.1(ai@7.0.18)(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2190,26 +2184,29 @@ importers: examples/with-openrouter: dependencies: '@openrouter/ai-sdk-provider': - specifier: ^2.3.1 - version: 2.3.1(ai@6.0.3)(zod@4.3.5) + specifier: ^3.0.0 + version: 3.0.0(ai@7.0.18)(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) + zod: + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2224,26 +2221,26 @@ importers: examples/with-peaka-mcp: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2261,29 +2258,29 @@ importers: specifier: ^6.1.1 version: 6.1.2 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) openai: specifier: ^4.91.0 - version: 4.104.0(ws@8.18.3)(zod@3.25.76) + version: 4.104.0(ws@8.18.3)(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2301,26 +2298,26 @@ importers: specifier: ^0.6.3 version: 0.6.3 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2347,23 +2344,23 @@ importers: specifier: ^1.51.1 version: 1.54.2 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) axios: specifier: ^1.5.0 version: 1.11.0 @@ -2374,8 +2371,8 @@ importers: specifier: ^9.0.1 version: 9.0.1 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2393,26 +2390,26 @@ importers: examples/with-postgres: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/postgres': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/postgres '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2430,29 +2427,29 @@ importers: specifier: ^1.15.0 version: 1.15.0(typescript@5.9.2) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) openai: specifier: ^4.91.0 - version: 4.104.0(ws@8.18.3)(zod@3.25.76) + version: 4.104.0(ws@8.18.3)(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2467,26 +2464,26 @@ importers: examples/with-rag-chatbot: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2501,23 +2498,23 @@ importers: examples/with-recipe-generator: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2532,23 +2529,23 @@ importers: examples/with-research-assistant: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2563,20 +2560,20 @@ importers: examples/with-resumable-streams: dependencies: '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/resumable-streams': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/resumable-streams '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) devDependencies: '@types/node': specifier: ^24.2.1 @@ -2591,29 +2588,29 @@ importers: examples/with-retries-fallback: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.12(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2628,26 +2625,26 @@ importers: examples/with-retrieval: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2662,29 +2659,29 @@ importers: examples/with-slack: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/sdk': - specifier: ^2.0.3 + specifier: ^3.0.0-next.0 version: link:../../packages/sdk '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2699,29 +2696,29 @@ importers: examples/with-subagents: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2736,29 +2733,29 @@ importers: examples/with-summarization: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.12(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2776,26 +2773,26 @@ importers: specifier: ^2.49.4 version: 2.55.0 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono '@voltagent/supabase': - specifier: ^2.1.3 + specifier: ^3.0.0-next.0 version: link:../../packages/supabase ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2810,26 +2807,26 @@ importers: examples/with-tavily-search: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2844,26 +2841,26 @@ importers: examples/with-thinking-tool: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2878,26 +2875,26 @@ importers: examples/with-tool-routing: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.12(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2912,29 +2909,29 @@ importers: examples/with-tools: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2949,26 +2946,26 @@ importers: examples/with-turso: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -2983,29 +2980,29 @@ importers: examples/with-vector-search: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3020,26 +3017,26 @@ importers: examples/with-vercel-ai: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3054,23 +3051,23 @@ importers: examples/with-viteval: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) consola: specifier: ^3.4.2 version: 3.4.2 @@ -3081,8 +3078,8 @@ importers: specifier: ^18.0.0 version: 18.0.0 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@tsconfig/node24': specifier: ^24.0.1 @@ -3106,29 +3103,29 @@ importers: examples/with-voice-elevenlabs: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono '@voltagent/voice': - specifier: ^2.1.0 + specifier: ^3.0.0-next.0 version: link:../../packages/voice ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3143,35 +3140,35 @@ importers: examples/with-voice-openai: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono '@voltagent/voice': - specifier: ^2.1.0 + specifier: ^3.0.0-next.0 version: link:../../packages/voice ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) dotenv: specifier: ^16.4.5 version: 16.6.1 openai: specifier: ^4.91.0 - version: 4.104.0(ws@8.18.3)(zod@3.25.76) + version: 4.104.0(ws@8.18.3)(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3186,35 +3183,35 @@ importers: examples/with-voice-xsai: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono '@voltagent/voice': - specifier: ^2.1.0 + specifier: ^3.0.0-next.0 version: link:../../packages/voice ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) dotenv: specifier: ^16.4.5 version: 16.6.1 openai: specifier: ^4.91.0 - version: 4.104.0(ws@8.18.3)(zod@3.25.76) + version: 4.104.0(ws@8.18.3)(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3229,23 +3226,23 @@ importers: examples/with-voltagent-actions: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/sdk': - specifier: ^2.0.3 + specifier: ^3.0.0-next.0 version: link:../../packages/sdk '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3260,26 +3257,26 @@ importers: examples/with-voltagent-exporter: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3294,26 +3291,26 @@ importers: examples/with-voltagent-managed-memory: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono '@voltagent/voltagent-memory': - specifier: ^1.0.4 + specifier: ^2.0.0-next.0 version: link:../../packages/voltagent-memory ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3328,20 +3325,20 @@ importers: examples/with-voltops-resumable-streams: dependencies: '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/resumable-streams': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/resumable-streams '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) devDependencies: '@types/node': specifier: ^24.2.1 @@ -3356,26 +3353,26 @@ importers: examples/with-voltops-retrieval: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3393,29 +3390,29 @@ importers: specifier: ^2.49.4 version: 2.58.0 '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) dotenv: specifier: ^16.4.5 version: 16.6.1 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3430,26 +3427,26 @@ importers: examples/with-workflow: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3464,26 +3461,26 @@ importers: examples/with-workflow-chain: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3498,26 +3495,26 @@ importers: examples/with-working-memory: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3532,29 +3529,29 @@ importers: examples/with-workspace: dependencies: '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.12(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3569,23 +3566,23 @@ importers: examples/with-xquik-tools: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3600,26 +3597,26 @@ importers: examples/with-youtube-to-blog: dependencies: '@voltagent/cli': - specifier: ^0.1.21 + specifier: ^1.0.0-next.0 version: link:../../packages/cli '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3634,23 +3631,23 @@ importers: examples/with-zapier-mcp: dependencies: '@voltagent/core': - specifier: ~2.9.0 + specifier: ~3.0.0-next.1 version: link:../../packages/core '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../../packages/libsql '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../../packages/logger '@voltagent/server-hono': - specifier: ^2.0.14 + specifier: ^3.0.0-next.0 version: link:../../packages/server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/node': specifier: ^24.2.1 @@ -3668,14 +3665,14 @@ importers: specifier: ^0.2.5 version: 0.2.5 '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@voltagent/core': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../core packages/ag-ui: @@ -3697,10 +3694,10 @@ importers: specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) '@voltagent/core': - specifier: ^2.6.13 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal tsup: specifier: ^8.5.0 @@ -3715,13 +3712,13 @@ importers: packages/cli: dependencies: '@voltagent/evals': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../evals '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal '@voltagent/sdk': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../sdk adm-zip: specifier: ^0.5.12 @@ -3821,87 +3818,81 @@ importers: specifier: ^4.20250408.0 version: 4.20250813.0 '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal devDependencies: '@vitest/coverage-v8': specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) '@voltagent/core': - specifier: ^2.4.4 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../logger ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) packages/core: dependencies: '@ai-sdk/amazon-bedrock': - specifier: ^3.0.0 - version: 3.0.7(zod@3.25.76) + specifier: ^5.0.0 + version: 5.0.14(zod@4.3.5) '@ai-sdk/anthropic': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.10(zod@4.3.5) '@ai-sdk/azure': - specifier: ^3.0.12 - version: 3.0.12(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@ai-sdk/cerebras': - specifier: ^2.0.14 - version: 2.0.14(zod@3.25.76) + specifier: ^3.0.0 + version: 3.0.6(zod@4.3.5) '@ai-sdk/cohere': - specifier: ^3.0.8 - version: 3.0.8(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.6(zod@4.3.5) '@ai-sdk/deepinfra': - specifier: ^2.0.13 - version: 2.0.13(zod@3.25.76) + specifier: ^3.0.0 + version: 3.0.6(zod@4.3.5) '@ai-sdk/gateway': - specifier: ^3.0.16 - version: 3.0.16(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.14(zod@4.3.5) '@ai-sdk/google': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.10(zod@4.3.5) '@ai-sdk/google-vertex': - specifier: ^3.0.25 - version: 3.0.25(zod@3.25.76) + specifier: ^5.0.0 + version: 5.0.13(zod@4.3.5) '@ai-sdk/groq': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.6(zod@4.3.5) '@ai-sdk/mistral': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.7(zod@4.3.5) '@ai-sdk/openai': - specifier: ^3.0.0 - version: 3.0.1(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@ai-sdk/openai-compatible': - specifier: ^2.0.13 - version: 2.0.13(zod@3.25.76) + specifier: ^3.0.0 + version: 3.0.6(zod@4.3.5) '@ai-sdk/perplexity': - specifier: ^3.0.8 - version: 3.0.8(zod@3.25.76) + specifier: ^4.0.0 + version: 4.0.7(zod@4.3.5) '@ai-sdk/togetherai': - specifier: ^2.0.13 - version: 2.0.13(zod@3.25.76) + specifier: ^3.0.0 + version: 3.0.7(zod@4.3.5) '@ai-sdk/vercel': - specifier: ^2.0.13 - version: 2.0.13(zod@3.25.76) + specifier: ^3.0.0 + version: 3.0.6(zod@4.3.5) '@ai-sdk/xai': - specifier: ^3.0.26 - version: 3.0.26(zod@3.25.76) - '@aihubmix/ai-sdk-provider': - specifier: ^1.0.1 - version: 1.0.1 + specifier: ^4.0.0 + version: 4.0.9(zod@4.3.5) '@gitlab/gitlab-ai-provider': - specifier: ^3.1.1 - version: 3.1.1(@ai-sdk/provider-utils@4.0.1)(@ai-sdk/provider@3.0.4)(graphql@16.11.0)(ws@8.18.3) + specifier: ^4.1.0 + version: 4.1.0(@ai-sdk/provider-utils@5.0.6)(@ai-sdk/provider@4.0.2)(graphql@16.11.0)(ws@8.18.3) '@modelcontextprotocol/sdk': specifier: ^1.12.1 version: 1.17.2 - '@mymediset/sap-ai-provider': - specifier: ^2.1.0 - version: 2.1.0(ai@6.0.3) '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 @@ -3939,10 +3930,10 @@ importers: specifier: ^1.28.0 version: 1.36.0 '@voltagent/internal': - specifier: ^1.0.3 + specifier: ^2.0.0-next.0 version: link:../internal '@voltagent/logger': - specifier: 2.0.2 + specifier: 3.0.0-next.0 version: link:../logger fast-glob: specifier: ^3.3.3 @@ -3953,9 +3944,6 @@ importers: micromatch: specifier: ^4.0.8 version: 4.0.8 - ollama-ai-provider-v2: - specifier: ^1.5.3 - version: 1.5.3(zod@3.25.76) ts-pattern: specifier: ^5.7.1 version: 5.8.0 @@ -3965,19 +3953,13 @@ importers: uuid: specifier: ^9.0.1 version: 9.0.1 - workers-ai-provider: - specifier: ^3.0.2 - version: 3.0.2(@ai-sdk/provider-utils@4.0.1)(@ai-sdk/provider@3.0.4)(ai@6.0.3)(zod@3.25.76) zod-from-json-schema: specifier: ^0.5.0 version: 0.5.0 - zod-from-json-schema-v3: - specifier: npm:zod-from-json-schema@^0.0.5 - version: /zod-from-json-schema@0.0.5 devDependencies: '@ai-sdk/provider-utils': - specifier: ^4.0.0 - version: 4.0.1(zod@3.25.76) + specifier: ^5.0.0 + version: 5.0.6(zod@4.3.5) '@types/micromatch': specifier: ^4.0.10 version: 4.0.10 @@ -3988,14 +3970,14 @@ importers: specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) msw: specifier: ^2.11.5 version: 2.11.6(@types/node@24.2.1)(typescript@5.9.2) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 packages/create-voltagent-app: dependencies: @@ -4085,26 +4067,29 @@ importers: specifier: ^0.15.0 version: 0.15.10 '@voltagent/core': - specifier: ^2.9.0 + specifier: ^3.0.0-next.1 version: link:../core '@voltagent/internal': - specifier: ^1.0.3 + specifier: ^2.0.0-next.0 version: link:../internal '@voltagent/libsql': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../libsql '@voltagent/postgres': - specifier: ^2.1.2 + specifier: ^3.0.0-next.0 version: link:../postgres + '@voltagent/server-hono': + specifier: ^3.0.0-next.0 + version: link:../server-hono ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) pg: specifier: ^8.16.0 version: 8.16.3 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 devDependencies: vitest: specifier: ^3.2.4 @@ -4113,13 +4098,13 @@ importers: packages/evals: dependencies: '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal '@voltagent/scorers': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../scorers '@voltagent/sdk': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../sdk packages/internal: @@ -4151,7 +4136,7 @@ importers: specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) '@voltagent/core': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../core packages/libsql: @@ -4160,21 +4145,21 @@ importers: specifier: ^0.15.0 version: 0.15.10 '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal devDependencies: '@vitest/coverage-v8': specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) '@voltagent/core': - specifier: ^2.4.4 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../logger ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) packages/logger: dependencies: @@ -4191,7 +4176,7 @@ importers: specifier: ^0.204.0 version: 0.204.0(@opentelemetry/api@1.9.0) '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal pino: specifier: ^9.7.0 @@ -4210,20 +4195,20 @@ importers: specifier: ^1.12.1 version: 1.17.2 '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal devDependencies: '@voltagent/core': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../core zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 packages/postgres: dependencies: '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal pg: specifier: ^8.16.0 @@ -4236,11 +4221,11 @@ importers: specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) '@voltagent/core': - specifier: ^2.4.4 + specifier: ^3.0.0-next.0 version: link:../core ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) packages/rag: dependencies: @@ -4255,14 +4240,14 @@ importers: packages/resumable-streams: dependencies: '@voltagent/core': - specifier: ^2.6.6 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) redis: specifier: ^4.7.0 version: 4.7.1 @@ -4286,7 +4271,7 @@ importers: specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) '@voltagent/core': - specifier: ^2.8.1 + specifier: ^3.0.0-next.0 version: link:../core tsup: specifier: ^8.5.0 @@ -4308,7 +4293,7 @@ importers: specifier: ^24.2.1 version: 24.6.2 '@voltagent/core': - specifier: ^2.8.1 + specifier: ^3.0.0-next.0 version: link:../core tsup: specifier: ^8.5.0 @@ -4327,7 +4312,7 @@ importers: specifier: ^24.2.1 version: 24.6.2 '@voltagent/core': - specifier: ^2.8.1 + specifier: ^3.0.0-next.0 version: link:../core tsup: specifier: ^8.5.0 @@ -4339,29 +4324,29 @@ importers: packages/scorers: dependencies: '@voltagent/core': - specifier: ^2.4.0 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal autoevals: specifier: ^0.0.131 version: 0.0.131 devDependencies: ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 packages/sdk: dependencies: '@voltagent/core': - specifier: ^2.7.4 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal devDependencies: '@vitest/coverage-v8': @@ -4374,14 +4359,14 @@ importers: specifier: ^1.12.1 version: 1.17.2 '@voltagent/core': - specifier: ^2.8.1 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal ai: - specifier: ^6.0.0 - version: 6.0.3(zod@3.25.76) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) jsonwebtoken: specifier: ^9.0.2 version: 9.0.2 @@ -4391,9 +4376,6 @@ importers: zod-from-json-schema: specifier: ^0.5.0 version: 0.5.0 - zod-from-json-schema-v3: - specifier: npm:zod-from-json-schema@^0.0.5 - version: /zod-from-json-schema@0.0.5 devDependencies: '@types/jsonwebtoken': specifier: ^9.0.10 @@ -4402,8 +4384,8 @@ importers: specifier: ^8.18.1 version: 8.18.1 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 packages/server-elysia: dependencies: @@ -4417,32 +4399,29 @@ importers: specifier: ^0.34.45 version: 0.34.45 '@voltagent/a2a-server': - specifier: ^2.0.3 + specifier: ^3.0.0-next.0 version: link:../a2a-server '@voltagent/core': - specifier: ^2.7.6 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal '@voltagent/mcp-server': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../mcp-server '@voltagent/resumable-streams': - specifier: ^2.0.1 + specifier: ^3.0.0-next.0 version: link:../resumable-streams '@voltagent/server-core': - specifier: ^2.1.18 + specifier: ^3.0.0-next.0 version: link:../server-core elysia: specifier: ^1.1.29 version: 1.4.19(@sinclair/typebox@0.34.45)(exact-mirror@0.2.5)(file-type@21.0.0)(openapi-types@12.1.3)(typescript@5.9.2) zod: - specifier: ^3.25.76 - version: 3.25.76 - zod-to-json-schema: - specifier: ^3.25.1 - version: 3.25.1(zod@3.25.76) + specifier: ^4.1.11 + version: 4.3.5 devDependencies: '@types/ws': specifier: ^8.18.1 @@ -4457,22 +4436,22 @@ importers: specifier: ^0.5.1 version: 0.5.2(hono@4.9.1) '@voltagent/a2a-server': - specifier: ^2.0.3 + specifier: ^3.0.0-next.0 version: link:../a2a-server '@voltagent/core': - specifier: ^2.7.6 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal '@voltagent/mcp-server': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../mcp-server '@voltagent/resumable-streams': - specifier: ^2.0.1 + specifier: ^3.0.0-next.0 version: link:../resumable-streams '@voltagent/server-core': - specifier: ^2.1.18 + specifier: ^3.0.0-next.0 version: link:../server-core fetch-to-node: specifier: ^2.1.0 @@ -4488,22 +4467,22 @@ importers: specifier: ^8.18.1 version: 8.18.1 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: ^4.1.11 + version: 4.3.5 packages/serverless-hono: dependencies: '@voltagent/core': - specifier: ^2.0.0 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal '@voltagent/resumable-streams': - specifier: ^2.0.1 + specifier: ^3.0.0-next.0 version: link:../resumable-streams '@voltagent/server-core': - specifier: ^2.1.18 + specifier: ^3.0.0-next.0 version: link:../server-core hono: specifier: ^4.7.7 @@ -4515,7 +4494,7 @@ importers: specifier: ^2.49.4 version: 2.55.0 '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal ts-pattern: specifier: ^5.7.1 @@ -4525,14 +4504,14 @@ importers: specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) '@voltagent/core': - specifier: ^2.4.4 + specifier: ^3.0.0-next.0 version: link:../core '@voltagent/logger': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../logger ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) packages/voice: dependencies: @@ -4547,7 +4526,7 @@ importers: version: 1.59.0 openai: specifier: ^4.91.0 - version: 4.104.0(ws@8.18.3)(zod@3.25.76) + version: 4.104.0(ws@8.18.3)(zod@4.3.5) devDependencies: '@types/node': specifier: ^24.2.1 @@ -4556,7 +4535,7 @@ importers: specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) '@voltagent/core': - specifier: ^2.0.2 + specifier: ^3.0.0-next.0 version: link:../core tsup: specifier: ^8.5.0 @@ -4571,18 +4550,18 @@ importers: packages/voltagent-memory: dependencies: '@voltagent/internal': - specifier: ^1.0.2 + specifier: ^2.0.0-next.0 version: link:../internal devDependencies: '@vitest/coverage-v8': specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) '@voltagent/core': - specifier: ^2.3.7 + specifier: ^3.0.0-next.0 version: link:../core ai: - specifier: ^6.0.0 - version: 6.0.3(zod@4.3.5) + specifier: ^7.0.0 + version: 7.0.18(zod@4.3.5) packages: @@ -4706,22 +4685,23 @@ packages: '@bufbuild/protobuf': 2.10.1 '@protobuf-ts/protoc': 2.11.1 - /@ai-sdk/amazon-bedrock@3.0.7(zod@3.25.76): - resolution: {integrity: sha512-WvgHvfLUk+Pa8a1xUXnzEBwIpi74i/oHWy/3HR2hyWe9b9b4cykLxsr93EuJ4201/FkA2gTkYTu7iZaSut5/Og==} - engines: {node: '>=18'} + /@ai-sdk/amazon-bedrock@5.0.14(zod@4.3.5): + resolution: {integrity: sha512-S2KDzYuaRM5jY+5oeOtcMS60lFVrJLeTguzEYN6M5uez6zBaE8EjDWC6JaCRZDoMzB1uLSXQYVzC5uisjWseyg==} + engines: {node: '>=22'} peerDependencies: - zod: ^3.25.76 || ^4 + zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/anthropic': 2.0.3(zod@3.25.76) - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.3(zod@3.25.76) - '@smithy/eventstream-codec': 4.0.5 - '@smithy/util-utf8': 4.0.0 + '@ai-sdk/anthropic': 4.0.10(zod@4.3.5) + '@ai-sdk/openai': 4.0.9(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + '@smithy/eventstream-codec': 4.4.7 + '@smithy/util-utf8': 4.4.7 aws4fetch: 1.0.20 - zod: 3.25.76 + zod: 4.3.5 dev: false - /@ai-sdk/anthropic@1.2.12(zod@3.25.76): + /@ai-sdk/anthropic@1.2.12(zod@4.3.5): resolution: {integrity: sha512-YSzjlko7JvuiyQFmI9RN1tNZdEiZxc+6xld/0tq/VkJaHpEzGAb1yiNxxvmYVcjvfu/PcvCxAAYXmTYQQ63IHQ==} engines: {node: '>=18'} requiresBuild: true @@ -4729,33 +4709,11 @@ packages: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/anthropic@2.0.15(zod@3.25.76): - resolution: {integrity: sha512-MxNGoYvKyF7IqMU0k9gogyiJi0/ogwg6i2Baw862BMjM2KJuBcCPqh6/lrpwiDg6pqphGUc+LfjPd6PRFARnng==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.8(zod@3.25.76) - zod: 3.25.76 - dev: false - - /@ai-sdk/anthropic@2.0.3(zod@3.25.76): - resolution: {integrity: sha512-aNPhnmJWDApvaiU5al2Sp0FjkvRxj4KEAvrRvIGzuM9NIPokIRsCgc5ZPeAtCZJiZCYDs+0SdObb0mdNxtFtkg==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.3(zod@3.25.76) - zod: 3.25.76 - dev: false - /@ai-sdk/anthropic@2.0.41(zod@3.25.76): resolution: {integrity: sha512-ZQebpyE6rM3JoeEyhJXUNDiRfVegw8ZrxT+rB8yurxI5JXDnlGpYQvSPmdR8TQfMbps4YkggfbcOwMeEZaTS+g==} engines: {node: '>=18'} @@ -4766,127 +4724,128 @@ packages: '@ai-sdk/provider-utils': 3.0.16(zod@3.25.76) zod: 3.25.76 - /@ai-sdk/anthropic@3.0.1(zod@3.25.76): - resolution: {integrity: sha512-MOiwKs76ilEmau/WRMnGWlheTUoB+cbvXCse+SAtpW5ATLreInsuYlspLABn12Dxu3w1Xzke1dT+tmEnxhy9SA==} - engines: {node: '>=18'} + /@ai-sdk/anthropic@4.0.10(zod@4.3.5): + resolution: {integrity: sha512-L9GlJyL8stPyv5QTRONnVoRVw82b6iBuX4LTiRJMM++I2RfDe+yrBsPa6gz6Msll9GZ7JsX0MRNUP4G1afjDTw==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) - zod: 3.25.76 - dev: false - - /@ai-sdk/anthropic@3.0.1(zod@4.3.5): - resolution: {integrity: sha512-MOiwKs76ilEmau/WRMnGWlheTUoB+cbvXCse+SAtpW5ATLreInsuYlspLABn12Dxu3w1Xzke1dT+tmEnxhy9SA==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) zod: 4.3.5 dev: false - /@ai-sdk/azure@1.3.25(zod@3.25.76): + /@ai-sdk/azure@1.3.25(zod@4.3.5): resolution: {integrity: sha512-cTME89A9UYrza0t5pbY9b80yYY02Q5ALQdB2WP3R7/Yl1PLwbFChx994Q3Un0G2XV5h3arlm4fZTViY10isjhQ==} engines: {node: '>=18'} requiresBuild: true peerDependencies: zod: ^3.0.0 dependencies: - '@ai-sdk/openai': 1.3.24(zod@3.25.76) + '@ai-sdk/openai': 1.3.24(zod@4.3.5) '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/azure@3.0.12(zod@3.25.76): - resolution: {integrity: sha512-TzKOIvO3G2QWYvc06WoR/jZO/IokCQqHRMl7GfkzOmxscrgK8sqXrT8l6cXb1FVs5D4pFQZV/enyFTrpcLkODg==} - engines: {node: '>=18'} + /@ai-sdk/azure@4.0.9(zod@4.3.5): + resolution: {integrity: sha512-+I+eCetnWfNZfC7rAq5hzpRVIb8GNrQQaXLg3Ma4eY1mvPTDZ0Yh+Wadrm10gJ/no818t341qjsjnKBldYsdIQ==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/openai': 3.0.12(zod@3.25.76) - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/deepseek': 3.0.6(zod@4.3.5) + '@ai-sdk/openai': 4.0.9(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false - /@ai-sdk/cerebras@0.2.16(zod@3.25.76): + /@ai-sdk/cerebras@0.2.16(zod@4.3.5): resolution: {integrity: sha512-FbT3gFYADXwyjQlpluWxl5fRnkJvGMHX5ahLZZ7qqpDQHH86ZO6X9j9Gk6vcMCwNPpI7+miiK79q1e5wzVHBSQ==} engines: {node: '>=18'} requiresBuild: true peerDependencies: zod: ^3.0.0 dependencies: - '@ai-sdk/openai-compatible': 0.2.16(zod@3.25.76) + '@ai-sdk/openai-compatible': 0.2.16(zod@4.3.5) '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/cerebras@2.0.14(zod@3.25.76): - resolution: {integrity: sha512-pwe82kSX2hI1+O/fU0sivl9OXKwrzqY1+fXPvZ7w/NEWG5Ak1grLH/SjD6hvbYwQPWk1NA0W5CxiLQCM6Jjc0A==} - engines: {node: '>=18'} + /@ai-sdk/cerebras@3.0.6(zod@4.3.5): + resolution: {integrity: sha512-QI02IBxolbJ9Ohk2ZKCiTzXN/hE1p0M5G1YVUIUiN/G/qafDtyyGcbiymuZsFiCEOWqTx+k9gYDR4MO+ksTsew==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/openai-compatible': 2.0.13(zod@3.25.76) - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/openai-compatible': 3.0.6(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false - /@ai-sdk/cohere@3.0.8(zod@3.25.76): - resolution: {integrity: sha512-8HbGsDsTAVLxzvbXk9Wd4q7raxemAxPyt3Ph9PtNDIB2FUBiD1spaLmnhlB/qF8p/32+w1qlpMS4qqxqFcr74A==} - engines: {node: '>=18'} + /@ai-sdk/cohere@4.0.6(zod@4.3.5): + resolution: {integrity: sha512-ieK271Znc1T2KApGWE9oz65wx/9MVyy93VsJuZiUj43J71lkVn1K5aX3sEG/tFDB+MxaMN/ofbhI8gWRzoOYfw==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false - /@ai-sdk/deepinfra@2.0.13(zod@3.25.76): - resolution: {integrity: sha512-FB8YfW2a3jDb7IJVKD6novnSvpFH98V5+hiIsdV+yADfAnNafbmFCAj30m2CTnoeNiszI7pFYjlMlPci27P+LA==} - engines: {node: '>=18'} + /@ai-sdk/deepinfra@3.0.6(zod@4.3.5): + resolution: {integrity: sha512-TPsJjIaYX2IqCsoiMdgqZ6AVcH3RBozn1aSyx1HQD4rxRBiudK2FMnsxHOEa5/ZRggNprkzyKfkSJJn7b6wmBw==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/openai-compatible': 2.0.13(zod@3.25.76) - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/openai-compatible': 3.0.6(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false - /@ai-sdk/deepseek@0.2.16(zod@3.25.76): + /@ai-sdk/deepseek@0.2.16(zod@4.3.5): resolution: {integrity: sha512-pIlwtjNehCpDr1wqxtSbXshynW4CiwS6S3yAKHzHi73QtmS2Hg9kE1DB0zgENKaZLmbsc4UgigGM6FzuUd4M8Q==} engines: {node: '>=18'} requiresBuild: true peerDependencies: zod: ^3.0.0 dependencies: - '@ai-sdk/openai-compatible': 0.2.16(zod@3.25.76) + '@ai-sdk/openai-compatible': 0.2.16(zod@4.3.5) '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/gateway@1.0.35(zod@3.25.76): + /@ai-sdk/deepseek@3.0.6(zod@4.3.5): + resolution: {integrity: sha512-mPX5fqMN6flScSq5XvU/Oli4r6GXRx57I7h/NVQSAHChzpZAl4bGirV3eEKCCR9pS65WVEc9iNI4w+hqrFBecQ==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + dependencies: + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 + dev: false + + /@ai-sdk/gateway@1.0.35(zod@4.3.5): resolution: {integrity: sha512-cdsXbeRRMi6QxbZscin69Asx2fi0d2TmmPngcPFUMpZbchGEBiJYVNvIfiALKFKXEq0l/w0xGNV3E13vroaleA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.11(zod@3.25.76) + '@ai-sdk/provider-utils': 3.0.11(zod@4.3.5) '@vercel/oidc': 3.0.2 - zod: 3.25.76 + zod: 4.3.5 dev: false /@ai-sdk/gateway@2.0.21(zod@3.25.76): @@ -4912,58 +4871,35 @@ packages: zod: 4.3.5 dev: false - /@ai-sdk/gateway@3.0.16(zod@3.25.76): - resolution: {integrity: sha512-OOY5CfRJiHvh/8np2vs1RQaCZ5hWv2qOeEmmeiABXK3gLQHUVnCO+1hhoLsZdHM5iElu6M407dAOfyvTsKJqcQ==} - engines: {node: '>=18'} + /@ai-sdk/gateway@4.0.14(zod@4.3.5): + resolution: {integrity: sha512-wbYqQKpASsuK7bdoa1fp+QA6oy3ddqqBOukN3IkyaR8PAp0pWoc66ch2td+ixeknoCcO4F6VTkSFKVC6MP3bTQ==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - '@vercel/oidc': 3.1.0 - zod: 3.25.76 - dev: false - - /@ai-sdk/gateway@3.0.2(zod@3.25.76): - resolution: {integrity: sha512-giJEg9ob45htbu3iautK+2kvplY2JnTj7ir4wZzYSQWvqGatWfBBfDuNCU5wSJt9BCGjymM5ZS9ziD42JGCZBw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) - '@vercel/oidc': 3.0.5 - zod: 3.25.76 + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + '@vercel/oidc': 3.2.0 + zod: 4.3.5 - /@ai-sdk/gateway@3.0.2(zod@4.3.5): - resolution: {integrity: sha512-giJEg9ob45htbu3iautK+2kvplY2JnTj7ir4wZzYSQWvqGatWfBBfDuNCU5wSJt9BCGjymM5ZS9ziD42JGCZBw==} - engines: {node: '>=18'} + /@ai-sdk/google-vertex@5.0.13(zod@4.3.5): + resolution: {integrity: sha512-WtAv5YsuwvxjqxwmRO0yTHGcz+QI2PZHHo0/lP5gveqOEs2GDU4ihLZrq+KJ5u+hfeEKRlIB5XHTenV3rcvCzg==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@4.3.5) - '@vercel/oidc': 3.0.5 + '@ai-sdk/anthropic': 4.0.10(zod@4.3.5) + '@ai-sdk/google': 4.0.10(zod@4.3.5) + '@ai-sdk/openai-compatible': 3.0.6(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + google-auth-library: 10.9.0 zod: 4.3.5 - - /@ai-sdk/google-vertex@3.0.25(zod@3.25.76): - resolution: {integrity: sha512-X4VRfFHTMr50wo8qvoA4WmxmehSAMzEAiJ5pPn0/EPB4kxytz53g7BijRBDL+MZpqXRNiwF3taf4p3P1WUMnVA==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - dependencies: - '@ai-sdk/anthropic': 2.0.15(zod@3.25.76) - '@ai-sdk/google': 2.0.13(zod@3.25.76) - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.8(zod@3.25.76) - google-auth-library: 9.15.1 - zod: 3.25.76 transitivePeerDependencies: - - encoding - supports-color dev: false - /@ai-sdk/google@1.2.22(zod@3.25.76): + /@ai-sdk/google@1.2.22(zod@4.3.5): resolution: {integrity: sha512-Ppxu3DIieF1G9pyQ5O1Z646GYR0gkC57YdBqXJ82qvCdhEhZHu0TWhmnOoeIWe2olSbuDeoOY+MfJrW8dzS3Hw==} engines: {node: '>=18'} requiresBuild: true @@ -4971,22 +4907,11 @@ packages: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/google@2.0.13(zod@3.25.76): - resolution: {integrity: sha512-5WauM+IrqbllWT4uXZVrfTnPCSKTtkHGNsD2CYD0JgGfeIOpa285UYCYUi0Z4RtcovwnZitvQABq465FfeLwzA==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.8(zod@3.25.76) - zod: 3.25.76 - dev: false - /@ai-sdk/google@2.0.29(zod@3.25.76): resolution: {integrity: sha512-wH8eEN5mUPOpbENsCkO3dBumWZ2FUbkh3iWj1ypYIVQNuJFvNxqHuWTb5t8C/F+5FoPM14McmeI/ceQ9qZ4lyw==} engines: {node: '>=18'} @@ -4997,29 +4922,18 @@ packages: '@ai-sdk/provider-utils': 3.0.16(zod@3.25.76) zod: 3.25.76 - /@ai-sdk/google@3.0.1(zod@3.25.76): - resolution: {integrity: sha512-gh7i4lEvd1CElmefkq7+RoUhNkhP2OTshzVxSt7/Vh2AV5wTPLhduKJMg1c7SFwErytqffO3el/M/LlfCsqzEw==} - engines: {node: '>=18'} + /@ai-sdk/google@4.0.10(zod@4.3.5): + resolution: {integrity: sha512-+g629pKE4xhLB6LnskHlOkie30UENhiKpdYMGQoGYm09191kfRU8qAU7wgF01PmzGFe0h3JYpls6Ok2aCYmjzQ==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) - zod: 3.25.76 - dev: false - - /@ai-sdk/google@3.0.1(zod@4.3.5): - resolution: {integrity: sha512-gh7i4lEvd1CElmefkq7+RoUhNkhP2OTshzVxSt7/Vh2AV5wTPLhduKJMg1c7SFwErytqffO3el/M/LlfCsqzEw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) zod: 4.3.5 dev: false - /@ai-sdk/groq@1.2.9(zod@3.25.76): + /@ai-sdk/groq@1.2.9(zod@4.3.5): resolution: {integrity: sha512-7MoDaxm8yWtiRbD1LipYZG0kBl+Xe0sv/EeyxnHnGPZappXdlgtdOgTZVjjXkT3nWP30jjZi9A45zoVrBMb3Xg==} engines: {node: '>=18'} requiresBuild: true @@ -5027,20 +4941,20 @@ packages: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/groq@3.0.1(zod@3.25.76): - resolution: {integrity: sha512-scG4Esc0AuFXxKDrcoXuO0ufPg/kFtavnGgll/LCqN7UqQ46mcNIBBaF9TT5LrkgAS8tEOUGLNrbU635HvscIA==} - engines: {node: '>=18'} + /@ai-sdk/groq@4.0.6(zod@4.3.5): + resolution: {integrity: sha512-8aKfwUElkmjvyMr7cCEGMO8Wbt9udvxeJtsTIgDan25jqhoT/GUqV1YcFXczwwveIjaRB2xR6m9hKfDuXcTrBA==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false /@ai-sdk/mcp@0.0.8(zod@3.25.76): @@ -5054,7 +4968,19 @@ packages: pkce-challenge: 5.0.0 zod: 3.25.76 - /@ai-sdk/mistral@1.2.8(zod@3.25.76): + /@ai-sdk/mcp@2.0.9(zod@4.3.5): + resolution: {integrity: sha512-Mokfd6Ff5QjpdftICnQ9jC9opJcUqfPE31oG9sTYiXEykj5InIt0FA+9acLtCrnM/hx3Tz2BgkNQCXibjSDhpA==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + dependencies: + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + pkce-challenge: 5.0.1 + zod: 4.3.5 + dev: false + + /@ai-sdk/mistral@1.2.8(zod@4.3.5): resolution: {integrity: sha512-lv857D9UJqCVxiq2Fcu7mSPTypEHBUqLl1K+lCaP6X/7QAkcaxI36QDONG+tOhGHJOXTsS114u8lrUTaEiGXbg==} engines: {node: '>=18'} requiresBuild: true @@ -5062,23 +4988,23 @@ packages: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/mistral@3.0.1(zod@3.25.76): - resolution: {integrity: sha512-Uc2FW8OLOY9is5tuLxCOOfDd11s38agtLUcs10oaIDGDwMeae/kAZufmkrPQq8aaGWtjPs1Sp06fJVcIMz7V7g==} - engines: {node: '>=18'} + /@ai-sdk/mistral@4.0.7(zod@4.3.5): + resolution: {integrity: sha512-HhXtQBZyQBUWvh3q4wtQoq99WUOjb7dgGnTgedkdISHiNRZ4OkSQ1kYVFlbNG4XRddvIUf4CJd2fKzq+sYedAQ==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false - /@ai-sdk/openai-compatible@0.2.16(zod@3.25.76): + /@ai-sdk/openai-compatible@0.2.16(zod@4.3.5): resolution: {integrity: sha512-LkvfcM8slJedRyJa/MiMiaOzcMjV1zNDwzTHEGz7aAsgsQV0maLfmJRi/nuSwf5jmp0EouC+JXXDUj2l94HgQw==} engines: {node: '>=18'} requiresBuild: true @@ -5086,23 +5012,23 @@ packages: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/openai-compatible@2.0.13(zod@3.25.76): - resolution: {integrity: sha512-DShpuHZ9wiy3QtxJ4/Uq5csLxgNgeA3w58isYhZ34pSod2cBlRmJl3EyQzxZ1HD8e6sQDa9fvc0cwF5/EugBMw==} - engines: {node: '>=18'} + /@ai-sdk/openai-compatible@3.0.6(zod@4.3.5): + resolution: {integrity: sha512-1YB8Wt2l3X1gCLuF5bYoaQn04XXw+GKqxSvnHAnGEpK+xflJfnJ1l93KHbijLBObM6KAC7amKT9KjM9iu1B6zA==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false - /@ai-sdk/openai@1.3.24(zod@3.25.76): + /@ai-sdk/openai@1.3.24(zod@4.3.5): resolution: {integrity: sha512-GYXnGJTHRTZc4gJMSmFRgEQudjqd4PUN0ZjQhPwOAYH1yOAvQoG/Ikqs+HyISRbLPCrhbZnPKCNHuRU4OfpW0Q==} engines: {node: '>=18'} requiresBuild: true @@ -5110,8 +5036,8 @@ packages: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true @@ -5125,40 +5051,18 @@ packages: '@ai-sdk/provider-utils': 3.0.19(zod@3.25.76) zod: 3.25.76 - /@ai-sdk/openai@3.0.1(zod@3.25.76): - resolution: {integrity: sha512-P+qxz2diOrh8OrpqLRg+E+XIFVIKM3z2kFjABcCJGHjGbXBK88AJqmuKAi87qLTvTe/xn1fhZBjklZg9bTyigw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) - zod: 3.25.76 - dev: false - - /@ai-sdk/openai@3.0.12(zod@3.25.76): - resolution: {integrity: sha512-zqLWEKuaKnjXhu7xCw1jgz/+yTbd3F7EtgU4T2Q8BAo8OJC5wZv14l+kwM7Jai7M1/2Y2T/zBkrfiIu+7NsvfQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - dependencies: - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 - dev: false - - /@ai-sdk/openai@3.0.12(zod@4.3.5): - resolution: {integrity: sha512-zqLWEKuaKnjXhu7xCw1jgz/+yTbd3F7EtgU4T2Q8BAo8OJC5wZv14l+kwM7Jai7M1/2Y2T/zBkrfiIu+7NsvfQ==} - engines: {node: '>=18'} + /@ai-sdk/openai@4.0.9(zod@4.3.5): + resolution: {integrity: sha512-j7x7FC6KQJMQaJoi6hFLzbB2aXMnR+IA8h0BQH8YCbQESppbM7SzmZ4VAPpobIvx0rqiVNJ1JjraElOLuA31Ag==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) zod: 4.3.5 dev: false - /@ai-sdk/perplexity@1.1.9(zod@3.25.76): + /@ai-sdk/perplexity@1.1.9(zod@4.3.5): resolution: {integrity: sha512-Ytolh/v2XupXbTvjE18EFBrHLoNMH0Ueji3lfSPhCoRUfkwrgZ2D9jlNxvCNCCRiGJG5kfinSHvzrH5vGDklYA==} engines: {node: '>=18'} requiresBuild: true @@ -5166,23 +5070,23 @@ packages: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/perplexity@3.0.8(zod@3.25.76): - resolution: {integrity: sha512-QtQylDjQGDC9ZeUgQkJEOnM6i/o45q85LZbiB5gXrvOJ3ZtqdZPZ4z5IcPJXM1yY77bBUPEnZxAmebt/Ib4Zpg==} - engines: {node: '>=18'} + /@ai-sdk/perplexity@4.0.7(zod@4.3.5): + resolution: {integrity: sha512-qrd8klmEo8XGRH2m5lXsj+Hc+CqkqeZuV2cdLlgttIm8HRQfe5dFna/DodNslCSxVJu9Erk2M6pN8VMkmNvOLg==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false - /@ai-sdk/provider-utils@2.2.8(zod@3.25.76): + /@ai-sdk/provider-utils@2.2.8(zod@4.3.5): resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==} engines: {node: '>=18'} peerDependencies: @@ -5191,10 +5095,10 @@ packages: '@ai-sdk/provider': 1.1.3 nanoid: 3.3.11 secure-json-parse: 2.7.0 - zod: 3.25.76 + zod: 4.3.5 dev: false - /@ai-sdk/provider-utils@3.0.11(zod@3.25.76): + /@ai-sdk/provider-utils@3.0.11(zod@4.3.5): resolution: {integrity: sha512-4hgHj89VqyOHzGaV85TkcgvO8WjecVF35TOUVg+C56vnzpWSgdIZu/ZWZNdZ6BTrv8y0N1toBWW7XcWiRRicLg==} engines: {node: '>=18'} peerDependencies: @@ -5203,7 +5107,7 @@ packages: '@ai-sdk/provider': 2.0.0 '@standard-schema/spec': 1.1.0 eventsource-parser: 3.0.6 - zod: 3.25.76 + zod: 4.3.5 dev: false /@ai-sdk/provider-utils@3.0.16(zod@3.25.76): @@ -5251,76 +5155,17 @@ packages: zod: 4.3.5 dev: false - /@ai-sdk/provider-utils@3.0.3(zod@3.25.76): - resolution: {integrity: sha512-kAxIw1nYmFW1g5TvE54ZB3eNtgZna0RnLjPUp1ltz1+t9xkXJIuDT4atrwfau9IbS0BOef38wqrI8CjFfQrxhw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - dependencies: - '@ai-sdk/provider': 2.0.0 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 - zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) - dev: false - - /@ai-sdk/provider-utils@3.0.8(zod@3.25.76): - resolution: {integrity: sha512-cDj1iigu7MW2tgAQeBzOiLhjHOUM9vENsgh4oAVitek0d//WdgfPCsKO3euP7m7LyO/j9a1vr/So+BGNdpFXYw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - dependencies: - '@ai-sdk/provider': 2.0.0 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 - zod: 3.25.76 - dev: false - - /@ai-sdk/provider-utils@4.0.1(zod@3.25.76): - resolution: {integrity: sha512-de2v8gH9zj47tRI38oSxhQIewmNc+OZjYIOOaMoVWKL65ERSav2PYYZHPSPCrfOeLMkv+Dyh8Y0QGwkO29wMWQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - dependencies: - '@ai-sdk/provider': 3.0.0 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 - zod: 3.25.76 - - /@ai-sdk/provider-utils@4.0.1(zod@4.3.5): - resolution: {integrity: sha512-de2v8gH9zj47tRI38oSxhQIewmNc+OZjYIOOaMoVWKL65ERSav2PYYZHPSPCrfOeLMkv+Dyh8Y0QGwkO29wMWQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - dependencies: - '@ai-sdk/provider': 3.0.0 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 - zod: 4.3.5 - - /@ai-sdk/provider-utils@4.0.8(zod@3.25.76): - resolution: {integrity: sha512-ns9gN7MmpI8vTRandzgz+KK/zNMLzhrriiKECMt4euLtQFSBgNfydtagPOX4j4pS1/3KvHF6RivhT3gNQgBZsg==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - dependencies: - '@ai-sdk/provider': 3.0.4 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 - zod: 3.25.76 - dev: false - - /@ai-sdk/provider-utils@4.0.8(zod@4.3.5): - resolution: {integrity: sha512-ns9gN7MmpI8vTRandzgz+KK/zNMLzhrriiKECMt4euLtQFSBgNfydtagPOX4j4pS1/3KvHF6RivhT3gNQgBZsg==} - engines: {node: '>=18'} + /@ai-sdk/provider-utils@5.0.6(zod@4.3.5): + resolution: {integrity: sha512-i4mVayGtC+HrRmtfPFOxvKKQgFU+1dwTTsh4MY0jY1MaGuppOwDFrNYrJ3dDXWMkO3o6FDVAKY8ZDsy7hLsO9Q==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/provider': 3.0.4 + '@ai-sdk/provider': 4.0.2 '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 + '@workflow/serde': 4.1.0 + eventsource-parser: 3.1.0 zod: 4.3.5 - dev: false /@ai-sdk/provider@1.1.3: resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==} @@ -5335,20 +5180,13 @@ packages: dependencies: json-schema: 0.4.0 - /@ai-sdk/provider@3.0.0: - resolution: {integrity: sha512-m9ka3ptkPQbaHHZHqDXDF9C9B5/Mav0KTdky1k2HZ3/nrW2t1AgObxIVPyGDWQNS9FXT/FS6PIoSjpcP/No8rQ==} - engines: {node: '>=18'} - dependencies: - json-schema: 0.4.0 - - /@ai-sdk/provider@3.0.4: - resolution: {integrity: sha512-5KXyBOSEX+l67elrEa+wqo/LSsSTtrPj9Uoh3zMbe/ceQX4ucHI3b9nUEfNkGF3Ry1svv90widAt+aiKdIJasQ==} - engines: {node: '>=18'} + /@ai-sdk/provider@4.0.2: + resolution: {integrity: sha512-pfPoy9J1B1xV7cqJ8MYHOsDYrMv5tR3+EMNfI249OhkD2uRakvav3Fo7XpD2luuN/YNCBY7KfEQc7vEV7KEtyw==} + engines: {node: '>=22'} dependencies: json-schema: 0.4.0 - dev: false - /@ai-sdk/react@1.2.12(react@19.2.3)(zod@3.25.76): + /@ai-sdk/react@1.2.12(react@19.2.3)(zod@4.3.5): resolution: {integrity: sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==} engines: {node: '>=18'} peerDependencies: @@ -5358,12 +5196,12 @@ packages: zod: optional: true dependencies: - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + '@ai-sdk/ui-utils': 1.2.11(zod@4.3.5) react: 19.2.3 swr: 2.3.6(react@19.2.3) throttleit: 2.1.0 - zod: 3.25.76 + zod: 4.3.5 dev: false /@ai-sdk/react@2.0.115(react@19.2.3)(zod@4.3.5): @@ -5384,72 +5222,74 @@ packages: zod: 4.3.5 dev: false - /@ai-sdk/react@3.0.3(react@19.2.3)(zod@3.25.76): - resolution: {integrity: sha512-mLIgQuBdIX9gxCYQN3Pv/J8ARoFreIKYr/TVQtI+FwEzejuGFimTyhDln7UIBfrnm3Mpn1xENIWZfDfCRF7wkw==} - engines: {node: '>=18'} + /@ai-sdk/react@4.0.19(react@19.2.3)(zod@4.3.5): + resolution: {integrity: sha512-3n/UxiZZh727ROIjQMEyphyzsz3N8bKyBIcfFHicLq7fJjuydQ8owcGRmLXoU5jrhGBRTf4O1QhwmgYNU+vkJA==} + engines: {node: '>=22'} peerDependencies: react: ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1 dependencies: - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) - ai: 6.0.3(zod@3.25.76) + '@ai-sdk/mcp': 2.0.9(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + ai: 7.0.18(zod@4.3.5) react: 19.2.3 - swr: 2.3.6(react@19.2.3) + swr: 2.4.2(react@19.2.3) throttleit: 2.1.0 transitivePeerDependencies: - zod dev: false - /@ai-sdk/togetherai@0.2.16(zod@3.25.76): + /@ai-sdk/togetherai@0.2.16(zod@4.3.5): resolution: {integrity: sha512-vCtYUrIdep0M6GIvemyYpwSa9SWOleb/2cuGNXcxzU2xy4GJQdHK/MigQbT9rfeuqnjU2W9KIdtAVJGVwIBogw==} engines: {node: '>=18'} requiresBuild: true peerDependencies: zod: ^3.0.0 dependencies: - '@ai-sdk/openai-compatible': 0.2.16(zod@3.25.76) + '@ai-sdk/openai-compatible': 0.2.16(zod@4.3.5) '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/togetherai@2.0.13(zod@3.25.76): - resolution: {integrity: sha512-/q4GmMGjWPAjhSeqEjKVTypwT2YB3rH6gXRqT1zlNLwlOQPTMtkNDaLOBdQ+bqtakmyJMavfJOu6awq6Phc5xw==} - engines: {node: '>=18'} + /@ai-sdk/togetherai@3.0.7(zod@4.3.5): + resolution: {integrity: sha512-qcnRe0MxiMO6TjgZVfi/4hIuGUkBJqyq0BEOzGsoyV7bTdgYvcfQdv+6O96rtp1y9kammCKsjYcxZTbOZjdtug==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/openai-compatible': 2.0.13(zod@3.25.76) - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/openai-compatible': 3.0.6(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false - /@ai-sdk/ui-utils@1.2.11(zod@3.25.76): + /@ai-sdk/ui-utils@1.2.11(zod@4.3.5): resolution: {integrity: sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==} engines: {node: '>=18'} peerDependencies: zod: ^3.23.8 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 + zod-to-json-schema: 3.25.1(zod@4.3.5) dev: false - /@ai-sdk/vercel@2.0.13(zod@3.25.76): - resolution: {integrity: sha512-UuqNZ2fc3SNCYbCXnIx5p6NtyFK7JRNDz223msF1WH2i5LhV6uqo4hCy+eb71qcMf3xn/q9wxL8dSaz08QiLvw==} - engines: {node: '>=18'} + /@ai-sdk/vercel@3.0.6(zod@4.3.5): + resolution: {integrity: sha512-rU6VKLiEi4FHoNHPPYbtG+Ig70ZS1ya/5ZETR4FYsptM8mcRfslwo/YizlB/BhwBATQteHbBHnyDwzZFvnRKAg==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/openai-compatible': 2.0.13(zod@3.25.76) - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/openai-compatible': 3.0.6(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + zod: 4.3.5 dev: false - /@ai-sdk/vue@2.0.63(vue@3.5.22)(zod@3.25.76): + /@ai-sdk/vue@2.0.63(vue@3.5.22)(zod@4.3.5): resolution: {integrity: sha512-hP387oM7E8SsYLR8eKU8xU3DH3a8O+VnY2k+A4rauGygscgSg2CIowRJoXi2MxIFaJDDJoSrhCp3+lxcShXmrQ==} engines: {node: '>=18'} peerDependencies: @@ -5461,48 +5301,36 @@ packages: zod: optional: true dependencies: - '@ai-sdk/provider-utils': 3.0.11(zod@3.25.76) - ai: 5.0.63(zod@3.25.76) + '@ai-sdk/provider-utils': 3.0.11(zod@4.3.5) + ai: 5.0.63(zod@4.3.5) swrv: 1.1.0(vue@3.5.22) vue: 3.5.22(typescript@5.9.3) - zod: 3.25.76 + zod: 4.3.5 dev: false - /@ai-sdk/xai@1.2.18(zod@3.25.76): + /@ai-sdk/xai@1.2.18(zod@4.3.5): resolution: {integrity: sha512-T70WEu+UKXD/Fdj9ck+ujIqUp5ru06mJ/7usePXeXL5EeTi8KXevXF9AMIDdhyD5MZPT2jI8t19lEr8Bhuh/Bg==} engines: {node: '>=18'} requiresBuild: true peerDependencies: zod: ^3.0.0 dependencies: - '@ai-sdk/openai-compatible': 0.2.16(zod@3.25.76) + '@ai-sdk/openai-compatible': 0.2.16(zod@4.3.5) '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + zod: 4.3.5 dev: false optional: true - /@ai-sdk/xai@3.0.26(zod@3.25.76): - resolution: {integrity: sha512-mwY6BjlO8fR6+j13k1XjsvdKa2VEa8DuA6gEW6Ihd7K7UB2Dqcw7+zrRhKIFyyQekjc8CFGtrA/W7khgd/aOCQ==} - engines: {node: '>=18'} + /@ai-sdk/xai@4.0.9(zod@4.3.5): + resolution: {integrity: sha512-hwK3vplmnjylCPfTvugj+n41ueFfW6C5U5twXHpkVdldOSp05Uc4ZocW+XVykWDyv4HdBUL0ia1BwAGXkJQt7g==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/openai-compatible': 2.0.13(zod@3.25.76) - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.8(zod@3.25.76) - zod: 3.25.76 - dev: false - - /@aihubmix/ai-sdk-provider@1.0.1: - resolution: {integrity: sha512-z4VIND5xkPNgKUpdncPhJmZ45fMrKgZUVus3p9wkbVXteia7MNQch4mw6ma/hjmeTcAW4Ym7m7HCy3gFhwWArQ==} - engines: {node: '>=18'} - dependencies: - '@ai-sdk/anthropic': 3.0.1(zod@4.3.5) - '@ai-sdk/google': 3.0.1(zod@4.3.5) - '@ai-sdk/openai': 3.0.12(zod@4.3.5) - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@4.3.5) + '@ai-sdk/openai-compatible': 3.0.6(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) zod: 4.3.5 dev: false @@ -6339,7 +6167,7 @@ packages: resolution: {integrity: sha512-Bei+RL0cDxxV+lW2UezLbCYYNeJm6Nzee0TpW0FfyTRBhH9C1XQh4+x+IClriXvgBnRquTMMYsmJfvx8iyLKrg==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/types': 4.3.2 + '@smithy/types': 4.12.0 tslib: 2.8.1 dev: false @@ -8219,7 +8047,7 @@ packages: - encoding dev: false - /@browserbasehq/stagehand@2.5.0(deepmerge@4.3.1)(dotenv@16.6.1)(react@19.2.3)(zod@3.25.76): + /@browserbasehq/stagehand@2.5.0(deepmerge@4.3.1)(dotenv@16.6.1)(react@19.2.3)(zod@4.3.5): resolution: {integrity: sha512-Cannwg1WfpiJGDMdPGyx4i59SPBEV9ctTVZctGn+XVbP/ymwcQVFsyYYwSV0cK8rOk90TZK80TkMiuQGpfCF6g==} peerDependencies: deepmerge: ^4.3.1 @@ -8230,31 +8058,31 @@ packages: '@browserbasehq/sdk': 2.6.0 '@google/genai': 0.8.0 '@modelcontextprotocol/sdk': 1.17.2 - ai: 4.3.19(react@19.2.3)(zod@3.25.76) + ai: 4.3.19(react@19.2.3)(zod@4.3.5) deepmerge: 4.3.1 devtools-protocol: 0.0.1464554 dotenv: 16.6.1 fetch-cookie: 3.1.0 - openai: 4.104.0(ws@8.18.3)(zod@3.25.76) + openai: 4.104.0(ws@8.18.3)(zod@4.3.5) pino: 9.9.0 pino-pretty: 13.1.1 playwright: 1.54.2 ws: 8.18.3 - zod: 3.25.76 - zod-to-json-schema: 3.25.0(zod@3.25.76) + zod: 4.3.5 + zod-to-json-schema: 3.25.0(zod@4.3.5) optionalDependencies: - '@ai-sdk/anthropic': 1.2.12(zod@3.25.76) - '@ai-sdk/azure': 1.3.25(zod@3.25.76) - '@ai-sdk/cerebras': 0.2.16(zod@3.25.76) - '@ai-sdk/deepseek': 0.2.16(zod@3.25.76) - '@ai-sdk/google': 1.2.22(zod@3.25.76) - '@ai-sdk/groq': 1.2.9(zod@3.25.76) - '@ai-sdk/mistral': 1.2.8(zod@3.25.76) - '@ai-sdk/openai': 1.3.24(zod@3.25.76) - '@ai-sdk/perplexity': 1.1.9(zod@3.25.76) - '@ai-sdk/togetherai': 0.2.16(zod@3.25.76) - '@ai-sdk/xai': 1.2.18(zod@3.25.76) - ollama-ai-provider: 1.2.0(zod@3.25.76) + '@ai-sdk/anthropic': 1.2.12(zod@4.3.5) + '@ai-sdk/azure': 1.3.25(zod@4.3.5) + '@ai-sdk/cerebras': 0.2.16(zod@4.3.5) + '@ai-sdk/deepseek': 0.2.16(zod@4.3.5) + '@ai-sdk/google': 1.2.22(zod@4.3.5) + '@ai-sdk/groq': 1.2.9(zod@4.3.5) + '@ai-sdk/mistral': 1.2.8(zod@4.3.5) + '@ai-sdk/openai': 1.3.24(zod@4.3.5) + '@ai-sdk/perplexity': 1.1.9(zod@4.3.5) + '@ai-sdk/togetherai': 0.2.16(zod@4.3.5) + '@ai-sdk/xai': 1.2.18(zod@4.3.5) + ollama-ai-provider: 1.2.0(zod@4.3.5) transitivePeerDependencies: - bufferutil - encoding @@ -8639,7 +8467,7 @@ packages: - supports-color dev: false - /@chroma-core/openai@0.1.7(chromadb@3.0.12)(zod@3.25.76): + /@chroma-core/openai@0.1.7(chromadb@3.0.12)(zod@4.3.5): resolution: {integrity: sha512-HNSgc6zXWNYUeoyCJwT1xYD3QME6pNJ4iujbZZ+GLsnlmBPZ+VwU+DF95XKaDRril8BWKffc5s8KprP8sJLvvg==} engines: {node: '>=20'} peerDependencies: @@ -8647,7 +8475,7 @@ packages: dependencies: '@chroma-core/ai-embeddings-common': 0.1.7 chromadb: 3.0.12 - openai: 4.104.0(ws@8.18.3)(zod@3.25.76) + openai: 4.104.0(ws@8.18.3)(zod@4.3.5) transitivePeerDependencies: - encoding - ws @@ -8746,6 +8574,7 @@ packages: /@colors/colors@1.6.0: resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} engines: {node: '>=0.1.90'} + dev: true /@commitlint/cli@18.6.1(@types/node@24.2.1)(typescript@5.9.2): resolution: {integrity: sha512-5IDE0a+lWGdkOvKH892HHAZgbAjcj1mT5QrfA/SVbLJV/BbBMGyKN0W5mhgjekPJJwEQdVNvhl9PwUacY58Usw==} @@ -9050,7 +8879,7 @@ packages: graphql-scalars: 1.25.0(graphql@16.11.0) graphql-yoga: 5.17.1(graphql@16.11.0) hono: 4.10.8 - openai: 5.23.2(zod@3.25.76) + openai: 5.23.2(zod@4.3.5) partial-json: 0.1.7 pino: 9.9.0 pino-pretty: 11.3.0 @@ -9155,7 +8984,7 @@ packages: cors: 2.8.5 express: 4.21.2 hono: 4.10.8 - openai: 5.23.2(zod@3.25.76) + openai: 5.23.2(zod@4.3.5) rxjs: 7.8.1 transitivePeerDependencies: - supports-color @@ -9193,14 +9022,6 @@ packages: kuler: 2.0.0 dev: true - /@dabh/diagnostics@2.0.8: - resolution: {integrity: sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==} - dependencies: - '@so-ric/colorspace': 1.1.6 - enabled: 2.0.0 - kuler: 2.0.0 - dev: false - /@daytonaio/api-client@0.139.0: resolution: {integrity: sha512-Xmjrkq7MW/DaZLQEf0HfT7Y38N8SesXvWqAKSEjdf3ifGVQVx37aOB8El1jOvfrndqzTcSbumSxro2nhKK5K5A==} dependencies: @@ -9275,40 +9096,18 @@ packages: dependencies: '@emnapi/wasi-threads': 1.2.2 tslib: 2.8.1 - optional: true - - /@emnapi/core@1.4.5: - resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} - dependencies: - '@emnapi/wasi-threads': 1.0.4 - tslib: 2.8.1 - dev: true /@emnapi/runtime@1.11.1: resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} requiresBuild: true dependencies: tslib: 2.8.1 - optional: true - - /@emnapi/runtime@1.4.5: - resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} - dependencies: - tslib: 2.8.1 - dev: true - - /@emnapi/wasi-threads@1.0.4: - resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} - dependencies: - tslib: 2.8.1 - dev: true /@emnapi/wasi-threads@1.2.2: resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} requiresBuild: true dependencies: tslib: 2.8.1 - optional: true /@envelop/core@5.4.0: resolution: {integrity: sha512-/1fat63pySE8rw/dZZArEVytLD90JApY85deDJ0/34gm+yhQ3k70CloSUevxoOE4YCGveG3s9SJJfQeeB4NAtQ==} @@ -10191,23 +9990,28 @@ packages: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} dev: true - /@gitlab/gitlab-ai-provider@3.1.1(@ai-sdk/provider-utils@4.0.1)(@ai-sdk/provider@3.0.4)(graphql@16.11.0)(ws@8.18.3): - resolution: {integrity: sha512-7AtFrCflq2NzC99bj7YaqbQDCZyaScM1+L4ujllV5syiRTFE239Uhnd/yEkPXa7sUAnNRfN3CWusCkQ2zK/q9g==} + /@gitlab/gitlab-ai-provider@4.1.0(@ai-sdk/provider-utils@5.0.6)(@ai-sdk/provider@4.0.2)(graphql@16.11.0)(ws@8.18.3): + resolution: {integrity: sha512-wYW0bB4qI4IA46vcs7zRTox6jkRjxJd357p6Nal84/kjAplOCskn8QhQTUXa8LpNutlYepJfOSZtKArGISCHdQ==} engines: {node: '>=18'} + deprecated: 'This package has moved to ''gitlab-ai-provider''. Please run: npm install gitlab-ai-provider' peerDependencies: '@ai-sdk/provider': '>=2.0.0' '@ai-sdk/provider-utils': '>=3.0.0' dependencies: - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) '@anthropic-ai/sdk': 0.71.2(zod@3.25.76) '@anycable/core': 0.9.2 graphql-request: 6.1.0(graphql@16.11.0) isomorphic-ws: 5.0.0(ws@8.18.3) + openai: 6.45.0(ws@8.18.3)(zod@3.25.76) socket.io-client: 4.8.3 vscode-jsonrpc: 8.2.1 zod: 3.25.76 transitivePeerDependencies: + - '@aws-sdk/credential-provider-node' + - '@smithy/hash-node' + - '@smithy/signature-v4' - bufferutil - encoding - graphql @@ -12262,6 +12066,34 @@ packages: transitivePeerDependencies: - supports-color + /@modelcontextprotocol/sdk@1.24.3(zod@4.3.5): + resolution: {integrity: sha512-YgSHW29fuzKKAHTGe9zjNoo+yF8KaQPzDC2W9Pv41E7/57IfY+AMGJ/aDFlgTLcVVELoggKE4syABCE75u3NCw==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + dependencies: + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.1.0 + express-rate-limit: 7.5.1(express@5.1.0) + jose: 6.1.3 + pkce-challenge: 5.0.0 + raw-body: 3.0.1 + zod: 4.3.5 + zod-to-json-schema: 3.25.0(zod@4.3.5) + transitivePeerDependencies: + - supports-color + dev: false + /@mole-inc/bin-wrapper@8.0.1: resolution: {integrity: sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -12288,23 +12120,6 @@ packages: strict-event-emitter: 0.5.1 dev: true - /@mymediset/sap-ai-provider@2.1.0(ai@6.0.3): - resolution: {integrity: sha512-mvm2p+evS51GfNJwObLnGruhBrnV7DBCrm3SafYoZHrlmcFsAvCmRcofvk5AX7LdQpTCH+Q8pfo+gZvISOvnzA==} - engines: {node: '>=18'} - peerDependencies: - ai: ^6.0.0 - dependencies: - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@4.3.5) - '@sap-ai-sdk/orchestration': 2.5.0 - ai: 6.0.3(zod@3.25.76) - zod: 4.3.5 - zod-to-json-schema: 3.25.1(zod@4.3.5) - transitivePeerDependencies: - - debug - - supports-color - dev: false - /@napi-rs/nice-android-arm-eabi@1.0.4: resolution: {integrity: sha512-OZFMYUkih4g6HCKTjqJHhMUlgvPiDuSLZPbPBWHLjKmFTv74COzRlq/gwHtmEVaR39mJQ6ZyttDl2HNMUbLVoA==} engines: {node: '>= 10'} @@ -12486,8 +12301,8 @@ packages: /@napi-rs/wasm-runtime@0.2.4: resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} dependencies: - '@emnapi/core': 1.4.5 - '@emnapi/runtime': 1.4.5 + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 '@tybys/wasm-util': 0.9.0 dev: true @@ -13746,7 +13561,7 @@ packages: - magicast dev: false - /@nuxt/ui@4.0.1(embla-carousel@8.6.0)(typescript@5.9.3)(vite@7.2.7)(vue-router@4.5.1)(vue@3.5.22)(zod@3.25.76): + /@nuxt/ui@4.0.1(embla-carousel@8.6.0)(typescript@5.9.3)(vite@7.2.7)(vue-router@4.5.1)(vue@3.5.22)(zod@4.3.5): resolution: {integrity: sha512-mtY8wairYw2WXotCYxXG0CmxbqyJWaMHYbes3p+vFaOJ2kdQHQh7QM/7ziQeZHxVNHciBcWayi6G+55ok/kHAQ==} hasBin: true peerDependencies: @@ -13774,7 +13589,7 @@ packages: zod: optional: true dependencies: - '@ai-sdk/vue': 2.0.63(vue@3.5.22)(zod@3.25.76) + '@ai-sdk/vue': 2.0.63(vue@3.5.22)(zod@4.3.5) '@iconify/vue': 5.0.0(vue@3.5.22) '@internationalized/date': 3.10.0 '@internationalized/number': 3.6.5 @@ -13821,7 +13636,7 @@ packages: vaul-vue: 0.4.1(reka-ui@2.5.1)(vue@3.5.22) vue-component-type-helpers: 3.1.1 vue-router: 4.5.1(vue@3.5.22) - zod: 3.25.76 + zod: 4.3.5 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -14797,14 +14612,14 @@ packages: resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} dev: true - /@openrouter/ai-sdk-provider@2.3.1(ai@6.0.3)(zod@4.3.5): - resolution: {integrity: sha512-RkOUMSetrbS1i8kW1wIkfuq0RpXtiJOiFCx/AfEjGNZA8xOjdAosqPiImo2805Q6Px/9k1LUxu8NUmlSnrWrqg==} - engines: {node: '>=18'} + /@openrouter/ai-sdk-provider@3.0.0(ai@7.0.18)(zod@4.3.5): + resolution: {integrity: sha512-m9XTSWoODH2RM5OsZpaGiN7QRR8cdP5paBWq699Tu3JVmGPBKT8xF8XwV0ZBVVsjikD/JgWfak4VSsTR4wAVbg==} + engines: {node: '>=22'} peerDependencies: - ai: ^6.0.0 - zod: ^3.25.0 || ^4.0.0 + ai: ^7.0.0 + zod: ^3.25.76 || ^4.1.8 dependencies: - ai: 6.0.3(zod@4.3.5) + ai: 7.0.18(zod@4.3.5) zod: 4.3.5 dev: false @@ -18022,138 +17837,6 @@ packages: requiresBuild: true optional: true - /@sap-ai-sdk/ai-api@2.5.0: - resolution: {integrity: sha512-jhijNSpb7zURSNBgx9vzoPH1GSp9yZRGnwpZ2gAgjK2j5dyx9uJgjBItCkb7U1SlDjby5Ju9T/Cu8AZInVdwfw==} - dependencies: - '@sap-ai-sdk/core': 2.5.0 - '@sap-cloud-sdk/connectivity': 4.3.1 - '@sap-cloud-sdk/util': 4.3.1 - transitivePeerDependencies: - - debug - - supports-color - dev: false - - /@sap-ai-sdk/core@2.5.0: - resolution: {integrity: sha512-BJQUG+kw9W4moaIB9GQ93teEOAU18Fvbr9BTwfT5gaiD1l9M+HAxirNSH9quTpdGOszbDtg4YbrQB2jh/JesLA==} - dependencies: - '@sap-cloud-sdk/connectivity': 4.3.1 - '@sap-cloud-sdk/http-client': 4.3.1 - '@sap-cloud-sdk/openapi': 4.3.1 - '@sap-cloud-sdk/util': 4.3.1 - transitivePeerDependencies: - - debug - - supports-color - dev: false - - /@sap-ai-sdk/orchestration@2.5.0: - resolution: {integrity: sha512-pztozIP1PXHSqilT1Lqmmn63iZczfdaldNpylLHmvDfSv9aWupBGer7z0uFUhq5Qjzglt5JuUK1L8QevKT8asg==} - dependencies: - '@sap-ai-sdk/ai-api': 2.5.0 - '@sap-ai-sdk/core': 2.5.0 - '@sap-ai-sdk/prompt-registry': 2.5.0 - '@sap-cloud-sdk/util': 4.3.1 - yaml: 2.8.2 - transitivePeerDependencies: - - debug - - supports-color - dev: false - - /@sap-ai-sdk/prompt-registry@2.5.0: - resolution: {integrity: sha512-NfQFXjRaUCQpqPlVuEkBuSCg8BP5Mz2ZnGjKwkydv1H7r+PQJu15peqP6JYcL+4Fk1EI9bgaYh5RCCCOjchVwg==} - dependencies: - '@sap-ai-sdk/core': 2.5.0 - zod: 4.3.5 - transitivePeerDependencies: - - debug - - supports-color - dev: false - - /@sap-cloud-sdk/connectivity@4.3.1: - resolution: {integrity: sha512-gugKiYtXQHOrvt2qnydGvk3g7xlX6F3lEVBWpPpFGUJPRQpAE/AptM9egnty2zv02a6YIhNcEc//kzBfM9A70Q==} - dependencies: - '@sap-cloud-sdk/resilience': 4.3.1 - '@sap-cloud-sdk/util': 4.3.1 - '@sap/xsenv': 6.0.0 - '@sap/xssec': 4.12.2 - async-retry: 1.3.3 - axios: 1.13.5 - jks-js: 1.1.5 - jsonwebtoken: 9.0.3 - transitivePeerDependencies: - - debug - - supports-color - dev: false - - /@sap-cloud-sdk/http-client@4.3.1: - resolution: {integrity: sha512-WnnffWMgvLR7C68T6ZRnSeWXGgPKIiPaPypE4BtijJKueTSk7kVLblu9t5dlH51S5pI9HoDFt9OVqRrsBTnFAQ==} - dependencies: - '@sap-cloud-sdk/connectivity': 4.3.1 - '@sap-cloud-sdk/resilience': 4.3.1 - '@sap-cloud-sdk/util': 4.3.1 - axios: 1.13.5 - transitivePeerDependencies: - - debug - - supports-color - dev: false - - /@sap-cloud-sdk/openapi@4.3.1: - resolution: {integrity: sha512-I5zlquFaNKr3gz/AOQ7cYFUi/rgDIkCalmAZUbWM4E0rR3jWuX1ochu650Qy2gAB7FOZ6nQtqPW+0kHDXnR1fg==} - dependencies: - '@sap-cloud-sdk/connectivity': 4.3.1 - '@sap-cloud-sdk/http-client': 4.3.1 - '@sap-cloud-sdk/resilience': 4.3.1 - '@sap-cloud-sdk/util': 4.3.1 - axios: 1.13.5 - transitivePeerDependencies: - - debug - - supports-color - dev: false - - /@sap-cloud-sdk/resilience@4.3.1: - resolution: {integrity: sha512-lw9tT+9l94bIKvpbN9016ELr+qYANfAgkp8qL0Wsm1OGCPbALWtfNVBPY4Ni4O6ep+6sIFL6ACcwjrdDrogF8A==} - dependencies: - '@sap-cloud-sdk/util': 4.3.1 - async-retry: 1.3.3 - axios: 1.13.5 - opossum: 9.0.0 - transitivePeerDependencies: - - debug - dev: false - - /@sap-cloud-sdk/util@4.3.1: - resolution: {integrity: sha512-ew3+RiyUAKKhb/h/M1g2di9DjoeDQ3uQIDS7a+rN9lqlaP2+mb0mbK8x1PHLJ8agvZNjFR5y5k2jKmIiHVFT3A==} - dependencies: - axios: 1.13.5 - chalk: 4.1.2 - logform: 2.7.0 - voca: 1.4.1 - winston: 3.19.0 - winston-transport: 4.9.0 - transitivePeerDependencies: - - debug - dev: false - - /@sap/xsenv@6.0.0: - resolution: {integrity: sha512-9bNpJXmxndWn5JbRCPPtbeMqldXOn2Od17ybS92PHd1rNkZ80IMmOURHNct5YSVQ1MKBIDAyC+ck6VL7cVAfUA==} - engines: {node: ^20.0.0 || ^22.0.0 || ^24.0.0} - dependencies: - debug: 4.4.1 - node-cache: 5.1.2 - verror: 1.10.1 - transitivePeerDependencies: - - supports-color - dev: false - - /@sap/xssec@4.12.2: - resolution: {integrity: sha512-T4yy/lXZerAREJnb2Yte3oL4iDJOKlmWrMwMLXY5/U33tuKDVzIVO3VQqfLTGTIJABk4msE+km0YWpds+fSv3w==} - engines: {node: '>=18'} - dependencies: - debug: 4.4.3(supports-color@10.2.2) - jwt-decode: 4.0.0 - transitivePeerDependencies: - - supports-color - dev: false - /@scalar/openapi-types@0.1.1: resolution: {integrity: sha512-NMy3QNk6ytcCoPUGJH0t4NNr36OWXgZhA3ormr3TvhX1NDgoF95wFyodGVH8xiHeUyn2/FxtETm8UBLbB5xEmg==} engines: {node: '>=18'} @@ -18456,6 +18139,14 @@ packages: tslib: 2.8.1 dev: false + /@smithy/core@3.29.2: + resolution: {integrity: sha512-DXUk6yU0C1Q1tYvJh1VCtl8QOBcSoZpKwjTPkxT6A4MUQYHvgeKGByL8mrEdxnvhdf9nq5GyzmRb5n/vPgu3Lw==} + engines: {node: '>=18.0.0'} + dependencies: + '@smithy/types': 4.16.0 + tslib: 2.8.1 + dev: false + /@smithy/credential-provider-imds@4.2.8: resolution: {integrity: sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==} engines: {node: '>=18.0.0'} @@ -18467,23 +18158,21 @@ packages: tslib: 2.8.1 dev: false - /@smithy/eventstream-codec@4.0.5: - resolution: {integrity: sha512-miEUN+nz2UTNoRYRhRqVTJCx7jMeILdAurStT2XoS+mhokkmz1xAPp95DFW9Gxt4iF2VBqpeF9HbTQ3kY1viOA==} + /@smithy/eventstream-codec@4.2.8: + resolution: {integrity: sha512-jS/O5Q14UsufqoGhov7dHLOPCzkYJl9QDzusI2Psh4wyYx/izhzvX9P4D69aTxcdfVhEPhjK+wYyn/PzLjKbbw==} engines: {node: '>=18.0.0'} dependencies: '@aws-crypto/crc32': 5.2.0 - '@smithy/types': 4.3.2 - '@smithy/util-hex-encoding': 4.0.0 + '@smithy/types': 4.12.0 + '@smithy/util-hex-encoding': 4.2.0 tslib: 2.8.1 dev: false - /@smithy/eventstream-codec@4.2.8: - resolution: {integrity: sha512-jS/O5Q14UsufqoGhov7dHLOPCzkYJl9QDzusI2Psh4wyYx/izhzvX9P4D69aTxcdfVhEPhjK+wYyn/PzLjKbbw==} + /@smithy/eventstream-codec@4.4.7: + resolution: {integrity: sha512-YNodWVjMFOMAyjQgpHBBCz62DbYu4xwhpt+z5HRf7OZPwrfHgNDCyUZxaC0fy9/2TWcO+niOMHSl8aMgfbWZTQ==} engines: {node: '>=18.0.0'} dependencies: - '@aws-crypto/crc32': 5.2.0 - '@smithy/types': 4.12.0 - '@smithy/util-hex-encoding': 4.2.0 + '@smithy/core': 3.29.2 tslib: 2.8.1 dev: false @@ -18577,13 +18266,6 @@ packages: tslib: 2.8.1 dev: false - /@smithy/is-array-buffer@4.0.0: - resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==} - engines: {node: '>=18.0.0'} - dependencies: - tslib: 2.8.1 - dev: false - /@smithy/is-array-buffer@4.2.0: resolution: {integrity: sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==} engines: {node: '>=18.0.0'} @@ -18758,8 +18440,8 @@ packages: tslib: 2.8.1 dev: false - /@smithy/types@4.3.2: - resolution: {integrity: sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw==} + /@smithy/types@4.16.0: + resolution: {integrity: sha512-aVUabzlBBmY0PfvVgLKQSOGFIL5/7R54JE3uD9a5Ay/jSED61SkuAcCYENNXJzYUvJ1NPrWO0P+rAXHCkbBUKw==} engines: {node: '>=18.0.0'} dependencies: tslib: 2.8.1 @@ -18805,14 +18487,6 @@ packages: tslib: 2.8.1 dev: false - /@smithy/util-buffer-from@4.0.0: - resolution: {integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/is-array-buffer': 4.0.0 - tslib: 2.8.1 - dev: false - /@smithy/util-buffer-from@4.2.0: resolution: {integrity: sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==} engines: {node: '>=18.0.0'} @@ -18860,13 +18534,6 @@ packages: tslib: 2.8.1 dev: false - /@smithy/util-hex-encoding@4.0.0: - resolution: {integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==} - engines: {node: '>=18.0.0'} - dependencies: - tslib: 2.8.1 - dev: false - /@smithy/util-hex-encoding@4.2.0: resolution: {integrity: sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==} engines: {node: '>=18.0.0'} @@ -18920,19 +18587,19 @@ packages: tslib: 2.8.1 dev: false - /@smithy/util-utf8@4.0.0: - resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==} + /@smithy/util-utf8@4.2.0: + resolution: {integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/util-buffer-from': 4.0.0 + '@smithy/util-buffer-from': 4.2.0 tslib: 2.8.1 dev: false - /@smithy/util-utf8@4.2.0: - resolution: {integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==} + /@smithy/util-utf8@4.4.7: + resolution: {integrity: sha512-NskAyOBZcHO+fa1HwkwWuPbMUQE7NZ4IWBnAc71E4f9IdoQ65WLkdJ2ed/n4Q8vePSgZUN/CbyGZLBiI7dMI+w==} engines: {node: '>=18.0.0'} dependencies: - '@smithy/util-buffer-from': 4.2.0 + '@smithy/core': 3.29.2 tslib: 2.8.1 dev: false @@ -18952,13 +18619,6 @@ packages: tslib: 2.8.1 dev: false - /@so-ric/colorspace@1.1.6: - resolution: {integrity: sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==} - dependencies: - color: 5.0.3 - text-hex: 1.0.0 - dev: false - /@socket.io/component-emitter@3.1.2: resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} dev: false @@ -18968,6 +18628,7 @@ packages: /@standard-schema/spec@1.0.0: resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + dev: false /@standard-schema/spec@1.1.0: resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -20931,6 +20592,7 @@ packages: /@types/triple-beam@1.3.5: resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + dev: true /@types/trusted-types@2.0.7: resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -21426,10 +21088,9 @@ packages: resolution: {integrity: sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==} engines: {node: '>= 20'} - /@vercel/oidc@3.1.0: - resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} + /@vercel/oidc@3.2.0: + resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} engines: {node: '>= 20'} - dev: false /@vitejs/plugin-react@5.1.2(vite@7.2.7): resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} @@ -21783,38 +21444,6 @@ packages: resolution: {integrity: sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==} dev: false - /@voltagent/internal@0.0.9: - resolution: {integrity: sha512-Kaa2jW60VsfYVotuXC81LmNOJ07Lf1yq36vMteNKKa5seIsKkJ75PvIbMp52eEZ/ky/oBXrs94UXrQNqXBJ80Q==} - dev: false - - /@voltagent/vercel-ai@1.0.0(@voltagent/core@packages+core)(zod@3.25.76): - resolution: {integrity: sha512-ooknKRG0G79YuHJAPuZ5Xoy1oiirq0XfyS5ncKO2+yMqasRSn5phd8wHq5x4nVwRFMY1mulo3YZJ2QGQLj1mIg==} - peerDependencies: - '@voltagent/core': ^0.1.71 - zod: ^3.25.0 - dependencies: - '@ai-sdk/openai': 2.0.85(zod@3.25.76) - '@voltagent/core': link:packages/core - ai: 5.0.113(zod@3.25.76) - ts-pattern: 5.8.0 - type-fest: 4.41.0 - zod: 3.25.76 - dev: false - - /@voltagent/vercel-ui@1.0.1(@voltagent/core@packages+core)(zod@3.25.76): - resolution: {integrity: sha512-0suTujwLPQX7TZIarEI6Z4PZUtnFZguuevLUBwlu9bIP32VpZoSn20+Voovm16qQ+2jirhltdjuj/XAy6hC3hQ==} - peerDependencies: - '@voltagent/core': ^0.1.71 - zod: ^3.25.0 - dependencies: - '@voltagent/core': link:packages/core - '@voltagent/internal': 0.0.9 - ai: 5.0.113(zod@3.25.76) - ts-pattern: 5.8.0 - type-fest: 4.41.0 - zod: 3.25.76 - dev: false - /@vue-macros/common@3.0.0-beta.16(vue@3.5.22): resolution: {integrity: sha512-8O2gWxWFiaoNkk7PGi0+p7NPGe/f8xJ3/INUufvje/RZOs7sJvlI1jnR4lydtRFa/mU0ylMXUXXjSK0fHDEYTA==} engines: {node: '>=20.18.0'} @@ -22297,6 +21926,9 @@ packages: '@whatwg-node/promise-helpers': 1.3.2 tslib: 2.8.1 + /@workflow/serde@4.1.0: + resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} + /@workflow/serde@4.1.0-beta.2: resolution: {integrity: sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww==} dev: false @@ -22608,7 +22240,7 @@ packages: indent-string: 4.0.0 dev: true - /ai@4.3.19(react@19.2.3)(zod@3.25.76): + /ai@4.3.19(react@19.2.3)(zod@4.3.5): resolution: {integrity: sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==} engines: {node: '>=18'} peerDependencies: @@ -22619,13 +22251,13 @@ packages: optional: true dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - '@ai-sdk/react': 1.2.12(react@19.2.3)(zod@3.25.76) - '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) + '@ai-sdk/react': 1.2.12(react@19.2.3)(zod@4.3.5) + '@ai-sdk/ui-utils': 1.2.11(zod@4.3.5) '@opentelemetry/api': 1.9.0 jsondiffpatch: 0.6.0 react: 19.2.3 - zod: 3.25.76 + zod: 4.3.5 dev: false /ai@5.0.113(zod@3.25.76): @@ -22653,41 +22285,28 @@ packages: zod: 4.3.5 dev: false - /ai@5.0.63(zod@3.25.76): + /ai@5.0.63(zod@4.3.5): resolution: {integrity: sha512-rQB8xSCDCZLvAue51hvufhSP82NtzZh8CMH7/Oj5rnn/5vNI2y+Rn0lmODJ/kC4bPvFX8XgDfys8i4r86YfkmQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/gateway': 1.0.35(zod@3.25.76) + '@ai-sdk/gateway': 1.0.35(zod@4.3.5) '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.11(zod@3.25.76) + '@ai-sdk/provider-utils': 3.0.11(zod@4.3.5) '@opentelemetry/api': 1.9.0 - zod: 3.25.76 + zod: 4.3.5 dev: false - /ai@6.0.3(zod@3.25.76): - resolution: {integrity: sha512-OOo+/C+sEyscoLnbY3w42vjQDICioVNyS+F+ogwq6O5RJL/vgWGuiLzFwuP7oHTeni/MkmX8tIge48GTdaV7QQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - dependencies: - '@ai-sdk/gateway': 3.0.2(zod@3.25.76) - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) - '@opentelemetry/api': 1.9.0 - zod: 3.25.76 - - /ai@6.0.3(zod@4.3.5): - resolution: {integrity: sha512-OOo+/C+sEyscoLnbY3w42vjQDICioVNyS+F+ogwq6O5RJL/vgWGuiLzFwuP7oHTeni/MkmX8tIge48GTdaV7QQ==} - engines: {node: '>=18'} + /ai@7.0.18(zod@4.3.5): + resolution: {integrity: sha512-/DsiRfbLPtoHf9C47Hy+LK+HkjNowX1DQo3id4zWegfU6z1WjVDRAHYJAiX7SXhGp0mWX4tcenUhfIFessDWnw==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 dependencies: - '@ai-sdk/gateway': 3.0.2(zod@4.3.5) - '@ai-sdk/provider': 3.0.0 - '@ai-sdk/provider-utils': 4.0.1(zod@4.3.5) - '@opentelemetry/api': 1.9.0 + '@ai-sdk/gateway': 4.0.14(zod@4.3.5) + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) zod: 4.3.5 /ajv-errors@3.0.0(ajv@8.17.1): @@ -22981,11 +22600,6 @@ packages: safer-buffer: 2.1.2 dev: false - /assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - dev: false - /assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -23052,12 +22666,6 @@ packages: resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==} dev: false - /async-retry@1.3.3: - resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} - dependencies: - retry: 0.13.1 - dev: false - /async-sema@3.1.1: resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} @@ -23086,7 +22694,7 @@ packages: js-yaml: 4.1.0 linear-sum-assignment: 1.0.7 mustache: 4.2.0 - openai: 4.104.0(ws@8.18.3)(zod@3.25.76) + openai: 4.104.0(zod@3.25.76) zod: 3.25.76 zod-to-json-schema: 3.25.0(zod@3.25.76) transitivePeerDependencies: @@ -24509,13 +24117,6 @@ packages: dependencies: color-name: 1.1.4 - /color-convert@3.1.3: - resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} - engines: {node: '>=14.6'} - dependencies: - color-name: 2.1.0 - dev: false - /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -24523,11 +24124,6 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} requiresBuild: true - /color-name@2.1.0: - resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} - engines: {node: '>=12.20'} - dev: false - /color-string@1.9.1: resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} requiresBuild: true @@ -24535,13 +24131,6 @@ packages: color-name: 1.1.4 simple-swizzle: 0.2.2 - /color-string@2.1.4: - resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} - engines: {node: '>=18'} - dependencies: - color-name: 2.1.0 - dev: false - /color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true @@ -24562,14 +24151,6 @@ packages: color-string: 1.9.1 optional: true - /color@5.0.3: - resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} - engines: {node: '>=18'} - dependencies: - color-convert: 3.1.3 - color-string: 2.1.4 - dev: false - /colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} dev: false @@ -24727,7 +24308,7 @@ packages: /compatx@0.2.0: resolution: {integrity: sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==} - /composio-core@0.5.39(@ai-sdk/openai@3.0.12)(@cloudflare/workers-types@4.20250813.0)(@langchain/core@0.3.70)(@langchain/openai@0.6.7)(ai@6.0.3)(langchain@0.3.30)(openai@4.104.0): + /composio-core@0.5.39(@ai-sdk/openai@4.0.9)(@cloudflare/workers-types@4.20250813.0)(@langchain/core@0.3.70)(@langchain/openai@0.6.7)(ai@7.0.18)(langchain@0.3.30)(openai@4.104.0): resolution: {integrity: sha512-7BeSFlfRzr1cbIfGYJW4jQ3BHwaObOaFKiRJIFuWOmvOrTABl1hbxGkWPA3C+uFw9CFXbZhrLWNyD7lhYy2Scg==} hasBin: true peerDependencies: @@ -24739,13 +24320,13 @@ packages: langchain: '>=0.2.11' openai: '>=4.50.0' dependencies: - '@ai-sdk/openai': 3.0.12(zod@3.25.76) + '@ai-sdk/openai': 4.0.9(zod@4.3.5) '@cloudflare/workers-types': 4.20250813.0 '@composio/mcp': 1.0.3-0 '@hey-api/client-axios': 0.2.12(axios@1.11.0) '@langchain/core': 0.3.70(openai@4.104.0) '@langchain/openai': 0.6.7(@langchain/core@0.3.70) - ai: 6.0.3(zod@3.25.76) + ai: 7.0.18(zod@4.3.5) axios: 1.11.0 chalk: 4.1.2 cli-progress: 3.12.0 @@ -24753,7 +24334,7 @@ packages: inquirer: 10.2.2 langchain: 0.3.30(@langchain/core@0.3.70)(axios@1.11.0)(openai@4.104.0) open: 8.4.2 - openai: 4.104.0(ws@8.18.3)(zod@3.25.76) + openai: 4.104.0(ws@8.18.3)(zod@4.3.5) pusher-js: 8.4.0-rc2 resolve-package-path: 4.0.3 uuid: 10.0.0 @@ -25019,10 +24600,6 @@ packages: dependencies: browserslist: 4.25.2 - /core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - dev: false - /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -25766,6 +25343,7 @@ packages: optional: true dependencies: ms: 2.1.3 + dev: true /debug@4.4.3(supports-color@10.2.2): resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -26344,7 +25922,7 @@ packages: /effect@3.17.7: resolution: {integrity: sha512-dpt0ONUn3zzAuul6k4nC/coTTw27AL5nhkORXgTi6NfMPzqWYa1M05oKmOMTxpVSTKepqXVcW9vIwkuaaqx9zA==} dependencies: - '@standard-schema/spec': 1.0.0 + '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 dev: true @@ -26508,6 +26086,7 @@ packages: /enabled@2.0.0: resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + dev: true /encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} @@ -27162,6 +26741,10 @@ packages: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} + /eventsource-parser@3.1.0: + resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + engines: {node: '>=18.0.0'} + /eventsource@3.0.7: resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} @@ -27441,11 +27024,6 @@ packages: - supports-color dev: true - /extsprintf@1.4.1: - resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==} - engines: {'0': node >=0.6.0} - dev: false - /fast-check@3.23.2: resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} engines: {node: '>=8.0.0'} @@ -27612,6 +27190,7 @@ packages: /fecha@4.2.3: resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + dev: true /fetch-blob@3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} @@ -27842,6 +27421,7 @@ packages: /fn.name@1.1.0: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + dev: true /folder-walker@3.2.0: resolution: {integrity: sha512-VjAQdSLsl6AkpZNyrQJfO7BXLo4chnStqb055bumZMbRUPpVuPN3a4ktsnRCmrFZjtMlYLkyXiR5rAs4WOpC4Q==} @@ -28204,6 +27784,17 @@ packages: - supports-color dev: false + /gaxios@7.2.0: + resolution: {integrity: sha512-CUVb4wcYe+771XevyH6HtGmXFAGGKkIC3kswAP8Z1JCe0j80JMaTPZH930DWFrvo0atjh18Arc0pEyUCWa5bfg==} + engines: {node: '>=18'} + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + dev: false + /gcp-metadata@6.1.1: resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} engines: {node: '>=14'} @@ -28227,6 +27818,17 @@ packages: - supports-color dev: false + /gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + dependencies: + gaxios: 7.2.0 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + /generic-pool@3.9.0: resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} engines: {node: '>= 4'} @@ -28665,7 +28267,21 @@ packages: gcp-metadata: 7.0.1 google-logging-utils: 1.1.1 gtoken: 8.0.0 - jws: 4.0.0 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /google-auth-library@10.9.0: + resolution: {integrity: sha512-xtvUqvINPhTaBm7nXqlYPcrMHJPm1lCNdSovxnKKhTm+4JsvQ+KGVYJViLoH9Yxu8w+T0Qv5HubzYT9BLrppJg==} + engines: {node: '>=18'} + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.2.0 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 transitivePeerDependencies: - supports-color dev: false @@ -28679,7 +28295,7 @@ packages: gaxios: 6.7.1 gcp-metadata: 6.1.1 gtoken: 7.1.0 - jws: 4.0.0 + jws: 4.0.1 transitivePeerDependencies: - encoding - supports-color @@ -28713,6 +28329,11 @@ packages: engines: {node: '>=14'} dev: false + /google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + dev: false + /gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -28857,7 +28478,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: gaxios: 6.7.1 - jws: 4.0.0 + jws: 4.0.1 transitivePeerDependencies: - encoding - supports-color @@ -28868,7 +28489,7 @@ packages: engines: {node: '>=18'} dependencies: gaxios: 7.1.2 - jws: 4.0.0 + jws: 4.0.1 transitivePeerDependencies: - supports-color dev: false @@ -30720,14 +30341,6 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - /jks-js@1.1.5: - resolution: {integrity: sha512-Kdl/twc+Nk8jPWqH3jCp3YE8jlG4Q7ijbAhhG65chfNnkQxOyXY60xLryz1Fnew8MV64rcXLtIT1PuTW0B15eA==} - dependencies: - node-forge: 1.3.3 - node-int64: 0.4.0 - node-rsa: 1.1.1 - dev: false - /jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} @@ -30971,22 +30584,6 @@ packages: ms: 2.1.3 semver: 7.7.2 - /jsonwebtoken@9.0.3: - resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} - engines: {node: '>=12', npm: '>=6'} - dependencies: - jws: 4.0.1 - lodash.includes: 4.3.0 - lodash.isboolean: 3.0.3 - lodash.isinteger: 4.0.4 - lodash.isnumber: 3.0.3 - lodash.isplainobject: 4.0.6 - lodash.isstring: 4.0.1 - lodash.once: 4.1.1 - ms: 2.1.3 - semver: 7.7.2 - dev: false - /junk@4.0.1: resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} engines: {node: '>=12.20'} @@ -31013,13 +30610,6 @@ packages: jwa: 1.4.2 safe-buffer: 5.2.1 - /jws@4.0.0: - resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} - dependencies: - jwa: 2.0.1 - safe-buffer: 5.2.1 - dev: false - /jws@4.0.1: resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} dependencies: @@ -31085,6 +30675,7 @@ packages: /kuler@2.0.0: resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + dev: true /ky@1.10.0: resolution: {integrity: sha512-YRPCzHEWZffbfvmRrfwa+5nwBHwZuYiTrfDX0wuhGBPV0pA/zCqcOq93MDssON/baIkpYbvehIX5aLpMxrRhaA==} @@ -31111,7 +30702,7 @@ packages: optional: true dependencies: dotenv: 16.6.1 - openai: 4.104.0(ws@8.18.3)(zod@3.25.76) + openai: 4.104.0(zod@3.25.76) zod: 3.25.76 zod-validation-error: 3.5.3(zod@3.25.76) transitivePeerDependencies: @@ -31243,7 +30834,7 @@ packages: '@types/uuid': 10.0.0 chalk: 4.1.2 console-table-printer: 2.14.6 - openai: 4.104.0(ws@8.18.3)(zod@3.25.76) + openai: 4.104.0(ws@8.18.3)(zod@4.3.5) p-queue: 6.6.2 p-retry: 4.6.2 semver: 7.7.2 @@ -31270,7 +30861,7 @@ packages: '@types/uuid': 10.0.0 chalk: 4.1.2 console-table-printer: 2.14.6 - openai: 5.23.2(zod@3.25.76) + openai: 5.23.2(zod@4.3.5) p-queue: 6.6.2 p-retry: 4.6.2 semver: 7.7.2 @@ -31890,6 +31481,7 @@ packages: ms: 2.1.3 safe-stable-stringify: 2.5.0 triple-beam: 1.4.1 + dev: true /long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} @@ -33869,13 +33461,6 @@ packages: /node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - /node-cache@5.1.2: - resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==} - engines: {node: '>= 8.0.0'} - dependencies: - clone: 2.1.2 - dev: false - /node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -33935,11 +33520,6 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} - /node-forge@1.3.3: - resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} - engines: {node: '>= 6.13.0'} - dev: false - /node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -33967,6 +33547,7 @@ packages: /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + dev: true /node-machine-id@1.1.12: resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} @@ -33978,12 +33559,6 @@ packages: /node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - /node-rsa@1.1.1: - resolution: {integrity: sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==} - dependencies: - asn1: 0.2.6 - dev: false - /node-source-walk@7.0.1: resolution: {integrity: sha512-3VW/8JpPqPvnJvseXowjZcirPisssnBuDikk6JIZ8jQzF7KJQX52iPFX4RYYxLycYH7IbMRSPUOga/esVjy5Yg==} engines: {node: '>=18'} @@ -34646,18 +34221,20 @@ packages: /ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - /ollama-ai-provider-v2@1.5.3(zod@3.25.76): - resolution: {integrity: sha512-LnpvKuxNJyE+cB03cfUjFJnaiBJoUqz3X97GFc71gz09gOdrxNh1AsVBxrpw3uX5aiMxRIWPOZ8god0dHSChsg==} - engines: {node: '>=18'} + /ollama-ai-provider-v2@4.0.1(ai@7.0.18)(zod@4.3.5): + resolution: {integrity: sha512-JHw/Knt4kOTSwQ0oqorbdgzukK6iE73U3MPUyOuCEBpAQGAzm80CQDwyaXMwF80yFjY21RY9qfzkoLyPFFts/w==} + engines: {node: '>=22'} peerDependencies: + ai: ^7.0.0 zod: ^4.0.16 dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.19(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider-utils': 5.0.6(zod@4.3.5) + ai: 7.0.18(zod@4.3.5) + zod: 4.3.5 dev: false - /ollama-ai-provider@1.2.0(zod@3.25.76): + /ollama-ai-provider@1.2.0(zod@4.3.5): resolution: {integrity: sha512-jTNFruwe3O/ruJeppI/quoOUxG7NA6blG3ZyQj3lei4+NnJo7bi3eIRWqlVpRlu/mbzbFXeJSBuYQWF6pzGKww==} engines: {node: '>=18'} requiresBuild: true @@ -34668,9 +34245,9 @@ packages: optional: true dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + '@ai-sdk/provider-utils': 2.2.8(zod@4.3.5) partial-json: 0.1.7 - zod: 3.25.76 + zod: 4.3.5 dev: false optional: true @@ -34713,6 +34290,7 @@ packages: resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} dependencies: fn.name: 1.1.0 + dev: true /onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} @@ -34803,7 +34381,7 @@ packages: is-docker: 2.2.1 is-wsl: 2.2.0 - /openai@4.104.0(ws@8.18.3)(zod@3.25.76): + /openai@4.104.0(ws@8.18.3)(zod@4.3.5): resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} hasBin: true peerDependencies: @@ -34823,6 +34401,30 @@ packages: formdata-node: 4.4.1 node-fetch: 2.7.0 ws: 8.18.3 + zod: 4.3.5 + transitivePeerDependencies: + - encoding + dev: false + + /openai@4.104.0(zod@3.25.76): + resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + dependencies: + '@types/node': 18.19.122 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 zod: 3.25.76 transitivePeerDependencies: - encoding @@ -34840,6 +34442,7 @@ packages: optional: true dependencies: zod: 3.25.76 + dev: false /openai@5.23.2(zod@4.3.5): resolution: {integrity: sha512-MQBzmTulj+MM5O8SKEk/gL8a7s5mktS9zUtAkU257WjvobGc9nKcBuVwjyEEcb9SI8a8Y2G/mzn3vm9n1Jlleg==} @@ -34854,7 +34457,30 @@ packages: optional: true dependencies: zod: 4.3.5 - dev: true + + /openai@6.45.0(ws@8.18.3)(zod@3.25.76): + resolution: {integrity: sha512-5DQVNErssk0afNpTTHUm/qZPU4iKR9OYdNid8Ib4puq4gHNNvGWZht2zY4h9a8JMF949Ik6m8gQutllVPbjdnw==} + peerDependencies: + '@aws-sdk/credential-provider-node': '>=3.972.0 <4' + '@smithy/hash-node': '>=4.3.0 <5' + '@smithy/signature-v4': '>=5.4.0 <6' + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@aws-sdk/credential-provider-node': + optional: true + '@smithy/hash-node': + optional: true + '@smithy/signature-v4': + optional: true + ws: + optional: true + zod: + optional: true + dependencies: + ws: 8.18.3 + zod: 3.25.76 + dev: false /openapi-fetch@0.14.1: resolution: {integrity: sha512-l7RarRHxlEZYjMLd/PR0slfMVse2/vvIAGm75/F7J6MlQ8/b9uUQmUF2kCPrQhJqMXSxmYWObVgeYXbFYzZR+A==} @@ -34885,11 +34511,6 @@ packages: resolution: {integrity: sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==} dev: false - /opossum@9.0.0: - resolution: {integrity: sha512-K76U0QkxOfUZamneQuzz+AP0fyfTJcCplZ2oZL93nxeupuJbN4s6uFNbmVCt4eWqqGqRnnowdFuBicJ1fLMVxw==} - engines: {node: ^24 || ^22 || ^20} - dev: false - /optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -35789,6 +35410,11 @@ packages: resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} engines: {node: '>=16.20.0'} + /pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + dev: false + /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -38551,6 +38177,7 @@ packages: /stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + dev: true /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} @@ -38998,6 +38625,16 @@ packages: use-sync-external-store: 1.5.0(react@19.2.3) dev: false + /swr@2.4.2(react@19.2.3): + resolution: {integrity: sha512-ej644Y2bvkIajfR32KGeSSdBXQW+ScjGjkybZgSE7kFpk9eGnV44XY9FJylXi+W75pavSX1PVNB57W5EbhGIYw==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + dependencies: + dequal: 2.0.3 + react: 19.2.3 + use-sync-external-store: 1.6.0(react@19.2.3) + dev: false + /swrv@1.1.0(vue@3.5.22): resolution: {integrity: sha512-pjllRDr2s0iTwiE5Isvip51dZGR7GjLH1gCSVyE8bQnbAx6xackXsFdojau+1O5u98yHF5V73HQGOFxKUXO9gQ==} peerDependencies: @@ -39307,6 +38944,7 @@ packages: /text-hex@1.0.0: resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + dev: true /thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} @@ -39577,6 +39215,7 @@ packages: /triple-beam@1.4.1: resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} engines: {node: '>= 14.0.0'} + dev: true /trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} @@ -41023,6 +40662,14 @@ packages: dependencies: react: 19.2.3 + /use-sync-external-store@1.6.0(react@19.2.3): + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + dependencies: + react: 19.2.3 + dev: false + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -41132,15 +40779,6 @@ packages: - '@vue/composition-api' dev: false - /verror@1.10.1: - resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} - engines: {node: '>=0.6.0'} - dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.4.1 - dev: false - /vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} dependencies: @@ -41725,10 +41363,6 @@ packages: - yaml dev: true - /voca@1.4.1: - resolution: {integrity: sha512-NJC/BzESaHT1p4B5k4JykxedeltmNbau4cummStd4RjFojgq/kLew5TzYge9N2geeWyI2w8T30wUET5v+F7ZHA==} - dev: false - /vscode-jsonrpc@8.2.0: resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} engines: {node: '>=14.0.0'} @@ -42093,6 +41727,7 @@ packages: logform: 2.7.0 readable-stream: 3.6.2 triple-beam: 1.4.1 + dev: true /winston@3.17.0: resolution: {integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==} @@ -42111,23 +41746,6 @@ packages: winston-transport: 4.9.0 dev: true - /winston@3.19.0: - resolution: {integrity: sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==} - engines: {node: '>= 12.0.0'} - dependencies: - '@colors/colors': 1.6.0 - '@dabh/diagnostics': 2.0.8 - async: 3.2.6 - is-stream: 2.0.1 - logform: 2.7.0 - one-time: 1.0.0 - readable-stream: 3.6.2 - safe-stable-stringify: 2.5.0 - stack-trace: 0.0.10 - triple-beam: 1.4.1 - winston-transport: 4.9.0 - dev: false - /wonka@6.3.5: resolution: {integrity: sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw==} dev: false @@ -42157,20 +41775,6 @@ packages: '@cloudflare/workerd-linux-arm64': 1.20250718.0 '@cloudflare/workerd-windows-64': 1.20250718.0 - /workers-ai-provider@3.0.2(@ai-sdk/provider-utils@4.0.1)(@ai-sdk/provider@3.0.4)(ai@6.0.3)(zod@3.25.76): - resolution: {integrity: sha512-HUPu5aQrPOHHaoBiRoUiNzK5wtVtCFl0g/OO3gk9wguGEUK4m81qrqmdte6xlkWeKtujCHIDfIdIN6rZAnzVew==} - peerDependencies: - '@ai-sdk/provider': ^3.0.0 - '@ai-sdk/provider-utils': ^4.0.0 - ai: ^6.0.0 - zod: ^3.25.0 || ^4.0.0 - dependencies: - '@ai-sdk/provider': 3.0.4 - '@ai-sdk/provider-utils': 4.0.1(zod@3.25.76) - ai: 6.0.3(zod@3.25.76) - zod: 3.25.76 - dev: false - /wrangler@3.114.14(@cloudflare/workers-types@4.20250813.0): resolution: {integrity: sha512-zytHJn5+S47sqgUHi71ieSSP44yj9mKsj0sTUCsY+Tw5zbH8EzB1d9JbRk2KHg7HFM1WpoTI7518EExPGenAmg==} engines: {node: '>=16.17.0'} @@ -42529,12 +42133,6 @@ packages: compress-commons: 6.0.2 readable-stream: 4.7.0 - /zod-from-json-schema@0.0.5: - resolution: {integrity: sha512-zYEoo86M1qpA1Pq6329oSyHLS785z/mTwfr9V1Xf/ZLhuuBGaMlDGu/pDVGVUe4H4oa1EFgWZT53DP0U3oT9CQ==} - dependencies: - zod: 3.25.76 - dev: false - /zod-from-json-schema@0.5.0: resolution: {integrity: sha512-W1v1YIoimOJfvuorGGp1QroizLL3jEGELJtgrHiVg/ytxVZdh/BTTVyPypGB7YK30LHrCkkebbjuyHIjBGCEzw==} dependencies: @@ -42548,6 +42146,14 @@ packages: dependencies: zod: 3.25.76 + /zod-to-json-schema@3.25.0(zod@4.3.5): + resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} + peerDependencies: + zod: ^3.25 || ^4 + dependencies: + zod: 4.3.5 + dev: false + /zod-to-json-schema@3.25.1(zod@3.25.76): resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} peerDependencies: diff --git a/website/docs/agents/cancellation.md b/website/docs/agents/cancellation.md index 4a17a63c2..2f3fc20b1 100644 --- a/website/docs/agents/cancellation.md +++ b/website/docs/agents/cancellation.md @@ -90,7 +90,7 @@ const response = await agent.streamText("Complex task...", { abortController, }); -for await (const event of response.fullStream) { +for await (const event of response.stream) { if (event.type === "error" && isAbortError(event.error)) { console.log("Cancelled during:", event.context); break; diff --git a/website/docs/agents/context.md b/website/docs/agents/context.md index aa1ef2418..a6bfdf1f2 100644 --- a/website/docs/agents/context.md +++ b/website/docs/agents/context.md @@ -81,6 +81,24 @@ const response = await agent.generateText("Hello!", { console.log("Language:", response.context?.get("language")); ``` +For object-style calls, put operation-specific context under `voltagent.context`: + +```typescript +const response = await agent.generateText({ + prompt: "Hello!", + voltagent: { + context: { + language: "English", + requestId: "req-123", + }, + }, +}); + +console.log("Language:", response.context?.get("language")); +``` + +Legacy top-level `context` is still supported, but `voltagent.context` is preferred for new object-style calls. If both are supplied, `voltagent.context` takes precedence. + ## Sending User Information You can pass user information to the agent using the `context`. This information is automatically picked up by the tracing system and associated with the trace. @@ -108,26 +126,40 @@ context.set("user.email", "john@example.com"); context.set("user.avatar", "https://example.com/avatar.jpg"); context.set("user.metadata", { plan: "pro" }); -await agent.generateText("Hello", { userId: "user_123", context }); +await agent.generateText({ + prompt: "Hello", + voltagent: { + memory: { + userId: "user_123", + }, + context, + }, +}); ``` -When using the REST API, you can pass user information in the `context` object. You can use either a nested `user` object or flat keys. +When using the REST API, pass user information in `options.voltagent.context`. You can use either a nested `user` object or flat keys. **Option 1: Nested User Object** ```json { - "prompt": "Hello", - "userId": "user_123", - "context": { - "user": { - "name": "John Doe", - "email": "john@example.com", - "avatar": "https://example.com/avatar.jpg", - "metadata": { "plan": "pro" } + "input": "Hello", + "options": { + "voltagent": { + "memory": { + "userId": "user_123" + }, + "context": { + "user": { + "name": "John Doe", + "email": "john@example.com", + "avatar": "https://example.com/avatar.jpg", + "metadata": { "plan": "pro" } + } + } } } } @@ -137,13 +169,19 @@ When using the REST API, you can pass user information in the `context` object. ```json { - "prompt": "Hello", - "userId": "user_123", - "context": { - "user.name": "John Doe", - "user.email": "john@example.com", - "user.avatar": "https://example.com/avatar.jpg", - "user.metadata": { "plan": "pro" } + "input": "Hello", + "options": { + "voltagent": { + "memory": { + "userId": "user_123" + }, + "context": { + "user.name": "John Doe", + "user.email": "john@example.com", + "user.avatar": "https://example.com/avatar.jpg", + "user.metadata": { "plan": "pro" } + } + } } } ``` diff --git a/website/docs/agents/dynamic-agents.md b/website/docs/agents/dynamic-agents.md index 5f55418a7..5aa07f29a 100644 --- a/website/docs/agents/dynamic-agents.md +++ b/website/docs/agents/dynamic-agents.md @@ -131,14 +131,19 @@ const agent = new Agent({ For direct in-process calls, pass `requestHeaders`: ```ts -await agent.generateText("Hello", { - requestHeaders: { - authorization: "Bearer token", - "x-tenant-id": "tenant-1", +await agent.generateText({ + prompt: "Hello", + voltagent: { + requestHeaders: { + authorization: "Bearer token", + "x-tenant-id": "tenant-1", + }, }, }); ``` +Legacy top-level `requestHeaders` is still supported, but `voltagent.requestHeaders` is preferred for new object-style calls. + ### Dynamic Models The model can be a static `LanguageModel`, a `provider/model` string, or a function returning either. The agent resolves the model at [agent.ts:1672](https://github.com/VoltAgent/voltagent/blob/main/packages/core/src/agent/agent.ts#L1672) before each generation call. diff --git a/website/docs/agents/hooks.md b/website/docs/agents/hooks.md index 62bb18561..aef4dea35 100644 --- a/website/docs/agents/hooks.md +++ b/website/docs/agents/hooks.md @@ -179,7 +179,7 @@ const agentWithInlineHooks = new Agent({ ## Passing Hooks to Methods -Pass hooks to `generateText`, `streamText`, `generateObject`, or `streamObject` to run hooks for that specific invocation only. +Pass hooks to `generateText` or `streamText` to run hooks for that specific invocation only. `generateObject` and `streamObject` remain deprecated compatibility wrappers and use the same hook pipeline. :::warning Method-level hooks do not override agent-level hooks. Both will execute. For most hooks, the method-level hook runs first, then the agent-level hook. For `onPrepareMessages` and `onPrepareModelMessages`, the method-level hook replaces the agent-level hook entirely. @@ -487,25 +487,34 @@ Tool hooks run for a specific tool instance and are called before/after executio - `onEnd`: `{ tool, args, output, error, options }` (return `{ output }` to override) ```ts -import { createTool } from "@voltagent/core"; +import { Agent, tool } from "@voltagent/core"; import { z } from "zod"; -const normalizeTool = createTool({ - name: "normalize_text", +const normalizeTool = tool({ description: "Normalize and trim text", - parameters: z.object({ text: z.string() }), + inputSchema: z.object({ text: z.string() }), execute: async ({ text }) => text, - hooks: { - onStart: ({ tool }) => { - console.log(`[tool] ${tool.name} starting`); - }, - onEnd: ({ output }) => { - if (typeof output === "string") { - return { output: output.trim() }; - } + voltagent: { + hooks: { + onStart: ({ tool }) => { + console.log(`[tool] ${tool.name} starting`); + }, + onEnd: ({ output }) => { + if (typeof output === "string") { + return { output: output.trim() }; + } + }, }, }, }); + +const agent = new Agent({ + name: "Normalizer", + model: "openai/gpt-4o-mini", + tools: { + normalize_text: normalizeTool, + }, +}); ``` ### `onHandoff` @@ -526,14 +535,14 @@ onHandoff: async ({ agent, sourceAgent }) => { - **Async Execution:** Hooks can be `async` functions. VoltAgent awaits completion before proceeding. Long-running operations in hooks add latency to agent response time. - **Error Handling:** Errors thrown inside hooks may interrupt agent execution. Use `try...catch` within hooks or design them to be reliable. - **Hook Merging:** When hooks are passed to both the Agent constructor and a method call: - - Most hooks (`onStart`, `onEnd`, `onError`, `onHandoff`, `onToolStart`, `onToolEnd`, `onToolError`, `onStepFinish`, `onRetry`, `onFallback`) execute both: method-level first, then agent-level. + - Most hooks (`onStart`, `onEnd`, `onError`, `onHandoff`, `onToolStart`, `onToolEnd`, `onToolError`, `onStepEnd`, `onRetry`, `onFallback`) execute both: method-level first, then agent-level. - Message hooks (`onPrepareMessages`, `onPrepareModelMessages`) do not merge: method-level replaces agent-level entirely. ## Additional Hooks - **`onError`**: Called when an error occurs during agent execution. Receives `{ agent: Agent, error: Error, context: OperationContext }`. - **`onToolError`**: Called when a tool throws, before default tool error serialization. Receives `{ agent, tool, args, error, originalError, context }` and can return `{ output }`. -- **`onStepFinish`**: Called after each step in multi-step agent execution. Receives `{ agent: Agent, step: any, context: OperationContext }`. +- **`onStepEnd`**: Called after each step in multi-step agent execution. Receives `{ agent: Agent, step: any, context: OperationContext }`. - **`onRetry`**: Called when VoltAgent schedules a retry. Receives `{ source, operation, ... }` with retry metadata. - **`onFallback`**: Called when VoltAgent selects the next model candidate. Receives `{ stage, fromModel, nextModel, error, ... }`. @@ -544,7 +553,7 @@ onHandoff: async ({ agent, sourceAgent }) => { 3. **Message Transformation**: Modify messages before they reach the LLM or provider. 4. **State Management**: Initialize or clean up request-specific resources. 5. **Workflow Orchestration**: Trigger external actions based on agent events. -6. **UI Integration**: Convert `OperationContext` to messages for the Vercel AI SDK using `@voltagent/vercel-ui`. +6. **UI Integration**: Attach metadata or transform messages before returning AI SDK-compatible UI streams. ## Examples diff --git a/website/docs/agents/memory.md b/website/docs/agents/memory.md index ab9c9e56b..dacacf2ae 100644 --- a/website/docs/agents/memory.md +++ b/website/docs/agents/memory.md @@ -43,18 +43,24 @@ const agent = new Agent({ }); // First message -await agent.generateText("My name is Sarah", { - memory: { - userId: "user-123", - conversationId: "chat-001", +await agent.generateText({ + prompt: "My name is Sarah", + voltagent: { + memory: { + userId: "user-123", + conversationId: "chat-001", + }, }, }); // Agent remembers context -await agent.generateText("What's my name?", { - memory: { - userId: "user-123", - conversationId: "chat-001", +await agent.generateText({ + prompt: "What's my name?", + voltagent: { + memory: { + userId: "user-123", + conversationId: "chat-001", + }, }, }); ``` diff --git a/website/docs/agents/memory/in-memory.md b/website/docs/agents/memory/in-memory.md index c2e64d1f0..f56e0de05 100644 --- a/website/docs/agents/memory/in-memory.md +++ b/website/docs/agents/memory/in-memory.md @@ -100,10 +100,13 @@ const testAgent = new Agent({ }); // Test conversations without persistence -await testAgent.generateText("Test message", { - memory: { - userId: "test-user", - conversationId: "test-conversation", +await testAgent.generateText({ + prompt: "Test message", + voltagent: { + memory: { + userId: "test-user", + conversationId: "test-conversation", + }, }, }); ``` @@ -121,10 +124,13 @@ export async function handler(event) { // Default in-memory storage }); - return await agent.generateText(event.message, { - memory: { - userId: event.userId, - conversationId: event.sessionId, + return await agent.generateText({ + prompt: event.message, + voltagent: { + memory: { + userId: event.userId, + conversationId: event.sessionId, + }, }, }); } diff --git a/website/docs/agents/memory/overview.md b/website/docs/agents/memory/overview.md index 032387ce6..68327b892 100644 --- a/website/docs/agents/memory/overview.md +++ b/website/docs/agents/memory/overview.md @@ -172,13 +172,16 @@ new VoltAgent({ ## Usage with User and Conversation IDs -Provide `memory.userId` and `memory.conversationId` in generation calls to scope memory: +Provide `voltagent.memory.userId` and `voltagent.memory.conversationId` in generation calls to scope memory: ```ts -const response = await agent.generateText("What did we discuss yesterday?", { - memory: { - userId: "user-123", - conversationId: "thread-abc", +const response = await agent.generateText({ + prompt: "What did we discuss yesterday?", + voltagent: { + memory: { + userId: "user-123", + conversationId: "thread-abc", + }, }, }); ``` @@ -245,15 +248,18 @@ const agent = new Agent({ }); // Enable semantic search per call -const result = await agent.generateText("What preferences did I mention?", { - memory: { - userId: "user-123", - conversationId: "thread-abc", - options: { - semanticMemory: { - enabled: true, - semanticLimit: 5, - semanticThreshold: 0.7, +const result = await agent.generateText({ + prompt: "What preferences did I mention?", + voltagent: { + memory: { + userId: "user-123", + conversationId: "thread-abc", + options: { + semanticMemory: { + enabled: true, + semanticLimit: 5, + semanticThreshold: 0.7, + }, }, }, }, @@ -356,11 +362,14 @@ const agent = new Agent({ }); // Pass tenant per request -await agent.generateText("Query", { - memory: { - userId: "user-123", +await agent.generateText({ + prompt: "Query", + voltagent: { + memory: { + userId: "user-123", + }, + context: { tenantId: "company-abc" }, // Different tenant = different data }, - context: { tenantId: "company-abc" }, // Different tenant = different data }); ``` diff --git a/website/docs/agents/message-types.md b/website/docs/agents/message-types.md index 0e8784ace..9e268e827 100644 --- a/website/docs/agents/message-types.md +++ b/website/docs/agents/message-types.md @@ -247,9 +247,9 @@ const agent = new Agent({ }); // Streaming with SubAgent tracking -const stream = await agent.streamText("Write and edit a blog post"); +const result = await agent.streamText("Write and edit a blog post"); -for await (const part of stream.fullStream) { +for await (const part of result.stream) { if (part.type === "text-delta") { // Check which SubAgent is responding if (part.subAgentId) { @@ -391,12 +391,12 @@ const coordinator = new Agent({ subAgents: [researchAgent, writerAgent], }); -const stream = await coordinator.streamText("Research and write about AI"); +const result = await coordinator.streamText("Research and write about AI"); // Track which agent is responding let currentAgent = null; -for await (const part of stream.fullStream) { +for await (const part of result.stream) { if (part.type === "text-delta") { // Detect agent switches if (part.subAgentId && part.subAgentId !== currentAgent) { @@ -516,7 +516,7 @@ extractText(uiMessage); // UIMessage **A**: Check the `subAgentId` and `subAgentName` properties: ```typescript -for await (const part of stream.fullStream) { +for await (const part of result.stream) { if (part.subAgentId) { console.log(`SubAgent: ${part.subAgentName}`); } else { diff --git a/website/docs/agents/overview.md b/website/docs/agents/overview.md index 4d3bcae98..32a95cebb 100644 --- a/website/docs/agents/overview.md +++ b/website/docs/agents/overview.md @@ -72,14 +72,14 @@ for await (const chunk of stream.textStream) { When using `streamText`, you can access detailed events and final values. -#### fullStream for Detailed Events +#### Stream for Detailed Events -Use `fullStream` to receive detailed streaming events including tool calls, reasoning steps, and completion status. +Use `stream` to receive detailed streaming events including tool calls, reasoning steps, and completion status. ```ts const response = await agent.streamText("Write a story"); -for await (const chunk of response.fullStream) { +for await (const chunk of response.stream) { switch (chunk.type) { case "reasoning-start": console.log("\nReasoning started"); @@ -184,7 +184,8 @@ For end-to-end examples (SDK, API, and useChat), see [Feedback](/observability-d ### Structured Data Generation Use `output` with `generateText`/`streamText` to get structured data while still using tools and all agent capabilities. -`generateObject` and `streamObject` are deprecated in VoltAgent 2.x. +`generateObject` and `streamObject` remain available as deprecated compatibility wrappers in VoltAgent 3.x. +See [Structured Output](/docs/agents/structured-output) for a dedicated guide. ```ts import { Output } from "ai"; @@ -198,13 +199,15 @@ const recipeSchema = z.object({ }); // With generateText - supports tool calling -const result = await agent.generateText("Create a pasta recipe", { +const result = await agent.generateText({ + prompt: "Create a pasta recipe", output: Output.object({ schema: recipeSchema }), }); console.log(result.output); // { name: "...", ingredients: [...], ... } // With streamText - stream partial objects while using tools -const stream = await agent.streamText("Create a detailed recipe", { +const stream = await agent.streamText({ + prompt: "Create a detailed recipe", output: Output.object({ schema: recipeSchema }), }); @@ -213,12 +216,110 @@ for await (const partial of stream.partialOutputStream ?? []) { } // Constrained text generation -const haiku = await agent.generateText("Write a haiku about coding", { +const haiku = await agent.generateText({ + prompt: "Write a haiku about coding", output: Output.text(), }); console.log(haiku.output); ``` +### Object-Style Calls and Runtime Options + +VoltAgent supports the existing positional call style and the newer object-style request shape. Keep AI SDK-compatible generation settings at the top level, and put VoltAgent runtime options under `voltagent`. + +```ts +const result = await agent.generateText({ + prompt: "Summarize this support ticket", + temperature: 0.2, + maxOutputTokens: 500, + providerOptions: { + openai: { + reasoningEffort: "low", + }, + }, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + tenantId: "acme", + requestId: "req-789", + }, + feedback: { + key: "support-quality", + }, + }, +}); + +console.log(result.text); +console.log(result.context.get("requestId")); +``` + +Use top-level fields for model call settings such as `temperature`, `maxOutputTokens`, `providerOptions`, `output`, `stopWhen`, and `toolChoice`. + +Use `voltagent` for runtime concerns such as: + +- `memory.userId` and `memory.conversationId` +- `context` +- `feedback` +- `guardrails` +- `middleware` +- `toolRouting` +- `requestHeaders` +- `resumableStream` + +Legacy top-level runtime options still work during the transition: + +```ts +await agent.generateText("Hello", { + userId: "user-123", + conversationId: "conversation-456", + context: { requestId: "req-789" }, +}); +``` + +When both legacy top-level runtime fields and `voltagent.*` are supplied, `voltagent.*` takes precedence. + +### AI SDK Compatibility Boundaries + +VoltAgent accepts most AI SDK generation settings, but it owns orchestration fields that affect memory, tools, retries, cancellation, hooks, and observability. + +| AI SDK field | VoltAgent behavior | +| -------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| `runtimeContext` | Use VoltAgent `context`, `memory`, and hooks instead. | +| `telemetry` / `experimental_telemetry` | Use VoltAgent OpenTelemetry and observability configuration. | +| `maxRetries` | VoltAgent owns retries and model fallback so tracing, memory, hooks, and fallback attempts stay consistent. | +| `abortSignal` | VoltAgent wires cancellation through its operation context and forwards a managed signal to the model call. | +| `onStepEnd`, `onEnd`, `onError` | Supported, but invoked through VoltAgent's managed lifecycle after internal work has completed. | + +Provider options, model settings, tool choice, stop conditions, structured output, `toolsContext`, and other AI SDK generation settings still belong at the top level. Use `toolsContext` for native AI SDK tools with `contextSchema`. Runtime context, memory identity, feedback, middleware, guardrails, and tool routing belong under `voltagent`. + +To migrate positional calls, move the prompt into `prompt` and runtime options into `voltagent`: + +```ts +// Before +await agent.generateText("Hello", { + temperature: 0.2, + userId: "user-123", + conversationId: "conversation-456", + context: { requestId: "req-789" }, +}); + +// Preferred +await agent.generateText({ + prompt: "Hello", + temperature: 0.2, + voltagent: { + memory: { + userId: "user-123", + conversationId: "conversation-456", + }, + context: { requestId: "req-789" }, + }, +}); +``` + ### Summarization Summarization inserts a system summary and keeps the last N non-system messages before each model call. Configure it with the `summarization` option on the agent. See [Summarization](./summarization.md) for configuration and storage details. @@ -243,11 +344,14 @@ const agent = new Agent({ You can also override this per call: ```ts -await agent.generateText("Run the workflow", { - memory: { - options: { - conversationPersistence: { - mode: "finish", +await agent.generateText({ + prompt: "Run the workflow", + voltagent: { + memory: { + options: { + conversationPersistence: { + mode: "finish", + }, }, }, }, @@ -362,10 +466,13 @@ import { agent } from "@/voltagent"; export async function POST(req: Request) { const { messages, conversationId, userId } = await req.json(); - const result = await agent.streamText(messages, { - memory: { - conversationId, - userId, + const result = await agent.streamText({ + messages, + voltagent: { + memory: { + conversationId, + userId, + }, }, }); @@ -390,6 +497,26 @@ const reader = response.body.getReader(); // ... process stream chunks ``` +REST requests accept the same runtime namespace inside `options.voltagent`: + +```json +{ + "input": "Hello", + "options": { + "temperature": 0.2, + "voltagent": { + "memory": { + "userId": "user-123", + "conversationId": "conversation-456" + }, + "context": { + "requestId": "req-789" + } + } + } +} +``` + ## Constructor Options You can configure agents with additional options: @@ -464,13 +591,12 @@ const agent = new Agent({ Tools let agents call functions to fetch data, perform actions, or interact with external systems. The LLM decides when to use tools based on the user's input. ```ts -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; -const weatherTool = createTool({ - name: "get_weather", +const weatherTool = tool({ description: "Get current weather for a location", - parameters: z.object({ + inputSchema: z.object({ location: z.string(), }), execute: async ({ location }) => { @@ -483,7 +609,9 @@ const agent = new Agent({ name: "Weather Assistant", instructions: "Answer weather questions using the get_weather tool.", model: "openai/gpt-4o", - tools: [weatherTool], + tools: { + get_weather: weatherTool, + }, }); ``` @@ -619,7 +747,7 @@ const coordinator = new Agent({ // Now receive all sub-agent events const response = await coordinator.streamText("Research and write about AI"); -for await (const chunk of response.fullStream) { +for await (const chunk of response.stream) { if (chunk.subAgentId && chunk.subAgentName) { console.log(`[${chunk.agentPath?.join(" > ") ?? chunk.subAgentName}] ${chunk.type}`); } @@ -715,18 +843,28 @@ await agent.generateText("Hello", { Pass request-specific data (like request IDs, user info) between hooks and tools using the operation context `Map`. Context is scoped to a single operation. ```ts +import { createHooks, tool } from "@voltagent/core"; +import { z } from "zod"; + const hooks = createHooks({ onStart: async ({ context }) => { context.context.set("requestId", `req-${Date.now()}`); }, }); -const tool = createTool({ - name: "logger", - parameters: z.object({ message: z.string() }), - execute: async (params, oc) => { - const requestId = oc?.context?.get("requestId"); - console.log(`[${requestId}] ${params.message}`); +const loggerTool = tool({ + description: "Log a message with the current request id", + inputSchema: z.object({ message: z.string() }), + execute: async ({ message }) => { + return { logged: true, message }; + }, + voltagent: { + hooks: { + onStart: ({ args, options }) => { + const requestId = options.context?.get("requestId"); + options.logger?.info(`[${requestId}] ${args.message}`); + }, + }, }, }); ``` diff --git a/website/docs/agents/resumable-streaming.md b/website/docs/agents/resumable-streaming.md index d1839c78c..63438b2ba 100644 --- a/website/docs/agents/resumable-streaming.md +++ b/website/docs/agents/resumable-streaming.md @@ -315,7 +315,7 @@ export async function POST(req: Request) { return result.toUIMessageStreamResponse({ consumeSseStream: session.consumeSseStream, - onFinish: session.onFinish, + onEnd: session.onEnd, }); } ``` @@ -634,7 +634,7 @@ const session = createResumableChatSession({ const result = await agent.streamText(input, { conversationId, userId }); return result.toUIMessageStreamResponse({ consumeSseStream: session.consumeSseStream, - onFinish: session.onFinish, + onEnd: session.onEnd, }); ``` diff --git a/website/docs/agents/structured-output.md b/website/docs/agents/structured-output.md new file mode 100644 index 000000000..fc5b6848d --- /dev/null +++ b/website/docs/agents/structured-output.md @@ -0,0 +1,92 @@ +--- +title: Structured Output +slug: /agents/structured-output +--- + +# Structured Output + +Use the AI SDK `output` option with `generateText` and `streamText` when you need typed structured data. This keeps tool calling, memory, hooks, observability, retries, and all other agent features on the same text-generation path. + +`generateObject` and `streamObject` are still available as compatibility wrappers, but they are deprecated in VoltAgent 3.x. New code should use `generateText` or `streamText` with `output: Output.object(...)`. + +## Generate an Object + +```ts +import { Agent } from "@voltagent/core"; +import { Output } from "ai"; +import { z } from "zod"; + +const recipeSchema = z.object({ + name: z.string(), + ingredients: z.array(z.string()), + steps: z.array(z.string()), + prepTimeMinutes: z.number(), +}); + +const agent = new Agent({ + name: "Recipe Assistant", + instructions: "Create practical recipes.", + model: "openai/gpt-4o-mini", +}); + +const result = await agent.generateText({ + prompt: "Create a weeknight pasta recipe", + output: Output.object({ schema: recipeSchema }), +}); + +console.log(result.output.name); +``` + +## Stream Partial Objects + +```ts +const stream = await agent.streamText({ + prompt: "Create a detailed dinner plan", + output: Output.object({ schema: recipeSchema }), +}); + +for await (const partial of stream.partialOutputStream ?? []) { + console.log(partial); +} + +const finalRecipe = await stream.output; +console.log(finalRecipe); +``` + +## Combine With Runtime Options + +Keep AI SDK generation settings such as `output`, `temperature`, `providerOptions`, `stopWhen`, and `toolChoice` at the top level. Put VoltAgent runtime options under `voltagent`. + +```ts +const result = await agent.generateText({ + prompt: "Create a recipe for this user", + output: Output.object({ schema: recipeSchema }), + temperature: 0.2, + voltagent: { + memory: { + userId: "user-123", + conversationId: "recipes-456", + }, + context: { + dietaryPreference: "vegetarian", + }, + }, +}); +``` + +## Migrate From generateObject + +```ts +// Before +const result = await agent.generateObject("Create a recipe", recipeSchema); +console.log(result.object); + +// Preferred +const result = await agent.generateText({ + prompt: "Create a recipe", + output: Output.object({ schema: recipeSchema }), +}); +console.log(result.output); +``` + +For HTTP requests, use `options.output` on `/agents/:id/text`, `/agents/:id/stream`, or `/agents/:id/chat`. The legacy `/object` and `/stream-object` endpoints remain available for compatibility. diff --git a/website/docs/agents/subagents.md b/website/docs/agents/subagents.md index 5db8a4583..126f60720 100644 --- a/website/docs/agents/subagents.md +++ b/website/docs/agents/subagents.md @@ -68,6 +68,10 @@ By default, sub-agents use the `streamText` method. You can specify different me See: [Advanced Configuration](#advanced-configuration) ::: +:::note Compatibility +The AI SDK-first agent call shape does not change sub-agent orchestration. Supervisor routing, delegation metadata, streaming events, and bail behavior remain the same. For new structured sub-agent outputs, prefer `generateText` or `streamText` with `output: Output.object(...)`; `generateObject` and `streamObject` remain available as compatibility wrappers. +::: + ## Customizing Supervisor Behavior Supervisor agents use an automatically generated system message that includes guidelines for managing sub-agents. Customize this behavior using the `supervisorConfig` option. @@ -244,7 +248,7 @@ supervisorConfig: { // Usage with custom error handling: const result = await supervisor.streamText("Process data"); -for await (const event of result.fullStream) { +for await (const event of result.stream) { if (event.type === "error") { // Provide custom user-friendly error message console.log("We're having trouble processing your request. Please try again."); @@ -311,7 +315,7 @@ the model provider or injected into the LLM messages. const result = await supervisorAgent.streamText("Create and edit content"); // Process different event types -for await (const event of result.fullStream) { +for await (const event of result.stream) { if (event.type === "tool-call") { if (event.subAgentName) { console.log(`[${event.subAgentName}] Tool called: ${event.toolName}`); @@ -336,7 +340,7 @@ Identify which events come from sub-agents by checking for `subAgentId` and `sub ```ts const result = await supervisorAgent.streamText("Create and edit content"); -for await (const event of result.fullStream) { +for await (const event of result.stream) { if (event.subAgentId && event.subAgentName) { console.log( `Event from sub-agent ${event.subAgentName} (path: ${event.agentPath?.join(" > ")})` diff --git a/website/docs/agents/tools.md b/website/docs/agents/tools.md index 17a628102..71b74e2eb 100644 --- a/website/docs/agents/tools.md +++ b/website/docs/agents/tools.md @@ -9,43 +9,212 @@ Tools enable agents to interact with external systems, APIs, databases, and perf ## Creating a Tool -Use `createTool` to define a tool with type-safe parameters and execution logic. +For new VoltAgent 3.x code, use AI SDK `tool()` from `ai` and pass tools as a `ToolSet` object. The tool name comes from the object key and the input schema uses `inputSchema`, matching AI SDK conventions. Raw AI SDK tools are first-class in VoltAgent. ```ts -import { createTool } from "@voltagent/core"; +import { tool } from "ai"; +import { Agent } from "@voltagent/core"; import { z } from "zod"; -const weatherTool = createTool({ - name: "get_weather", - description: "Get current weather for a location", - parameters: z.object({ - location: z.string().describe("The city name"), - }), - execute: async ({ location }) => { - // Call weather API - const response = await fetch(`https://api.weather.com/current?city=${location}`); - const data = await response.json(); +const agent = new Agent({ + name: "Weather Assistant", + instructions: "Answer weather questions using the weather tool.", + model: "openai/gpt-4o", + tools: { + get_weather: tool({ + description: "Get current weather for a location", + inputSchema: z.object({ + location: z.string().describe("The city name"), + }), + execute: async ({ location }) => { + // Call weather API + const response = await fetch(`https://api.weather.com/current?city=${location}`); + const data = await response.json(); + + return { + location, + temperature: data.temp, + conditions: data.conditions, + }; + }, + }), + }, +}); +``` - return { - location, - temperature: data.temp, - conditions: data.conditions, - }; +Native AI SDK tool options pass through unchanged. For example, use `contextSchema` on the tool and `toolsContext` on the agent call for per-tool runtime context: + +```ts +import { tool } from "ai"; + +const agent = new Agent({ + name: "Weather Assistant", + instructions: "Answer weather questions using the weather tool.", + model: "openai/gpt-4o", + tools: { + get_weather: tool({ + description: "Get current weather for a location", + inputSchema: z.object({ + location: z.string(), + }), + contextSchema: z.object({ + apiKey: z.string(), + defaultUnit: z.enum(["celsius", "fahrenheit"]), + }), + execute: async ({ location }, { context }) => { + return fetchWeather(location, { + apiKey: context.apiKey, + unit: context.defaultUnit, + }); + }, + }), }, }); + +await agent.generateText({ + prompt: "What is the weather in San Francisco?", + toolsContext: { + get_weather: { + apiKey: process.env.WEATHER_API_KEY!, + defaultUnit: "fahrenheit", + }, + }, +}); +``` + +VoltAgent-specific tool metadata is optional and additive. Attach it with `withVoltAgentMetadata`; metadata is stored out-of-band and is not sent to the model provider: + +```ts +import { tool } from "ai"; +import { withVoltAgentMetadata } from "@voltagent/core"; + +const getWeather = withVoltAgentMetadata( + tool({ + description: "Get current weather for a location", + inputSchema: z.object({ + location: z.string(), + }), + execute: async ({ location }) => { + return { location, temperature: 22, conditions: "sunny" }; + }, + }), + { + name: "Get Weather", + purpose: "Fetch current weather for a location", + tags: ["weather", "external-api"], + hooks: { + onStart: ({ tool }) => { + console.log(`[tool] ${tool.name} starting`); + }, + }, + } +); ``` -Each tool has: +Each AI SDK-style tool has: -- **name**: Unique identifier +- **object key**: Unique identifier, such as `get_weather` - **description**: Explains what the tool does (the model uses this to decide when to call it) -- **parameters**: Input schema defined with Zod +- **inputSchema**: Input schema defined with Zod - **execute**: Function that runs when the tool is called +- **outputSchema** (optional): Output schema for validating tool results +- **contextSchema** (optional): AI SDK context schema for per-tool runtime context - **providerOptions** (optional): Provider-specific options for advanced features -- **tags** (optional): Optional user-defined tags for organizing or labeling tools. +- **toModelOutput** (optional): Converts rich tool results into AI SDK model output +- **VoltAgent metadata `name`** (optional): VoltAgent-facing name for display or metadata consumers. The ToolSet key remains the execution name. +- **VoltAgent metadata `purpose`** (optional): VoltAgent-facing purpose for display or metadata consumers. +- **VoltAgent metadata `tags`** (optional): Optional user-defined tags for organizing or labeling tools. +- **VoltAgent metadata `hooks`** (optional): VoltAgent lifecycle hooks for observing or post-processing tool execution. +- **VoltAgent metadata `needsApproval`** (optional): Static approval metadata for existing VoltAgent approval or tool-policy flows. Prefer call-level `toolApproval` for new per-request approval flows. + +VoltAgent observability and tool execution use the ToolSet key as the canonical `tool.name`. If you set metadata `name`, it is exposed as display metadata (`tool.display_name`) for the Console and telemetry consumers without changing the name the model calls. + +VoltAgent also exports a convenience `tool()` helper that accepts inline `voltagent` metadata, but raw AI SDK `tool()` from `ai` is the primary API and supports native AI SDK options directly. See [AI SDK Compatibility Boundaries](/docs/agents/overview#ai-sdk-compatibility-boundaries) for the agent-level ownership rules. The `execute` function's parameter types are automatically inferred from the Zod schema, providing full IntelliSense support. +## Using AI SDK Provider Tools + +AI SDK user-defined tools and provider-defined tools can be used together on the same agent. Use `withVoltAgentMetadata` when VoltAgent should provide hooks, tags, approval metadata, API metadata, and observability around a user-defined tool. Use provider-defined tools when the model provider owns the tool implementation. + +```ts +import { tool } from "ai"; +import { Agent, type ProviderTool } from "@voltagent/core"; +import { z } from "zod"; + +const webSearchTool: ProviderTool = { + name: "web_search", + description: "Search the web using the model provider's hosted search tool.", + type: "provider", + id: "openai.web_search_preview", + args: {}, +}; + +const agent = new Agent({ + name: "Research Assistant", + instructions: "Use the right tool for weather or current web research.", + model: "openai/gpt-4o", + tools: { + get_weather: tool({ + description: "Get current weather for a location", + inputSchema: z.object({ + location: z.string(), + }), + execute: async ({ location }) => { + return { location, temperature: 22, conditions: "sunny" }; + }, + }), + web_search: webSearchTool, + }, +}); +``` + +Provider-defined tools are passed through to the AI SDK unchanged. Use the exact `id` and `args` shape from your provider's AI SDK docs. They are not wrapped with VoltAgent tool hooks or `execute` handlers, so use user-defined AI SDK tools plus `withVoltAgentMetadata` for tools that need VoltAgent-managed lifecycle metadata or application-side execution. + +## Native Tool Approval + +Use AI SDK v7's native `toolApproval` option when approval should be decided per request. This takes precedence over tool-level `needsApproval`. + +```ts +const result = await agent.generateText({ + prompt: "Delete the stale report", + tools: { + delete_file: tool({ + description: "Delete a file", + inputSchema: z.object({ + path: z.string(), + }), + execute: async ({ path }) => deleteFile(path), + }), + }, + toolApproval: { + delete_file: "user-approval", + }, +}); +``` + +Use `voltagent.needsApproval` only when approval should be static tool metadata or part of an existing VoltAgent tool policy. If both are provided, call-level `toolApproval` takes precedence: + +```ts +const agent = new Agent({ + name: "Workspace Assistant", + instructions: "Manage workspace files.", + model: "openai/gpt-4o", + tools: { + delete_file: tool({ + description: "Delete a file", + inputSchema: z.object({ + path: z.string(), + }), + execute: async ({ path }) => deleteFile(path), + voltagent: { + needsApproval: true, + }, + }), + }, +}); +``` + ## Tool Hooks You can attach tool-specific hooks to observe or post-process a tool result. Tool hooks run before agent-level hooks, and agent `onToolEnd` can still override the output afterward. @@ -58,22 +227,23 @@ You can attach tool-specific hooks to observe or post-process a tool result. Too > Overrides are re-validated if the tool has an `outputSchema`. For streaming tools (AsyncIterable), overrides apply only to the final output. ```ts -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; -const summarizeTool = createTool({ - name: "summarize_text", +const summarizeTool = tool({ description: "Summarize text with a hard cap", - parameters: z.object({ text: z.string() }), + inputSchema: z.object({ text: z.string() }), execute: async ({ text }) => text, - hooks: { - onStart: ({ tool }) => { - console.log(`[tool] ${tool.name} starting`); - }, - onEnd: ({ output }) => { - if (typeof output === "string") { - return { output: output.slice(0, 500) }; - } + voltagent: { + hooks: { + onStart: ({ tool }) => { + console.log(`[tool] ${tool.name} starting`); + }, + onEnd: ({ output }) => { + if (typeof output === "string") { + return { output: output.slice(0, 500) }; + } + }, }, }, }); @@ -85,7 +255,7 @@ If your tool can provide progress or intermediate status, return an `AsyncIterab Each `yield` is emitted as a preliminary tool result, and the **last yielded value** is treated as the final result. ```ts -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; const weatherOutputSchema = z.discriminatedUnion("status", [ @@ -104,10 +274,9 @@ const weatherOutputSchema = z.discriminatedUnion("status", [ }), ]); -const weatherTool = createTool({ - name: "get_weather", +const weatherTool = tool({ description: "Get the current weather for a location", - parameters: z.object({ + inputSchema: z.object({ location: z.string().describe("The city name"), }), outputSchema: weatherOutputSchema, @@ -136,28 +305,27 @@ const weatherTool = createTool({ Tags are optional string labels that help organize and categorize tools. ```ts -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; // Example: Database tools with tags -const queryTool = createTool({ - name: "query_database", +const queryTool = tool({ description: "Execute a read-only SQL query", - tags: ["database", "read-only", "sql"], - parameters: z.object({ + inputSchema: z.object({ query: z.string().describe("SQL query to execute"), }), execute: async ({ query }) => { // Execute query return { results: [] }; }, + voltagent: { + tags: ["database", "read-only", "sql"], + }, }); -const updateTool = createTool({ - name: "update_record", +const updateTool = tool({ description: "Update database records", - tags: ["database", "write", "sql", "destructive"], - parameters: z.object({ + inputSchema: z.object({ table: z.string().describe("Table name"), id: z.string().describe("Record ID"), data: z.record(z.unknown()).describe("Data to update"), @@ -166,20 +334,24 @@ const updateTool = createTool({ // Update record return { success: true }; }, + voltagent: { + tags: ["database", "write", "sql", "destructive"], + }, }); // Example: External API tools -const weatherTool = createTool({ - name: "get_weather", +const weatherTool = tool({ description: "Get current weather data", - tags: ["weather", "external-api", "read-only"], - parameters: z.object({ + inputSchema: z.object({ location: z.string().describe("City name"), }), execute: async ({ location }) => { // Fetch weather return { temperature: 72, conditions: "sunny" }; }, + voltagent: { + tags: ["weather", "external-api", "read-only"], + }, }); ``` @@ -196,13 +368,12 @@ You can pass provider-specific options to enable advanced features like caching. Anthropic's prompt caching can reduce costs and latency for repeated tool calls: ```ts -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; -const cityAttractionsTool = createTool({ - name: "get_city_attractions", +const cityAttractionsTool = tool({ description: "Get tourist attractions for a city", - parameters: z.object({ + inputSchema: z.object({ city: z.string().describe("The city name"), }), providerOptions: { @@ -229,7 +400,9 @@ const agent = new Agent({ name: "Weather Assistant", instructions: "An assistant that provides weather information", model: "openai/gpt-4o", - tools: [weatherTool], + tools: { + get_weather: weatherTool, + }, }); // The model calls the tool when appropriate @@ -243,10 +416,9 @@ console.log(response.text); Agents can use multiple tools together to answer complex queries. ```ts -const calculatorTool = createTool({ - name: "calculate", +const calculatorTool = tool({ description: "Perform mathematical calculations", - parameters: z.object({ + inputSchema: z.object({ expression: z.string().describe("The mathematical expression to evaluate"), }), execute: async ({ expression }) => { @@ -260,7 +432,10 @@ const agent = new Agent({ name: "Multi-Tool Assistant", instructions: "An assistant that can check weather and perform calculations", model: "openai/gpt-4o", - tools: [weatherTool, calculatorTool], + tools: { + get_weather: weatherTool, + calculate: calculatorTool, + }, }); const response = await agent.generateText("What's the weather in Paris? Also, what is 24 * 7?"); @@ -269,136 +444,74 @@ const response = await agent.generateText("What's the weather in Paris? Also, wh ### Dynamic Tool Registration -Add tools to an agent after creation or provide them per request. +Provide additional tools per request with the same ToolSet shape. ```ts -// Add tools after agent creation -agent.addTools([calculatorTool]); - // Provide tools for a specific request only const response = await agent.generateText("Calculate 123 * 456", { - tools: [calculatorTool], + tools: { + calculate: calculatorTool, + }, }); ``` -## Accessing Operation Context +## Accessing Tool Context + +The `execute` function follows the AI SDK tool signature. Its second parameter includes AI SDK execution data such as `toolCallId`, `messages`, and `abortSignal`. -The `execute` function receives a `ToolExecuteOptions` object as its second parameter, which extends `Partial` and provides access to all operation metadata and control mechanisms. +VoltAgent operation context is available in `voltagent.hooks`, where `options` contains the operation-scoped logger, `context` map, user/conversation identifiers, trace context, and tool metadata. ```ts -const debugTool = createTool({ - name: "log_debug_info", +const debugTool = tool({ description: "Logs debugging information", - parameters: z.object({ + inputSchema: z.object({ message: z.string().describe("Debug message to log"), }), execute: async (args, options) => { - // Access tool context (tool-specific metadata) - const { name, callId, messages } = options?.toolContext || {}; - console.log("Tool name:", name); - console.log("Tool call ID:", callId); - console.log("Message history length:", messages?.length); - - // Access operation metadata directly from options - console.log("Operation ID:", options?.operationId); - console.log("User ID:", options?.userId); - console.log("Conversation ID:", options?.conversationId); + console.log("Tool call ID:", options.toolCallId); + console.log("Message history length:", options.messages.length); - // Access the original input - console.log("Original input:", options?.input); - - // Access user-defined context Map - const customValue = options?.context?.get("customKey"); - - // Use the operation-scoped logger with tool name - options?.logger?.info(`${name}: Logging ${args.message}`); - - // Check if operation is still active - if (!options?.isActive) { - throw new Error("Operation has been cancelled"); + if (options.abortSignal?.aborted) { + throw new Error("Tool call was cancelled"); } return `Logged: ${args.message}`; }, -}); -``` - -The `options` parameter includes all `OperationContext` fields plus an **optional** `toolContext` object: - -**Tool execution context (`toolContext?` - optional):** - -> **Note:** `toolContext` is always populated when your tool is called from a VoltAgent agent. It may be `undefined` when called from external systems (e.g., MCP servers). Always use optional chaining: `options?.toolContext?.name`. - -- `toolContext.name`: Name of the tool being executed -- `toolContext.callId`: Unique identifier for this specific tool call (from AI SDK) -- `toolContext.messages`: Message history at the time of tool call (from AI SDK) -- `toolContext.abortSignal`: Abort signal for detecting cancellation (from AI SDK) - -**From OperationContext:** - -- `operationId`: Unique identifier for this operation -- `userId`: Optional user identifier -- `conversationId`: Optional conversation identifier -- `workspace`: Workspace instance configured on the agent (if available) -- `context`: Map for user-provided context values -- `systemContext`: Map for internal system values -- `isActive`: Whether the operation is still active -- `input`: The original input (string, UIMessage[], or BaseMessage[]) -- `abortController`: AbortController for cancelling the operation -- `logger`: Execution-scoped logger with full context -- `traceContext`: OpenTelemetry trace context -- `elicitation`: Optional function for requesting user input - -> - Since `ToolExecuteOptions` extends `Partial`, you can name the second parameter anything you like (`options`, `context`, `ctx`, etc.) - -Example: reading workspace content inside a custom tool call: - -```ts -const readWorkspaceData = createTool({ - name: "read_workspace_data", - description: "Read a workspace file and inspect sandbox output", - parameters: z.object({ path: z.string() }), - execute: async ({ path }, options) => { - const workspace = options?.workspace; - if (!workspace) { - return "No workspace configured"; - } - - const content = await workspace.filesystem.read(path); - const sandboxResult = await workspace.sandbox?.execute({ - command: "cat", - args: [path], - operationContext: options as any, - }); - - return `filesystem=${content}\nsandbox=${sandboxResult?.stdout ?? ""}`; + voltagent: { + hooks: { + onStart: ({ args, options }) => { + options?.logger?.info("Starting debug tool", { + args, + operationId: options.operationId, + userId: options.userId, + conversationId: options.conversationId, + requestId: options.context?.get("requestId"), + }); + }, + }, }, }); ``` ## Cancellation with AbortController -Tools can respond to cancellation signals and cancel the entire operation when needed. +Tools can respond to cancellation signals from the active generation call. ```ts -const searchTool = createTool({ - name: "search_web", +const searchTool = tool({ description: "Search the web for information", - parameters: z.object({ + inputSchema: z.object({ query: z.string().describe("The search query"), }), execute: async (args, options) => { - const abortController = options?.abortController; - const signal = abortController?.signal; + const signal = options.abortSignal; // Check if already aborted if (signal?.aborted) { throw new Error("Search was cancelled before it started"); } - // Tool can trigger abort to cancel the entire operation if (args.query.includes("forbidden")) { - abortController?.abort("Forbidden query detected"); throw new Error("Search query contains forbidden terms"); } @@ -406,9 +519,7 @@ const searchTool = createTool({ // Pass signal to fetch for cancellation support const response = await fetch(`https://api.search.com?q=${args.query}`, { signal }); - // Abort based on response if (!response.ok && response.status === 429) { - abortController?.abort("Rate limit exceeded"); throw new Error("API rate limit exceeded"); } @@ -452,37 +563,39 @@ try { Some tools should not run automatically because they trigger sensitive actions (payments, file changes, command execution, etc). Set `needsApproval` to require explicit user approval before the tool executes. ```ts -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; -const runCommandTool = createTool({ - name: "runCommand", +const runCommandTool = tool({ description: "Run a shell command", - parameters: z.object({ + inputSchema: z.object({ command: z.string().describe("Command to execute"), }), - needsApproval: true, execute: async ({ command }) => { // Execute safely return { ok: true, command }; }, + voltagent: { + needsApproval: true, + }, }); ``` `needsApproval` can also be a function for dynamic policies: ```ts -const processPaymentTool = createTool({ - name: "processPayment", +const processPaymentTool = tool({ description: "Charge a customer", - parameters: z.object({ + inputSchema: z.object({ amount: z.number(), customerId: z.string(), }), - needsApproval: async ({ amount }) => amount > 1000, execute: async ({ amount, customerId }) => { return { success: true, amount, customerId }; }, + voltagent: { + needsApproval: async ({ amount }) => amount > 1000, + }, }); ``` @@ -566,25 +679,29 @@ A tool without an `execute` function is automatically client-side. ```ts // Client-side tool (no execute function) -const getLocationTool = createTool({ - name: "getLocation", +const getLocationTool = tool({ description: "Get the user's current location", - parameters: z.object({}), + inputSchema: z.object({}), + outputSchema: z.object({ + latitude: z.number(), + longitude: z.number(), + }), // No execute = client-side }); // Another client-side tool -const readClipboardTool = createTool({ - name: "readClipboard", +const readClipboardTool = tool({ description: "Read content from the user's clipboard", - parameters: z.object({}), + inputSchema: z.object({}), + outputSchema: z.object({ + text: z.string(), + }), }); // Server-side tool (has execute) -const getWeatherTool = createTool({ - name: "getWeather", +const getWeatherTool = tool({ description: "Get current weather for a city", - parameters: z.object({ + inputSchema: z.object({ city: z.string().describe("City name"), }), execute: async ({ city }) => { @@ -764,7 +881,9 @@ const agent = new Agent({ name: "Assistant with Tool Hooks", instructions: "An assistant that logs tool execution", model: "openai/gpt-4o", - tools: [weatherTool], + tools: { + get_weather: weatherTool, + }, hooks: hooks, }); ``` @@ -801,7 +920,11 @@ const agent = new Agent({ name: "Controlled Assistant", instructions: "An assistant with tag-based access control", model: "openai/gpt-4o", - tools: [queryTool, updateTool, weatherTool], + tools: { + query_database: queryTool, + update_record: updateTool, + get_weather: weatherTool, + }, hooks: hooks, }); @@ -874,14 +997,13 @@ Tools can return images and media content to the LLM using the `toModelOutput` f #### Screenshot Tool Example ```ts -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; import fs from "fs"; -const screenshotTool = createTool({ - name: "take_screenshot", +const screenshotTool = tool({ description: "Takes a screenshot of the screen", - parameters: z.object({ + inputSchema: z.object({ region: z.string().optional().describe("Region to capture"), }), execute: async ({ region }) => { @@ -974,10 +1096,9 @@ Provide clear descriptions for tools and parameters. The model relies on these t **Bad:** ```ts -const badTool = createTool({ - name: "search", +const badTool = tool({ description: "Searches things", // Too vague - parameters: z.object({ + inputSchema: z.object({ q: z.string(), // No description }), execute: async (args) => { @@ -989,11 +1110,10 @@ const badTool = createTool({ **Good:** ```ts -const goodTool = createTool({ - name: "search_web", +const goodTool = tool({ description: "Searches the web for current information. Use when you need recent or factual information not in your training data.", - parameters: z.object({ + inputSchema: z.object({ query: z.string().describe("The search query. Be specific about what information is needed."), results_count: z .number() @@ -1036,9 +1156,8 @@ execute: async (args, options) => { try { // Listen to parent abort if provided - const parentController = options?.abortController; - if (parentController?.signal) { - parentController.signal.addEventListener("abort", () => { + if (options.abortSignal) { + options.abortSignal.addEventListener("abort", () => { timeoutController.abort("Parent operation aborted"); clearTimeout(timeoutId); }); diff --git a/website/docs/api/endpoints/agents.md b/website/docs/api/endpoints/agents.md index 1034dbdd2..ae7f4563c 100644 --- a/website/docs/api/endpoints/agents.md +++ b/website/docs/api/endpoints/agents.md @@ -112,6 +112,9 @@ Generate a text response from an agent synchronously. "reasoningEffort": "medium" } }, + "toolApproval": { + "delete_file": "user-approval" + }, "context": { "role": "admin", "tier": "premium" @@ -213,6 +216,8 @@ Generate a text response from an agent synchronously. | `seed` | number | - | For reproducible results | | `stopSequences` | string[] | - | Stop generation sequences | | `providerOptions` | object | - | Provider-specific options | +| `toolApproval` | object | - | AI SDK native per-tool approval status map: `not-applicable`, `approved`, `denied`, or `user-approval` | +| `experimental_toolApprovalSecret` | string | - | Secret used by AI SDK to sign native tool approval requests | | `context` | object | - | Dynamic agent context | | `conversationPersistence` | object | - | Deprecated: use `memory.options.conversationPersistence` (groups `mode`, `debounceMs`, `flushOnToolResult`) | | `conversationPersistence.mode` | string | `"step"` | Deprecated: use `memory.options.conversationPersistence.mode` | @@ -554,9 +559,11 @@ function ChatComponent({ agentId }) { body: { input: [lastMessage], // Send as array of UIMessage options: { - memory: { - userId: "user-123", - conversationId: "conv-456", + voltagent: { + memory: { + userId: "user-123", + conversationId: "conv-456", + }, }, temperature: 0.7, maxSteps: 10, @@ -590,7 +597,7 @@ function ChatComponent({ agentId }) { } ``` -**Note:** VoltAgent requires a custom transport with `prepareSendMessagesRequest` to format the request body correctly. The endpoint expects `input` as an array of UIMessage objects and options in a specific format. +**Note:** VoltAgent requires a custom transport with `prepareSendMessagesRequest` to format the request body correctly. The endpoint expects `input` as an array of UIMessage objects and options in a specific format. Legacy top-level runtime options such as `options.memory` still work, but `options.voltagent.memory` is preferred for new clients. ## Generate Object diff --git a/website/docs/getting-started/migration-guide.md b/website/docs/getting-started/migration-guide.md index 5fe4c1ecf..3a8e80c0b 100644 --- a/website/docs/getting-started/migration-guide.md +++ b/website/docs/getting-started/migration-guide.md @@ -1,6 +1,640 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; +# Migration guide: 2.x → 3.x + +VoltAgent 3.x aligns the framework with AI SDK v7. This is a major release, so the runtime boundary is intentionally stricter: Node.js 22 or later and ESM-only packages. The agent, memory, tool, workflow, guardrail, observability, server, MCP, A2A, AG-UI, and VoltOps features remain available, but some AI SDK-facing names and result fields changed. + +If you are still on 1.x, follow the **Migration guide: 1.x → 2.x** section first, then come back here. + +## What changed + +- Runtime: Node.js `>=22` is required. +- Module format: VoltAgent 3.x is ESM-only. CommonJS `require("@voltagent/core")` is no longer supported. +- AI SDK: `ai` moves to `^7`. +- AI SDK provider packages need v7-compatible majors, for example `@ai-sdk/openai@^4`. +- Zod: `zod` moves to `^4`. Zod 3 is no longer a supported peer dependency in VoltAgent 3.x. +- AI SDK callbacks use `onEnd` and `onStepEnd`. +- `stepCountIs` is now `isStepCount`. +- `streamText` detailed events are exposed as `stream`. `fullStream` remains as a deprecated alias during the transition. +- Structured output uses `output`, not `experimental_output`. +- `generateObject` and `streamObject` are still available as deprecated compatibility wrappers. Prefer `generateText`/`streamText` with `Output.object`. + +## Step 1. Upgrade your runtime to Node.js 22 + +Before installing VoltAgent 3.x, make sure local development, CI, and production all use Node.js 22 or later: + +```bash +node --version +``` + +Update your application package metadata: + +```json +{ + "engines": { + "node": ">=22" + } +} +``` + +If you cannot move off Node.js 20 yet, stay on VoltAgent 2.x until your runtime is ready. + +## Step 2. Move your app to ESM + +VoltAgent 3.x publishes ESM runtime entrypoints. Use ESM imports and mark your package as a module: + +```json +{ + "type": "module" +} +``` + +Before: + +```js +const { Agent } = require("@voltagent/core"); +const { openai } = require("@ai-sdk/openai"); +``` + +After: + +```ts +import { Agent } from "@voltagent/core"; +import { openai } from "@ai-sdk/openai"; +``` + +For TypeScript projects, use a module resolution mode that matches your toolchain. `NodeNext` and `Bundler` are both common choices: + +```json +{ + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext" + } +} +``` + +## Step 3. Update packages + +### 3.1 Update VoltAgent packages + +Use the Volt CLI if your project already has it: + +```bash +npm run volt update +``` + +Or update the packages manually: + +```bash +pnpm add @voltagent/core@latest @voltagent/server-hono@latest @voltagent/logger@latest +``` + +If you use memory/storage/server/protocol packages, update all `@voltagent/*` packages to the same major version. + +### 3.2 Update AI SDK packages + +Install AI SDK v7 and v7-compatible provider packages: + +```bash +pnpm add ai@^7 @ai-sdk/openai@^4 +pnpm add @ai-sdk/provider@^4 @ai-sdk/provider-utils@^5 +pnpm add zod@^4 +``` + +If you use AI SDK UI helpers: + +```bash +pnpm add @ai-sdk/react@^4 +``` + +Provider package majors vary by provider. Common upgrades: + +| Package | Use with AI SDK v7 | +| --------------------------- | ------------------ | +| `@ai-sdk/openai` | `^4` | +| `@ai-sdk/anthropic` | `^4` | +| `@ai-sdk/google` | `^4` | +| `@ai-sdk/azure` | `^4` | +| `@ai-sdk/groq` | `^4` | +| `@ai-sdk/mistral` | `^4` | +| `@ai-sdk/perplexity` | `^4` | +| `@ai-sdk/openai-compatible` | `^3` | +| `@ai-sdk/amazon-bedrock` | `^5` | +| `@ai-sdk/google-vertex` | `^5` | + +After changing dependencies, reinstall and refresh the lockfile: + +```bash +pnpm install +``` + +### 3.3 Update Zod + +VoltAgent 3.x is Zod 4-only. Remove Zod 3 pins from your app and templates: + +```bash +pnpm add zod@^4 +``` + +If you have custom code that imports Zod 3-specific internals or `zod/v3`, update it to the public Zod 4 API before upgrading VoltAgent. + +## Step 4. Keep using the AI SDK-style agent call shape + +The object-style call shape introduced in 2.x remains the preferred API. Keep AI SDK generation settings at the top level and VoltAgent runtime options under `voltagent`: + +VoltAgent 3.x derives most public generation options from AI SDK v7 `generateText` and `streamText`, so AI SDK settings such as `timeout`, `headers`, `include`, `activeTools`, `toolOrder`, `experimental_download`, `onChunk`, and stream lifecycle callbacks can be used directly on the agent call. + +```ts +const result = await agent.generateText({ + prompt: "Summarize this ticket", + temperature: 0.2, + maxOutputTokens: 500, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, +}); +``` + +The same shape works for `streamText`: + +```ts +const result = await agent.streamText({ + prompt: "Write a short release note", + timeout: { + totalMs: 30_000, + chunkMs: 5_000, + }, + include: { + rawChunks: true, + }, + onChunk: async ({ chunk }) => { + // Native AI SDK stream callback. + }, + voltagent: { + memory: { + userId: "user-123", + conversationId: "release-456", + }, + }, +}); +``` + +VoltAgent composes a small set of fields instead of passing them through unchanged: `model`, `prompt`/`messages`, `tools`, `abortSignal`, `maxRetries`, `onStepEnd`, `onEnd`/`onFinish`, and `onError`. You still pass the callbacks at the top level; VoltAgent invokes them after its memory, guardrail, hook, tracing, and recovery work has run. + +Top-level AI SDK `toolsContext` is passed through for native AI SDK tools that declare `contextSchema`. Use it for per-tool AI SDK execution context. Top-level AI SDK `runtimeContext`, `telemetry`, and `experimental_telemetry` are intentionally not supported on VoltAgent calls. Use `voltagent.context` for per-call application context and VoltAgent observability/OpenTelemetry configuration for telemetry. + +Legacy positional calls are still accepted: + +```ts +const result = await agent.generateText("Summarize this ticket", { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, +}); +``` + +For new code, prefer the object-style form because it matches AI SDK field names and keeps VoltAgent-specific runtime concerns explicit. + +## Step 5. Rename `stepCountIs` to `isStepCount` + +AI SDK v7 renamed `stepCountIs` to `isStepCount`. VoltAgent re-exports `isStepCount` for convenience. + +Before: + +```ts +import { stepCountIs } from "ai"; + +const result = await agent.generateText({ + prompt: "Research and summarize", + stopWhen: stepCountIs(5), +}); +``` + +After: + +```ts +import { isStepCount } from "@voltagent/core"; + +const result = await agent.generateText({ + prompt: "Research and summarize", + stopWhen: isStepCount(5), +}); +``` + +You can also import `isStepCount` directly from `ai`. + +## Step 6. Rename stream result access from `fullStream` to `stream` + +AI SDK v7 exposes detailed stream parts on `stream`. VoltAgent follows that name. `fullStream` remains available as a deprecated alias, but new code should use `stream`. + +Before: + +```ts +const result = await agent.streamText("Write a changelog"); + +for await (const part of result.fullStream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } +} +``` + +After: + +```ts +const result = await agent.streamText("Write a changelog"); + +for await (const part of result.stream) { + if (part.type === "text-delta") { + process.stdout.write(part.text); + } +} +``` + +`textStream`, `toUIMessageStream`, `toUIMessageStreamResponse`, `pipeTextStreamToResponse`, and `toTextStreamResponse` remain available on stream results. + +## Step 7. Rename lifecycle callbacks + +AI SDK v7 uses `onEnd` and `onStepEnd`. Update callback names in per-call options and hooks. + +Before: + +```ts +const result = await agent.streamText({ + prompt: "Plan the task", + onFinish: async (event) => { + console.log(event.finishReason); + }, + hooks: { + onStepFinish: async ({ step }) => { + console.log(step.finishReason); + }, + }, +}); +``` + +After: + +```ts +const result = await agent.streamText({ + prompt: "Plan the task", + onEnd: async (event) => { + console.log(event.finishReason); + }, + hooks: { + onStepEnd: async ({ step }) => { + console.log(step.finishReason); + }, + }, +}); +``` + +Agent-level hooks use the same names: + +```ts +const agent = new Agent({ + name: "assistant", + model, + instructions: "You are a helpful assistant.", + hooks: { + onEnd: async ({ output, error }) => { + // Persist metadata, emit logs, or update your own analytics. + }, + onStepEnd: async ({ step }) => { + // Inspect each AI SDK step. + }, + }, +}); +``` + +## Step 8. Use `instructions` for system prompts + +AI SDK v7 separates instructions from regular model messages. For VoltAgent agents, keep using the `instructions` field: + +```ts +const agent = new Agent({ + name: "support", + model, + instructions: "Answer support questions with short, direct replies.", +}); +``` + +For per-call overrides, prefer `instructions`: + +```ts +const result = await agent.generateText({ + prompt: "Draft a reply", + instructions: "Write in a calm support tone.", +}); +``` + +VoltAgent normalizes older system-message input where possible, but new code should not add `{ role: "system" }` messages to the request message list. + +## Step 9. Update structured output + +Use AI SDK v7 `output` with `Output.object`. Do not use `experimental_output`. + +Before: + +```ts +const result = await agent.generateText({ + prompt: "Create a user profile", + experimental_output: Output.object({ schema }), +}); +``` + +After: + +```ts +import { Output } from "ai"; + +const result = await agent.generateText({ + prompt: "Create a user profile", + output: Output.object({ schema }), +}); + +console.log(result.output); +``` + +`generateObject` and `streamObject` still work as compatibility wrappers, but they are deprecated. Prefer: + +```ts +const result = await agent.generateText({ + prompt: "Create a user profile", + output: Output.object({ schema }), +}); +``` + +For streaming structured output: + +```ts +const result = await agent.streamText({ + prompt: "Create a user profile", + output: Output.object({ schema }), +}); + +for await (const partial of result.partialOutputStream ?? []) { + console.log(partial); +} +``` + +## Step 10. Prefer AI SDK-style tools for new custom tools + +VoltAgent 3.x accepts AI SDK-style `ToolSet` records directly on agents. For new code, prefer AI SDK `tool()` from `ai`. The tool name comes from the `tools` object key and the schema field is `inputSchema`. + +Before: + +```ts +import { createTool } from "@voltagent/core"; +import { z } from "zod"; + +const weatherTool = createTool({ + name: "get_weather", + description: "Get weather for a city", + parameters: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, temperature: 72 }; + }, +}); +``` + +After: + +```ts +import { tool } from "ai"; +import { Agent } from "@voltagent/core"; +import { z } from "zod"; + +const agent = new Agent({ + name: "assistant", + model, + instructions: "You are a helpful assistant.", + tools: { + get_weather: tool({ + description: "Get weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + execute: async ({ city }) => { + return { city, temperature: 72 }; + }, + }), + }, +}); +``` + +Native AI SDK tool features such as `contextSchema` and call-level `toolsContext` pass through unchanged: + +```ts +import { tool } from "ai"; + +const agent = new Agent({ + name: "assistant", + model, + instructions: "You are a helpful assistant.", + tools: { + get_weather: tool({ + description: "Get weather for a city", + inputSchema: z.object({ + city: z.string(), + }), + contextSchema: z.object({ + apiKey: z.string(), + defaultUnit: z.enum(["celsius", "fahrenheit"]), + }), + execute: async ({ city }, { context }) => { + return fetchWeather(city, { + apiKey: context.apiKey, + unit: context.defaultUnit, + }); + }, + }), + }, +}); + +await agent.generateText({ + prompt: "What is the weather in San Francisco?", + toolsContext: { + get_weather: { + apiKey: process.env.WEATHER_API_KEY!, + defaultUnit: "fahrenheit", + }, + }, +}); +``` + +VoltAgent-specific tool metadata is optional and additive. Use `withVoltAgentMetadata` to attach it to a raw AI SDK tool without changing the native tool definition or sending metadata to the model provider: + +```ts +import { tool } from "ai"; +import { withVoltAgentMetadata } from "@voltagent/core"; + +const refundCustomer = withVoltAgentMetadata( + tool({ + description: "Refund a customer order", + inputSchema: z.object({ + orderId: z.string(), + reason: z.string(), + }), + contextSchema: z.object({ + actorId: z.string(), + permissions: z.array(z.string()), + }), + execute: async ({ orderId, reason }, { context }) => { + if (!context.permissions.includes("refund:write")) { + throw new Error("Not allowed to refund orders"); + } + + return issueRefund({ + orderId, + reason, + actorId: context.actorId, + }); + }, + }), + { + name: "Refund Customer", + purpose: "Issue customer refunds", + tags: ["billing", "dangerous", "customer-support"], + metadata: { + owner: "payments-team", + riskLevel: "high", + }, + } +); +``` + +For new approval flows, prefer AI SDK v7's native call-level `toolApproval` option. It takes precedence over tool-level `needsApproval`: + +```ts +import { tool } from "ai"; + +const result = await agent.generateText({ + prompt: "Delete the stale report", + tools: { + delete_file: tool({ + description: "Delete a file", + inputSchema: z.object({ + path: z.string(), + }), + execute: async ({ path }) => deleteFile(path), + }), + }, + toolApproval: { + delete_file: "user-approval", + }, +}); +``` + +`createTool` is now a legacy compatibility helper for existing class-style tools. New custom tools should use `tool()`. When migrating from `createTool` to `tool()`: + +- move `name` to the `tools` object key. +- rename `parameters` to `inputSchema`. +- move `tags`, `hooks`, and other VoltAgent-only metadata to `withVoltAgentMetadata`. +- use VoltAgent metadata `name` only as display metadata. Telemetry and tool calls keep using the ToolSet key as canonical `tool.name`; metadata `name` is exposed as `tool.display_name`. +- keep `execute`, `outputSchema`, `providerOptions`, and `toModelOutput` in the AI SDK tool definition. +- keep AI SDK `contextSchema` in the tool definition and pass matching per-tool values through call-level `toolsContext`. +- use `voltagent.context` on the agent call for general per-request application context, and VoltAgent observability/OpenTelemetry configuration for telemetry. + +Use call-level `toolApproval` when approval should be controlled per request, per user, or per runtime context. Use `voltagent.needsApproval` only for static tool metadata or compatibility with existing VoltAgent tool policies. + +If you type the AI SDK tool execution options, import the v7-compatible type from `@ai-sdk/provider-utils`: + +```ts +import type { ToolExecutionOptions } from "@ai-sdk/provider-utils"; +``` + +If you use `toModelOutput`, keep the AI SDK v7 argument object shape: + +```ts +const screenshotTool = tool({ + description: "Capture a screenshot", + inputSchema: z.object({ + url: z.string(), + }), + execute: async ({ url }) => captureScreenshot(url), + toModelOutput: ({ output }) => ({ + type: "content", + value: [ + { + type: "media", + data: output.imageBase64, + mediaType: "image/png", + }, + ], + }), +}); +``` + +`tool()` from `@voltagent/core` remains available as a convenience wrapper when you prefer inline `voltagent` metadata, but raw AI SDK tools are first-class and do not require a VoltAgent wrapper. + +Provider-defined AI SDK tools can also be passed in the same `tools` object. Provider-owned tools are still passed through to AI SDK unchanged; use `withVoltAgentMetadata` when VoltAgent should apply hooks, preserve tags, or attach approval/API metadata around a user-executed AI SDK tool. + +## Step 11. Update direct AI SDK tests and mocks + +If your tests import AI SDK mocks directly, update them to the v7 mock names and result shapes: + +```ts +import { MockLanguageModelV3 } from "ai/test"; +``` + +Also update assertions that read AI SDK stream results: + +```ts +expect(result.stream).toBeDefined(); +``` + +Use `result.output` for structured output assertions instead of `result.experimental_output`. + +## Step 12. Validate the migration + +Run your normal checks after the package and code changes: + +```bash +pnpm lint +pnpm build +pnpm test +``` + +For VoltAgent monorepos, also validate package boundaries and docs/examples if applicable: + +```bash +pnpm build:all +pnpm test:all +pnpm publint:all +pnpm --dir website build +``` + +## Quick checklist + +- [ ] Node.js is `>=22` everywhere. +- [ ] The app is ESM (`"type": "module"` or ESM output from your framework). +- [ ] `ai` is `^7`. +- [ ] AI SDK provider packages are v7-compatible. +- [ ] `@ai-sdk/react` is `^4` if used. +- [ ] `zod` is `^4`. +- [ ] CommonJS `require()` imports are replaced with ESM imports. +- [ ] `stepCountIs` is replaced with `isStepCount`. +- [ ] `result.fullStream` is replaced with `result.stream` in new code. +- [ ] `onFinish`/`onStepFinish` usages are replaced with `onEnd`/`onStepEnd`. +- [ ] `experimental_output` is replaced with `output`. +- [ ] New custom tools use AI SDK `tool()` + `inputSchema`; VoltAgent-only metadata uses `withVoltAgentMetadata` when needed. +- [ ] New approval flows use call-level `toolApproval` where possible. +- [ ] New structured output code uses `generateText`/`streamText` with `Output.object`. + +--- + # Migration guide: 1.x → 2.x VoltAgent 2.x aligns the framework with AI SDK v6 and adds new features. There are no breaking changes in VoltAgent APIs. If you only use VoltAgent APIs, follow the steps below. If your app calls AI SDK functions directly, also review the upstream AI SDK v6 migration guide. @@ -67,9 +701,66 @@ Notes: - If you use `useChat` or other UI helpers, upgrade `@ai-sdk/react` to `^3`. - If you are in a monorepo, update all `@voltagent/*` packages to the same major version. -## Step 2. Update custom tools (only if you use advanced tool hooks) +## Step 2. Adopt object-style agent calls (recommended) + +Existing positional calls still work: + +```ts +const result = await agent.generateText("Summarize this ticket", { + temperature: 0.2, + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, +}); +``` + +For new code, prefer the AI SDK-style object shape. Keep model generation settings at the top level and move VoltAgent runtime options under `voltagent`: + +```ts +const result = await agent.generateText({ + prompt: "Summarize this ticket", + temperature: 0.2, + voltagent: { + memory: { + userId: "user-123", + conversationId: "ticket-456", + }, + context: { + requestId: "req-789", + }, + }, +}); +``` + +The same shape works for `streamText`. REST requests use the same namespace inside `options.voltagent`: + +```json +{ + "input": "Summarize this ticket", + "options": { + "temperature": 0.2, + "voltagent": { + "memory": { + "userId": "user-123", + "conversationId": "ticket-456" + }, + "context": { + "requestId": "req-789" + } + } + } +} +``` + +Legacy top-level runtime options such as `memory`, `userId`, `conversationId`, `context`, `feedback`, `hooks`, `guardrails`, and `requestHeaders` are still accepted during the transition. If both legacy fields and `voltagent.*` are provided, `voltagent.*` takes precedence. + +## Step 3. Update custom tools (only if you use advanced tool hooks) -### 2.1 Tool output mapping signature change +### 3.1 Tool output mapping signature change If you use `toModelOutput`, it now receives `{ output }`: @@ -77,7 +768,7 @@ If you use `toModelOutput`, it now receives `{ output }`: toModelOutput: ({ output }) => ({ type: "text", value: output }), ``` -### 2.2 Tool execution options type rename (if you type it) +### 3.2 Tool execution options type rename (if you type it) If you type the second `execute` parameter, use: @@ -85,7 +776,7 @@ If you type the second `execute` parameter, use: import type { ToolExecutionOptions } from "@ai-sdk/provider-utils"; ``` -## Step 3. Structured output (if you use generateObject/streamObject) +## Step 4. Structured output (if you use generateObject/streamObject) VoltAgent 2.x deprecates `generateObject` and `streamObject`. Migrate to `generateText`/`streamText` with `Output.object`. @@ -122,14 +813,16 @@ const schema = z.object({ age: z.number(), }); -const result = await agent.generateText("Create a profile", { +const result = await agent.generateText({ + prompt: "Create a profile", output: Output.object({ schema }), }); console.log(result.output); ``` ```ts -const stream = await agent.streamText("Create a profile", { +const stream = await agent.streamText({ + prompt: "Create a profile", output: Output.object({ schema }), }); @@ -138,7 +831,7 @@ for await (const partial of stream.partialOutputStream ?? []) { } ``` -## Step 4. Tests (if you use AI SDK mocks directly) +## Step 5. Tests (if you use AI SDK mocks directly) Update V2 mocks to V3 mocks: @@ -569,7 +1262,7 @@ supervisorConfig: { If you want prefixed labels, use the stream metadata from ai-sdk and add it yourself: ```ts -for await (const evt of response.fullStream!) { +for await (const evt of response.stream) { if (evt.subAgentName && evt.type === "tool-call") { console.log(`[${evt.subAgentName}] Using: ${evt.toolName}`); } @@ -581,10 +1274,10 @@ Example (streamText): ```ts const res = await agent.streamText("hi"); -// ai-sdk v5 fullStream -if (res.fullStream) { - for await (const part of res.fullStream) { - if (part.type === "text-delta") process.stdout.write(part.textDelta); +// ai-sdk v7 stream +if (res.stream) { + for await (const part of res.stream) { + if (part.type === "text-delta") process.stdout.write(part.text); else if (part.type === "tool-call") console.log("tool:", part.toolName); else if (part.type === "tool-result") console.log("done:", part.toolName); else if (part.type === "finish") console.log("usage:", part.usage); @@ -607,7 +1300,7 @@ console.log(out.context); // VoltAgent Map ### stopWhen override (advanced) - You can pass a custom ai-sdk `stopWhen` predicate in method options to control when to stop step execution. -- This overrides VoltAgent's default `stepCountIs(maxSteps)` guard. +- This overrides VoltAgent's default `isStepCount(maxSteps)` guard. - Be cautious: permissive predicates can lead to long-running or looping generations; overly strict ones may stop before tools complete. ### prepareStep callback (advanced) @@ -810,7 +1503,7 @@ If you previously relied on core’s internal server exports (custom endpoints, ### Convenience exports & logger -- Convenience from `@voltagent/core`: `zodSchemaToJsonUI`, `stepCountIs`, `hasToolCall`, `convertUsage`. +- Convenience from `@voltagent/core`: `zodSchemaToJsonUI`, `isStepCount`, `hasToolCall`, `convertUsage`. - Logger helpers: `LoggerProxy`, `getGlobalLogger`, `getGlobalLogBuffer`. Logger is SSR/Edge-friendly via `globalThis` in Next.js. ### Runtime & TypeScript diff --git a/website/docs/getting-started/model-router.md b/website/docs/getting-started/model-router.md index deaf84531..b980d8d2d 100644 --- a/website/docs/getting-started/model-router.md +++ b/website/docs/getting-started/model-router.md @@ -7,6 +7,10 @@ slug: /getting-started/model-router VoltAgent can resolve models from strings like `openai/gpt-4o-mini` without requiring you to import provider packages. This is powered by a bundled provider registry and a small model router in `@voltagent/core`. +:::note VoltAgent 2.x migration +The AI SDK-first agent API does not change model string routing. Existing `model: "provider/model"` usage continues to work. You only need to update provider packages if you import ai-sdk providers directly. +::: + For the full provider directory and model lists, see [Models](/models-docs/). ## Model String Format diff --git a/website/docs/getting-started/quick-start.md b/website/docs/getting-started/quick-start.md index 184eb2743..b8ff8671e 100644 --- a/website/docs/getting-started/quick-start.md +++ b/website/docs/getting-started/quick-start.md @@ -59,7 +59,7 @@ cd my-agent-app ``` :::info requirement -Be sure your environment is running Node.js 20.19 or newer so the generated tsdown build works without ESM resolution issues. +Be sure your environment is running Node.js 22 or newer. VoltAgent 3.x follows AI SDK 7's Node.js and ESM-only runtime boundary. ::: diff --git a/website/docs/integrations/nextjs.md b/website/docs/integrations/nextjs.md index a30650df8..b0b67a436 100644 --- a/website/docs/integrations/nextjs.md +++ b/website/docs/integrations/nextjs.md @@ -33,7 +33,7 @@ Follow the prompts, selecting TypeScript and App Router. Install the necessary VoltAgent packages and dependencies: ```bash -npm install @voltagent/core @ai-sdk/react ai zod@^3.25.76 +npm install @voltagent/core @ai-sdk/react ai zod@^4 ``` - `@voltagent/core`: The core VoltAgent library. diff --git a/website/docs/rag/chroma.md b/website/docs/rag/chroma.md index 73ade5be4..ebf5e2532 100644 --- a/website/docs/rag/chroma.md +++ b/website/docs/rag/chroma.md @@ -11,7 +11,7 @@ slug: /rag/chroma Before starting, ensure you have: -- Node.js 18+ installed +- Node.js 22+ installed - OpenAI API key (for embeddings) **Note**: Docker or Python are no longer required since Chroma CLI is now bundled with the JS/TS package. diff --git a/website/docs/rag/lancedb.md b/website/docs/rag/lancedb.md index 7bb3ed186..da1ef3b3a 100644 --- a/website/docs/rag/lancedb.md +++ b/website/docs/rag/lancedb.md @@ -11,7 +11,7 @@ slug: /rag/lancedb Before starting, ensure you have: -- Node.js 20+ installed +- Node.js 22+ installed - OpenAI API key (for embeddings) - (Optional) LanceDB Cloud account if deploying to production diff --git a/website/docs/rag/pinecone.md b/website/docs/rag/pinecone.md index 1ab34b569..395566a4d 100644 --- a/website/docs/rag/pinecone.md +++ b/website/docs/rag/pinecone.md @@ -11,7 +11,7 @@ slug: /rag/pinecone Before starting, ensure you have: -- Node.js 18+ installed +- Node.js 22+ installed - Pinecone account (free tier available) - Pinecone API key - OpenAI API key (for embeddings) diff --git a/website/docs/rag/qdrant.md b/website/docs/rag/qdrant.md index 1302e936d..8be6246b4 100644 --- a/website/docs/rag/qdrant.md +++ b/website/docs/rag/qdrant.md @@ -11,7 +11,7 @@ slug: /rag/qdrant Before starting, ensure you have: -- Node.js 18+ installed +- Node.js 22+ installed - Qdrant instance (local or cloud) - Qdrant API key (if using cloud) - OpenAI API key (for embeddings) diff --git a/website/docs/tools/overview.md b/website/docs/tools/overview.md index 2c4eae83c..9512f070f 100644 --- a/website/docs/tools/overview.md +++ b/website/docs/tools/overview.md @@ -8,25 +8,24 @@ VoltAgent allows you to extend the capabilities of your AI agents by providing t ## Defining a Single Tool -The most basic way to define a tool is using the `createTool` helper function (or instantiating the `Tool` class directly). +For new VoltAgent 3.x code, define custom tools with the AI SDK-style `tool()` helper and pass them to agents as a `ToolSet` object. The tool name comes from the object key. A tool requires: -- `name`: A unique name for the tool (used by the LLM to call it). - `description`: A clear description of what the tool does (used by the LLM to decide when to use it). -- `parameters`: A Zod schema defining the input arguments the tool expects. +- `inputSchema`: A Zod schema defining the input arguments the tool expects. - `execute`: An asynchronous function that contains the tool's logic, taking the validated arguments as input. - `outputSchema` (optional): A Zod schema defining the expected output format. When provided, the tool's output will be validated against this schema. +- `voltagent` (optional): VoltAgent-only metadata such as tags, hooks, and static approval metadata. ```typescript -import { Agent, createTool } from "@voltagent/core"; +import { Agent, tool } from "@voltagent/core"; import { z } from "zod"; // Define a simple weather tool -const getWeatherTool = createTool({ - name: "get_weather", +const getWeatherTool = tool({ description: "Fetches the current weather for a given location.", - parameters: z.object({ + inputSchema: z.object({ location: z.string().describe("The city and state, e.g., San Francisco, CA"), }), execute: async ({ location }) => { @@ -43,48 +42,47 @@ const agent = new Agent({ name: "WeatherAgent", instructions: "An agent that can fetch weather information.", model: "openai/gpt-4o-mini", - tools: [getWeatherTool], // Add the tool to the agent + tools: { + get_weather: getWeatherTool, + }, }); // Now the agent can use the 'get_weather' tool when asked about weather. ``` -## Accessing Operation Context in Tools +## Accessing Tool Context -Tools can access operation metadata, user context, and control mechanisms through the second parameter: +The `execute` function receives AI SDK tool execution options such as `toolCallId`, `messages`, and `abortSignal`. VoltAgent lifecycle context is available through `voltagent.hooks`. ```typescript -import { Agent, createTool } from "@voltagent/core"; +import { Agent, tool } from "@voltagent/core"; import { z } from "zod"; -// Tool that uses operation context -const contextAwareWeatherTool = createTool({ - name: "get_weather", +// Tool that observes VoltAgent lifecycle context +const contextAwareWeatherTool = tool({ description: "Fetches weather with user preferences", - parameters: z.object({ + inputSchema: z.object({ location: z.string().describe("The city name"), }), execute: async ({ location }, options) => { - // Access user-defined context - const units = options?.context?.get("preferredUnits") || "celsius"; - const userId = options?.userId; - - // Use operation-scoped logger - options?.logger?.info(`Fetching weather for ${location} in ${units}`); - - // Check abort signal - if (options?.abortSignal?.aborted) { + if (options.abortSignal?.aborted) { throw new Error("Request was cancelled"); } - // Call weather API with user preferences - const response = await fetch( - `https://api.weather.com/current?city=${location}&units=${units}`, - { signal: options?.abortSignal } - ); + const response = await fetch(`https://api.weather.com/current?city=${location}`, { + signal: options.abortSignal, + }); return await response.json(); }, + voltagent: { + hooks: { + onStart: ({ args, options }) => { + const units = options?.context?.get("preferredUnits") || "celsius"; + options?.logger?.info(`Fetching weather for ${args.location} in ${units}`); + }, + }, + }, }); // Use the tool with context @@ -95,24 +93,27 @@ const agent = new Agent({ name: "WeatherAgent", instructions: "An agent that respects user preferences", model: "openai/gpt-4o-mini", - tools: [contextAwareWeatherTool], + tools: { + get_weather: contextAwareWeatherTool, + }, }); const response = await agent.generateText("What's the weather in Paris?", { - userId: "user123", + memory: { + userId: "user123", + }, context, }); ``` -The `options` parameter includes: +In `voltagent.hooks`, the `options` parameter includes: - **Operation metadata**: `operationId`, `userId`, `conversationId` - **User context**: `context` (Map for custom data) -- **Control mechanisms**: `abortController`, `abortSignal` - **Logging**: `logger` (operation-scoped logger) -- **AI SDK data**: `toolCallId`, `messages` +- **Tool context**: `toolContext.callId`, `toolContext.messages`, `toolContext.abortSignal` -For more details, see the [Tools documentation](/docs/agents/tools#accessing-operation-context). +For more details, see the [Tools documentation](/docs/agents/tools#accessing-tool-context). ## Tool Output Schema Validation @@ -127,7 +128,7 @@ VoltAgent supports optional output schema validation for tools. This feature ens ### Example with Output Schema ```typescript -import { createTool } from "@voltagent/core"; +import { tool } from "@voltagent/core"; import { z } from "zod"; // Define the output schema @@ -144,10 +145,9 @@ const weatherOutputSchema = z.object({ }); // Create a tool with output validation -const weatherTool = createTool({ - name: "get_weather", +const weatherTool = tool({ description: "Get current weather with forecast", - parameters: z.object({ + inputSchema: z.object({ location: z.string().describe("City name"), }), outputSchema: weatherOutputSchema, // Optional output schema @@ -195,18 +195,22 @@ const weatherTool = createTool({ Often, several tools work together logically. For instance, tools for step-by-step reasoning (`think`, `analyze`) or a set of tools interacting with the same API. For these scenarios, VoltAgent provides **Toolkits**. +For new standalone agent tools, prefer `tool()` and a ToolSet object as shown above. The current toolkit helper still accepts class-style tool instances for compatibility; use the toolkit examples below only when you need toolkit-level instructions today. + A `Toolkit` allows you to: 1. **Group related tools:** Keep your tool management organized. 2. **Define shared instructions:** Provide common guidance to the LLM on how to use all tools within the toolkit. 3. **Control instruction injection:** Decide if the toolkit's shared instructions should be automatically added to the agent's system prompt. -### Defining a Toolkit +### Defining a Toolkit with Compatibility Tools + +`createToolkit` currently groups named class-style tools. This keeps existing toolkit behavior working while VoltAgent moves standalone tools to the AI SDK-style `tool()` helper. A `Toolkit` is an object with the following structure: ```typescript -import { createTool, createToolkit, type Tool, type Toolkit } from "@voltagent/core"; +import { createTool, createToolkit } from "@voltagent/core"; const myCalculatorToolkit = createToolkit({ name: "calculator_toolkit", @@ -231,11 +235,11 @@ const myCalculatorToolkit = createToolkit({ ### Adding Tools and Toolkits to an Agent -The `tools` option in the `Agent` constructor now accepts an array containing both individual `Tool` objects and `Toolkit` objects. The `ToolManager` handles both seamlessly. +The `tools` option in the `Agent` constructor accepts a ToolSet object for AI SDK-style tools, or an array containing class-style tools, provider-defined tools, and `Toolkit` objects. Use a ToolSet object for new standalone tools; use arrays when you need toolkits. ```typescript import { openai } from "@ai-sdk/openai"; -import { Agent, createTool, createToolkit, type Toolkit } from "@voltagent/core"; +import { Agent } from "@voltagent/core"; // ... import other tools and toolkits ... const agent = new Agent({ diff --git a/website/docs/tools/tool-routing.md b/website/docs/tools/tool-routing.md index 403b76e7e..045716680 100644 --- a/website/docs/tools/tool-routing.md +++ b/website/docs/tools/tool-routing.md @@ -22,8 +22,9 @@ Only `searchTools`, `callTool`, and any tools listed in `toolRouting.expose` are This configuration enables embedding-based tool search and exposes only `searchTools` and `callTool` to the model. +`toolRouting.pool` and `toolRouting.expose` currently use named compatibility tools and toolkits. For normal agent tools, prefer the AI SDK-style `tool()` helper; for routing pools, keep using named tools until ToolSet support is added to the routing config. + ```ts -import { openai } from "@ai-sdk/openai"; import { Agent, createTool } from "@voltagent/core"; import { z } from "zod"; diff --git a/website/docs/ui/ai-sdk-integration.md b/website/docs/ui/ai-sdk-integration.md index 98f54af56..60eaaca79 100644 --- a/website/docs/ui/ai-sdk-integration.md +++ b/website/docs/ui/ai-sdk-integration.md @@ -457,7 +457,7 @@ curl "http://localhost:3141/api/memory/conversations/conv-1/messages?agentId=ass | `providerOptions.google.thinkingConfig` | object | Gemini thinking budget/configuration | | `providerOptions.xai.reasoningEffort` | string | xAI reasoning effort | | `providerOptions.extraOptions` | object | Additional provider-specific options | -| `providerOptions.onStepFinish` | function | Callback when a step completes | +| `providerOptions.onStepEnd` | function | Callback when a step completes | ### Semantic Memory Options diff --git a/website/docs/workflows/streaming.md b/website/docs/workflows/streaming.md index 7259bd547..4096cf464 100644 --- a/website/docs/workflows/streaming.md +++ b/website/docs/workflows/streaming.md @@ -216,8 +216,8 @@ Asynchronously forwards events from an agent's fullStream to the workflow stream const agent = new Agent({ /* ... */ }); const response = await agent.streamText(prompt); - if (response.fullStream) { - await writer.pipeFrom(response.fullStream, { + if (response.stream) { + await writer.pipeFrom(response.stream, { prefix: "agent-", // Prefix for event types agentId: agent.id, // Override 'from' field filter: (part) => { // Filter events diff --git a/website/sidebars.ts b/website/sidebars.ts index 160d22981..3bd99f4a0 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -61,6 +61,7 @@ const sidebars: SidebarsConfig = { }, "agents/prompts", "agents/tools", + "agents/structured-output", { type: "doc", id: "agents/plan-agent", diff --git a/website/src/components/live-preview/index.tsx b/website/src/components/live-preview/index.tsx index 411ef0dcc..e20428bc1 100644 --- a/website/src/components/live-preview/index.tsx +++ b/website/src/components/live-preview/index.tsx @@ -214,16 +214,16 @@ export const fetchRepoContributorsTool = createTool({ "volt": "volt" }, "dependencies": { - "ai": "^5.0.0", - "@ai-sdk/openai": "^2.0.0", + "ai": "^7.0.0", + "@ai-sdk/openai": "^4.0.0", "@octokit/rest": "^21.0.0", - "@voltagent/core": "^1.0.0", - "@voltagent/server-hono": "^1.0.0", - "zod": "^3.25.72" + "@voltagent/core": "^3.0.0", + "@voltagent/server-hono": "^3.0.0", + "zod": "^4.1.11" }, "devDependencies": { - "@types/node": "^20.10.4", - "@voltagent/cli": "^0.1.0", + "@types/node": "^22.10.5", + "@voltagent/cli": "^1.0.0", "tsx": "^4.6.2", "typescript": "^5.3.3" }