From 239e7214bb9a1f47237805d5f24ba089dd3b572f Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:36:01 +0200
Subject: [PATCH 01/17] chore(monorepo): tighten build/CI scope, defensive
 changeset ignores, bump vite

- Exclude testing/** alongside examples/** in build, build:all, test:ci, test:pr,
  test:lib, test:types, test:eslint, test:build, test:coverage. Internal test
  harnesses (testing/e2e, testing/panel) had build scripts but no exclude,
  so they were getting built on every release pipeline.
- Add an `ignore` list to .changeset/config.json covering every in-workspace
  private package. Defends against accidental publication if `"private": true`
  is ever dropped from a package by mistake.
- Bump vite from ^7.2.7 to ^7.3.3 across every declaring package.json. Resolves
  a transitive version skew (some dev-only plugins pull vite@7.3.x) that was
  breaking typechecking of vite.config.ts files.
- Add `engines` to the root package.json: `node >=24`, `pnpm >=11.0.0`.
---
 .changeset/config.json                        |   18 +-
 examples/ts-code-mode-web/package.json        |    2 +-
 examples/ts-group-chat/package.json           |    2 +-
 examples/ts-react-chat/package.json           |    2 +-
 examples/ts-react-media/package.json          |    2 +-
 examples/ts-react-search/package.json         |    2 +-
 examples/ts-solid-chat/package.json           |    2 +-
 examples/ts-svelte-chat/package.json          |    2 +-
 examples/ts-vue-chat/package.json             |    2 +-
 examples/vanilla-chat/package.json            |    2 +-
 package.json                                  |   24 +-
 packages/typescript/ai-client/package.json    |    2 +-
 packages/typescript/ai-devtools/package.json  |    2 +-
 packages/typescript/ai-fal/package.json       |    2 +-
 packages/typescript/ai-gemini/package.json    |    2 +-
 packages/typescript/ai-grok/package.json      |    2 +-
 packages/typescript/ai-groq/package.json      |    2 +-
 packages/typescript/ai-ollama/package.json    |    2 +-
 packages/typescript/ai-openai/package.json    |    2 +-
 .../typescript/ai-openrouter/package.json     |    2 +-
 packages/typescript/ai-preact/package.json    |    2 +-
 packages/typescript/ai-react-ui/package.json  |    2 +-
 packages/typescript/ai-react/package.json     |    2 +-
 packages/typescript/ai-solid-ui/package.json  |    2 +-
 packages/typescript/ai-svelte/package.json    |    2 +-
 packages/typescript/ai-utils/package.json     |    2 +-
 packages/typescript/ai-vue-ui/package.json    |    2 +-
 packages/typescript/openai-base/package.json  |    2 +-
 .../preact-ai-devtools/package.json           |    2 +-
 .../typescript/react-ai-devtools/package.json |    2 +-
 .../typescript/solid-ai-devtools/package.json |    2 +-
 pnpm-lock.yaml                                | 1003 ++++++-----------
 testing/e2e/package.json                      |    2 +-
 testing/panel/package.json                    |    2 +-
 34 files changed, 391 insertions(+), 716 deletions(-)

diff --git a/.changeset/config.json b/.changeset/config.json
index a81213883..c727b374e 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -10,7 +10,23 @@
   "updateInternalDependencies": "patch",
   "fixed": [],
   "linked": [],
-  "ignore": [],
+  "ignore": [
+    "@tanstack/ai-codemods",
+    "@tanstack/ai-code-mode-models-eval",
+    "@tanstack/ai-e2e",
+    "stream-processor-panel",
+    "php-slim",
+    "python-fastapi",
+    "ts-code-mode-web",
+    "ts-group-chat",
+    "ts-react-chat",
+    "ts-react-media",
+    "ts-react-search",
+    "ts-solid-chat",
+    "ts-svelte-chat",
+    "ts-vue-chat",
+    "vanilla-chat"
+  ],
   "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
     "onlyUpdatePeerDependentsWhenOutOfRange": true
   }
diff --git a/examples/ts-code-mode-web/package.json b/examples/ts-code-mode-web/package.json
index a302b0fbc..a3893c246 100644
--- a/examples/ts-code-mode-web/package.json
+++ b/examples/ts-code-mode-web/package.json
@@ -52,6 +52,6 @@
     "@types/react-dom": "^19.2.3",
     "@vitejs/plugin-react": "^5.1.2",
     "typescript": "5.9.3",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/examples/ts-group-chat/package.json b/examples/ts-group-chat/package.json
index 61b41b2b2..26793e37f 100644
--- a/examples/ts-group-chat/package.json
+++ b/examples/ts-group-chat/package.json
@@ -37,7 +37,7 @@
     "@vitejs/plugin-react": "^5.1.2",
     "jsdom": "^27.2.0",
     "typescript": "5.9.3",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "vitest": "^4.0.14",
     "web-vitals": "^5.1.0"
   }
diff --git a/examples/ts-react-chat/package.json b/examples/ts-react-chat/package.json
index 60cfe6836..17e0861a6 100644
--- a/examples/ts-react-chat/package.json
+++ b/examples/ts-react-chat/package.json
@@ -56,7 +56,7 @@
     "@vitejs/plugin-react": "^5.1.2",
     "jsdom": "^27.2.0",
     "typescript": "5.9.3",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "vitest": "^4.0.14",
     "web-vitals": "^5.1.0"
   }
diff --git a/examples/ts-react-media/package.json b/examples/ts-react-media/package.json
index f5be09f00..80bc30ce8 100644
--- a/examples/ts-react-media/package.json
+++ b/examples/ts-react-media/package.json
@@ -30,6 +30,6 @@
     "@types/react-dom": "^19.2.3",
     "@vitejs/plugin-react": "^5.1.2",
     "typescript": "5.9.3",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/examples/ts-react-search/package.json b/examples/ts-react-search/package.json
index 4e6cbb8e1..591bf158e 100644
--- a/examples/ts-react-search/package.json
+++ b/examples/ts-react-search/package.json
@@ -48,7 +48,7 @@
     "@vitejs/plugin-react": "^5.1.2",
     "jsdom": "^27.2.0",
     "typescript": "5.9.3",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "vitest": "^4.0.14",
     "web-vitals": "^5.1.0"
   }
diff --git a/examples/ts-solid-chat/package.json b/examples/ts-solid-chat/package.json
index a54d44197..80a7a5a77 100644
--- a/examples/ts-solid-chat/package.json
+++ b/examples/ts-solid-chat/package.json
@@ -45,7 +45,7 @@
     "@types/node": "^24.10.1",
     "jsdom": "^27.2.0",
     "typescript": "5.9.3",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "vite-plugin-solid": "^2.11.10",
     "vitest": "^4.0.14",
     "web-vitals": "^5.1.0"
diff --git a/examples/ts-svelte-chat/package.json b/examples/ts-svelte-chat/package.json
index 1d185ca0f..91418fc4e 100644
--- a/examples/ts-svelte-chat/package.json
+++ b/examples/ts-svelte-chat/package.json
@@ -36,6 +36,6 @@
     "tailwindcss": "^4.1.18",
     "tslib": "^2.8.1",
     "typescript": "5.9.3",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/examples/ts-vue-chat/package.json b/examples/ts-vue-chat/package.json
index 5f8cc03b9..24fa9ea85 100644
--- a/examples/ts-vue-chat/package.json
+++ b/examples/ts-vue-chat/package.json
@@ -34,7 +34,7 @@
     "tailwindcss": "^4.1.18",
     "tsx": "^4.21.0",
     "typescript": "5.9.3",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "vue-tsc": "^2.2.10"
   }
 }
diff --git a/examples/vanilla-chat/package.json b/examples/vanilla-chat/package.json
index dfd8bda0b..7a41b6e90 100644
--- a/examples/vanilla-chat/package.json
+++ b/examples/vanilla-chat/package.json
@@ -13,6 +13,6 @@
     "@tanstack/ai-client": "workspace:*"
   },
   "devDependencies": {
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/package.json b/package.json
index 09140f496..8ef5fc652 100644
--- a/package.json
+++ b/package.json
@@ -7,26 +7,30 @@
   },
   "packageManager": "pnpm@11.1.1",
   "type": "module",
+  "engines": {
+    "node": ">=24",
+    "pnpm": ">=11.0.0"
+  },
   "scripts": {
     "clean": "pnpm --filter \"./packages/**\" run clean",
     "clean:all": "git clean -fdx --exclude=\"!.env\"",
     "test": "pnpm run test:ci",
-    "test:pr": "nx affected --targets=test:sherif,test:knip,test:docs,test:eslint,test:lib,test:types,test:build,build",
-    "test:ci": "nx run-many --targets=test:sherif,test:knip,test:docs,test:eslint,test:lib,test:types,test:build,build",
-    "test:eslint": "nx affected --target=test:eslint --exclude=examples/**",
+    "test:pr": "nx affected --targets=test:sherif,test:knip,test:docs,test:eslint,test:lib,test:types,test:build,build --exclude=examples/**,testing/**",
+    "test:ci": "nx run-many --targets=test:sherif,test:knip,test:docs,test:eslint,test:lib,test:types,test:build,build --exclude=examples/**,testing/**",
+    "test:eslint": "nx affected --target=test:eslint --exclude=examples/**,testing/**",
     "test:sherif": "sherif",
-    "test:lib": "nx affected --targets=test:lib --exclude=examples/**",
+    "test:lib": "nx affected --targets=test:lib --exclude=examples/**,testing/**",
     "test:lib:dev": "pnpm test:lib && nx watch --all -- pnpm test:lib",
-    "test:coverage": "nx affected --targets=test:coverage --exclude=examples/**",
-    "test:build": "nx affected --target=test:build --exclude=examples/**",
-    "test:types": "nx affected --targets=test:types --exclude=examples/**",
+    "test:coverage": "nx affected --targets=test:coverage --exclude=examples/**,testing/**",
+    "test:build": "nx affected --target=test:build --exclude=examples/**,testing/**",
+    "test:types": "nx affected --targets=test:types --exclude=examples/**,testing/**",
     "test:knip": "knip",
     "test:docs": "node scripts/verify-links.ts",
     "test:e2e": "pnpm --filter @tanstack/ai-e2e test:e2e",
     "test:e2e:ui": "pnpm --filter @tanstack/ai-e2e test:e2e:ui",
     "codemod:ag-ui-compliance": "pnpm --filter @tanstack/ai-codemods exec node ./run.mjs ag-ui-compliance",
-    "build": "nx affected --skip-nx-cache --targets=build --exclude=examples/**",
-    "build:all": "nx run-many --targets=build --exclude=examples/**",
+    "build": "nx affected --skip-nx-cache --targets=build --exclude=examples/**,testing/**",
+    "build:all": "nx run-many --targets=build --exclude=examples/**,testing/**",
     "watch": "pnpm run build:all && env NX_DAEMON=true nx watch --all -- pnpm run build:all",
     "dev": "pnpm run watch",
     "dev:chat": "pnpm --filter ts-react-chat dev",
@@ -70,7 +74,7 @@
     "tinyglobby": "^0.2.15",
     "tsx": "^4.21.0",
     "typescript": "5.9.3",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "vitest": "^4.0.14"
   }
 }
diff --git a/packages/typescript/ai-client/package.json b/packages/typescript/ai-client/package.json
index 93e0ad699..543d7b8fd 100644
--- a/packages/typescript/ai-client/package.json
+++ b/packages/typescript/ai-client/package.json
@@ -49,7 +49,7 @@
   "devDependencies": {
     "@standard-schema/spec": "^1.1.0",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "zod": "^4.2.0"
   }
 }
diff --git a/packages/typescript/ai-devtools/package.json b/packages/typescript/ai-devtools/package.json
index c503ca1c0..c716e0c38 100644
--- a/packages/typescript/ai-devtools/package.json
+++ b/packages/typescript/ai-devtools/package.json
@@ -90,7 +90,7 @@
     "jsdom": "^27.2.0",
     "tsup": "^8.5.1",
     "tsup-preset-solid": "^2.2.0",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "vite-plugin-solid": "^2.11.10"
   }
 }
diff --git a/packages/typescript/ai-fal/package.json b/packages/typescript/ai-fal/package.json
index bcf0e7025..5842dcf8e 100644
--- a/packages/typescript/ai-fal/package.json
+++ b/packages/typescript/ai-fal/package.json
@@ -52,7 +52,7 @@
   "devDependencies": {
     "@tanstack/ai": "workspace:*",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   },
   "peerDependencies": {
     "@tanstack/ai": "workspace:*"
diff --git a/packages/typescript/ai-gemini/package.json b/packages/typescript/ai-gemini/package.json
index 14d5ea910..97b5b53e7 100644
--- a/packages/typescript/ai-gemini/package.json
+++ b/packages/typescript/ai-gemini/package.json
@@ -53,7 +53,7 @@
   "devDependencies": {
     "@tanstack/ai": "workspace:*",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "zod": "^4.2.0"
   }
 }
diff --git a/packages/typescript/ai-grok/package.json b/packages/typescript/ai-grok/package.json
index aeb36aeec..c111ba330 100644
--- a/packages/typescript/ai-grok/package.json
+++ b/packages/typescript/ai-grok/package.json
@@ -52,7 +52,7 @@
     "@tanstack/ai": "workspace:*",
     "@tanstack/ai-client": "workspace:*",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   },
   "peerDependencies": {
     "@tanstack/ai": "workspace:^",
diff --git a/packages/typescript/ai-groq/package.json b/packages/typescript/ai-groq/package.json
index a59f9d158..7d418b893 100644
--- a/packages/typescript/ai-groq/package.json
+++ b/packages/typescript/ai-groq/package.json
@@ -44,7 +44,7 @@
   ],
   "devDependencies": {
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   },
   "peerDependencies": {
     "@tanstack/ai": "workspace:^",
diff --git a/packages/typescript/ai-ollama/package.json b/packages/typescript/ai-ollama/package.json
index 2f14642bb..638b11650 100644
--- a/packages/typescript/ai-ollama/package.json
+++ b/packages/typescript/ai-ollama/package.json
@@ -50,6 +50,6 @@
   "devDependencies": {
     "@tanstack/ai": "workspace:*",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/packages/typescript/ai-openai/package.json b/packages/typescript/ai-openai/package.json
index 585e30106..f68e31940 100644
--- a/packages/typescript/ai-openai/package.json
+++ b/packages/typescript/ai-openai/package.json
@@ -57,7 +57,7 @@
     "@tanstack/ai": "workspace:*",
     "@tanstack/ai-client": "workspace:*",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "zod": "^4.2.0"
   }
 }
diff --git a/packages/typescript/ai-openrouter/package.json b/packages/typescript/ai-openrouter/package.json
index 745492bef..3e60088df 100644
--- a/packages/typescript/ai-openrouter/package.json
+++ b/packages/typescript/ai-openrouter/package.json
@@ -49,7 +49,7 @@
   "devDependencies": {
     "@tanstack/ai": "workspace:*",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "zod": "^4.2.0"
   },
   "peerDependencies": {
diff --git a/packages/typescript/ai-preact/package.json b/packages/typescript/ai-preact/package.json
index da23f6f07..ff3e1ace8 100644
--- a/packages/typescript/ai-preact/package.json
+++ b/packages/typescript/ai-preact/package.json
@@ -48,7 +48,7 @@
     "@vitest/coverage-v8": "4.0.14",
     "jsdom": "^27.2.0",
     "preact": "^10.26.9",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   },
   "peerDependencies": {
     "@tanstack/ai": "workspace:^",
diff --git a/packages/typescript/ai-react-ui/package.json b/packages/typescript/ai-react-ui/package.json
index 7548e5b0b..352cbc1dc 100644
--- a/packages/typescript/ai-react-ui/package.json
+++ b/packages/typescript/ai-react-ui/package.json
@@ -58,6 +58,6 @@
     "@vitest/coverage-v8": "4.0.14",
     "react": "^19.2.3",
     "react-dom": "^19.2.3",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/packages/typescript/ai-react/package.json b/packages/typescript/ai-react/package.json
index 2e7e4ce40..ce016058b 100644
--- a/packages/typescript/ai-react/package.json
+++ b/packages/typescript/ai-react/package.json
@@ -56,6 +56,6 @@
     "@vitest/coverage-v8": "4.0.14",
     "jsdom": "^27.2.0",
     "react": "^19.2.3",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/packages/typescript/ai-solid-ui/package.json b/packages/typescript/ai-solid-ui/package.json
index 334d1eb06..905b6cf4c 100644
--- a/packages/typescript/ai-solid-ui/package.json
+++ b/packages/typescript/ai-solid-ui/package.json
@@ -57,6 +57,6 @@
     "@tanstack/ai-solid": "workspace:*",
     "@vitest/coverage-v8": "4.0.14",
     "solid-js": "^1.9.10",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/packages/typescript/ai-svelte/package.json b/packages/typescript/ai-svelte/package.json
index 38591ba73..e5dc0f314 100644
--- a/packages/typescript/ai-svelte/package.json
+++ b/packages/typescript/ai-svelte/package.json
@@ -60,6 +60,6 @@
     "svelte": "^5.20.0",
     "svelte-check": "^4.2.0",
     "typescript": "5.9.3",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/packages/typescript/ai-utils/package.json b/packages/typescript/ai-utils/package.json
index c2e880bbb..91447e6b5 100644
--- a/packages/typescript/ai-utils/package.json
+++ b/packages/typescript/ai-utils/package.json
@@ -40,6 +40,6 @@
   "devDependencies": {
     "@types/node": "^24.10.1",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/packages/typescript/ai-vue-ui/package.json b/packages/typescript/ai-vue-ui/package.json
index e9ba21c7d..a16141499 100644
--- a/packages/typescript/ai-vue-ui/package.json
+++ b/packages/typescript/ai-vue-ui/package.json
@@ -52,7 +52,7 @@
   "devDependencies": {
     "@vitejs/plugin-vue": "^6.0.2",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "vue": "^3.5.25",
     "vue-tsc": "^2.2.10"
   }
diff --git a/packages/typescript/openai-base/package.json b/packages/typescript/openai-base/package.json
index 99b666d5c..74be6952d 100644
--- a/packages/typescript/openai-base/package.json
+++ b/packages/typescript/openai-base/package.json
@@ -48,7 +48,7 @@
   "devDependencies": {
     "@tanstack/ai": "workspace:*",
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "zod": "^4.2.0"
   }
 }
diff --git a/packages/typescript/preact-ai-devtools/package.json b/packages/typescript/preact-ai-devtools/package.json
index ff608e645..c0019ebf0 100644
--- a/packages/typescript/preact-ai-devtools/package.json
+++ b/packages/typescript/preact-ai-devtools/package.json
@@ -53,7 +53,7 @@
   },
   "devDependencies": {
     "@vitest/coverage-v8": "4.0.14",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   },
   "peerDependencies": {
     "preact": "^10.0.0"
diff --git a/packages/typescript/react-ai-devtools/package.json b/packages/typescript/react-ai-devtools/package.json
index 350ccdae4..dcfdff80c 100644
--- a/packages/typescript/react-ai-devtools/package.json
+++ b/packages/typescript/react-ai-devtools/package.json
@@ -59,6 +59,6 @@
     "@types/react": "^19.2.7",
     "@vitest/coverage-v8": "4.0.14",
     "react": "^19.2.3",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/packages/typescript/solid-ai-devtools/package.json b/packages/typescript/solid-ai-devtools/package.json
index 5ed80b659..3abca4aa0 100644
--- a/packages/typescript/solid-ai-devtools/package.json
+++ b/packages/typescript/solid-ai-devtools/package.json
@@ -56,7 +56,7 @@
   "devDependencies": {
     "@vitest/coverage-v8": "4.0.14",
     "solid-js": "^1.9.10",
-    "vite": "^7.2.7",
+    "vite": "^7.3.3",
     "vite-plugin-solid": "^2.11.10"
   }
 }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 18d04cffa..e7dba0a2f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -31,7 +31,7 @@ importers:
         version: 0.3.1(typescript@5.9.3)
       '@tanstack/vite-config':
         specifier: 0.4.1
-        version: 0.4.1(@types/node@24.10.3)(rollup@4.60.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 0.4.1(@types/node@24.10.3)(rollup@4.60.1)(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@types/node':
         specifier: ^24.10.1
         version: 24.10.3
@@ -78,8 +78,8 @@ importers:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vitest:
         specifier: ^4.0.14
         version: 4.0.15(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -100,7 +100,7 @@ importers:
         version: 5.9.3
       vitest:
         specifier: ^4.0.14
-        version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
 
   examples/php-slim:
     devDependencies:
@@ -121,7 +121,7 @@ importers:
         version: 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/ai':
         specifier: workspace:*
         version: link:../../packages/typescript/ai
@@ -160,16 +160,16 @@ importers:
         version: link:../../packages/typescript/ai-react
       '@tanstack/nitro-v2-vite-plugin':
         specifier: ^1.154.7
-        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/react-router':
         specifier: ^1.158.4
         version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start':
         specifier: ^1.159.0
-        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-plugin':
         specifier: ^1.158.4
-        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/store':
         specifier: ^0.8.0
         version: 0.8.0
@@ -217,14 +217,14 @@ importers:
         version: 4.1.18
       vite-tsconfig-paths:
         specifier: ^5.1.4
-        version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       zod:
         specifier: ^4.2.0
         version: 4.3.6
     devDependencies:
       '@tanstack/devtools-vite':
         specifier: ^0.5.3
-        version: 0.5.3(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 0.5.3(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@types/node':
         specifier: ^24.10.1
         version: 24.10.3
@@ -236,19 +236,19 @@ importers:
         version: 19.2.3(@types/react@19.2.7)
       '@vitejs/plugin-react':
         specifier: ^5.1.2
-        version: 5.1.2(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       typescript:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   examples/ts-group-chat:
     dependencies:
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/ai':
         specifier: workspace:*
         version: link:../../packages/typescript/ai
@@ -275,10 +275,10 @@ importers:
         version: 1.159.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start':
         specifier: ^1.159.0
-        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-plugin':
         specifier: ^1.158.4
-        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       capnweb:
         specifier: ^0.1.0
         version: 0.1.0
@@ -293,14 +293,14 @@ importers:
         version: 4.1.18
       vite-tsconfig-paths:
         specifier: ^5.1.4
-        version: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       ws:
         specifier: ^8.18.3
         version: 8.18.3
     devDependencies:
       '@tanstack/devtools-vite':
         specifier: ^0.5.3
-        version: 0.5.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 0.5.3(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@testing-library/dom':
         specifier: ^10.4.1
         version: 10.4.1
@@ -321,7 +321,7 @@ importers:
         version: 8.18.1
       '@vitejs/plugin-react':
         specifier: ^5.1.2
-        version: 5.1.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       jsdom:
         specifier: ^27.2.0
         version: 27.3.0(postcss@8.5.9)
@@ -329,8 +329,8 @@ importers:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vitest:
         specifier: ^4.0.14
         version: 4.0.15(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -342,7 +342,7 @@ importers:
     dependencies:
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/ai':
         specifier: workspace:*
         version: link:../../packages/typescript/ai
@@ -384,7 +384,7 @@ importers:
         version: link:../../packages/typescript/ai-react-ui
       '@tanstack/nitro-v2-vite-plugin':
         specifier: ^1.154.7
-        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/react-devtools':
         specifier: ^0.9.10
         version: 0.9.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)
@@ -399,13 +399,13 @@ importers:
         version: 1.159.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start':
         specifier: ^1.159.0
-        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/react-store':
         specifier: ^0.8.0
         version: 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/router-plugin':
         specifier: ^1.158.4
-        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/store':
         specifier: ^0.8.0
         version: 0.8.0
@@ -441,14 +441,14 @@ importers:
         version: 4.1.18
       vite-tsconfig-paths:
         specifier: ^5.1.4
-        version: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       zod:
         specifier: ^4.2.0
         version: 4.2.1
     devDependencies:
       '@tanstack/devtools-vite':
         specifier: ^0.5.3
-        version: 0.5.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 0.5.3(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/react-ai-devtools':
         specifier: workspace:*
         version: link:../../packages/typescript/react-ai-devtools
@@ -469,7 +469,7 @@ importers:
         version: 19.2.3(@types/react@19.2.7)
       '@vitejs/plugin-react':
         specifier: ^5.1.2
-        version: 5.1.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       jsdom:
         specifier: ^27.2.0
         version: 27.3.0(postcss@8.5.9)
@@ -477,8 +477,8 @@ importers:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vitest:
         specifier: ^4.0.14
         version: 4.0.15(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -490,7 +490,7 @@ importers:
     dependencies:
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/ai':
         specifier: workspace:*
         version: link:../../packages/typescript/ai
@@ -505,16 +505,16 @@ importers:
         version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start':
         specifier: ^1.159.0
-        version: 1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-plugin':
         specifier: ^1.158.4
-        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       lucide-react:
         specifier: ^0.561.0
         version: 0.561.0(react@19.2.3)
       nitro:
         specifier: 3.0.1-alpha.2
-        version: 3.0.1-alpha.2(chokidar@5.0.0)(ioredis@5.9.2)(lru-cache@11.2.4)(rolldown@1.0.0-rc.17)(rollup@4.60.1)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 3.0.1-alpha.2(chokidar@5.0.0)(ioredis@5.9.2)(lru-cache@11.2.4)(rolldown@1.0.0-rc.17)(rollup@4.60.1)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       react:
         specifier: ^19.2.3
         version: 19.2.3
@@ -526,7 +526,7 @@ importers:
         version: 4.1.18
       vite-tsconfig-paths:
         specifier: ^5.1.4
-        version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
     devDependencies:
       '@types/node':
         specifier: ^24.10.1
@@ -539,13 +539,13 @@ importers:
         version: 19.2.3(@types/react@19.2.7)
       '@vitejs/plugin-react':
         specifier: ^5.1.2
-        version: 5.1.2(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       typescript:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   examples/ts-react-search:
     dependencies:
@@ -554,7 +554,7 @@ importers:
         version: 1.2.4(@types/react@19.2.7)(react@19.2.3)
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/ai':
         specifier: workspace:*
         version: link:../../packages/typescript/ai
@@ -587,10 +587,10 @@ importers:
         version: 1.159.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.159.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start':
         specifier: ^1.159.0
-        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-plugin':
         specifier: ^1.158.4
-        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/zod-adapter':
         specifier: ^1.140.1
         version: 1.166.9(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(zod@4.3.6)
@@ -605,7 +605,7 @@ importers:
         version: 0.561.0(react@19.2.3)
       nitro:
         specifier: latest
-        version: 3.0.260429-beta(chokidar@5.0.0)(dotenv@17.2.3)(giget@2.0.0)(jiti@2.6.1)(miniflare@4.20260504.0)(rollup@4.60.1)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 3.0.260429-beta(chokidar@5.0.0)(dotenv@17.2.3)(giget@2.0.0)(jiti@2.6.1)(miniflare@4.20260504.0)(rollup@4.60.1)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       radix-ui:
         specifier: ^1.4.3
         version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -629,14 +629,14 @@ importers:
         version: 1.4.0
       vite-tsconfig-paths:
         specifier: ^5.1.4
-        version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       zod:
         specifier: ^4.2.0
         version: 4.3.6
     devDependencies:
       '@tanstack/devtools-vite':
         specifier: ^0.5.3
-        version: 0.5.3(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 0.5.3(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@testing-library/dom':
         specifier: ^10.4.1
         version: 10.4.1
@@ -654,7 +654,7 @@ importers:
         version: 19.2.3(@types/react@19.2.7)
       '@vitejs/plugin-react':
         specifier: ^5.1.2
-        version: 5.1.2(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       jsdom:
         specifier: ^27.2.0
         version: 27.3.0(postcss@8.5.9)
@@ -662,11 +662,11 @@ importers:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vitest:
         specifier: ^4.0.14
-        version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       web-vitals:
         specifier: ^5.1.0
         version: 5.1.0
@@ -675,7 +675,7 @@ importers:
     dependencies:
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/ai':
         specifier: workspace:*
         version: link:../../packages/typescript/ai
@@ -705,10 +705,10 @@ importers:
         version: link:../../packages/typescript/ai-solid-ui
       '@tanstack/nitro-v2-vite-plugin':
         specifier: ^1.154.7
-        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-plugin':
         specifier: ^1.158.4
-        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/solid-ai-devtools':
         specifier: workspace:*
         version: link:../../packages/typescript/solid-ai-devtools
@@ -726,7 +726,7 @@ importers:
         version: 1.141.1(@tanstack/query-core@5.90.12)(@tanstack/router-core@1.159.4)(@tanstack/solid-query@5.90.15(solid-js@1.9.10))(@tanstack/solid-router@1.141.1(solid-js@1.9.10))(eslint@9.39.4(jiti@2.6.1))(solid-js@1.9.10)(typescript@5.9.3)
       '@tanstack/solid-start':
         specifier: ^1.139.10
-        version: 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/solid-store':
         specifier: ^0.8.0
         version: 0.8.0(solid-js@1.9.10)
@@ -750,7 +750,7 @@ importers:
         version: 4.1.18
       vite-tsconfig-paths:
         specifier: ^5.1.4
-        version: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       zod:
         specifier: ^4.2.0
         version: 4.2.1
@@ -763,7 +763,7 @@ importers:
         version: 0.4.1
       '@tanstack/devtools-vite':
         specifier: ^0.5.3
-        version: 0.5.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 0.5.3(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@testing-library/dom':
         specifier: ^10.4.1
         version: 10.4.1
@@ -777,11 +777,11 @@ importers:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vite-plugin-solid:
         specifier: ^2.11.10
-        version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vitest:
         specifier: ^4.0.14
         version: 4.0.15(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
@@ -830,16 +830,16 @@ importers:
     devDependencies:
       '@sveltejs/adapter-auto':
         specifier: ^3.3.1
-        version: 3.3.1(@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))
+        version: 3.3.1(@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))
       '@sveltejs/kit':
         specifier: ^2.15.10
-        version: 2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@sveltejs/vite-plugin-svelte':
         specifier: ^5.1.1
-        version: 5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@types/node':
         specifier: ^24.10.1
         version: 24.10.3
@@ -859,8 +859,8 @@ importers:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   examples/ts-vue-chat:
     dependencies:
@@ -903,13 +903,13 @@ importers:
     devDependencies:
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@types/node':
         specifier: ^24.10.1
         version: 24.10.3
       '@vitejs/plugin-vue':
         specifier: ^6.0.2
-        version: 6.0.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))
+        version: 6.0.3(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))
       autoprefixer:
         specifier: ^10.4.21
         version: 10.4.22(postcss@8.5.9)
@@ -932,8 +932,8 @@ importers:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vue-tsc:
         specifier: ^2.2.10
         version: 2.2.12(typescript@5.9.3)
@@ -945,8 +945,8 @@ importers:
         version: link:../../packages/typescript/ai-client
     devDependencies:
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai:
     dependencies:
@@ -1008,8 +1008,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       zod:
         specifier: ^4.2.0
         version: 4.2.1
@@ -1141,11 +1141,11 @@ importers:
         specifier: ^2.2.0
         version: 2.2.0(esbuild@0.27.7)(solid-js@1.9.10)(tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@24.10.3))(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vite-plugin-solid:
         specifier: ^2.11.10
-        version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
 
   packages/typescript/ai-elevenlabs:
     dependencies:
@@ -1198,8 +1198,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-gemini:
     dependencies:
@@ -1217,8 +1217,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       zod:
         specifier: ^4.2.0
         version: 4.3.6
@@ -1248,8 +1248,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-groq:
     dependencies:
@@ -1273,8 +1273,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-isolate-cloudflare:
     dependencies:
@@ -1334,8 +1334,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-openai:
     dependencies:
@@ -1359,8 +1359,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       zod:
         specifier: ^4.2.0
         version: 4.3.6
@@ -1381,8 +1381,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       zod:
         specifier: ^4.2.0
         version: 4.3.6
@@ -1409,8 +1409,8 @@ importers:
         specifier: ^10.26.9
         version: 10.28.2
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-react:
     dependencies:
@@ -1440,8 +1440,8 @@ importers:
         specifier: ^19.2.3
         version: 19.2.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-react-ui:
     dependencies:
@@ -1480,8 +1480,8 @@ importers:
         specifier: ^19.2.3
         version: 19.2.3(react@19.2.3)
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-solid:
     dependencies:
@@ -1551,8 +1551,8 @@ importers:
         specifier: ^1.9.10
         version: 1.9.10
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-svelte:
     dependencies:
@@ -1568,7 +1568,7 @@ importers:
         version: 2.5.7(svelte@5.45.10)(typescript@5.9.3)
       '@sveltejs/vite-plugin-svelte':
         specifier: ^5.1.1
-        version: 5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/ai':
         specifier: workspace:*
         version: link:../ai
@@ -1591,8 +1591,8 @@ importers:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-utils:
     devDependencies:
@@ -1603,8 +1603,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/ai-vue:
     dependencies:
@@ -1666,13 +1666,13 @@ importers:
     devDependencies:
       '@vitejs/plugin-vue':
         specifier: ^6.0.2
-        version: 6.0.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))
+        version: 6.0.3(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))
       '@vitest/coverage-v8':
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vue:
         specifier: ^3.5.25
         version: 3.5.25(typescript@5.9.3)
@@ -1696,8 +1696,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       zod:
         specifier: ^4.2.0
         version: 4.3.6
@@ -1718,8 +1718,8 @@ importers:
         specifier: 4.0.14
         version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/react-ai-devtools:
     dependencies:
@@ -1740,8 +1740,8 @@ importers:
         specifier: ^19.2.3
         version: 19.2.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   packages/typescript/solid-ai-devtools:
     dependencies:
@@ -1759,17 +1759,17 @@ importers:
         specifier: ^1.9.10
         version: 1.9.10
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vite-plugin-solid:
         specifier: ^2.11.10
-        version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
 
   testing/e2e:
     dependencies:
       '@copilotkit/aimock':
         specifier: ^1.18.0
-        version: 1.18.0(vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))
+        version: 1.18.0(vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))
       '@openrouter/sdk':
         specifier: 0.12.14
         version: 0.12.14
@@ -1778,7 +1778,7 @@ importers:
         version: 1.9.1
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/ai':
         specifier: workspace:*
         version: link:../../packages/typescript/ai
@@ -1817,13 +1817,13 @@ importers:
         version: link:../../packages/typescript/ai-react-ui
       '@tanstack/nitro-v2-vite-plugin':
         specifier: ^1.154.7
-        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/react-router':
         specifier: ^1.158.4
         version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start':
         specifier: ^1.159.0
-        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       react:
         specifier: ^19.2.3
         version: 19.2.3
@@ -1850,7 +1850,7 @@ importers:
         version: 4.1.18
       vite-tsconfig-paths:
         specifier: ^5.1.4
-        version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       zod:
         specifier: ^4.2.0
         version: 4.3.6
@@ -1869,19 +1869,19 @@ importers:
         version: 19.2.3(@types/react@19.2.7)
       '@vitejs/plugin-react':
         specifier: ^5.1.2
-        version: 5.1.2(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       typescript:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   testing/panel:
     dependencies:
       '@tailwindcss/vite':
         specifier: ^4.1.18
-        version: 4.1.18(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/ai':
         specifier: workspace:*
         version: link:../../packages/typescript/ai
@@ -1917,16 +1917,16 @@ importers:
         version: link:../../packages/typescript/ai-react-ui
       '@tanstack/nitro-v2-vite-plugin':
         specifier: ^1.154.7
-        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.154.7(rolldown@1.0.0-rc.17)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/react-router':
         specifier: ^1.158.4
         version: 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start':
         specifier: ^1.159.0
-        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start':
         specifier: ^1.120.20
-        version: 1.120.20(@types/node@24.10.3)(crossws@0.4.5(srvx@0.11.15))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
+        version: 1.120.20(@types/node@24.10.3)(crossws@0.4.5(srvx@0.11.15))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
       highlight.js:
         specifier: ^11.11.1
         version: 11.11.1
@@ -1959,7 +1959,7 @@ importers:
         version: 4.1.18
       vite-tsconfig-paths:
         specifier: ^5.1.4
-        version: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       zod:
         specifier: ^4.2.0
         version: 4.2.1
@@ -1978,7 +1978,7 @@ importers:
         version: 19.2.3(@types/react@19.2.7)
       '@vitejs/plugin-react':
         specifier: ^5.1.2
-        version: 5.1.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+        version: 5.1.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       dotenv:
         specifier: ^17.2.3
         version: 17.2.3
@@ -1986,8 +1986,8 @@ importers:
         specifier: 5.9.3
         version: 5.9.3
       vite:
-        specifier: ^7.2.7
-        version: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+        specifier: ^7.3.3
+        version: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
 packages:
 
@@ -5239,11 +5239,6 @@ packages:
       rollup:
         optional: true
 
-  '@rollup/rollup-android-arm-eabi@4.53.3':
-    resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==}
-    cpu: [arm]
-    os: [android]
-
   '@rollup/rollup-android-arm-eabi@4.57.1':
     resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==}
     cpu: [arm]
@@ -5254,11 +5249,6 @@ packages:
     cpu: [arm]
     os: [android]
 
-  '@rollup/rollup-android-arm64@4.53.3':
-    resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==}
-    cpu: [arm64]
-    os: [android]
-
   '@rollup/rollup-android-arm64@4.57.1':
     resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==}
     cpu: [arm64]
@@ -5269,11 +5259,6 @@ packages:
     cpu: [arm64]
     os: [android]
 
-  '@rollup/rollup-darwin-arm64@4.53.3':
-    resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==}
-    cpu: [arm64]
-    os: [darwin]
-
   '@rollup/rollup-darwin-arm64@4.57.1':
     resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==}
     cpu: [arm64]
@@ -5284,11 +5269,6 @@ packages:
     cpu: [arm64]
     os: [darwin]
 
-  '@rollup/rollup-darwin-x64@4.53.3':
-    resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==}
-    cpu: [x64]
-    os: [darwin]
-
   '@rollup/rollup-darwin-x64@4.57.1':
     resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==}
     cpu: [x64]
@@ -5299,11 +5279,6 @@ packages:
     cpu: [x64]
     os: [darwin]
 
-  '@rollup/rollup-freebsd-arm64@4.53.3':
-    resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==}
-    cpu: [arm64]
-    os: [freebsd]
-
   '@rollup/rollup-freebsd-arm64@4.57.1':
     resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==}
     cpu: [arm64]
@@ -5314,11 +5289,6 @@ packages:
     cpu: [arm64]
     os: [freebsd]
 
-  '@rollup/rollup-freebsd-x64@4.53.3':
-    resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==}
-    cpu: [x64]
-    os: [freebsd]
-
   '@rollup/rollup-freebsd-x64@4.57.1':
     resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==}
     cpu: [x64]
@@ -5329,12 +5299,6 @@ packages:
     cpu: [x64]
     os: [freebsd]
 
-  '@rollup/rollup-linux-arm-gnueabihf@4.53.3':
-    resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==}
-    cpu: [arm]
-    os: [linux]
-    libc: [glibc]
-
   '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
     resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==}
     cpu: [arm]
@@ -5347,12 +5311,6 @@ packages:
     os: [linux]
     libc: [glibc]
 
-  '@rollup/rollup-linux-arm-musleabihf@4.53.3':
-    resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==}
-    cpu: [arm]
-    os: [linux]
-    libc: [musl]
-
   '@rollup/rollup-linux-arm-musleabihf@4.57.1':
     resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==}
     cpu: [arm]
@@ -5365,12 +5323,6 @@ packages:
     os: [linux]
     libc: [musl]
 
-  '@rollup/rollup-linux-arm64-gnu@4.53.3':
-    resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==}
-    cpu: [arm64]
-    os: [linux]
-    libc: [glibc]
-
   '@rollup/rollup-linux-arm64-gnu@4.57.1':
     resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==}
     cpu: [arm64]
@@ -5383,12 +5335,6 @@ packages:
     os: [linux]
     libc: [glibc]
 
-  '@rollup/rollup-linux-arm64-musl@4.53.3':
-    resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==}
-    cpu: [arm64]
-    os: [linux]
-    libc: [musl]
-
   '@rollup/rollup-linux-arm64-musl@4.57.1':
     resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==}
     cpu: [arm64]
@@ -5401,12 +5347,6 @@ packages:
     os: [linux]
     libc: [musl]
 
-  '@rollup/rollup-linux-loong64-gnu@4.53.3':
-    resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==}
-    cpu: [loong64]
-    os: [linux]
-    libc: [glibc]
-
   '@rollup/rollup-linux-loong64-gnu@4.57.1':
     resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==}
     cpu: [loong64]
@@ -5431,12 +5371,6 @@ packages:
     os: [linux]
     libc: [musl]
 
-  '@rollup/rollup-linux-ppc64-gnu@4.53.3':
-    resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==}
-    cpu: [ppc64]
-    os: [linux]
-    libc: [glibc]
-
   '@rollup/rollup-linux-ppc64-gnu@4.57.1':
     resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==}
     cpu: [ppc64]
@@ -5461,12 +5395,6 @@ packages:
     os: [linux]
     libc: [musl]
 
-  '@rollup/rollup-linux-riscv64-gnu@4.53.3':
-    resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==}
-    cpu: [riscv64]
-    os: [linux]
-    libc: [glibc]
-
   '@rollup/rollup-linux-riscv64-gnu@4.57.1':
     resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==}
     cpu: [riscv64]
@@ -5479,12 +5407,6 @@ packages:
     os: [linux]
     libc: [glibc]
 
-  '@rollup/rollup-linux-riscv64-musl@4.53.3':
-    resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==}
-    cpu: [riscv64]
-    os: [linux]
-    libc: [musl]
-
   '@rollup/rollup-linux-riscv64-musl@4.57.1':
     resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==}
     cpu: [riscv64]
@@ -5497,12 +5419,6 @@ packages:
     os: [linux]
     libc: [musl]
 
-  '@rollup/rollup-linux-s390x-gnu@4.53.3':
-    resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==}
-    cpu: [s390x]
-    os: [linux]
-    libc: [glibc]
-
   '@rollup/rollup-linux-s390x-gnu@4.57.1':
     resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==}
     cpu: [s390x]
@@ -5515,12 +5431,6 @@ packages:
     os: [linux]
     libc: [glibc]
 
-  '@rollup/rollup-linux-x64-gnu@4.53.3':
-    resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==}
-    cpu: [x64]
-    os: [linux]
-    libc: [glibc]
-
   '@rollup/rollup-linux-x64-gnu@4.57.1':
     resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==}
     cpu: [x64]
@@ -5533,12 +5443,6 @@ packages:
     os: [linux]
     libc: [glibc]
 
-  '@rollup/rollup-linux-x64-musl@4.53.3':
-    resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==}
-    cpu: [x64]
-    os: [linux]
-    libc: [musl]
-
   '@rollup/rollup-linux-x64-musl@4.57.1':
     resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==}
     cpu: [x64]
@@ -5561,11 +5465,6 @@ packages:
     cpu: [x64]
     os: [openbsd]
 
-  '@rollup/rollup-openharmony-arm64@4.53.3':
-    resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==}
-    cpu: [arm64]
-    os: [openharmony]
-
   '@rollup/rollup-openharmony-arm64@4.57.1':
     resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==}
     cpu: [arm64]
@@ -5576,11 +5475,6 @@ packages:
     cpu: [arm64]
     os: [openharmony]
 
-  '@rollup/rollup-win32-arm64-msvc@4.53.3':
-    resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==}
-    cpu: [arm64]
-    os: [win32]
-
   '@rollup/rollup-win32-arm64-msvc@4.57.1':
     resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==}
     cpu: [arm64]
@@ -5591,11 +5485,6 @@ packages:
     cpu: [arm64]
     os: [win32]
 
-  '@rollup/rollup-win32-ia32-msvc@4.53.3':
-    resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==}
-    cpu: [ia32]
-    os: [win32]
-
   '@rollup/rollup-win32-ia32-msvc@4.57.1':
     resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==}
     cpu: [ia32]
@@ -5606,11 +5495,6 @@ packages:
     cpu: [ia32]
     os: [win32]
 
-  '@rollup/rollup-win32-x64-gnu@4.53.3':
-    resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==}
-    cpu: [x64]
-    os: [win32]
-
   '@rollup/rollup-win32-x64-gnu@4.57.1':
     resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==}
     cpu: [x64]
@@ -5621,11 +5505,6 @@ packages:
     cpu: [x64]
     os: [win32]
 
-  '@rollup/rollup-win32-x64-msvc@4.53.3':
-    resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==}
-    cpu: [x64]
-    os: [win32]
-
   '@rollup/rollup-win32-x64-msvc@4.57.1':
     resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==}
     cpu: [x64]
@@ -10714,11 +10593,6 @@ packages:
       rollup:
         optional: true
 
-  rollup@4.53.3:
-    resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==}
-    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
-    hasBin: true
-
   rollup@4.57.1:
     resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==}
     engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -11914,8 +11788,8 @@ packages:
       vite:
         optional: true
 
-  vite@6.4.1:
-    resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==}
+  vite@6.4.2:
+    resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==}
     engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
     hasBin: true
     peerDependencies:
@@ -11954,8 +11828,8 @@ packages:
       yaml:
         optional: true
 
-  vite@7.2.7:
-    resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==}
+  vite@7.3.1:
+    resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
     engines: {node: ^20.19.0 || >=22.12.0}
     hasBin: true
     peerDependencies:
@@ -11994,8 +11868,8 @@ packages:
       yaml:
         optional: true
 
-  vite@7.3.1:
-    resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
+  vite@7.3.3:
+    resolution: {integrity: sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==}
     engines: {node: ^20.19.0 || >=22.12.0}
     hasBin: true
     peerDependencies:
@@ -12963,9 +12837,9 @@ snapshots:
 
   '@cloudflare/workers-types@4.20260317.1': {}
 
-  '@copilotkit/aimock@1.18.0(vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))':
+  '@copilotkit/aimock@1.18.0(vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))':
     optionalDependencies:
-      vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
 
   '@crazydos/vue-markdown@1.1.4(vue@3.5.25(typescript@5.9.3))':
     dependencies:
@@ -15130,17 +15004,17 @@ snapshots:
 
   '@rolldown/pluginutils@1.0.0-rc.17': {}
 
-  '@rollup/plugin-alias@5.1.1(rollup@4.57.1)':
+  '@rollup/plugin-alias@5.1.1(rollup@4.60.1)':
     optionalDependencies:
-      rollup: 4.57.1
+      rollup: 4.60.1
 
   '@rollup/plugin-alias@6.0.0(rollup@4.57.1)':
     optionalDependencies:
       rollup: 4.57.1
 
-  '@rollup/plugin-commonjs@28.0.9(rollup@4.57.1)':
+  '@rollup/plugin-commonjs@28.0.9(rollup@4.60.1)':
     dependencies:
-      '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+      '@rollup/pluginutils': 5.3.0(rollup@4.60.1)
       commondir: 1.0.1
       estree-walker: 2.0.2
       fdir: 6.5.0(picomatch@4.0.4)
@@ -15148,7 +15022,7 @@ snapshots:
       magic-string: 0.30.21
       picomatch: 4.0.4
     optionalDependencies:
-      rollup: 4.57.1
+      rollup: 4.60.1
 
   '@rollup/plugin-commonjs@29.0.0(rollup@4.57.1)':
     dependencies:
@@ -15170,12 +15044,26 @@ snapshots:
     optionalDependencies:
       rollup: 4.57.1
 
+  '@rollup/plugin-inject@5.0.5(rollup@4.60.1)':
+    dependencies:
+      '@rollup/pluginutils': 5.3.0(rollup@4.60.1)
+      estree-walker: 2.0.2
+      magic-string: 0.30.21
+    optionalDependencies:
+      rollup: 4.60.1
+
   '@rollup/plugin-json@6.1.0(rollup@4.57.1)':
     dependencies:
       '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
     optionalDependencies:
       rollup: 4.57.1
 
+  '@rollup/plugin-json@6.1.0(rollup@4.60.1)':
+    dependencies:
+      '@rollup/pluginutils': 5.3.0(rollup@4.60.1)
+    optionalDependencies:
+      rollup: 4.60.1
+
   '@rollup/plugin-node-resolve@16.0.3(rollup@4.57.1)':
     dependencies:
       '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
@@ -15186,6 +15074,16 @@ snapshots:
     optionalDependencies:
       rollup: 4.57.1
 
+  '@rollup/plugin-node-resolve@16.0.3(rollup@4.60.1)':
+    dependencies:
+      '@rollup/pluginutils': 5.3.0(rollup@4.60.1)
+      '@types/resolve': 1.20.2
+      deepmerge: 4.3.1
+      is-module: 1.0.0
+      resolve: 1.22.11
+    optionalDependencies:
+      rollup: 4.60.1
+
   '@rollup/plugin-replace@6.0.3(rollup@4.57.1)':
     dependencies:
       '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
@@ -15193,6 +15091,13 @@ snapshots:
     optionalDependencies:
       rollup: 4.57.1
 
+  '@rollup/plugin-replace@6.0.3(rollup@4.60.1)':
+    dependencies:
+      '@rollup/pluginutils': 5.3.0(rollup@4.60.1)
+      magic-string: 0.30.21
+    optionalDependencies:
+      rollup: 4.60.1
+
   '@rollup/plugin-terser@0.4.4(rollup@4.57.1)':
     dependencies:
       serialize-javascript: 6.0.2
@@ -15201,6 +15106,14 @@ snapshots:
     optionalDependencies:
       rollup: 4.57.1
 
+  '@rollup/plugin-terser@0.4.4(rollup@4.60.1)':
+    dependencies:
+      serialize-javascript: 6.0.2
+      smob: 1.5.0
+      terser: 5.44.1
+    optionalDependencies:
+      rollup: 4.60.1
+
   '@rollup/pluginutils@5.3.0(rollup@4.57.1)':
     dependencies:
       '@types/estree': 1.0.8
@@ -15217,99 +15130,66 @@ snapshots:
     optionalDependencies:
       rollup: 4.60.1
 
-  '@rollup/rollup-android-arm-eabi@4.53.3':
-    optional: true
-
   '@rollup/rollup-android-arm-eabi@4.57.1':
     optional: true
 
   '@rollup/rollup-android-arm-eabi@4.60.1':
     optional: true
 
-  '@rollup/rollup-android-arm64@4.53.3':
-    optional: true
-
   '@rollup/rollup-android-arm64@4.57.1':
     optional: true
 
   '@rollup/rollup-android-arm64@4.60.1':
     optional: true
 
-  '@rollup/rollup-darwin-arm64@4.53.3':
-    optional: true
-
   '@rollup/rollup-darwin-arm64@4.57.1':
     optional: true
 
   '@rollup/rollup-darwin-arm64@4.60.1':
     optional: true
 
-  '@rollup/rollup-darwin-x64@4.53.3':
-    optional: true
-
   '@rollup/rollup-darwin-x64@4.57.1':
     optional: true
 
   '@rollup/rollup-darwin-x64@4.60.1':
     optional: true
 
-  '@rollup/rollup-freebsd-arm64@4.53.3':
-    optional: true
-
   '@rollup/rollup-freebsd-arm64@4.57.1':
     optional: true
 
   '@rollup/rollup-freebsd-arm64@4.60.1':
     optional: true
 
-  '@rollup/rollup-freebsd-x64@4.53.3':
-    optional: true
-
   '@rollup/rollup-freebsd-x64@4.57.1':
     optional: true
 
   '@rollup/rollup-freebsd-x64@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-arm-gnueabihf@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
     optional: true
 
   '@rollup/rollup-linux-arm-gnueabihf@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-arm-musleabihf@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-arm-musleabihf@4.57.1':
     optional: true
 
   '@rollup/rollup-linux-arm-musleabihf@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-arm64-gnu@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-arm64-gnu@4.57.1':
     optional: true
 
   '@rollup/rollup-linux-arm64-gnu@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-arm64-musl@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-arm64-musl@4.57.1':
     optional: true
 
   '@rollup/rollup-linux-arm64-musl@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-loong64-gnu@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-loong64-gnu@4.57.1':
     optional: true
 
@@ -15322,9 +15202,6 @@ snapshots:
   '@rollup/rollup-linux-loong64-musl@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-ppc64-gnu@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-ppc64-gnu@4.57.1':
     optional: true
 
@@ -15337,45 +15214,30 @@ snapshots:
   '@rollup/rollup-linux-ppc64-musl@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-riscv64-gnu@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-riscv64-gnu@4.57.1':
     optional: true
 
   '@rollup/rollup-linux-riscv64-gnu@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-riscv64-musl@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-riscv64-musl@4.57.1':
     optional: true
 
   '@rollup/rollup-linux-riscv64-musl@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-s390x-gnu@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-s390x-gnu@4.57.1':
     optional: true
 
   '@rollup/rollup-linux-s390x-gnu@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-x64-gnu@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-x64-gnu@4.57.1':
     optional: true
 
   '@rollup/rollup-linux-x64-gnu@4.60.1':
     optional: true
 
-  '@rollup/rollup-linux-x64-musl@4.53.3':
-    optional: true
-
   '@rollup/rollup-linux-x64-musl@4.57.1':
     optional: true
 
@@ -15388,45 +15250,30 @@ snapshots:
   '@rollup/rollup-openbsd-x64@4.60.1':
     optional: true
 
-  '@rollup/rollup-openharmony-arm64@4.53.3':
-    optional: true
-
   '@rollup/rollup-openharmony-arm64@4.57.1':
     optional: true
 
   '@rollup/rollup-openharmony-arm64@4.60.1':
     optional: true
 
-  '@rollup/rollup-win32-arm64-msvc@4.53.3':
-    optional: true
-
   '@rollup/rollup-win32-arm64-msvc@4.57.1':
     optional: true
 
   '@rollup/rollup-win32-arm64-msvc@4.60.1':
     optional: true
 
-  '@rollup/rollup-win32-ia32-msvc@4.53.3':
-    optional: true
-
   '@rollup/rollup-win32-ia32-msvc@4.57.1':
     optional: true
 
   '@rollup/rollup-win32-ia32-msvc@4.60.1':
     optional: true
 
-  '@rollup/rollup-win32-x64-gnu@4.53.3':
-    optional: true
-
   '@rollup/rollup-win32-x64-gnu@4.57.1':
     optional: true
 
   '@rollup/rollup-win32-x64-gnu@4.60.1':
     optional: true
 
-  '@rollup/rollup-win32-x64-msvc@4.53.3':
-    optional: true
-
   '@rollup/rollup-win32-x64-msvc@4.57.1':
     optional: true
 
@@ -15621,16 +15468,16 @@ snapshots:
     dependencies:
       acorn: 8.15.0
 
-  '@sveltejs/adapter-auto@3.3.1(@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))':
+  '@sveltejs/adapter-auto@3.3.1(@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))':
     dependencies:
-      '@sveltejs/kit': 2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@sveltejs/kit': 2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       import-meta-resolve: 4.2.0
 
-  '@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@sveltejs/kit@2.49.2(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@standard-schema/spec': 1.0.0
       '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0)
-      '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@types/cookie': 0.6.0
       acorn: 8.15.0
       cookie: 0.6.0
@@ -15643,7 +15490,7 @@ snapshots:
       set-cookie-parser: 2.7.2
       sirv: 3.0.2
       svelte: 5.45.10
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     optionalDependencies:
       '@opentelemetry/api': 1.9.1
 
@@ -15658,25 +15505,25 @@ snapshots:
     transitivePeerDependencies:
       - typescript
 
-  '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
-      '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       debug: 4.4.3
       svelte: 5.45.10
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - supports-color
 
-  '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
-      '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.45.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       debug: 4.4.3
       deepmerge: 4.3.1
       kleur: 4.1.5
       magic-string: 0.30.21
       svelte: 5.45.10
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vitefu: 1.1.1(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vitefu: 1.1.1(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
     transitivePeerDependencies:
       - supports-color
 
@@ -15750,19 +15597,12 @@ snapshots:
       '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
       '@tailwindcss/oxide-win32-x64-msvc': 4.1.18
 
-  '@tailwindcss/vite@4.1.18(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
-    dependencies:
-      '@tailwindcss/node': 4.1.18
-      '@tailwindcss/oxide': 4.1.18
-      tailwindcss: 4.1.18
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-
-  '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tailwindcss/vite@4.1.18(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@tailwindcss/node': 4.1.18
       '@tailwindcss/oxide': 4.1.18
       tailwindcss: 4.1.18
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   '@tanstack/db-ivm@0.1.18(typescript@5.9.3)':
     dependencies:
@@ -15843,25 +15683,7 @@ snapshots:
       solid-js: 1.9.10
       vue: 3.5.25(typescript@5.9.3)
 
-  '@tanstack/devtools-vite@0.5.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
-    dependencies:
-      '@babel/core': 7.28.5
-      '@babel/generator': 7.28.5
-      '@babel/parser': 7.29.0
-      '@babel/traverse': 7.28.5
-      '@babel/types': 7.29.0
-      '@tanstack/devtools-client': 0.0.6
-      '@tanstack/devtools-event-bus': 0.4.1
-      chalk: 5.6.2
-      launch-editor: 2.12.0
-      picomatch: 4.0.3
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-    transitivePeerDependencies:
-      - bufferutil
-      - supports-color
-      - utf-8-validate
-
-  '@tanstack/devtools-vite@0.5.3(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/devtools-vite@0.5.3(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/core': 7.28.5
       '@babel/generator': 7.28.5
@@ -15873,7 +15695,7 @@ snapshots:
       chalk: 5.6.2
       launch-editor: 2.12.0
       picomatch: 4.0.3
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - bufferutil
       - supports-color
@@ -15911,7 +15733,7 @@ snapshots:
       - csstype
       - utf-8-validate
 
-  '@tanstack/directive-functions-plugin@1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/directive-functions-plugin@1.131.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/code-frame': 7.27.1
       '@babel/core': 7.28.5
@@ -15920,11 +15742,11 @@ snapshots:
       '@tanstack/router-utils': 1.131.2
       babel-dead-code-elimination: 1.0.10
       tiny-invariant: 1.3.3
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - supports-color
 
-  '@tanstack/directive-functions-plugin@1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/directive-functions-plugin@1.141.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/code-frame': 7.27.1
       '@babel/core': 7.28.5
@@ -15934,7 +15756,7 @@ snapshots:
       babel-dead-code-elimination: 1.0.10
       pathe: 2.0.3
       tiny-invariant: 1.3.3
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - supports-color
 
@@ -15960,47 +15782,11 @@ snapshots:
 
   '@tanstack/history@1.154.14': {}
 
-  '@tanstack/nitro-v2-vite-plugin@1.154.7(rolldown@1.0.0-rc.17)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/nitro-v2-vite-plugin@1.154.7(rolldown@1.0.0-rc.17)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       nitropack: 2.13.1(rolldown@1.0.0-rc.17)
       pathe: 2.0.3
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-    transitivePeerDependencies:
-      - '@azure/app-configuration'
-      - '@azure/cosmos'
-      - '@azure/data-tables'
-      - '@azure/identity'
-      - '@azure/keyvault-secrets'
-      - '@azure/storage-blob'
-      - '@capacitor/preferences'
-      - '@deno/kv'
-      - '@electric-sql/pglite'
-      - '@libsql/client'
-      - '@netlify/blobs'
-      - '@planetscale/database'
-      - '@upstash/redis'
-      - '@vercel/blob'
-      - '@vercel/functions'
-      - '@vercel/kv'
-      - aws4fetch
-      - bare-abort-controller
-      - better-sqlite3
-      - drizzle-orm
-      - encoding
-      - idb-keyval
-      - mysql2
-      - react-native-b4a
-      - rolldown
-      - sqlite3
-      - supports-color
-      - uploadthing
-      - xml2js
-
-  '@tanstack/nitro-v2-vite-plugin@1.154.7(rolldown@1.0.0-rc.17)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
-    dependencies:
-      nitropack: 2.13.1(rolldown@1.0.0-rc.17)
-      pathe: 2.0.3
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - '@azure/app-configuration'
       - '@azure/cosmos'
@@ -16133,12 +15919,12 @@ snapshots:
       tiny-invariant: 1.3.3
       tiny-warning: 1.0.3
 
-  '@tanstack/react-start-plugin@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-rc.17)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/react-start-plugin@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-rc.17)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
-      '@tanstack/start-plugin-core': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-rc.17)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-      '@vitejs/plugin-react': 4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/start-plugin-core': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-rc.17)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@vitejs/plugin-react': 4.7.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       pathe: 2.0.3
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       zod: 3.25.76
     transitivePeerDependencies:
       - '@azure/app-configuration'
@@ -16261,39 +16047,19 @@ snapshots:
     transitivePeerDependencies:
       - crossws
 
-  '@tanstack/react-start@1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/react-start@1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start-client': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start-server': 1.159.5(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/router-utils': 1.158.0
       '@tanstack/start-client-core': 1.159.4
-      '@tanstack/start-plugin-core': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.10.1))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/start-plugin-core': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.10.1))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.10.1))
       pathe: 2.0.3
       react: 19.2.3
       react-dom: 19.2.3(react@19.2.3)
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-    transitivePeerDependencies:
-      - '@rsbuild/core'
-      - crossws
-      - supports-color
-      - vite-plugin-solid
-      - webpack
-
-  '@tanstack/react-start@1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
-    dependencies:
-      '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      '@tanstack/react-start-client': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      '@tanstack/react-start-server': 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      '@tanstack/router-utils': 1.158.0
-      '@tanstack/start-client-core': 1.159.4
-      '@tanstack/start-plugin-core': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-      '@tanstack/start-server-core': 1.159.4(crossws@0.4.5(srvx@0.11.15))
-      pathe: 2.0.3
-      react: 19.2.3
-      react-dom: 19.2.3(react@19.2.3)
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - '@rsbuild/core'
       - crossws
@@ -16301,19 +16067,19 @@ snapshots:
       - vite-plugin-solid
       - webpack
 
-  '@tanstack/react-start@1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/react-start@1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start-client': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start-server': 1.159.5(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/router-utils': 1.158.0
       '@tanstack/start-client-core': 1.159.4
-      '@tanstack/start-plugin-core': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/start-plugin-core': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start-server-core': 1.159.4(crossws@0.4.5(srvx@0.11.15))
       pathe: 2.0.3
       react: 19.2.3
       react-dom: 19.2.3(react@19.2.3)
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - '@rsbuild/core'
       - crossws
@@ -16426,7 +16192,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@tanstack/router-plugin@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/router-plugin@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/core': 7.28.5
       '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
@@ -16444,12 +16210,12 @@ snapshots:
       zod: 3.25.76
     optionalDependencies:
       '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
     transitivePeerDependencies:
       - supports-color
 
-  '@tanstack/router-plugin@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/router-plugin@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/core': 7.28.5
       '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
@@ -16467,12 +16233,12 @@ snapshots:
       zod: 3.25.76
     optionalDependencies:
       '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
     transitivePeerDependencies:
       - supports-color
 
-  '@tanstack/router-plugin@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/router-plugin@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/core': 7.28.5
       '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
@@ -16489,30 +16255,8 @@ snapshots:
       zod: 3.25.76
     optionalDependencies:
       '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-    transitivePeerDependencies:
-      - supports-color
-
-  '@tanstack/router-plugin@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
-    dependencies:
-      '@babel/core': 7.28.5
-      '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
-      '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
-      '@babel/template': 7.27.2
-      '@babel/traverse': 7.28.5
-      '@babel/types': 7.29.0
-      '@tanstack/router-core': 1.159.4
-      '@tanstack/router-generator': 1.159.4
-      '@tanstack/router-utils': 1.158.0
-      '@tanstack/virtual-file-routes': 1.154.7
-      chokidar: 3.6.0
-      unplugin: 2.3.11
-      zod: 3.25.76
-    optionalDependencies:
-      '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite-plugin-solid: 2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
     transitivePeerDependencies:
       - supports-color
 
@@ -16564,7 +16308,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@tanstack/server-functions-plugin@1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/server-functions-plugin@1.131.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/code-frame': 7.27.1
       '@babel/core': 7.28.5
@@ -16573,14 +16317,14 @@ snapshots:
       '@babel/template': 7.27.2
       '@babel/traverse': 7.28.5
       '@babel/types': 7.29.0
-      '@tanstack/directive-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/directive-functions-plugin': 1.131.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       babel-dead-code-elimination: 1.0.10
       tiny-invariant: 1.3.3
     transitivePeerDependencies:
       - supports-color
       - vite
 
-  '@tanstack/server-functions-plugin@1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/server-functions-plugin@1.141.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/code-frame': 7.27.1
       '@babel/core': 7.28.5
@@ -16589,7 +16333,7 @@ snapshots:
       '@babel/template': 7.27.2
       '@babel/traverse': 7.28.5
       '@babel/types': 7.29.0
-      '@tanstack/directive-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/directive-functions-plugin': 1.141.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       babel-dead-code-elimination: 1.0.10
       tiny-invariant: 1.3.3
     transitivePeerDependencies:
@@ -16668,17 +16412,17 @@ snapshots:
     transitivePeerDependencies:
       - crossws
 
-  '@tanstack/solid-start@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/solid-start@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(solid-js@1.9.10)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@tanstack/solid-router': 1.141.1(solid-js@1.9.10)
       '@tanstack/solid-start-client': 1.141.1(solid-js@1.9.10)
       '@tanstack/solid-start-server': 1.141.1(crossws@0.4.5(srvx@0.11.15))(solid-js@1.9.10)
       '@tanstack/start-client-core': 1.141.1
-      '@tanstack/start-plugin-core': 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/start-plugin-core': 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start-server-core': 1.141.1(crossws@0.4.5(srvx@0.11.15))
       pathe: 2.0.3
       solid-js: 1.9.10
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - '@rsbuild/core'
       - '@tanstack/react-router'
@@ -16768,22 +16512,22 @@ snapshots:
       tiny-invariant: 1.3.3
       tiny-warning: 1.0.3
 
-  '@tanstack/start-config@1.120.20(@types/node@24.10.3)(crossws@0.4.5(srvx@0.11.15))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
+  '@tanstack/start-config@1.120.20(@types/node@24.10.3)(crossws@0.4.5(srvx@0.11.15))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
     dependencies:
       '@tanstack/react-router': 1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      '@tanstack/react-start-plugin': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-rc.17)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/react-start-plugin': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@vitejs/plugin-react@4.7.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rolldown@1.0.0-rc.17)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-generator': 1.141.1
-      '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-      '@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/server-functions-plugin': 1.141.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start-server-functions-handler': 1.120.19(crossws@0.4.5(srvx@0.11.15))
-      '@vitejs/plugin-react': 4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@vitejs/plugin-react': 4.7.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       import-meta-resolve: 4.2.0
       nitropack: 2.12.9(rolldown@1.0.0-rc.17)
       ofetch: 1.5.1
       react: 19.2.3
       react-dom: 19.2.3(react@19.2.3)
       vinxi: 0.5.3(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       zod: 3.25.76
     transitivePeerDependencies:
       - '@azure/app-configuration'
@@ -16836,16 +16580,16 @@ snapshots:
 
   '@tanstack/start-fn-stubs@1.154.7': {}
 
-  '@tanstack/start-plugin-core@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-rc.17)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/start-plugin-core@1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(rolldown@1.0.0-rc.17)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/code-frame': 7.26.2
       '@babel/core': 7.28.5
       '@babel/types': 7.29.0
       '@tanstack/router-core': 1.131.50
       '@tanstack/router-generator': 1.131.50
-      '@tanstack/router-plugin': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/router-plugin': 1.131.50(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-utils': 1.131.2
-      '@tanstack/server-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/server-functions-plugin': 1.131.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start-server-core': 1.131.50
       '@types/babel__code-frame': 7.0.6
       '@types/babel__core': 7.20.5
@@ -16855,8 +16599,8 @@ snapshots:
       nitropack: 2.12.9(rolldown@1.0.0-rc.17)
       pathe: 2.0.3
       ufo: 1.6.1
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vitefu: 1.1.1(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vitefu: 1.1.1(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       xmlbuilder2: 3.1.1
       zod: 3.25.76
     transitivePeerDependencies:
@@ -16894,7 +16638,7 @@ snapshots:
       - webpack
       - xml2js
 
-  '@tanstack/start-plugin-core@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/start-plugin-core@1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/code-frame': 7.26.2
       '@babel/core': 7.28.5
@@ -16902,9 +16646,9 @@ snapshots:
       '@rolldown/pluginutils': 1.0.0-beta.40
       '@tanstack/router-core': 1.141.1
       '@tanstack/router-generator': 1.141.1
-      '@tanstack/router-plugin': 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/router-plugin': 1.141.1(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-utils': 1.141.0
-      '@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/server-functions-plugin': 1.141.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start-client-core': 1.141.1
       '@tanstack/start-server-core': 1.141.1(crossws@0.4.5(srvx@0.11.15))
       babel-dead-code-elimination: 1.0.10
@@ -16914,8 +16658,8 @@ snapshots:
       srvx: 0.8.16
       tinyglobby: 0.2.16
       ufo: 1.6.1
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vitefu: 1.1.1(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vitefu: 1.1.1(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       xmlbuilder2: 4.0.3
       zod: 3.25.76
     transitivePeerDependencies:
@@ -16926,7 +16670,7 @@ snapshots:
       - vite-plugin-solid
       - webpack
 
-  '@tanstack/start-plugin-core@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.10.1))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/start-plugin-core@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.4(srvx@0.10.1))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/code-frame': 7.27.1
       '@babel/core': 7.28.5
@@ -16934,7 +16678,7 @@ snapshots:
       '@rolldown/pluginutils': 1.0.0-beta.40
       '@tanstack/router-core': 1.159.4
       '@tanstack/router-generator': 1.159.4
-      '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-utils': 1.158.0
       '@tanstack/start-client-core': 1.159.4
       '@tanstack/start-server-core': 1.159.4(crossws@0.4.4(srvx@0.10.1))
@@ -16944,38 +16688,8 @@ snapshots:
       srvx: 0.11.2
       tinyglobby: 0.2.16
       ufo: 1.6.3
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-      xmlbuilder2: 4.0.3
-      zod: 3.25.76
-    transitivePeerDependencies:
-      - '@rsbuild/core'
-      - '@tanstack/react-router'
-      - crossws
-      - supports-color
-      - vite-plugin-solid
-      - webpack
-
-  '@tanstack/start-plugin-core@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
-    dependencies:
-      '@babel/code-frame': 7.27.1
-      '@babel/core': 7.28.5
-      '@babel/types': 7.29.0
-      '@rolldown/pluginutils': 1.0.0-beta.40
-      '@tanstack/router-core': 1.159.4
-      '@tanstack/router-generator': 1.159.4
-      '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-      '@tanstack/router-utils': 1.158.0
-      '@tanstack/start-client-core': 1.159.4
-      '@tanstack/start-server-core': 1.159.4(crossws@0.4.5(srvx@0.11.15))
-      cheerio: 1.1.2
-      exsolve: 1.0.8
-      pathe: 2.0.3
-      srvx: 0.11.2
-      tinyglobby: 0.2.16
-      ufo: 1.6.3
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vitefu: 1.1.1(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vitefu: 1.1.1(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       xmlbuilder2: 4.0.3
       zod: 3.25.76
     transitivePeerDependencies:
@@ -16986,7 +16700,7 @@ snapshots:
       - vite-plugin-solid
       - webpack
 
-  '@tanstack/start-plugin-core@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/start-plugin-core@1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(crossws@0.4.5(srvx@0.11.15))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/code-frame': 7.27.1
       '@babel/core': 7.28.5
@@ -16994,7 +16708,7 @@ snapshots:
       '@rolldown/pluginutils': 1.0.0-beta.40
       '@tanstack/router-core': 1.159.4
       '@tanstack/router-generator': 1.159.4
-      '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/router-plugin': 1.159.5(@tanstack/react-router@1.159.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/router-utils': 1.158.0
       '@tanstack/start-client-core': 1.159.4
       '@tanstack/start-server-core': 1.159.4(crossws@0.4.5(srvx@0.11.15))
@@ -17004,8 +16718,8 @@ snapshots:
       srvx: 0.11.2
       tinyglobby: 0.2.16
       ufo: 1.6.3
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vitefu: 1.1.1(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       xmlbuilder2: 4.0.3
       zod: 3.25.76
     transitivePeerDependencies:
@@ -17064,9 +16778,9 @@ snapshots:
     transitivePeerDependencies:
       - crossws
 
-  '@tanstack/start-server-functions-client@1.131.50(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/start-server-functions-client@1.131.50(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
-      '@tanstack/server-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/server-functions-plugin': 1.131.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start-server-functions-fetcher': 1.131.50
     transitivePeerDependencies:
       - supports-color
@@ -17086,17 +16800,17 @@ snapshots:
     transitivePeerDependencies:
       - crossws
 
-  '@tanstack/start-server-functions-server@1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/start-server-functions-server@1.131.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
-      '@tanstack/server-functions-plugin': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/server-functions-plugin': 1.131.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       tiny-invariant: 1.3.3
     transitivePeerDependencies:
       - supports-color
       - vite
 
-  '@tanstack/start-server-functions-ssr@1.120.19(crossws@0.4.5(srvx@0.11.15))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/start-server-functions-ssr@1.120.19(crossws@0.4.5(srvx@0.11.15))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
-      '@tanstack/server-functions-plugin': 1.141.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/server-functions-plugin': 1.141.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start-client-core': 1.141.1
       '@tanstack/start-server-core': 1.141.1(crossws@0.4.5(srvx@0.11.15))
       '@tanstack/start-server-functions-fetcher': 1.131.50
@@ -17118,17 +16832,17 @@ snapshots:
     dependencies:
       '@tanstack/router-core': 1.159.4
 
-  '@tanstack/start@1.120.20(@types/node@24.10.3)(crossws@0.4.5(srvx@0.11.15))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
+  '@tanstack/start@1.120.20(@types/node@24.10.3)(crossws@0.4.5(srvx@0.11.15))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)':
     dependencies:
       '@tanstack/react-start-client': 1.141.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/react-start-router-manifest': 1.120.19(@types/node@24.10.3)(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       '@tanstack/react-start-server': 1.141.1(crossws@0.4.5(srvx@0.11.15))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
       '@tanstack/start-api-routes': 1.120.19(@types/node@24.10.3)(crossws@0.4.5(srvx@0.11.15))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      '@tanstack/start-config': 1.120.20(@types/node@24.10.3)(crossws@0.4.5(srvx@0.11.15))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
-      '@tanstack/start-server-functions-client': 1.131.50(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/start-config': 1.120.20(@types/node@24.10.3)(crossws@0.4.5(srvx@0.11.15))(db0@0.3.4)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rolldown@1.0.0-rc.17)(terser@5.44.1)(tsx@4.21.0)(vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)
+      '@tanstack/start-server-functions-client': 1.131.50(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@tanstack/start-server-functions-handler': 1.120.19(crossws@0.4.5(srvx@0.11.15))
-      '@tanstack/start-server-functions-server': 1.131.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-      '@tanstack/start-server-functions-ssr': 1.120.19(crossws@0.4.5(srvx@0.11.15))(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/start-server-functions-server': 1.131.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@tanstack/start-server-functions-ssr': 1.120.19(crossws@0.4.5(srvx@0.11.15))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
     transitivePeerDependencies:
       - '@azure/app-configuration'
       - '@azure/cosmos'
@@ -17199,12 +16913,12 @@ snapshots:
 
   '@tanstack/virtual-file-routes@1.154.7': {}
 
-  '@tanstack/vite-config@0.4.1(@types/node@24.10.3)(rollup@4.60.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@tanstack/vite-config@0.4.1(@types/node@24.10.3)(rollup@4.60.1)(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       rollup-plugin-preserve-directives: 0.4.0(rollup@4.60.1)
-      vite-plugin-dts: 4.2.3(@types/node@24.10.3)(rollup@4.60.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-      vite-plugin-externalize-deps: 0.10.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-      vite-tsconfig-paths: 5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite-plugin-dts: 4.2.3(@types/node@24.10.3)(rollup@4.60.1)(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite-plugin-externalize-deps: 0.10.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite-tsconfig-paths: 5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
     transitivePeerDependencies:
       - '@types/node'
       - rollup
@@ -17560,10 +17274,10 @@ snapshots:
   '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
     optional: true
 
-  '@vercel/nft@0.30.4(rollup@4.57.1)':
+  '@vercel/nft@0.30.4(rollup@4.60.1)':
     dependencies:
       '@mapbox/node-pre-gyp': 2.0.3
-      '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+      '@rollup/pluginutils': 5.3.0(rollup@4.60.1)
       acorn: 8.15.0
       acorn-import-attributes: 1.9.5(acorn@8.15.0)
       async-sema: 3.1.1
@@ -17618,7 +17332,7 @@ snapshots:
       untun: 0.1.3
       uqr: 0.1.2
 
-  '@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@vitejs/plugin-react@4.7.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/core': 7.28.5
       '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
@@ -17626,23 +17340,11 @@ snapshots:
       '@rolldown/pluginutils': 1.0.0-beta.27
       '@types/babel__core': 7.20.5
       react-refresh: 0.17.0
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-    transitivePeerDependencies:
-      - supports-color
-
-  '@vitejs/plugin-react@5.1.2(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
-    dependencies:
-      '@babel/core': 7.28.5
-      '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
-      '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5)
-      '@rolldown/pluginutils': 1.0.0-beta.53
-      '@types/babel__core': 7.20.5
-      react-refresh: 0.18.0
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - supports-color
 
-  '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@vitejs/plugin-react@5.1.2(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@babel/core': 7.28.5
       '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
@@ -17650,14 +17352,14 @@ snapshots:
       '@rolldown/pluginutils': 1.0.0-beta.53
       '@types/babel__core': 7.20.5
       react-refresh: 0.18.0
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - supports-color
 
-  '@vitejs/plugin-vue@6.0.3(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))':
+  '@vitejs/plugin-vue@6.0.3(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))':
     dependencies:
       '@rolldown/pluginutils': 1.0.0-beta.53
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       vue: 3.5.25(typescript@5.9.3)
 
   '@vitest/coverage-v8@4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
@@ -17737,13 +17439,13 @@ snapshots:
     optionalDependencies:
       vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
-  '@vitest/mocker@4.1.4(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
+  '@vitest/mocker@4.1.4(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
     dependencies:
       '@vitest/spy': 4.1.4
       estree-walker: 3.0.3
       magic-string: 0.30.21
     optionalDependencies:
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   '@vitest/pretty-format@4.0.14':
     dependencies:
@@ -17859,7 +17561,7 @@ snapshots:
       '@vue/shared': 3.5.25
       estree-walker: 2.0.2
       magic-string: 0.30.21
-      postcss: 8.5.6
+      postcss: 8.5.9
       source-map-js: 1.2.1
 
   '@vue/compiler-ssr@3.5.25':
@@ -19499,7 +19201,7 @@ snapshots:
     dependencies:
       magic-string: 0.30.21
       mlly: 1.8.0
-      rollup: 4.57.1
+      rollup: 4.60.1
 
   flat-cache@4.0.1:
     dependencies:
@@ -21176,7 +20878,7 @@ snapshots:
 
   nf3@0.3.16: {}
 
-  nitro@3.0.1-alpha.2(chokidar@5.0.0)(ioredis@5.9.2)(lru-cache@11.2.4)(rolldown@1.0.0-rc.17)(rollup@4.60.1)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+  nitro@3.0.1-alpha.2(chokidar@5.0.0)(ioredis@5.9.2)(lru-cache@11.2.4)(rolldown@1.0.0-rc.17)(rollup@4.60.1)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
     dependencies:
       consola: 3.4.2
       crossws: 0.4.4(srvx@0.10.1)
@@ -21195,7 +20897,7 @@ snapshots:
     optionalDependencies:
       rolldown: 1.0.0-rc.17
       rollup: 4.60.1
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - '@azure/app-configuration'
       - '@azure/cosmos'
@@ -21225,7 +20927,7 @@ snapshots:
       - sqlite3
       - uploadthing
 
-  nitro@3.0.260429-beta(chokidar@5.0.0)(dotenv@17.2.3)(giget@2.0.0)(jiti@2.6.1)(miniflare@4.20260504.0)(rollup@4.60.1)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+  nitro@3.0.260429-beta(chokidar@5.0.0)(dotenv@17.2.3)(giget@2.0.0)(jiti@2.6.1)(miniflare@4.20260504.0)(rollup@4.60.1)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
     dependencies:
       consola: 3.4.2
       crossws: 0.4.5(srvx@0.11.15)
@@ -21246,7 +20948,7 @@ snapshots:
       giget: 2.0.0
       jiti: 2.6.1
       rollup: 4.60.1
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - '@azure/app-configuration'
       - '@azure/cosmos'
@@ -21281,14 +20983,14 @@ snapshots:
   nitropack@2.12.9(rolldown@1.0.0-rc.17):
     dependencies:
       '@cloudflare/kv-asset-handler': 0.4.2
-      '@rollup/plugin-alias': 5.1.1(rollup@4.57.1)
-      '@rollup/plugin-commonjs': 28.0.9(rollup@4.57.1)
-      '@rollup/plugin-inject': 5.0.5(rollup@4.57.1)
-      '@rollup/plugin-json': 6.1.0(rollup@4.57.1)
-      '@rollup/plugin-node-resolve': 16.0.3(rollup@4.57.1)
-      '@rollup/plugin-replace': 6.0.3(rollup@4.57.1)
-      '@rollup/plugin-terser': 0.4.4(rollup@4.57.1)
-      '@vercel/nft': 0.30.4(rollup@4.57.1)
+      '@rollup/plugin-alias': 5.1.1(rollup@4.60.1)
+      '@rollup/plugin-commonjs': 28.0.9(rollup@4.60.1)
+      '@rollup/plugin-inject': 5.0.5(rollup@4.60.1)
+      '@rollup/plugin-json': 6.1.0(rollup@4.60.1)
+      '@rollup/plugin-node-resolve': 16.0.3(rollup@4.60.1)
+      '@rollup/plugin-replace': 6.0.3(rollup@4.60.1)
+      '@rollup/plugin-terser': 0.4.4(rollup@4.60.1)
+      '@vercel/nft': 0.30.4(rollup@4.60.1)
       archiver: 7.0.1
       c12: 3.3.2(magicast@0.5.2)
       chokidar: 4.0.3
@@ -21330,8 +21032,8 @@ snapshots:
       pkg-types: 2.3.0
       pretty-bytes: 7.1.0
       radix3: 1.1.2
-      rollup: 4.57.1
-      rollup-plugin-visualizer: 6.0.5(rolldown@1.0.0-rc.17)(rollup@4.57.1)
+      rollup: 4.60.1
+      rollup-plugin-visualizer: 6.0.5(rolldown@1.0.0-rc.17)(rollup@4.60.1)
       scule: 1.3.0
       semver: 7.7.4
       serve-placeholder: 2.0.2
@@ -22521,33 +22223,15 @@ snapshots:
       rolldown: 1.0.0-rc.17
       rollup: 4.57.1
 
-  rollup@4.53.3:
+  rollup-plugin-visualizer@6.0.5(rolldown@1.0.0-rc.17)(rollup@4.60.1):
     dependencies:
-      '@types/estree': 1.0.8
+      open: 8.4.2
+      picomatch: 4.0.4
+      source-map: 0.7.6
+      yargs: 17.7.2
     optionalDependencies:
-      '@rollup/rollup-android-arm-eabi': 4.53.3
-      '@rollup/rollup-android-arm64': 4.53.3
-      '@rollup/rollup-darwin-arm64': 4.53.3
-      '@rollup/rollup-darwin-x64': 4.53.3
-      '@rollup/rollup-freebsd-arm64': 4.53.3
-      '@rollup/rollup-freebsd-x64': 4.53.3
-      '@rollup/rollup-linux-arm-gnueabihf': 4.53.3
-      '@rollup/rollup-linux-arm-musleabihf': 4.53.3
-      '@rollup/rollup-linux-arm64-gnu': 4.53.3
-      '@rollup/rollup-linux-arm64-musl': 4.53.3
-      '@rollup/rollup-linux-loong64-gnu': 4.53.3
-      '@rollup/rollup-linux-ppc64-gnu': 4.53.3
-      '@rollup/rollup-linux-riscv64-gnu': 4.53.3
-      '@rollup/rollup-linux-riscv64-musl': 4.53.3
-      '@rollup/rollup-linux-s390x-gnu': 4.53.3
-      '@rollup/rollup-linux-x64-gnu': 4.53.3
-      '@rollup/rollup-linux-x64-musl': 4.53.3
-      '@rollup/rollup-openharmony-arm64': 4.53.3
-      '@rollup/rollup-win32-arm64-msvc': 4.53.3
-      '@rollup/rollup-win32-ia32-msvc': 4.53.3
-      '@rollup/rollup-win32-x64-gnu': 4.53.3
-      '@rollup/rollup-win32-x64-msvc': 4.53.3
-      fsevents: 2.3.3
+      rolldown: 1.0.0-rc.17
+      rollup: 4.60.1
 
   rollup@4.57.1:
     dependencies:
@@ -23784,7 +23468,7 @@ snapshots:
       unctx: 2.4.1
       unenv: 1.10.0
       unstorage: 1.17.4(db0@0.3.4)(ioredis@5.8.2)
-      vite: 6.4.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 6.4.2(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       zod: 3.25.76
     transitivePeerDependencies:
       - '@azure/app-configuration'
@@ -23831,7 +23515,7 @@ snapshots:
       - xml2js
       - yaml
 
-  vite-plugin-dts@4.2.3(@types/node@24.10.3)(rollup@4.60.1)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+  vite-plugin-dts@4.2.3(@types/node@24.10.3)(rollup@4.60.1)(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
     dependencies:
       '@microsoft/api-extractor': 7.47.7(@types/node@24.10.3)
       '@rollup/pluginutils': 5.3.0(rollup@4.60.1)
@@ -23844,17 +23528,17 @@ snapshots:
       magic-string: 0.30.21
       typescript: 5.9.3
     optionalDependencies:
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - '@types/node'
       - rollup
       - supports-color
 
-  vite-plugin-externalize-deps@0.10.0(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+  vite-plugin-externalize-deps@0.10.0(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
     dependencies:
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
-  vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+  vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
     dependencies:
       '@babel/core': 7.28.5
       '@types/babel__core': 7.20.5
@@ -23862,54 +23546,29 @@ snapshots:
       merge-anything: 5.1.7
       solid-js: 1.9.10
       solid-refresh: 0.6.3(solid-js@1.9.10)
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vitefu: 1.1.1(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vitefu: 1.1.1(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
     transitivePeerDependencies:
       - supports-color
 
-  vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
-    dependencies:
-      '@babel/core': 7.28.5
-      '@types/babel__core': 7.20.5
-      babel-preset-solid: 1.9.10(@babel/core@7.28.5)(solid-js@1.9.10)
-      merge-anything: 5.1.7
-      solid-js: 1.9.10
-      solid-refresh: 0.6.3(solid-js@1.9.10)
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-      vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
-    transitivePeerDependencies:
-      - supports-color
-    optional: true
-
-  vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+  vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
     dependencies:
       debug: 4.4.3
       globrex: 0.1.2
       tsconfck: 3.1.6(typescript@5.9.3)
     optionalDependencies:
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
     transitivePeerDependencies:
       - supports-color
       - typescript
 
-  vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
-    dependencies:
-      debug: 4.4.3
-      globrex: 0.1.2
-      tsconfck: 3.1.6(typescript@5.9.3)
-    optionalDependencies:
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-    transitivePeerDependencies:
-      - supports-color
-      - typescript
-
-  vite@6.4.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
+  vite@6.4.2(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
     dependencies:
       esbuild: 0.25.12
       fdir: 6.5.0(picomatch@4.0.4)
       picomatch: 4.0.4
-      postcss: 8.5.6
-      rollup: 4.57.1
+      postcss: 8.5.9
+      rollup: 4.60.1
       tinyglobby: 0.2.16
     optionalDependencies:
       '@types/node': 24.10.3
@@ -23920,13 +23579,13 @@ snapshots:
       tsx: 4.21.0
       yaml: 2.8.2
 
-  vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
+  vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
     dependencies:
-      esbuild: 0.25.12
+      esbuild: 0.27.3
       fdir: 6.5.0(picomatch@4.0.3)
       picomatch: 4.0.3
       postcss: 8.5.6
-      rollup: 4.53.3
+      rollup: 4.57.1
       tinyglobby: 0.2.15
     optionalDependencies:
       '@types/node': 24.10.3
@@ -23937,14 +23596,14 @@ snapshots:
       tsx: 4.21.0
       yaml: 2.8.2
 
-  vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
+  vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
     dependencies:
-      esbuild: 0.27.3
-      fdir: 6.5.0(picomatch@4.0.3)
-      picomatch: 4.0.3
-      postcss: 8.5.6
-      rollup: 4.57.1
-      tinyglobby: 0.2.15
+      esbuild: 0.27.7
+      fdir: 6.5.0(picomatch@4.0.4)
+      picomatch: 4.0.4
+      postcss: 8.5.9
+      rollup: 4.60.1
+      tinyglobby: 0.2.16
     optionalDependencies:
       '@types/node': 24.10.3
       fsevents: 2.3.3
@@ -23954,13 +23613,9 @@ snapshots:
       tsx: 4.21.0
       yaml: 2.8.2
 
-  vitefu@1.1.1(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+  vitefu@1.1.1(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
     optionalDependencies:
-      vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
-
-  vitefu@1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
-    optionalDependencies:
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
 
   vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2):
     dependencies:
@@ -24042,10 +23697,10 @@ snapshots:
       - tsx
       - yaml
 
-  vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
+  vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jsdom@27.3.0(postcss@8.5.9))(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)):
     dependencies:
       '@vitest/expect': 4.1.4
-      '@vitest/mocker': 4.1.4(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
+      '@vitest/mocker': 4.1.4(vite@7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
       '@vitest/pretty-format': 4.1.4
       '@vitest/runner': 4.1.4
       '@vitest/snapshot': 4.1.4
@@ -24062,7 +23717,7 @@ snapshots:
       tinyexec: 1.1.1
       tinyglobby: 0.2.16
       tinyrainbow: 3.1.0
-      vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
+      vite: 7.3.3(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
       why-is-node-running: 2.3.0
     optionalDependencies:
       '@opentelemetry/api': 1.9.1
diff --git a/testing/e2e/package.json b/testing/e2e/package.json
index 05ebe10f0..0a561087f 100644
--- a/testing/e2e/package.json
+++ b/testing/e2e/package.json
@@ -48,6 +48,6 @@
     "@types/react-dom": "^19.2.3",
     "@vitejs/plugin-react": "^5.1.2",
     "typescript": "5.9.3",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }
diff --git a/testing/panel/package.json b/testing/panel/package.json
index 7dd5d1f9e..38bfc2558 100644
--- a/testing/panel/package.json
+++ b/testing/panel/package.json
@@ -47,6 +47,6 @@
     "@vitejs/plugin-react": "^5.1.2",
     "dotenv": "^17.2.3",
     "typescript": "5.9.3",
-    "vite": "^7.2.7"
+    "vite": "^7.3.3"
   }
 }

From 2ab32d9970b1346a1b2668d6062dba8f31ed32ae Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:36:21 +0200
Subject: [PATCH 02/17] chore(tsconfig): consolidate to root tsconfig.base.json
 and include tests

- Introduce tsconfig.base.json at the repo root with the shared compilerOptions.
  Root tsconfig.json now extends it for the small set of root-level files
  (scripts, config files) we still typecheck.
- Migrate every package tsconfig to extend tsconfig.base.json with a consistent
  shape: only the package's unique compilerOptions overrides (outDir, rootDir
  where needed, JSX runtime, framework lib) plus a uniform
  `include: ["src", "tests"]` / `exclude: ["node_modules", "dist"]`.
- Drop brittle one-off patterns: per-package duplicated compilerOptions
  (ai-devtools, ai-isolate-cloudflare), explicit single-test-file includes
  (ai-anthropic, ai-gemini), and `**/*.config.ts` excludes that were silently
  hiding test files from `tsc`.
- Config files (vite.config.ts, vitest.config.ts) are no longer in the include
  set. They're typechecked at build time by vite/vitest themselves and the
  cross-tool type matrix makes them brittle to check via `tsc`.

Net effect: `pnpm test:types` now actually typechecks the tests in every
package. Prior to this commit several packages were silently excluding tests
from the typecheck pipeline.
---
 .../typescript/ai-anthropic/tsconfig.json     | 12 ++++---
 packages/typescript/ai-client/tsconfig.json   | 12 +++++--
 .../ai-code-mode-skills/tsconfig.json         | 12 +++++--
 .../typescript/ai-code-mode/tsconfig.json     | 15 +++++---
 packages/typescript/ai-devtools/tsconfig.json | 34 ++++++-------------
 .../typescript/ai-elevenlabs/tsconfig.json    | 12 +++++--
 .../typescript/ai-event-client/tsconfig.json  | 16 ++++++---
 packages/typescript/ai-fal/tsconfig.json      | 17 +++++-----
 packages/typescript/ai-gemini/tsconfig.json   | 12 ++++---
 packages/typescript/ai-grok/tsconfig.json     | 15 +++++---
 packages/typescript/ai-groq/tsconfig.json     | 15 +++++---
 .../ai-isolate-cloudflare/tsconfig.json       | 30 +++++++++-------
 .../typescript/ai-isolate-node/tsconfig.json  | 12 +++++--
 .../ai-isolate-quickjs/tsconfig.json          | 12 +++++--
 packages/typescript/ai-ollama/tsconfig.json   | 12 +++++--
 packages/typescript/ai-openai/tsconfig.json   | 12 ++++---
 .../typescript/ai-openrouter/tsconfig.json    | 12 +++++--
 packages/typescript/ai-preact/tsconfig.json   | 17 +++++++---
 packages/typescript/ai-react-ui/tsconfig.json | 17 +++++++---
 packages/typescript/ai-react/tsconfig.json    | 18 +++++++---
 packages/typescript/ai-solid-ui/tsconfig.json | 17 +++++++---
 packages/typescript/ai-solid/tsconfig.json    | 21 ++++++++----
 packages/typescript/ai-svelte/tsconfig.json   | 19 ++++++++---
 packages/typescript/ai-utils/tsconfig.json    | 15 +++++---
 packages/typescript/ai-vue-ui/tsconfig.json   | 17 +++++++---
 packages/typescript/ai-vue/tsconfig.json      | 17 +++++++---
 packages/typescript/ai/tsconfig.json          |  9 ++---
 packages/typescript/openai-base/tsconfig.json | 15 +++++---
 .../preact-ai-devtools/tsconfig.json          | 15 +++++---
 .../react-ai-devtools/tsconfig.json           | 15 +++++---
 .../solid-ai-devtools/tsconfig.json           | 15 +++++---
 tsconfig.base.json                            | 27 +++++++++++++++
 tsconfig.json                                 | 32 ++---------------
 33 files changed, 350 insertions(+), 198 deletions(-)
 create mode 100644 tsconfig.base.json

diff --git a/packages/typescript/ai-anthropic/tsconfig.json b/packages/typescript/ai-anthropic/tsconfig.json
index 0c50acadb..127dc2038 100644
--- a/packages/typescript/ai-anthropic/tsconfig.json
+++ b/packages/typescript/ai-anthropic/tsconfig.json
@@ -1,12 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
   "include": [
-    "vite.config.ts",
-    "./src",
-    "tests/tools-per-model-type-safety.test.ts"
+    "src",
+    "tests"
   ],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-client/tsconfig.json b/packages/typescript/ai-client/tsconfig.json
index 3e93ac127..127dc2038 100644
--- a/packages/typescript/ai-client/tsconfig.json
+++ b/packages/typescript/ai-client/tsconfig.json
@@ -1,8 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts", "vite.config.ts"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts", "eslint.config.js"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-code-mode-skills/tsconfig.json b/packages/typescript/ai-code-mode-skills/tsconfig.json
index 31b14bdfe..127dc2038 100644
--- a/packages/typescript/ai-code-mode-skills/tsconfig.json
+++ b/packages/typescript/ai-code-mode-skills/tsconfig.json
@@ -1,8 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": ["vite.config.ts", "./src", "./tests"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-code-mode/tsconfig.json b/packages/typescript/ai-code-mode/tsconfig.json
index b2eaed1a0..127dc2038 100644
--- a/packages/typescript/ai-code-mode/tsconfig.json
+++ b/packages/typescript/ai-code-mode/tsconfig.json
@@ -1,9 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
-    "outDir": "dist",
-    "rootDir": "."
+    "outDir": "dist"
   },
-  "include": ["vite.config.ts", "./src"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-devtools/tsconfig.json b/packages/typescript/ai-devtools/tsconfig.json
index 062239fe8..e9cd78b37 100644
--- a/packages/typescript/ai-devtools/tsconfig.json
+++ b/packages/typescript/ai-devtools/tsconfig.json
@@ -1,29 +1,17 @@
 {
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
+    "outDir": "dist",
     "jsx": "preserve",
     "jsxImportSource": "solid-js",
-    "allowJs": true,
-    "allowSyntheticDefaultImports": true,
-    "allowUnreachableCode": false,
-    "allowUnusedLabels": false,
-    "checkJs": true,
-    "declaration": true,
-    "esModuleInterop": true,
-    "forceConsistentCasingInFileNames": true,
-    "isolatedModules": true,
-    "lib": ["DOM", "DOM.Iterable", "ES2022"],
-    "module": "ES2022",
-    "moduleResolution": "Bundler",
-    "noEmit": true,
-    "noImplicitReturns": true,
-    "noUncheckedIndexedAccess": true,
-    "noUnusedLocals": false, // TODO enable
-    "noUnusedParameters": true,
-    "resolveJsonModule": true,
-    "skipLibCheck": true,
-    "strict": true,
-    "target": "ES2020"
+    "noUnusedLocals": false
   },
-  "include": ["src", "vite.config.ts"],
-  "exclude": ["node_modules", "dist"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-elevenlabs/tsconfig.json b/packages/typescript/ai-elevenlabs/tsconfig.json
index e5e872741..127dc2038 100644
--- a/packages/typescript/ai-elevenlabs/tsconfig.json
+++ b/packages/typescript/ai-elevenlabs/tsconfig.json
@@ -1,8 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": ["vite.config.ts", "./src"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-event-client/tsconfig.json b/packages/typescript/ai-event-client/tsconfig.json
index e9b3860cf..5cf18c316 100644
--- a/packages/typescript/ai-event-client/tsconfig.json
+++ b/packages/typescript/ai-event-client/tsconfig.json
@@ -1,11 +1,19 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist",
     "paths": {
-      "@tanstack/ai-event-client": ["./src/index.ts"]
+      "@tanstack/ai-event-client": [
+        "./src/index.ts"
+      ]
     }
   },
-  "include": ["src/**/*.ts", "vite.config.ts"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts", "eslint.config.js"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-fal/tsconfig.json b/packages/typescript/ai-fal/tsconfig.json
index 20ecbb361..9f177f7e6 100644
--- a/packages/typescript/ai-fal/tsconfig.json
+++ b/packages/typescript/ai-fal/tsconfig.json
@@ -1,16 +1,15 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
   "include": [
-    "scripts/**/*.ts",
-    "src/**/*.ts",
-    "src/**/*.tsx",
-    "./tests/**/*.ts",
-    "openapi-ts.config.ts",
-    "eslint.config.ts",
-    "vite.config.ts"
+    "src",
+    "tests",
+    "scripts"
   ],
-  "exclude": ["node_modules", "dist"]
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-gemini/tsconfig.json b/packages/typescript/ai-gemini/tsconfig.json
index 0c50acadb..127dc2038 100644
--- a/packages/typescript/ai-gemini/tsconfig.json
+++ b/packages/typescript/ai-gemini/tsconfig.json
@@ -1,12 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
   "include": [
-    "vite.config.ts",
-    "./src",
-    "tests/tools-per-model-type-safety.test.ts"
+    "src",
+    "tests"
   ],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-grok/tsconfig.json b/packages/typescript/ai-grok/tsconfig.json
index ea11c1096..127dc2038 100644
--- a/packages/typescript/ai-grok/tsconfig.json
+++ b/packages/typescript/ai-grok/tsconfig.json
@@ -1,9 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
-    "outDir": "dist",
-    "rootDir": "src"
+    "outDir": "dist"
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-groq/tsconfig.json b/packages/typescript/ai-groq/tsconfig.json
index ea11c1096..127dc2038 100644
--- a/packages/typescript/ai-groq/tsconfig.json
+++ b/packages/typescript/ai-groq/tsconfig.json
@@ -1,9 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
-    "outDir": "dist",
-    "rootDir": "src"
+    "outDir": "dist"
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-isolate-cloudflare/tsconfig.json b/packages/typescript/ai-isolate-cloudflare/tsconfig.json
index 1cd2cbbc8..67fda246c 100644
--- a/packages/typescript/ai-isolate-cloudflare/tsconfig.json
+++ b/packages/typescript/ai-isolate-cloudflare/tsconfig.json
@@ -1,18 +1,22 @@
 {
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
-    "target": "ES2022",
-    "module": "ESNext",
-    "lib": ["ES2022"],
-    "moduleResolution": "bundler",
-    "strict": true,
-    "esModuleInterop": true,
-    "skipLibCheck": true,
-    "declaration": true,
-    "declarationMap": true,
     "outDir": "./dist/esm",
-    "rootDir": "./src",
-    "types": ["@cloudflare/workers-types"]
+    "declarationMap": true,
+    "lib": [
+      "ES2022"
+    ],
+    "types": [
+      "@cloudflare/workers-types"
+    ]
   },
-  "include": ["src/**/*"],
-  "exclude": ["node_modules", "dist", "worker"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist",
+    "worker"
+  ]
 }
diff --git a/packages/typescript/ai-isolate-node/tsconfig.json b/packages/typescript/ai-isolate-node/tsconfig.json
index e5e872741..127dc2038 100644
--- a/packages/typescript/ai-isolate-node/tsconfig.json
+++ b/packages/typescript/ai-isolate-node/tsconfig.json
@@ -1,8 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": ["vite.config.ts", "./src"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-isolate-quickjs/tsconfig.json b/packages/typescript/ai-isolate-quickjs/tsconfig.json
index e5e872741..127dc2038 100644
--- a/packages/typescript/ai-isolate-quickjs/tsconfig.json
+++ b/packages/typescript/ai-isolate-quickjs/tsconfig.json
@@ -1,8 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": ["vite.config.ts", "./src"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-ollama/tsconfig.json b/packages/typescript/ai-ollama/tsconfig.json
index 9028fa3bd..127dc2038 100644
--- a/packages/typescript/ai-ollama/tsconfig.json
+++ b/packages/typescript/ai-ollama/tsconfig.json
@@ -1,8 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-openai/tsconfig.json b/packages/typescript/ai-openai/tsconfig.json
index 0c50acadb..127dc2038 100644
--- a/packages/typescript/ai-openai/tsconfig.json
+++ b/packages/typescript/ai-openai/tsconfig.json
@@ -1,12 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
   "include": [
-    "vite.config.ts",
-    "./src",
-    "tests/tools-per-model-type-safety.test.ts"
+    "src",
+    "tests"
   ],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-openrouter/tsconfig.json b/packages/typescript/ai-openrouter/tsconfig.json
index 2d3b235e9..127dc2038 100644
--- a/packages/typescript/ai-openrouter/tsconfig.json
+++ b/packages/typescript/ai-openrouter/tsconfig.json
@@ -1,8 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx", "./tests/**/*.ts"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-preact/tsconfig.json b/packages/typescript/ai-preact/tsconfig.json
index 2fcecae9f..478f9b6cc 100644
--- a/packages/typescript/ai-preact/tsconfig.json
+++ b/packages/typescript/ai-preact/tsconfig.json
@@ -1,11 +1,20 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist",
     "jsx": "react-jsx",
     "jsxImportSource": "preact",
-    "lib": ["ES2022", "DOM"]
+    "lib": [
+      "ES2022",
+      "DOM"
+    ]
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts", "tests/**/*.tsx"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-react-ui/tsconfig.json b/packages/typescript/ai-react-ui/tsconfig.json
index ed5723d43..ec08aeb4b 100644
--- a/packages/typescript/ai-react-ui/tsconfig.json
+++ b/packages/typescript/ai-react-ui/tsconfig.json
@@ -1,14 +1,21 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "./dist",
     "rootDir": "./src",
     "jsx": "react-jsx",
-    "declaration": true,
     "declarationMap": true,
     "composite": true,
-    "lib": ["ES2022", "DOM"]
+    "lib": [
+      "ES2022",
+      "DOM"
+    ]
   },
-  "include": ["src/**/*"],
-  "exclude": ["node_modules", "dist"]
+  "include": [
+    "src"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-react/tsconfig.json b/packages/typescript/ai-react/tsconfig.json
index 3bbc679df..0f90b8d47 100644
--- a/packages/typescript/ai-react/tsconfig.json
+++ b/packages/typescript/ai-react/tsconfig.json
@@ -1,11 +1,19 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist",
-    "rootDir": "src",
     "jsx": "react-jsx",
-    "lib": ["ES2022", "DOM"]
+    "lib": [
+      "ES2022",
+      "DOM"
+    ]
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-solid-ui/tsconfig.json b/packages/typescript/ai-solid-ui/tsconfig.json
index 77fad8ab7..f240896ee 100644
--- a/packages/typescript/ai-solid-ui/tsconfig.json
+++ b/packages/typescript/ai-solid-ui/tsconfig.json
@@ -1,15 +1,22 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "./dist",
     "rootDir": "./src",
     "jsx": "preserve",
     "jsxImportSource": "solid-js",
-    "declaration": true,
     "declarationMap": true,
     "composite": true,
-    "lib": ["ES2022", "DOM"]
+    "lib": [
+      "ES2022",
+      "DOM"
+    ]
   },
-  "include": ["src/**/*"],
-  "exclude": ["node_modules", "dist"]
+  "include": [
+    "src"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-solid/tsconfig.json b/packages/typescript/ai-solid/tsconfig.json
index 3bbc679df..7492469d6 100644
--- a/packages/typescript/ai-solid/tsconfig.json
+++ b/packages/typescript/ai-solid/tsconfig.json
@@ -1,11 +1,20 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist",
-    "rootDir": "src",
-    "jsx": "react-jsx",
-    "lib": ["ES2022", "DOM"]
+    "jsx": "preserve",
+    "jsxImportSource": "solid-js",
+    "lib": [
+      "ES2022",
+      "DOM"
+    ]
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-svelte/tsconfig.json b/packages/typescript/ai-svelte/tsconfig.json
index 4a74026c5..0833a339c 100644
--- a/packages/typescript/ai-svelte/tsconfig.json
+++ b/packages/typescript/ai-svelte/tsconfig.json
@@ -1,10 +1,19 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist",
-    "rootDir": "src",
-    "lib": ["ES2022", "DOM"]
+    "lib": [
+      "ES2022",
+      "DOM"
+    ]
   },
-  "include": ["src/**/*.ts"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests",
+    "**/*.svelte"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-utils/tsconfig.json b/packages/typescript/ai-utils/tsconfig.json
index ea11c1096..127dc2038 100644
--- a/packages/typescript/ai-utils/tsconfig.json
+++ b/packages/typescript/ai-utils/tsconfig.json
@@ -1,9 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
-    "outDir": "dist",
-    "rootDir": "src"
+    "outDir": "dist"
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-vue-ui/tsconfig.json b/packages/typescript/ai-vue-ui/tsconfig.json
index b96b7d788..60963fbbd 100644
--- a/packages/typescript/ai-vue-ui/tsconfig.json
+++ b/packages/typescript/ai-vue-ui/tsconfig.json
@@ -1,14 +1,21 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "./dist",
     "rootDir": "./src",
     "jsx": "preserve",
-    "declaration": true,
     "declarationMap": true,
     "composite": true,
-    "lib": ["ES2022", "DOM"]
+    "lib": [
+      "ES2022",
+      "DOM"
+    ]
   },
-  "include": ["src/**/*"],
-  "exclude": ["node_modules", "dist"]
+  "include": [
+    "src"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai-vue/tsconfig.json b/packages/typescript/ai-vue/tsconfig.json
index 0474232a5..b797eda55 100644
--- a/packages/typescript/ai-vue/tsconfig.json
+++ b/packages/typescript/ai-vue/tsconfig.json
@@ -1,10 +1,19 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist",
     "jsx": "preserve",
-    "lib": ["ES2022", "DOM"]
+    "lib": [
+      "ES2022",
+      "DOM"
+    ]
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/ai/tsconfig.json b/packages/typescript/ai/tsconfig.json
index 9f8ee86c1..0fcff08d0 100644
--- a/packages/typescript/ai/tsconfig.json
+++ b/packages/typescript/ai/tsconfig.json
@@ -1,14 +1,15 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts", "vite.config.ts"],
+  "include": [
+    "src",
+    "tests"
+  ],
   "exclude": [
     "node_modules",
     "dist",
-    "**/*.config.ts",
-    "eslint.config.js",
     "tests/**/*.test-d.ts"
   ]
 }
diff --git a/packages/typescript/openai-base/tsconfig.json b/packages/typescript/openai-base/tsconfig.json
index ea11c1096..127dc2038 100644
--- a/packages/typescript/openai-base/tsconfig.json
+++ b/packages/typescript/openai-base/tsconfig.json
@@ -1,9 +1,14 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
-    "outDir": "dist",
-    "rootDir": "src"
+    "outDir": "dist"
   },
-  "include": ["src/**/*.ts", "src/**/*.tsx"],
-  "exclude": ["node_modules", "dist", "**/*.config.ts"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/preact-ai-devtools/tsconfig.json b/packages/typescript/preact-ai-devtools/tsconfig.json
index ea4330466..0cb9c00df 100644
--- a/packages/typescript/preact-ai-devtools/tsconfig.json
+++ b/packages/typescript/preact-ai-devtools/tsconfig.json
@@ -1,11 +1,16 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "jsx": "preserve",
     "jsxFactory": "h",
-    "jsxFragmentFactory": "Fragment",
-    "moduleResolution": "bundler",
-    "strictNullChecks": true
+    "jsxFragmentFactory": "Fragment"
   },
-  "include": ["eslint.config.js", "prettier.config.js", "src"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/react-ai-devtools/tsconfig.json b/packages/typescript/react-ai-devtools/tsconfig.json
index 0600e4996..1f0c39cb5 100644
--- a/packages/typescript/react-ai-devtools/tsconfig.json
+++ b/packages/typescript/react-ai-devtools/tsconfig.json
@@ -1,10 +1,15 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "jsx": "preserve",
-    "jsxFactory": "solid",
-    "moduleResolution": "bundler",
-    "strictNullChecks": true
+    "jsxFactory": "solid"
   },
-  "include": ["eslint.config.js", "prettier.config.js", "src"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/packages/typescript/solid-ai-devtools/tsconfig.json b/packages/typescript/solid-ai-devtools/tsconfig.json
index 0600e4996..1f0c39cb5 100644
--- a/packages/typescript/solid-ai-devtools/tsconfig.json
+++ b/packages/typescript/solid-ai-devtools/tsconfig.json
@@ -1,10 +1,15 @@
 {
-  "extends": "../../../tsconfig.json",
+  "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "jsx": "preserve",
-    "jsxFactory": "solid",
-    "moduleResolution": "bundler",
-    "strictNullChecks": true
+    "jsxFactory": "solid"
   },
-  "include": ["eslint.config.js", "prettier.config.js", "src"]
+  "include": [
+    "src",
+    "tests"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
 }
diff --git a/tsconfig.base.json b/tsconfig.base.json
new file mode 100644
index 000000000..e3b153db4
--- /dev/null
+++ b/tsconfig.base.json
@@ -0,0 +1,27 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "compilerOptions": {
+    "allowJs": true,
+    "allowSyntheticDefaultImports": true,
+    "allowUnreachableCode": false,
+    "allowUnusedLabels": false,
+    "checkJs": true,
+    "declaration": true,
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "isolatedModules": true,
+    "lib": ["DOM", "DOM.Iterable", "ES2023"],
+    "module": "ES2022",
+    "moduleResolution": "Bundler",
+    "noEmit": true,
+    "noImplicitReturns": true,
+    "noUncheckedIndexedAccess": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "resolveJsonModule": true,
+    "skipLibCheck": true,
+    "strict": true,
+    "target": "ES2020",
+    "noErrorTruncation": true
+  }
+}
diff --git a/tsconfig.json b/tsconfig.json
index b907b6d51..7b2458fd6 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,33 +1,5 @@
 {
   "$schema": "https://json.schemastore.org/tsconfig",
-  "compilerOptions": {
-    "allowJs": true,
-    "allowSyntheticDefaultImports": true,
-    "allowUnreachableCode": false,
-    "allowUnusedLabels": false,
-    "checkJs": true,
-    "declaration": true,
-    "esModuleInterop": true,
-    "forceConsistentCasingInFileNames": true,
-    "isolatedModules": true,
-    "lib": ["DOM", "DOM.Iterable", "ES2023"],
-    "module": "ES2022",
-    "moduleResolution": "Bundler",
-    "noEmit": true,
-    "noImplicitReturns": true,
-    "noUncheckedIndexedAccess": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "resolveJsonModule": true,
-    "skipLibCheck": true,
-    "strict": true,
-    "target": "ES2020",
-    "noErrorTruncation": true
-  },
-  "include": [
-    "eslint.config.js",
-    "prettier.config.js",
-    "scripts",
-    "vitest.workspace.js"
-  ]
+  "extends": "./tsconfig.base.json",
+  "include": ["scripts", "*.config.ts", "*.config.js"]
 }

From 77c947b5ef807720c3de42e2744ea14744005944 Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:36:35 +0200
Subject: [PATCH 03/17] refactor(ai-gemini): merge
 GeminiThinking{,Advanced}Options into one interface
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The old shape kept thinking config in two separate interfaces — one with
required `includeThoughts` + optional `thinkingBudget`, the other with
`thinkingLevel` — and intersected both into ExternalTextProviderOptions.
The intersection produced a `thinkingConfig` shape where neither
`includeThoughts`+`thinkingBudget` nor `thinkingLevel` could be passed
cleanly, even though the adapter reads both at runtime
(see src/adapters/text.ts mapCommonOptionsToGemini).

Merge into a single GeminiThinkingOptions with all three fields optional.
Drop GeminiThinkingAdvancedOptions entirely. Update model-meta intersections
and the sync-provider-models template that references the type.

GeminiThinkingOptions is the only thinking type exported from
@tanstack/ai-gemini, so no public-API breakage. GeminiThinkingAdvancedOptions
was never exported.
---
 .../typescript/ai-gemini/src/model-meta.ts    | 22 ++++++-----------
 .../src/text/text-provider-options.ts         | 24 +++++++++----------
 scripts/sync-provider-models.ts               |  4 ++--
 3 files changed, 21 insertions(+), 29 deletions(-)

diff --git a/packages/typescript/ai-gemini/src/model-meta.ts b/packages/typescript/ai-gemini/src/model-meta.ts
index 9127aa04e..a0d5f24d6 100644
--- a/packages/typescript/ai-gemini/src/model-meta.ts
+++ b/packages/typescript/ai-gemini/src/model-meta.ts
@@ -3,7 +3,6 @@ import type {
   GeminiCommonConfigOptions,
   GeminiSafetyOptions,
   GeminiStructuredOutputOptions,
-  GeminiThinkingAdvancedOptions,
   GeminiThinkingOptions,
   GeminiToolConfigOptions,
 } from './text/text-provider-options'
@@ -81,8 +80,7 @@ const GEMINI_3_1_PRO = {
     GeminiCommonConfigOptions &
     GeminiCachedContentOptions &
     GeminiStructuredOutputOptions &
-    GeminiThinkingOptions &
-    GeminiThinkingAdvancedOptions
+    GeminiThinkingOptions
 >
 
 const GEMINI_3_PRO = {
@@ -116,8 +114,7 @@ const GEMINI_3_PRO = {
     GeminiCommonConfigOptions &
     GeminiCachedContentOptions &
     GeminiStructuredOutputOptions &
-    GeminiThinkingOptions &
-    GeminiThinkingAdvancedOptions
+    GeminiThinkingOptions
 >
 
 const GEMINI_3_FLASH = {
@@ -151,8 +148,7 @@ const GEMINI_3_FLASH = {
     GeminiCommonConfigOptions &
     GeminiCachedContentOptions &
     GeminiStructuredOutputOptions &
-    GeminiThinkingOptions &
-    GeminiThinkingAdvancedOptions
+    GeminiThinkingOptions
 >
 
 const GEMINI_3_PRO_IMAGE = {
@@ -180,8 +176,7 @@ const GEMINI_3_PRO_IMAGE = {
     GeminiCommonConfigOptions &
     GeminiCachedContentOptions &
     GeminiStructuredOutputOptions &
-    GeminiThinkingOptions &
-    GeminiThinkingAdvancedOptions
+    GeminiThinkingOptions
 >
 
 const GEMINI_3_1_FLASH_IMAGE = {
@@ -1080,22 +1075,19 @@ export type GeminiChatModelProviderOptionsByName = {
     GeminiCommonConfigOptions &
     GeminiCachedContentOptions &
     GeminiStructuredOutputOptions &
-    GeminiThinkingOptions &
-    GeminiThinkingAdvancedOptions
+    GeminiThinkingOptions
   [GEMINI_3_PRO.name]: GeminiToolConfigOptions &
     GeminiSafetyOptions &
     GeminiCommonConfigOptions &
     GeminiCachedContentOptions &
     GeminiStructuredOutputOptions &
-    GeminiThinkingOptions &
-    GeminiThinkingAdvancedOptions
+    GeminiThinkingOptions
   [GEMINI_3_FLASH.name]: GeminiToolConfigOptions &
     GeminiSafetyOptions &
     GeminiCommonConfigOptions &
     GeminiCachedContentOptions &
     GeminiStructuredOutputOptions &
-    GeminiThinkingOptions &
-    GeminiThinkingAdvancedOptions
+    GeminiThinkingOptions
   [GEMINI_3_1_FLASH_LITE.name]: GeminiToolConfigOptions &
     GeminiSafetyOptions &
     GeminiCommonConfigOptions &
diff --git a/packages/typescript/ai-gemini/src/text/text-provider-options.ts b/packages/typescript/ai-gemini/src/text/text-provider-options.ts
index 4c53ec2ad..6c69f3a21 100644
--- a/packages/typescript/ai-gemini/src/text/text-provider-options.ts
+++ b/packages/typescript/ai-gemini/src/text/text-provider-options.ts
@@ -218,28 +218,29 @@ Cyclic references are unrolled to a limited degree and, as such, may only be use
 
 export interface GeminiThinkingOptions {
   /**
-   * Config for thinking features. An error will be returned if this field is set for models that don't support thinking.
+   * Config for thinking features. An error will be returned if this field is
+   * set for models that don't support thinking.
+   *
+   * All fields are optional so the same shape can be used for both budget-based
+   * thinking (Gemini 2.x: `includeThoughts` + `thinkingBudget`) and the newer
+   * level-based thinking (Gemini 3.x: `thinkingLevel`). The adapter reads
+   * whichever fields are present at runtime.
    */
   thinkingConfig?: {
     /**
-     * Indicates whether to include thoughts in the response. If true, thoughts are returned only when available.
+     * Indicates whether to include thoughts in the response. If true, thoughts
+     * are returned only when available.
      */
-    includeThoughts: boolean
+    includeThoughts?: boolean
 
     /**
      * The number of thoughts tokens that the model should generate.
      */
     thinkingBudget?: number
-  }
-}
 
-export interface GeminiThinkingAdvancedOptions {
-  /**
-   * Config for thinking features. An error will be returned if this field is set for models that don't support thinking.
-   */
-  thinkingConfig?: {
     /**
-     * The level of thoughts tokens that the model should generate.
+     * The level of thoughts tokens that the model should generate
+     * (Gemini 3.x and later).
      */
     thinkingLevel?: keyof typeof ThinkingLevel
   }
@@ -250,5 +251,4 @@ export type ExternalTextProviderOptions = GeminiToolConfigOptions &
   GeminiCommonConfigOptions &
   GeminiCachedContentOptions &
   GeminiThinkingOptions &
-  GeminiThinkingAdvancedOptions &
   GeminiStructuredOutputOptions
diff --git a/scripts/sync-provider-models.ts b/scripts/sync-provider-models.ts
index 5f0199cc7..f35e289ee 100644
--- a/scripts/sync-provider-models.ts
+++ b/scripts/sync-provider-models.ts
@@ -123,9 +123,9 @@ const PROVIDER_MAP: Record<string, ProviderConfig> = {
     capabilities: ['batch_api', 'caching', 'function_calling', 'structured_output', 'thinking'],
     tools: ['code_execution', 'file_search', 'google_search', 'url_context'],`,
     referenceSatisfies:
-      'ModelMeta<GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions & GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions & GeminiThinkingAdvancedOptions>',
+      'ModelMeta<GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions & GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions>',
     referenceProviderOptionsEntry:
-      'GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions & GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions & GeminiThinkingAdvancedOptions',
+      'GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions & GeminiCachedContentOptions & GeminiStructuredOutputOptions & GeminiThinkingOptions',
     hasBothNameAndId: false,
     providerOptionsIsMappedType: false,
     skipPatterns: [

From 66737a5e3fdd7b99b2e2acb18a1aa2a69c20063c Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:36:49 +0200
Subject: [PATCH 04/17] refactor(ai-anthropic): drop modelOptions.system escape
 hatch

`system` was sneaking into modelOptions via `validKeys` and getting spread
over the system block constructed from systemPrompts. That was a leaky
abstraction: it bypassed the cross-provider `systemPrompts` API and forced
users to construct Anthropic's TextBlockParam shape manually to attach
features like cache_control.

- Remove `'system'` from validKeys in adapters/text.ts. The adapter no longer
  accepts a system override from modelOptions.
- Keep `system?: string | Array<TextBlockParam>` on InternalTextProviderOptions
  (the adapter still constructs it internally from `options.systemPrompts`).
  Mark it explicitly as internal in the JSDoc.
- Delete the test that exercised the override behaviour and prune the
  `system` field + `& { system: string }` satisfies intersection from the
  one other test that was using modelOptions.system.

Regression to be aware of: there is currently no public way to attach
Anthropic `cache_control` to system prompts. A follow-up will extend
`systemPrompts` to accept `{ content, metadata }` with provider-specific
metadata (cache_control for Anthropic, others later).
---
 .../ai-anthropic/src/adapters/text.ts         |   1 -
 .../src/text/text-provider-options.ts         |  12 ++-
 .../tests/anthropic-adapter.test.ts           | 102 ++++--------------
 3 files changed, 31 insertions(+), 84 deletions(-)

diff --git a/packages/typescript/ai-anthropic/src/adapters/text.ts b/packages/typescript/ai-anthropic/src/adapters/text.ts
index 95362fb7b..e08919164 100644
--- a/packages/typescript/ai-anthropic/src/adapters/text.ts
+++ b/packages/typescript/ai-anthropic/src/adapters/text.ts
@@ -301,7 +301,6 @@ export class AnthropicTextAdapter<
         'mcp_servers',
         'service_tier',
         'stop_sequences',
-        'system',
         'thinking',
         'tool_choice',
         'top_k',
diff --git a/packages/typescript/ai-anthropic/src/text/text-provider-options.ts b/packages/typescript/ai-anthropic/src/text/text-provider-options.ts
index b26da487d..975f29240 100644
--- a/packages/typescript/ai-anthropic/src/text/text-provider-options.ts
+++ b/packages/typescript/ai-anthropic/src/text/text-provider-options.ts
@@ -170,10 +170,14 @@ export interface InternalTextProviderOptions extends ExternalTextProviderOptions
    */
   stream?: boolean
   /**
-    * stem prompt.
- 
- A system prompt is a way of providing context and instructions to Claude, such as specifying a particular goal or role.
-    */
+   * System prompt — built by the adapter from the user-facing
+   * `systemPrompts: Array<string>` on the chat call. This field is internal:
+   * users should pass system prompts via `systemPrompts`, not via
+   * `modelOptions`.
+   *
+   * A system prompt is a way of providing context and instructions to Claude,
+   * such as specifying a particular goal or role.
+   */
   system?: string | Array<TextBlockParam>
   /**
    * Amount of randomness injected into the response.
diff --git a/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts b/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts
index b0f330bee..1db419993 100644
--- a/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts
+++ b/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts
@@ -35,7 +35,7 @@ vi.mock('@anthropic-ai/sdk', () => {
   return { default: MockAnthropic }
 })
 
-const createAdapter = <TModel extends 'claude-3-7-sonnet-20250219'>(
+const createAdapter = <TModel extends 'claude-3-7-sonnet'>(
   model: TModel,
 ) => new AnthropicTextAdapter({ apiKey: 'test-key' }, model)
 
@@ -98,7 +98,7 @@ describe('Anthropic adapter option mapping', () => {
 
     mocks.betaMessagesCreate.mockResolvedValueOnce(mockStream)
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     const chunks: StreamChunk[] = []
     for await (const chunk of chat({
@@ -109,7 +109,7 @@ describe('Anthropic adapter option mapping', () => {
       chunks.push(chunk)
     }
 
-    const [payload] = mocks.betaMessagesCreate.mock.calls[0]
+    const [payload] = mocks.betaMessagesCreate.mock.calls[0]!
 
     // system should be an array of TextBlockParam, not a joined string
     expect(payload.system).toEqual([
@@ -118,60 +118,6 @@ describe('Anthropic adapter option mapping', () => {
     ])
   })
 
-  it('allows modelOptions.system to override systemPrompts with cache_control', async () => {
-    const mockStream = (async function* () {
-      yield {
-        type: 'content_block_start',
-        index: 0,
-        content_block: { type: 'text', text: '' },
-      }
-      yield {
-        type: 'content_block_delta',
-        index: 0,
-        delta: { type: 'text_delta', text: 'Hello' },
-      }
-      yield {
-        type: 'message_delta',
-        delta: { stop_reason: 'end_turn' },
-        usage: { output_tokens: 3 },
-      }
-      yield { type: 'message_stop' }
-    })()
-
-    mocks.betaMessagesCreate.mockResolvedValueOnce(mockStream)
-
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
-
-    const chunks: StreamChunk[] = []
-    for await (const chunk of chat({
-      adapter,
-      messages: [{ role: 'user', content: 'Hi' }],
-      systemPrompts: ['This should be overridden'],
-      modelOptions: {
-        system: [
-          {
-            type: 'text',
-            text: 'You are a helpful assistant.',
-            cache_control: { type: 'ephemeral' },
-          },
-        ],
-      },
-    })) {
-      chunks.push(chunk)
-    }
-
-    const [payload] = mocks.betaMessagesCreate.mock.calls[0]
-
-    // modelOptions.system should take precedence over systemPrompts
-    expect(payload.system).toEqual([
-      {
-        type: 'text',
-        text: 'You are a helpful assistant.',
-        cache_control: { type: 'ephemeral' },
-      },
-    ])
-  })
-
   it('maps normalized options and Anthropic provider settings', async () => {
     // Mock the streaming response
     const mockStream = (async function* () {
@@ -218,10 +164,9 @@ describe('Anthropic adapter option mapping', () => {
       stop_sequences: ['</done>'],
       thinking: { type: 'enabled', budget_tokens: 1500 },
       top_k: 5,
-      system: 'Respond with JSON',
-    } satisfies AnthropicTextProviderOptions & { system: string }
+    } satisfies AnthropicTextProviderOptions
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     // Consume the stream to trigger the API call
     const chunks: StreamChunk[] = []
@@ -251,10 +196,10 @@ describe('Anthropic adapter option mapping', () => {
     }
 
     expect(mocks.betaMessagesCreate).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.betaMessagesCreate.mock.calls[0]
+    const [payload] = mocks.betaMessagesCreate.mock.calls[0]!
 
     expect(payload).toMatchObject({
-      model: 'claude-3-7-sonnet-20250219',
+      model: 'claude-3-7-sonnet',
       max_tokens: 3000,
       temperature: 0.4,
       container: providerOptions.container,
@@ -263,7 +208,6 @@ describe('Anthropic adapter option mapping', () => {
       stop_sequences: providerOptions.stop_sequences,
       thinking: providerOptions.thinking,
       top_k: providerOptions.top_k,
-      system: providerOptions.system,
     })
     expect(payload.stream).toBe(true)
 
@@ -331,7 +275,7 @@ describe('Anthropic adapter option mapping', () => {
 
     mocks.betaMessagesCreate.mockResolvedValueOnce(mockStream)
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     // Multi-turn: user -> assistant(tool_calls) -> tool_result -> follow-up user
     const chunks: StreamChunk[] = []
@@ -359,7 +303,7 @@ describe('Anthropic adapter option mapping', () => {
     }
 
     expect(mocks.betaMessagesCreate).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.betaMessagesCreate.mock.calls[0]
+    const [payload] = mocks.betaMessagesCreate.mock.calls[0]!
 
     // The tool_result (user) and follow-up user message should be merged into one user message
     expect(payload.messages).toEqual([
@@ -404,7 +348,7 @@ describe('Anthropic adapter option mapping', () => {
       createTextStream('Follow-up answer'),
     )
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     const chunks: StreamChunk[] = []
     for await (const chunk of chat({
@@ -434,13 +378,13 @@ describe('Anthropic adapter option mapping', () => {
       tools: [weatherTool],
       modelOptions: {
         thinking: { type: 'enabled', budget_tokens: 1024 },
-      } as AnthropicTextProviderOptions,
+      } satisfies AnthropicTextProviderOptions,
     })) {
       chunks.push(chunk)
     }
 
     expect(mocks.betaMessagesCreate).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.betaMessagesCreate.mock.calls[0]
+    const [payload] = mocks.betaMessagesCreate.mock.calls[0]!
 
     expect(payload.betas).toEqual(['interleaved-thinking-2025-05-14'])
     expect(payload.messages[1].content).toEqual([
@@ -463,7 +407,7 @@ describe('Anthropic adapter option mapping', () => {
       createTextStream('Next answer'),
     )
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     const chunks: StreamChunk[] = []
     for await (const chunk of chat({
@@ -484,12 +428,12 @@ describe('Anthropic adapter option mapping', () => {
       ],
       modelOptions: {
         thinking: { type: 'enabled', budget_tokens: 1024 },
-      } as AnthropicTextProviderOptions,
+      } satisfies AnthropicTextProviderOptions,
     })) {
       chunks.push(chunk)
     }
 
-    const [payload] = mocks.betaMessagesCreate.mock.calls[0]
+    const [payload] = mocks.betaMessagesCreate.mock.calls[0]!
 
     expect(payload.messages[1].content).toEqual([
       {
@@ -529,7 +473,7 @@ describe('Anthropic adapter option mapping', () => {
 
     mocks.betaMessagesCreate.mockResolvedValueOnce(mockStream)
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     const chunks: StreamChunk[] = []
     for await (const chunk of chat({
@@ -567,7 +511,7 @@ describe('Anthropic adapter option mapping', () => {
     }
 
     expect(mocks.betaMessagesCreate).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.betaMessagesCreate.mock.calls[0]
+    const [payload] = mocks.betaMessagesCreate.mock.calls[0]!
 
     // Both tool results should be merged into a single user message
     expect(payload.messages).toEqual([
@@ -645,7 +589,7 @@ describe('Anthropic adapter option mapping', () => {
 
     mocks.betaMessagesCreate.mockResolvedValueOnce(mockStream)
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     const chunks: StreamChunk[] = []
     for await (const chunk of chat({
@@ -700,7 +644,7 @@ describe('Anthropic adapter option mapping', () => {
     }
 
     expect(mocks.betaMessagesCreate).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.betaMessagesCreate.mock.calls[0]
+    const [payload] = mocks.betaMessagesCreate.mock.calls[0]!
 
     // Verify: no consecutive same-role messages, no empty assistants, no duplicate tool_results
     const roles = payload.messages.map((m: any) => m.role)
@@ -757,7 +701,7 @@ describe('Anthropic adapter option mapping', () => {
 
     mocks.betaMessagesCreate.mockResolvedValueOnce(mockStream)
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     const chunks: StreamChunk[] = []
     for await (const chunk of chat({
@@ -772,7 +716,7 @@ describe('Anthropic adapter option mapping', () => {
     }
 
     expect(mocks.betaMessagesCreate).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.betaMessagesCreate.mock.calls[0]
+    const [payload] = mocks.betaMessagesCreate.mock.calls[0]!
 
     // The empty assistant message should be filtered out, and consecutive
     // user messages should be merged
@@ -821,7 +765,7 @@ describe('Anthropic stream processing', () => {
 
     mocks.betaMessagesCreate.mockResolvedValueOnce(mockStream)
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     const chunks: StreamChunk[] = []
     for await (const chunk of chat({
@@ -884,7 +828,7 @@ describe('Anthropic stream processing', () => {
 
     mocks.betaMessagesCreate.mockResolvedValueOnce(mockStream)
 
-    const adapter = createAdapter('claude-3-7-sonnet-20250219')
+    const adapter = createAdapter('claude-3-7-sonnet')
 
     const chunks: StreamChunk[] = []
     for await (const chunk of chat({

From d618ed47ccd0fee23a2936399ee658cd648356c0 Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:37:00 +0200
Subject: [PATCH 05/17] fix(ai): expose Logger via the adapter-internals
 subpath

`Logger` was declared as an `export interface` in src/logger/types.ts but
wasn't re-exported from src/adapter-internals.ts. Provider adapter packages
consume internals only via the `@tanstack/ai/adapter-internals` subpath, so
without this re-export they couldn't reach the `Logger` type without an
ambient import that would break the encapsulation boundary.

Surfaced by the openai-base tests once `tsc` started checking tests.
---
 packages/typescript/ai/src/adapter-internals.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/packages/typescript/ai/src/adapter-internals.ts b/packages/typescript/ai/src/adapter-internals.ts
index 875ae9b4e..e8a5ac27c 100644
--- a/packages/typescript/ai/src/adapter-internals.ts
+++ b/packages/typescript/ai/src/adapter-internals.ts
@@ -4,5 +4,6 @@
 
 export type { ResolvedCategories } from './logger/internal-logger'
 export { InternalLogger } from './logger/internal-logger'
+export type { Logger } from './logger/types'
 export { resolveDebugOption } from './logger/resolve'
 export { toRunErrorPayload } from './activities/error-payload'

From 31bfa1cbd6205a18ef311e7c91b745d15c75b0b7 Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:37:34 +0200
Subject: [PATCH 06/17] test: fix type rot and unsafe casts surfaced by
 typecheck standardization
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Including tests in `tsc` (see the tsconfig commit) surfaced ~200 pre-existing
type errors across the test suite that had silently rotted as source types
evolved. This commit fixes them and tightens the remaining type assertions.

Patterns fixed:

- Stale model name literals (`claude-3-7-sonnet-20250219` →
  `claude-3-7-sonnet`, `grok-4-0709` → `grok-4`, `chatgpt-4.0` →
  `chatgpt-4o-latest`, etc.).
- EventType string literals replaced with the enum values from
  `@tanstack/ai`/`@ag-ui/core` in groq/grok/openai-base/openai tests.
- Removed/renamed provider option fields (`generationConfig.*` flattened
  onto top-level Gemini options; `system` removed from anthropic
  modelOptions tests).
- Required fields added to mock generation result objects (`id` on
  image/speech/transcription mocks, `id` + `usage` on summarize mocks)
  to satisfy GenerationFetcher result types.
- `MakeInputModalitiesTypes<['text', 'image', ...]>` wrappers and
  provider-typed content parts (`AnthropicTextPart`, `OpenAITextPart`,
  `GeminiImagePart`, etc.) plumbed into the model-meta tests.
- `tools` array entries replaced with typed `AnyClientTool` factories
  for the elevenlabs realtime tests.
- Cloudflare worker tests: 7 `as any` casts collapsed into a single
  `readJson<T>` helper with one trust-boundary cast and `Extract<>` types
  per response status arm.
- ai-react/ai-solid `useChat({ onToolCall })` tests: `onToolCall` is not
  a public UseChatOptions field — it's set internally by ChatClient via
  the `tools` array. Deleted one test of nonexistent behaviour and
  removed dead `onToolCall` options from two `addToolResult` tests.
- ai-react/ai-solid `useGeneration` tests: explicit generic arguments
  instead of `onResult ... as any`; `as const` on inline chunk arrays so
  StreamChunk literals infer with EventType enum values intact.
- ai-svelte `create-generation` tests: EventType enum + required fields
  on AGUIEvent shapes (`threadId` on RUN_STARTED/RUN_FINISHED, `message`
  on RUN_ERROR).
- openai-base tests now build a real `new OpenAI({ apiKey })` and
  monkey-patch a typed `MockChatCompletionCreate` / `MockResponsesCreate`
  signature instead of `as unknown as OpenAI`.

Remaining `as`-style casts in the touched files: 5 total, all at trust
boundaries with justification comments (Response.json() → typed shape;
discriminated-union narrowing for the schemaless useChat branch; AGUI
RUN_ERROR carrying both spec-shape `message` and legacy `error.message`).

`@ts-expect-error` is used in one place (audio-adapter.test.ts) for the
"unsupported model name is rejected" test, replacing an `as never` cast.

No production code changes other than:
- A new export of an existing `Logger` interface (separate commit).
- The anthropic modelOptions.system removal (separate commit).
---
 .../ai-anthropic/tests/model-meta.test.ts     | 148 +++++----
 .../typescript/ai-client/tests/test-utils.ts  |   2 +-
 .../tests/create-code-mode-tool.test.ts       |  30 +-
 .../ai-elevenlabs/tests/audio-adapter.test.ts |  19 +-
 .../tests/realtime-adapter.test.ts            | 109 ++++---
 .../ai-gemini/tests/gemini-adapter.test.ts    |  73 ++---
 .../ai-gemini/tests/image-adapter.test.ts     |   8 +-
 .../ai-gemini/tests/model-meta.test.ts        | 147 +++++----
 .../ai-grok/tests/grok-adapter.test.ts        |  17 +-
 .../ai-groq/tests/groq-adapter.test.ts        |  11 +-
 .../tests/isolate-driver.test.ts              |  22 +-
 .../tests/worker.test.ts                      |  53 ++-
 .../ai-openai/tests/image-adapter.test.ts     |  64 ++--
 .../ai-openai/tests/model-meta.test.ts        | 301 +++++++++---------
 .../ai-openai/tests/openai-adapter.test.ts    |   4 +-
 .../typescript/ai-react/tests/test-utils.ts   |   2 +-
 .../tests/use-chat-structured-output.test.ts  |  22 +-
 .../ai-react/tests/use-chat.test.ts           | 189 +++++------
 .../ai-react/tests/use-generation.test.ts     |  96 ++++--
 .../typescript/ai-solid/tests/test-utils.ts   |   2 +-
 .../ai-solid/tests/use-chat.test.ts           |  45 +--
 .../ai-solid/tests/use-generation.test.ts     |  89 ++++--
 .../ai-svelte/tests/create-generation.test.ts |  48 ++-
 .../ai-svelte/tests/use-chat.test.ts          |   2 +-
 ...mpletions-structured-output-stream.test.ts |  31 +-
 .../tests/chat-completions-text.test.ts       |  75 +++--
 ...responses-structured-output-stream.test.ts |  28 +-
 .../openai-base/tests/responses-text.test.ts  |  41 +--
 28 files changed, 962 insertions(+), 716 deletions(-)

diff --git a/packages/typescript/ai-anthropic/tests/model-meta.test.ts b/packages/typescript/ai-anthropic/tests/model-meta.test.ts
index 0caddc281..a5f7c5bfc 100644
--- a/packages/typescript/ai-anthropic/tests/model-meta.test.ts
+++ b/packages/typescript/ai-anthropic/tests/model-meta.test.ts
@@ -3,6 +3,7 @@ import type {
   AnthropicChatModelProviderOptionsByName,
   AnthropicModelInputModalitiesByName,
 } from '../src/model-meta'
+import type { AnthropicMessageMetadataByModality } from '../src/message-types'
 import type {
   AnthropicContainerOptions,
   AnthropicContextManagementOptions,
@@ -18,10 +19,20 @@ import type {
   ConstrainedModelMessage,
   DocumentPart,
   ImagePart,
+  Modality,
   TextPart,
   VideoPart,
 } from '@tanstack/ai'
 
+/**
+ * Helper type to construct InputModalitiesTypes from modalities array and metadata.
+ * This is used to properly type ConstrainedModelMessage in tests.
+ */
+type MakeInputModalitiesTypes<TModalities extends ReadonlyArray<Modality>> = {
+  inputModalities: TModalities
+  messageMetadataByModality: AnthropicMessageMetadataByModality
+}
+
 /**
  * Type assertion tests for Anthropic model provider options.
  *
@@ -531,166 +542,181 @@ describe('Anthropic Model Provider Options Type Assertions', () => {
  * No Claude models support: audio, video
  */
 describe('Anthropic Model Input Modality Type Assertions', () => {
-  // Helper type for creating a user message with specific content
+  // Helper type for creating a user message with specific content.
+  // Uses provider-specific metadata so that ConstrainedModelMessage extension
+  // checks succeed for the modalities this provider supports.
+  type AnthropicTextPart = TextPart<AnthropicMessageMetadataByModality['text']>
+  type AnthropicImagePart = ImagePart<
+    AnthropicMessageMetadataByModality['image']
+  >
+  type AnthropicAudioPart = AudioPart<
+    AnthropicMessageMetadataByModality['audio']
+  >
+  type AnthropicVideoPart = VideoPart<
+    AnthropicMessageMetadataByModality['video']
+  >
+  type AnthropicDocumentPart = DocumentPart<
+    AnthropicMessageMetadataByModality['document']
+  >
   type MessageWithContent<T> = { role: 'user'; content: Array<T> }
 
   describe('Claude Opus 4.5 (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-opus-4-5']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 
   describe('Claude Sonnet 4.6 (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-sonnet-4-6']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 
   describe('Claude Sonnet 4.5 (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-sonnet-4-5']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 
   describe('Claude Haiku 4.5 (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-haiku-4-5']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 
   describe('Claude Opus 4.1 (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-opus-4-1']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 
   describe('Claude Sonnet 4 (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-sonnet-4']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 
   describe('Claude 3.7 Sonnet (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-3-7-sonnet']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 
   describe('Claude Opus 4 (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-opus-4']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 
   describe('Claude 3.5 Haiku (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-3-5-haiku']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 
   describe('Claude 3 Haiku (text + image + document)', () => {
     type Modalities = AnthropicModelInputModalitiesByName['claude-3-haiku']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
     })
   })
 })
diff --git a/packages/typescript/ai-client/tests/test-utils.ts b/packages/typescript/ai-client/tests/test-utils.ts
index 1ee379303..20a728a8f 100644
--- a/packages/typescript/ai-client/tests/test-utils.ts
+++ b/packages/typescript/ai-client/tests/test-utils.ts
@@ -4,7 +4,7 @@ import type { UIMessage } from '../src/types'
 /**
  * Options for creating a mock connection adapter
  */
-interface MockConnectionAdapterOptions {
+export interface MockConnectionAdapterOptions {
   /**
    * Chunks to yield from the stream
    */
diff --git a/packages/typescript/ai-code-mode/tests/create-code-mode-tool.test.ts b/packages/typescript/ai-code-mode/tests/create-code-mode-tool.test.ts
index 831623103..978644f5d 100644
--- a/packages/typescript/ai-code-mode/tests/create-code-mode-tool.test.ts
+++ b/packages/typescript/ai-code-mode/tests/create-code-mode-tool.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it, vi, beforeEach } from 'vitest'
+import { describe, expect, it, vi } from 'vitest'
 import { z } from 'zod'
 import { toolDefinition } from '@tanstack/ai'
 import { createCodeModeTool } from '../src/create-code-mode-tool'
@@ -65,7 +65,7 @@ describe('createCodeModeTool', () => {
       tools: [createMockTool('fetchWeather')],
     })
 
-    await tool.execute({ typescriptCode: 'const x: string = "hi"\nreturn x' })
+    await tool.execute!({ typescriptCode: 'const x: string = "hi"\nreturn x' })
 
     expect(driver.createContext).toHaveBeenCalledTimes(1)
     const executeCall = (mockContext.execute as any).mock.calls[0][0]
@@ -88,7 +88,7 @@ describe('createCodeModeTool', () => {
       tools: [createMockTool('fetchWeather')],
     })
 
-    await tool.execute({ typescriptCode: 'return 1' })
+    await tool.execute!({ typescriptCode: 'return 1' })
 
     expect(mockContext.dispose).toHaveBeenCalledTimes(1)
   })
@@ -105,7 +105,7 @@ describe('createCodeModeTool', () => {
       tools: [createMockTool('fetchWeather')],
     })
 
-    const result = await tool.execute({ typescriptCode: 'return 42' })
+    const result = await tool.execute!({ typescriptCode: 'return 42' })
     expect(result).toEqual({
       success: true,
       result: { answer: 42 },
@@ -125,7 +125,7 @@ describe('createCodeModeTool', () => {
       tools: [createMockTool('fetchWeather')],
     })
 
-    const result = await tool.execute({ typescriptCode: 'return x' })
+    const result = await tool.execute!({ typescriptCode: 'return x' })
     expect(result.success).toBe(false)
     expect(result.error?.name).toBe('ReferenceError')
     expect(result.error?.message).toBe('x is not defined')
@@ -140,7 +140,7 @@ describe('createCodeModeTool', () => {
     })
 
     // Invalid syntax that esbuild will reject — stripTypeScript now throws
-    const result = await tool.execute({
+    const result = await tool.execute!({
       typescriptCode: 'const x: = invalid{{{syntax',
     })
     expect(result.success).toBe(false)
@@ -156,7 +156,7 @@ describe('createCodeModeTool', () => {
       tools: [createMockTool('fetchWeather')],
     })
 
-    await tool.execute({ typescriptCode: 'return 1' }, { emitCustomEvent })
+    await tool.execute!({ typescriptCode: 'return 1' }, { emitCustomEvent })
 
     expect(emitCustomEvent).toHaveBeenCalledWith(
       'code_mode:execution_started',
@@ -180,29 +180,29 @@ describe('createCodeModeTool', () => {
       tools: [createMockTool('fetchWeather')],
     })
 
-    await tool.execute({ typescriptCode: 'return null' }, { emitCustomEvent })
+    await tool.execute!({ typescriptCode: 'return null' }, { emitCustomEvent })
 
     const consoleEvents = emitCustomEvent.mock.calls.filter(
       (c: any) => c[0] === 'code_mode:console',
     )
 
     expect(consoleEvents).toHaveLength(4)
-    expect(consoleEvents[0][1]).toEqual(
+    expect(consoleEvents[0]![1]).toEqual(
       expect.objectContaining({ level: 'log', message: 'hello' }),
     )
-    expect(consoleEvents[1][1]).toEqual(
+    expect(consoleEvents[1]![1]).toEqual(
       expect.objectContaining({ level: 'error', message: 'bad' }),
     )
-    expect(consoleEvents[2][1]).toEqual(
+    expect(consoleEvents[2]![1]).toEqual(
       expect.objectContaining({ level: 'warn', message: 'careful' }),
     )
-    expect(consoleEvents[3][1]).toEqual(
+    expect(consoleEvents[3]![1]).toEqual(
       expect.objectContaining({ level: 'info', message: 'fyi' }),
     )
   })
 
   it('getSkillBindings merges dynamic bindings into context', async () => {
-    const { driver, mockContext } = createMockDriver()
+    const { driver } = createMockDriver()
 
     const skillBinding = {
       name: 'skill_greet',
@@ -217,7 +217,7 @@ describe('createCodeModeTool', () => {
       getSkillBindings: async () => ({ skill_greet: skillBinding }),
     })
 
-    await tool.execute({ typescriptCode: 'return 1' })
+    await tool.execute!({ typescriptCode: 'return 1' })
 
     const contextConfig = (driver.createContext as any).mock.calls[0][0]
     expect(contextConfig.bindings).toHaveProperty('skill_greet')
@@ -231,7 +231,7 @@ describe('createCodeModeTool', () => {
       tools: [createMockTool('fetchWeather')],
     })
 
-    const result = await tool.execute({ typescriptCode: '' })
+    const result = await tool.execute!({ typescriptCode: '' })
     expect(result.success).toBe(false)
     expect(result.error?.name).toBe('ValidationError')
   })
diff --git a/packages/typescript/ai-elevenlabs/tests/audio-adapter.test.ts b/packages/typescript/ai-elevenlabs/tests/audio-adapter.test.ts
index af4988251..46e942f4b 100644
--- a/packages/typescript/ai-elevenlabs/tests/audio-adapter.test.ts
+++ b/packages/typescript/ai-elevenlabs/tests/audio-adapter.test.ts
@@ -1,5 +1,5 @@
 import { beforeEach, describe, expect, it, vi } from 'vitest'
-import type { AudioGenerationOptions } from '@tanstack/ai'
+import { resolveDebugOption } from '@tanstack/ai/adapter-internals'
 
 const composeMock = vi.fn()
 const sfxConvertMock = vi.fn()
@@ -13,13 +13,13 @@ vi.mock('@elevenlabs/elevenlabs-js', () => ({
 
 import { elevenlabsAudio } from '../src/adapters/audio'
 
+/**
+ * Build a real `InternalLogger` so tests run against the actual logging API
+ * surface (`request`, `provider`, `errors`, etc.) rather than a hand-crafted
+ * stub. Tests that need to observe a category call should `vi.spyOn` it.
+ */
 function makeLogger() {
-  return {
-    request: vi.fn(),
-    response: vi.fn(),
-    provider: vi.fn(),
-    errors: vi.fn(),
-  } as unknown as AudioGenerationOptions['logger']
+  return resolveDebugOption(false)
 }
 
 function makeStream(bytes: Uint8Array): ReadableStream<Uint8Array> {
@@ -151,8 +151,11 @@ describe('elevenlabsAudio adapter — unknown model', () => {
   })
 
   it('throws a helpful error for unrecognized models', async () => {
+    // @ts-expect-error - testing runtime rejection of unknown model;
+    // the public signature constrains model to ElevenLabsAudioModel.
     const adapter = elevenlabsAudio('not-a-real-model', { apiKey: 'k' })
     const logger = makeLogger()
+    const errorsSpy = vi.spyOn(logger, 'errors')
     await expect(
       adapter.generateAudio({
         model: 'not-a-real-model',
@@ -160,6 +163,6 @@ describe('elevenlabsAudio adapter — unknown model', () => {
         logger,
       }),
     ).rejects.toThrow(/Unsupported ElevenLabs audio model/i)
-    expect(logger.errors).toHaveBeenCalled()
+    expect(errorsSpy).toHaveBeenCalled()
   })
 })
diff --git a/packages/typescript/ai-elevenlabs/tests/realtime-adapter.test.ts b/packages/typescript/ai-elevenlabs/tests/realtime-adapter.test.ts
index a4cbb8a4a..37c9ba79b 100644
--- a/packages/typescript/ai-elevenlabs/tests/realtime-adapter.test.ts
+++ b/packages/typescript/ai-elevenlabs/tests/realtime-adapter.test.ts
@@ -1,13 +1,24 @@
 import { describe, expect, it, vi, beforeEach } from 'vitest'
 import type { RealtimeConnection } from '@tanstack/ai-client'
-import type { AnyClientTool, RealtimeMessage } from '@tanstack/ai'
+import type { AnyClientTool, JSONSchema, RealtimeMessage } from '@tanstack/ai'
+
+/**
+ * Captured `startSession` argument shape. Only the fields the realtime
+ * adapter actually sets on the session-options bag are listed; tests
+ * `expect(...).toBeUndefined()` against absent keys, so optional is fine.
+ */
+type CapturedSessionOptions = {
+  onConnect?: () => void
+  onMessage?: (msg: { message: string; source: 'user' | 'ai' }) => void
+  clientTools?: Record<string, (params: Record<string, unknown>) => unknown>
+}
 
 // Capture the session options passed to Conversation.startSession
-let capturedSessionOptions: Record<string, any> = {}
+let capturedSessionOptions: CapturedSessionOptions = {}
 
 vi.mock('@elevenlabs/client', () => ({
   Conversation: {
-    startSession: vi.fn(async (options: Record<string, any>) => {
+    startSession: vi.fn(async (options: CapturedSessionOptions) => {
       capturedSessionOptions = options
       // Call onConnect to simulate connection established
       options.onConnect?.()
@@ -31,9 +42,11 @@ describe('elevenlabsRealtime adapter', () => {
   })
 
   const fakeToken = {
+    provider: 'elevenlabs',
     token: 'wss://fake-signed-url',
     expiresAt: Date.now() + 60_000,
-  }
+    config: {},
+  } as const
 
   async function createConnection(
     tools?: ReadonlyArray<AnyClientTool>,
@@ -43,25 +56,28 @@ describe('elevenlabsRealtime adapter', () => {
   }
 
   describe('onMessage duplicate user messages', () => {
+    type TranscriptEvent = {
+      role: string
+      transcript: string
+      isFinal: boolean
+    }
+    type MessageCompleteEvent = { message: RealtimeMessage }
+
     it('should emit only transcript for user messages, not message_complete', async () => {
       const connection = await createConnection()
 
-      const transcriptEvents: Array<{
-        role: string
-        transcript: string
-        isFinal: boolean
-      }> = []
-      const messageCompleteEvents: Array<{ message: RealtimeMessage }> = []
+      const transcriptEvents: Array<TranscriptEvent> = []
+      const messageCompleteEvents: Array<MessageCompleteEvent> = []
 
       connection.on('transcript', (payload) => {
-        transcriptEvents.push(payload as any)
+        transcriptEvents.push(payload)
       })
       connection.on('message_complete', (payload) => {
-        messageCompleteEvents.push(payload as any)
+        messageCompleteEvents.push(payload)
       })
 
       // Simulate a user message from ElevenLabs
-      capturedSessionOptions.onMessage({
+      capturedSessionOptions.onMessage!({
         message: 'Hello from user',
         source: 'user',
       })
@@ -82,22 +98,18 @@ describe('elevenlabsRealtime adapter', () => {
     it('should emit only message_complete for assistant messages, not transcript', async () => {
       const connection = await createConnection()
 
-      const transcriptEvents: Array<{
-        role: string
-        transcript: string
-        isFinal: boolean
-      }> = []
-      const messageCompleteEvents: Array<{ message: RealtimeMessage }> = []
+      const transcriptEvents: Array<TranscriptEvent> = []
+      const messageCompleteEvents: Array<MessageCompleteEvent> = []
 
       connection.on('transcript', (payload) => {
-        transcriptEvents.push(payload as any)
+        transcriptEvents.push(payload)
       })
       connection.on('message_complete', (payload) => {
-        messageCompleteEvents.push(payload as any)
+        messageCompleteEvents.push(payload)
       })
 
       // Simulate an assistant message from ElevenLabs
-      capturedSessionOptions.onMessage({
+      capturedSessionOptions.onMessage!({
         message: 'Hello from assistant',
         source: 'ai',
       })
@@ -117,8 +129,8 @@ describe('elevenlabsRealtime adapter', () => {
     it('should not produce duplicate messages when both user and assistant speak', async () => {
       const connection = await createConnection()
 
-      const transcriptEvents: Array<any> = []
-      const messageCompleteEvents: Array<any> = []
+      const transcriptEvents: Array<TranscriptEvent> = []
+      const messageCompleteEvents: Array<MessageCompleteEvent> = []
 
       connection.on('transcript', (payload) => transcriptEvents.push(payload))
       connection.on('message_complete', (payload) =>
@@ -126,36 +138,59 @@ describe('elevenlabsRealtime adapter', () => {
       )
 
       // User speaks, then assistant responds
-      capturedSessionOptions.onMessage({
+      capturedSessionOptions.onMessage!({
         message: 'What is the weather?',
         source: 'user',
       })
-      capturedSessionOptions.onMessage({
+      capturedSessionOptions.onMessage!({
         message: 'It is sunny today.',
         source: 'ai',
       })
 
       // One transcript event (user only)
       expect(transcriptEvents).toHaveLength(1)
-      expect(transcriptEvents[0].role).toBe('user')
+      expect(transcriptEvents[0]!.role).toBe('user')
 
       // One message_complete event (assistant only)
       expect(messageCompleteEvents).toHaveLength(1)
-      expect(messageCompleteEvents[0].message.role).toBe('assistant')
+      expect(messageCompleteEvents[0]!.message.role).toBe('assistant')
     })
   })
 
   describe('clientTools registration', () => {
+    /**
+     * Build a fully-typed `AnyClientTool` for tests. Returns a `ClientTool`
+     * (the `__toolSide: 'client'` branch of `AnyClientTool`) so it satisfies
+     * the union shape `connect()` expects without resorting to `as`.
+     */
+    function createMockClientTool(args: {
+      name: string
+      description?: string
+      inputSchema?: JSONSchema
+      execute: (input: Record<string, unknown>) => unknown | Promise<unknown>
+    }): AnyClientTool {
+      return {
+        __toolSide: 'client',
+        name: args.name,
+        description: args.description ?? '',
+        inputSchema: args.inputSchema,
+        execute: args.execute,
+      }
+    }
+
     it('should pass client tools as plain functions to @elevenlabs/client', async () => {
-      const mockTool: AnyClientTool = {
+      const executeMock = vi.fn(
+        async (params: Record<string, unknown>) => `Sunny in ${params.city}`,
+      )
+      const mockTool = createMockClientTool({
         name: 'get_weather',
         description: 'Get current weather',
         inputSchema: {
           type: 'object',
           properties: { city: { type: 'string' } },
-        } as any,
-        execute: vi.fn(async (params: any) => `Sunny in ${params.city}`),
-      }
+        },
+        execute: executeMock,
+      })
 
       await createConnection([mockTool])
 
@@ -165,22 +200,22 @@ describe('elevenlabsRealtime adapter', () => {
       expect(typeof registeredTool).toBe('function')
 
       // Calling the function directly should invoke the tool's execute
-      const result = await registeredTool({ city: 'Seattle' })
+      const result = await registeredTool!({ city: 'Seattle' })
       expect(result).toBe('Sunny in Seattle')
-      expect(mockTool.execute).toHaveBeenCalledWith({ city: 'Seattle' })
+      expect(executeMock).toHaveBeenCalledWith({ city: 'Seattle' })
     })
 
     it('should JSON-stringify non-string tool results', async () => {
-      const mockTool: AnyClientTool = {
+      const mockTool = createMockClientTool({
         name: 'get_data',
         description: 'Get data',
         execute: vi.fn(async () => ({ temp: 72, unit: 'F' })),
-      }
+      })
 
       await createConnection([mockTool])
 
       const registeredTool = capturedSessionOptions.clientTools?.get_data
-      const result = await registeredTool({})
+      const result = await registeredTool!({})
       expect(result).toBe(JSON.stringify({ temp: 72, unit: 'F' }))
     })
 
diff --git a/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts b/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts
index b894da9f3..9f4a574e5 100644
--- a/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts
+++ b/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts
@@ -112,7 +112,7 @@ describe('GeminiAdapter through AI', () => {
     }
 
     expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]
+    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]!
     expect(payload.model).toBe('gemini-2.5-pro')
     expect(payload.config).toMatchObject({
       temperature: 0.4,
@@ -171,34 +171,32 @@ describe('GeminiAdapter through AI', () => {
 
     const providerOptions: GeminiTextProviderOptions = {
       safetySettings,
-      generationConfig: {
-        stopSequences: ['<done>', '###'],
-        responseMimeType: 'application/json',
-        responseSchema,
-        responseJsonSchema,
-        responseModalities: ['TEXT'],
-        candidateCount: 2,
-        topK: 6,
-        seed: 7,
-        presencePenalty: 0.2,
-        frequencyPenalty: 0.4,
-        responseLogprobs: true,
-        logprobs: 3,
-        enableEnhancedCivicAnswers: true,
-        speechConfig: {
-          voiceConfig: {
-            prebuiltVoiceConfig: {
-              voiceName: 'Studio',
-            },
+      stopSequences: ['<done>', '###'],
+      responseMimeType: 'application/json',
+      responseSchema,
+      responseJsonSchema,
+      responseModalities: ['TEXT'],
+      candidateCount: 2,
+      topK: 6,
+      seed: 7,
+      presencePenalty: 0.2,
+      frequencyPenalty: 0.4,
+      responseLogprobs: true,
+      logprobs: 3,
+      enableEnhancedCivicAnswers: true,
+      speechConfig: {
+        voiceConfig: {
+          prebuiltVoiceConfig: {
+            voiceName: 'Studio',
           },
         },
-        thinkingConfig: {
-          includeThoughts: true,
-          thinkingBudget: 128,
-        },
-        imageConfig: {
-          aspectRatio: '1:1',
-        },
+      },
+      thinkingConfig: {
+        includeThoughts: true,
+        thinkingBudget: 128,
+      },
+      imageConfig: {
+        aspectRatio: '1:1',
       },
       cachedContent: 'cachedContents/weather-context',
     } as const
@@ -219,7 +217,7 @@ describe('GeminiAdapter through AI', () => {
     }
 
     expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]
+    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]!
     const config = payload.config
 
     expect(config.temperature).toBe(0.61)
@@ -295,7 +293,7 @@ describe('GeminiAdapter through AI', () => {
     }
 
     expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(1)
-    const [streamPayload] = mocks.generateContentStreamSpy.mock.calls[0]
+    const [streamPayload] = mocks.generateContentStreamSpy.mock.calls[0]!
     expect(streamPayload.config?.topK).toBe(3)
 
     // AG-UI events: RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT..., TEXT_MESSAGE_END, RUN_FINISHED
@@ -376,7 +374,7 @@ describe('GeminiAdapter through AI', () => {
     }
 
     expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]
+    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]!
 
     // Tool result (user) and follow-up user message should be merged
     const roles = payload.contents.map((m: any) => m.role)
@@ -478,7 +476,7 @@ describe('GeminiAdapter through AI', () => {
     }
 
     expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]
+    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]!
 
     // No consecutive same-role messages
     const roles = payload.contents.map((m: any) => m.role)
@@ -569,7 +567,10 @@ describe('GeminiAdapter through AI', () => {
       tools: [sumTool],
       messages: [{ role: 'user', content: 'What is 1 + 2 + 5?' }],
       modelOptions: {
-        thinkingConfig: { includeThoughts: true, thinkingLevel: 'LOW' },
+        thinkingConfig: {
+          includeThoughts: true,
+          thinkingLevel: 'LOW',
+        },
       },
     })) {
       /* consume stream */
@@ -578,7 +579,7 @@ describe('GeminiAdapter through AI', () => {
     expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(2)
 
     // Inspect the second call's payload (the turn that includes history)
-    const [secondPayload] = mocks.generateContentStreamSpy.mock.calls[1]
+    const [secondPayload] = mocks.generateContentStreamSpy.mock.calls[1]!
     const modelTurn = secondPayload.contents.find(
       (c: any) => c.role === 'model',
     )
@@ -662,7 +663,7 @@ describe('GeminiAdapter through AI', () => {
 
     expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(2)
 
-    const [secondPayload] = mocks.generateContentStreamSpy.mock.calls[1]
+    const [secondPayload] = mocks.generateContentStreamSpy.mock.calls[1]!
     const modelTurn = secondPayload.contents.find(
       (c: any) => c.role === 'model',
     )
@@ -741,7 +742,7 @@ describe('GeminiAdapter through AI', () => {
 
     expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(2)
 
-    const [secondPayload] = mocks.generateContentStreamSpy.mock.calls[1]
+    const [secondPayload] = mocks.generateContentStreamSpy.mock.calls[1]!
     const userTurn = secondPayload.contents.find((c: any) =>
       c.parts?.some((p: any) => p.functionResponse),
     )
@@ -785,7 +786,7 @@ describe('GeminiAdapter through AI', () => {
     })
 
     expect(mocks.generateContentStreamSpy).toHaveBeenCalledTimes(1)
-    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]
+    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]!
     expect(payload.model).toBe('gemini-2.0-flash')
     expect(payload.config.systemInstruction).toContain(
       'professional summarizer',
diff --git a/packages/typescript/ai-gemini/tests/image-adapter.test.ts b/packages/typescript/ai-gemini/tests/image-adapter.test.ts
index 4eb4192f6..e250ac788 100644
--- a/packages/typescript/ai-gemini/tests/image-adapter.test.ts
+++ b/packages/typescript/ai-gemini/tests/image-adapter.test.ts
@@ -209,7 +209,7 @@ describe('Gemini Image Adapter', () => {
 
       expect(result.model).toBe('imagen-3.0-generate-002')
       expect(result.images).toHaveLength(1)
-      expect(result.images[0].b64Json).toBe('base64encodedimage')
+      expect(result.images[0]!.b64Json).toBe('base64encodedimage')
     })
 
     it('generates a unique ID for each response', async () => {
@@ -305,7 +305,7 @@ describe('Gemini Image Adapter', () => {
 
       expect(result.model).toBe('gemini-3.1-flash-image-preview')
       expect(result.images).toHaveLength(1)
-      expect(result.images[0].b64Json).toBe('gemini-base64-image')
+      expect(result.images[0]!.b64Json).toBe('gemini-base64-image')
     })
 
     it('calls generateContent without imageConfig when no size provided', async () => {
@@ -532,8 +532,8 @@ describe('Gemini Image Adapter', () => {
 
       // Collects all inlineData parts, skipping text parts
       expect(result.images).toHaveLength(2)
-      expect(result.images[0].b64Json).toBe('img1')
-      expect(result.images[1].b64Json).toBe('img2')
+      expect(result.images[0]!.b64Json).toBe('img1')
+      expect(result.images[1]!.b64Json).toBe('img2')
     })
 
     it('does not augment prompt when numberOfImages is 1', async () => {
diff --git a/packages/typescript/ai-gemini/tests/model-meta.test.ts b/packages/typescript/ai-gemini/tests/model-meta.test.ts
index d843abe7a..305533358 100644
--- a/packages/typescript/ai-gemini/tests/model-meta.test.ts
+++ b/packages/typescript/ai-gemini/tests/model-meta.test.ts
@@ -12,15 +12,25 @@ import type {
   GeminiCommonConfigOptions,
   GeminiCachedContentOptions,
 } from '../src/text/text-provider-options'
+import type { GeminiMessageMetadataByModality } from '../src/message-types'
 import type {
   AudioPart,
   ConstrainedModelMessage,
   DocumentPart,
   ImagePart,
+  Modality,
   TextPart,
   VideoPart,
 } from '@tanstack/ai'
 
+/**
+ * Helper type to construct InputModalitiesTypes from modalities array and metadata.
+ */
+type MakeInputModalitiesTypes<TModalities extends ReadonlyArray<Modality>> = {
+  inputModalities: TModalities
+  messageMetadataByModality: GeminiMessageMetadataByModality
+}
+
 /**
  * Type assertion tests for Gemini model provider options.
  *
@@ -53,7 +63,7 @@ describe('Gemini Model Provider Options Type Assertions', () => {
       expectTypeOf<Options>().toExtend<BaseOptions>()
 
       // Verify specific properties exist
-      expectTypeOf<Options>().toHaveProperty('generationConfig')
+      expectTypeOf<Options>().toHaveProperty('stopSequences')
       expectTypeOf<Options>().toHaveProperty('safetySettings')
       expectTypeOf<Options>().toHaveProperty('toolConfig')
       expectTypeOf<Options>().toHaveProperty('cachedContent')
@@ -75,7 +85,7 @@ describe('Gemini Model Provider Options Type Assertions', () => {
       expectTypeOf<Options>().toExtend<BaseOptions>()
 
       // Verify specific properties exist
-      expectTypeOf<Options>().toHaveProperty('generationConfig')
+      expectTypeOf<Options>().toHaveProperty('stopSequences')
       expectTypeOf<Options>().toHaveProperty('safetySettings')
       expectTypeOf<Options>().toHaveProperty('toolConfig')
       expectTypeOf<Options>().toHaveProperty('cachedContent')
@@ -167,7 +177,7 @@ describe('Gemini Model Provider Options Type Assertions', () => {
       expectTypeOf<Options>().toExtend<BaseOptions>()
 
       // Verify specific properties exist
-      expectTypeOf<Options>().toHaveProperty('generationConfig')
+      expectTypeOf<Options>().toHaveProperty('stopSequences')
       expectTypeOf<Options>().toHaveProperty('safetySettings')
       expectTypeOf<Options>().toHaveProperty('toolConfig')
       expectTypeOf<Options>().toHaveProperty('cachedContent')
@@ -235,7 +245,7 @@ describe('Gemini Model Provider Options Type Assertions', () => {
 
       // The generationConfig should include thinkingConfig from GeminiCommonConfigOptions
       // which intersects with GeminiThinkingOptions
-      expectTypeOf<Options>().toHaveProperty('generationConfig')
+      expectTypeOf<Options>().toHaveProperty('stopSequences')
     })
 
     it('structured output options should have responseMimeType and responseSchema', () => {
@@ -436,88 +446,95 @@ describe('Gemini Model Provider Options Type Assertions', () => {
  * - gemini-2.0-flash (and lite)
  */
 describe('Gemini Model Input Modality Type Assertions', () => {
-  // Helper type for creating a user message with specific content
+  // Helper types using provider-specific metadata.
+  type GeminiTextPart = TextPart<GeminiMessageMetadataByModality['text']>
+  type GeminiImagePart = ImagePart<GeminiMessageMetadataByModality['image']>
+  type GeminiAudioPart = AudioPart<GeminiMessageMetadataByModality['audio']>
+  type GeminiVideoPart = VideoPart<GeminiMessageMetadataByModality['video']>
+  type GeminiDocumentPart = DocumentPart<
+    GeminiMessageMetadataByModality['document']
+  >
   type MessageWithContent<T> = { role: 'user'; content: Array<T> }
 
   // ===== Full Multimodal Models (text + image + audio + video + document) =====
 
   describe('gemini-3-pro-preview (full multimodal)', () => {
     type Modalities = GeminiModelInputModalitiesByName['gemini-3-pro-preview']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow all content part types', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().toExtend<Message>()
     })
   })
 
   describe('gemini-3-flash-preview (full multimodal)', () => {
     type Modalities = GeminiModelInputModalitiesByName['gemini-3-flash-preview']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow all content part types', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().toExtend<Message>()
     })
   })
 
   describe('gemini-2.5-pro (full multimodal)', () => {
     type Modalities = GeminiModelInputModalitiesByName['gemini-2.5-pro']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow all content part types', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().toExtend<Message>()
     })
   })
 
   describe('gemini-3.1-flash-lite-preview (full multimodal)', () => {
     type Modalities =
       GeminiModelInputModalitiesByName['gemini-3.1-flash-lite-preview']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow all content part types', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().toExtend<Message>()
     })
   })
 
   describe('gemini-2.5-flash-lite (full multimodal)', () => {
     type Modalities = GeminiModelInputModalitiesByName['gemini-2.5-flash-lite']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow all content part types', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().toExtend<Message>()
     })
   })
 
   describe('gemini-2.5-flash-lite-preview-09-2025 (full multimodal)', () => {
     type Modalities =
       GeminiModelInputModalitiesByName['gemini-2.5-flash-lite-preview-09-2025']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow all content part types', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().toExtend<Message>()
     })
   })
 
@@ -525,66 +542,66 @@ describe('Gemini Model Input Modality Type Assertions', () => {
 
   describe('gemini-2.5-flash (no document)', () => {
     type Modalities = GeminiModelInputModalitiesByName['gemini-2.5-flash']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, AudioPart, and VideoPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
     })
 
     it('should NOT allow DocumentPart', () => {
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().not.toExtend<Message>()
     })
   })
 
   describe('gemini-2.5-flash-preview-09-2025 (no document)', () => {
     type Modalities =
       GeminiModelInputModalitiesByName['gemini-2.5-flash-preview-09-2025']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, AudioPart, and VideoPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
     })
 
     it('should NOT allow DocumentPart', () => {
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().not.toExtend<Message>()
     })
   })
 
   describe('gemini-2.0-flash (no document)', () => {
     type Modalities = GeminiModelInputModalitiesByName['gemini-2.0-flash']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, AudioPart, and VideoPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
     })
 
     it('should NOT allow DocumentPart', () => {
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().not.toExtend<Message>()
     })
   })
 
   describe('gemini-2.0-flash-lite (no document)', () => {
     type Modalities = GeminiModelInputModalitiesByName['gemini-2.0-flash-lite']
-    type Message = ConstrainedModelMessage<Modalities>
+    type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart, ImagePart, AudioPart, and VideoPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiTextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiAudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiVideoPart>>().toExtend<Message>()
     })
 
     it('should NOT allow DocumentPart', () => {
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().not.toExtend<Message>()
     })
   })
 })
diff --git a/packages/typescript/ai-grok/tests/grok-adapter.test.ts b/packages/typescript/ai-grok/tests/grok-adapter.test.ts
index 2f6f2741c..9ff697753 100644
--- a/packages/typescript/ai-grok/tests/grok-adapter.test.ts
+++ b/packages/typescript/ai-grok/tests/grok-adapter.test.ts
@@ -3,6 +3,7 @@ import { resolveDebugOption } from '@tanstack/ai/adapter-internals'
 import { createGrokText, grokText } from '../src/adapters/text'
 import { createGrokImage, grokImage } from '../src/adapters/image'
 import { createGrokSummarize, grokSummarize } from '../src/adapters/summarize'
+import { EventType } from '@tanstack/ai'
 import type { StreamChunk, Tool } from '@tanstack/ai'
 
 // Test helper: a silent logger for test chatStream calls.
@@ -85,11 +86,11 @@ describe('Grok adapters', () => {
     it('creates a text adapter from environment variable', () => {
       vi.stubEnv('XAI_API_KEY', 'env-api-key')
 
-      const adapter = grokText('grok-4-0709')
+      const adapter = grokText('grok-4')
 
       expect(adapter).toBeDefined()
       expect(adapter.kind).toBe('text')
-      expect(adapter.model).toBe('grok-4-0709')
+      expect(adapter.model).toBe('grok-4')
     })
 
     it('throws if XAI_API_KEY is not set when using grokText', () => {
@@ -148,7 +149,7 @@ describe('Grok adapters', () => {
     it('creates a summarize adapter from environment variable', () => {
       vi.stubEnv('XAI_API_KEY', 'env-api-key')
 
-      const adapter = grokSummarize('grok-4-0709')
+      const adapter = grokSummarize('grok-4')
 
       expect(adapter).toBeDefined()
       expect(adapter.kind).toBe('summarize')
@@ -490,7 +491,7 @@ describe('Grok AG-UI event emission', () => {
     const runErrorChunk = chunks.find((c) => c.type === 'RUN_ERROR')
     expect(runErrorChunk).toBeDefined()
     if (runErrorChunk?.type === 'RUN_ERROR') {
-      expect(runErrorChunk.error.message).toBe('Stream interrupted')
+      expect(runErrorChunk.error!.message).toBe('Stream interrupted')
     }
   })
 
@@ -542,14 +543,14 @@ describe('Grok AG-UI event emission', () => {
     expect(eventTypes[0]).toBe('RUN_STARTED')
 
     // Should have TEXT_MESSAGE_START before TEXT_MESSAGE_CONTENT
-    const textStartIndex = eventTypes.indexOf('TEXT_MESSAGE_START')
-    const textContentIndex = eventTypes.indexOf('TEXT_MESSAGE_CONTENT')
+    const textStartIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_START)
+    const textContentIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_CONTENT)
     expect(textStartIndex).toBeGreaterThan(-1)
     expect(textContentIndex).toBeGreaterThan(textStartIndex)
 
     // Should have TEXT_MESSAGE_END before RUN_FINISHED
-    const textEndIndex = eventTypes.indexOf('TEXT_MESSAGE_END')
-    const runFinishedIndex = eventTypes.indexOf('RUN_FINISHED')
+    const textEndIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_END)
+    const runFinishedIndex = eventTypes.indexOf(EventType.RUN_FINISHED)
     expect(textEndIndex).toBeGreaterThan(-1)
     expect(runFinishedIndex).toBeGreaterThan(textEndIndex)
 
diff --git a/packages/typescript/ai-groq/tests/groq-adapter.test.ts b/packages/typescript/ai-groq/tests/groq-adapter.test.ts
index f09944346..42e8cfb97 100644
--- a/packages/typescript/ai-groq/tests/groq-adapter.test.ts
+++ b/packages/typescript/ai-groq/tests/groq-adapter.test.ts
@@ -12,6 +12,7 @@ import {
   createGroqText as _realCreateGroqText,
   groqText as _realGroqText,
 } from '../src/adapters/text'
+import { EventType } from '@tanstack/ai'
 import type { StreamChunk, Tool } from '@tanstack/ai'
 
 // Test helper: a silent logger for test chatStream calls.
@@ -471,7 +472,7 @@ describe('Groq AG-UI event emission', () => {
     const runErrorChunk = chunks.find((c) => c.type === 'RUN_ERROR')
     expect(runErrorChunk).toBeDefined()
     if (runErrorChunk?.type === 'RUN_ERROR') {
-      expect(runErrorChunk.error.message).toBe('Stream interrupted')
+      expect(runErrorChunk.error!.message).toBe('Stream interrupted')
     }
   })
 
@@ -525,14 +526,14 @@ describe('Groq AG-UI event emission', () => {
     expect(eventTypes[0]).toBe('RUN_STARTED')
 
     // Should have TEXT_MESSAGE_START before TEXT_MESSAGE_CONTENT
-    const textStartIndex = eventTypes.indexOf('TEXT_MESSAGE_START')
-    const textContentIndex = eventTypes.indexOf('TEXT_MESSAGE_CONTENT')
+    const textStartIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_START)
+    const textContentIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_CONTENT)
     expect(textStartIndex).toBeGreaterThan(-1)
     expect(textContentIndex).toBeGreaterThan(textStartIndex)
 
     // Should have TEXT_MESSAGE_END before RUN_FINISHED
-    const textEndIndex = eventTypes.indexOf('TEXT_MESSAGE_END')
-    const runFinishedIndex = eventTypes.indexOf('RUN_FINISHED')
+    const textEndIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_END)
+    const runFinishedIndex = eventTypes.indexOf(EventType.RUN_FINISHED)
     expect(textEndIndex).toBeGreaterThan(-1)
     expect(runFinishedIndex).toBeGreaterThan(textEndIndex)
 
diff --git a/packages/typescript/ai-isolate-cloudflare/tests/isolate-driver.test.ts b/packages/typescript/ai-isolate-cloudflare/tests/isolate-driver.test.ts
index 2c97c9a7b..e64d65c41 100644
--- a/packages/typescript/ai-isolate-cloudflare/tests/isolate-driver.test.ts
+++ b/packages/typescript/ai-isolate-cloudflare/tests/isolate-driver.test.ts
@@ -83,7 +83,7 @@ describe('createCloudflareIsolateDriver', () => {
       expect(result.logs).toEqual(['hello'])
 
       expect(fetchMock).toHaveBeenCalledTimes(1)
-      const [url, options] = fetchMock.mock.calls[0]
+      const [url, options] = fetchMock.mock.calls[0]!
       expect(url).toBe(WORKER_URL)
       expect(options.method).toBe('POST')
       expect(options.headers['Content-Type']).toBe('application/json')
@@ -117,7 +117,7 @@ describe('createCloudflareIsolateDriver', () => {
 
       await context.execute('return 1')
 
-      const body: ExecuteRequest = JSON.parse(fetchMock.mock.calls[0][1].body)
+      const body: ExecuteRequest = JSON.parse(fetchMock.mock.calls[0]![1].body)
       expect(body.timeout).toBe(10000)
     })
   })
@@ -170,7 +170,7 @@ describe('createCloudflareIsolateDriver', () => {
 
       await context.execute('return 1')
 
-      const headers = fetchMock.mock.calls[0][1].headers
+      const headers = fetchMock.mock.calls[0]![1].headers
       expect(headers).not.toHaveProperty('Authorization')
     })
   })
@@ -222,13 +222,13 @@ describe('createCloudflareIsolateDriver', () => {
       expect(fetchMock).toHaveBeenCalledTimes(2)
 
       // First request: code + tools, no toolResults
-      const body1: ExecuteRequest = JSON.parse(fetchMock.mock.calls[0][1].body)
+      const body1: ExecuteRequest = JSON.parse(fetchMock.mock.calls[0]![1].body)
       expect(body1.toolResults).toBeUndefined()
       expect(body1.tools).toHaveLength(1)
-      expect(body1.tools[0].name).toBe('add')
+      expect(body1.tools[0]!.name).toBe('add')
 
       // Second request: same code + tools + toolResults
-      const body2: ExecuteRequest = JSON.parse(fetchMock.mock.calls[1][1].body)
+      const body2: ExecuteRequest = JSON.parse(fetchMock.mock.calls[1]![1].body)
       expect(body2.toolResults).toBeDefined()
       expect(body2.toolResults!['add_1']).toEqual({ success: true, value: 5 })
     })
@@ -292,7 +292,7 @@ describe('createCloudflareIsolateDriver', () => {
       expect(fetchMock).toHaveBeenCalledTimes(3)
 
       // Round 3 body MUST include both tc_0 and tc_1 (regression guard)
-      const body3: ExecuteRequest = JSON.parse(fetchMock.mock.calls[2][1].body)
+      const body3: ExecuteRequest = JSON.parse(fetchMock.mock.calls[2]![1].body)
       expect(body3.toolResults!['tc_0']).toEqual({ success: true, value: 'a' })
       expect(body3.toolResults!['tc_1']).toEqual({ success: true, value: 'b' })
     })
@@ -338,7 +338,7 @@ describe('createCloudflareIsolateDriver', () => {
       expect(result.success).toBe(true)
       expect(result.value).toBe('AB')
 
-      const body2: ExecuteRequest = JSON.parse(fetchMock.mock.calls[1][1].body)
+      const body2: ExecuteRequest = JSON.parse(fetchMock.mock.calls[1]![1].body)
       expect(body2.toolResults!['getA_1']).toEqual({
         success: true,
         value: 'A',
@@ -383,7 +383,7 @@ describe('createCloudflareIsolateDriver', () => {
 
       await context.execute('await failTool({})')
 
-      const body2: ExecuteRequest = JSON.parse(fetchMock.mock.calls[1][1].body)
+      const body2: ExecuteRequest = JSON.parse(fetchMock.mock.calls[1]![1].body)
       expect(body2.toolResults!['failTool_1']).toEqual({
         success: false,
         error: 'Tool failed',
@@ -416,9 +416,9 @@ describe('createCloudflareIsolateDriver', () => {
       const driver = createCloudflareIsolateDriver({ workerUrl: WORKER_URL })
       const context = await driver.createContext({ bindings: {} })
 
-      const result = await context.execute('await unknownTool({})')
+      await context.execute('await unknownTool({})')
 
-      const body2: ExecuteRequest = JSON.parse(fetchMock.mock.calls[1][1].body)
+      const body2: ExecuteRequest = JSON.parse(fetchMock.mock.calls[1]![1].body)
       expect(body2.toolResults!['unknown_1']).toEqual({
         success: false,
         error: 'Unknown tool: unknownTool',
diff --git a/packages/typescript/ai-isolate-cloudflare/tests/worker.test.ts b/packages/typescript/ai-isolate-cloudflare/tests/worker.test.ts
index 1b692ef63..d342f7aa3 100644
--- a/packages/typescript/ai-isolate-cloudflare/tests/worker.test.ts
+++ b/packages/typescript/ai-isolate-cloudflare/tests/worker.test.ts
@@ -1,8 +1,33 @@
 import { describe, expect, it } from 'vitest'
 import { generateToolWrappers, wrapCode } from '../src/worker/wrap-code'
-import type { ToolResultPayload, ToolSchema } from '../src/types'
+import type {
+  ExecuteResponse,
+  ToolResultPayload,
+  ToolSchema,
+} from '../src/types'
 import workerModule from '../src/worker/index'
 
+/**
+ * Error envelope returned by the outer worker for invalid requests (e.g.
+ * non-POST methods or missing `code`). Not part of `ExecuteResponse` — these
+ * are short-circuit responses produced before `executeCode` is called.
+ */
+interface SimpleErrorResponse {
+  error: string
+}
+
+/**
+ * Single trust-boundary cast: the Fetch API types `Response.json()` as
+ * `Promise<unknown>`, but tests know the worker's response shape from the
+ * source. This helper is the ONLY place where we assert that shape; all
+ * callers get a properly typed value back without sprinkling `as` casts at
+ * each call site.
+ */
+async function readJson<T>(response: Response): Promise<T> {
+  // Trust boundary: Response.json() returns unknown; tests own the shape.
+  return (await response.json()) as T
+}
+
 const worker = workerModule as {
   fetch: (
     request: Request,
@@ -170,7 +195,7 @@ describe('Worker fetch handler', () => {
     const response = await worker.fetch(request, {}, mockExecutionContext)
 
     expect(response.status).toBe(405)
-    const json = await response.json()
+    const json = await readJson<SimpleErrorResponse>(response)
     expect(json).toHaveProperty('error', 'Method not allowed')
     expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
   })
@@ -184,7 +209,7 @@ describe('Worker fetch handler', () => {
     const response = await worker.fetch(request, {}, mockExecutionContext)
 
     expect(response.status).toBe(400)
-    const json = await response.json()
+    const json = await readJson<SimpleErrorResponse>(response)
     expect(json).toHaveProperty('error', 'Code is required')
   })
 
@@ -200,7 +225,9 @@ describe('Worker fetch handler', () => {
     const response = await worker.fetch(request, {}, mockExecutionContext)
 
     expect(response.status).toBe(200)
-    const json = await response.json()
+    const json = await readJson<Extract<ExecuteResponse, { status: 'error' }>>(
+      response,
+    )
     expect(json.status).toBe('error')
     expect(json.error.name).toBe('WorkerLoaderNotAvailable')
     expect(json.error.message).toContain('LOADER')
@@ -260,7 +287,9 @@ describe('Worker fetch handler', () => {
     expect(capturedOptions!.modules['main.js']).toContain('export default')
     expect(capturedOptions!.globalOutbound).toBeNull()
     expect(response.status).toBe(200)
-    const json = await response.json()
+    const json = await readJson<Extract<ExecuteResponse, { status: 'done' }>>(
+      response,
+    )
     expect(json.status).toBe('done')
     expect(json.success).toBe(true)
     expect(json.value).toBe(42)
@@ -297,10 +326,12 @@ describe('Worker fetch handler', () => {
     const response = await worker.fetch(request, env, mockExecutionContext)
 
     expect(response.status).toBe(200)
-    const json = await response.json()
+    const json = await readJson<
+      Extract<ExecuteResponse, { status: 'need_tools' }>
+    >(response)
     expect(json.status).toBe('need_tools')
     expect(json.toolCalls).toHaveLength(1)
-    expect(json.toolCalls[0].name).toBe('fetchData')
+    expect(json.toolCalls[0]!.name).toBe('fetchData')
     expect(typeof json.continuationId).toBe('string')
   })
 
@@ -341,7 +372,9 @@ describe('Worker fetch handler', () => {
     expect(receivedSignal!.aborted).toBe(true)
 
     expect(response.status).toBe(200)
-    const json = await response.json()
+    const json = await readJson<Extract<ExecuteResponse, { status: 'error' }>>(
+      response,
+    )
     expect(json.status).toBe('error')
     expect(json.error.name).toBe('TimeoutError')
     expect(json.error.message).toContain('50ms')
@@ -356,7 +389,9 @@ describe('Worker fetch handler', () => {
     const response = await worker.fetch(request, {}, mockExecutionContext)
 
     expect(response.status).toBe(500)
-    const json = await response.json()
+    const json = await readJson<Extract<ExecuteResponse, { status: 'error' }>>(
+      response,
+    )
     expect(json.status).toBe('error')
     expect(json.error.name).toBe('RequestError')
   })
diff --git a/packages/typescript/ai-openai/tests/image-adapter.test.ts b/packages/typescript/ai-openai/tests/image-adapter.test.ts
index 429306bcd..34cb5fda7 100644
--- a/packages/typescript/ai-openai/tests/image-adapter.test.ts
+++ b/packages/typescript/ai-openai/tests/image-adapter.test.ts
@@ -1,14 +1,32 @@
-import { describe, it, expect, beforeEach, vi } from 'vitest'
+import { describe, it, expect, vi } from 'vitest'
 import { resolveDebugOption } from '@tanstack/ai/adapter-internals'
+import type OpenAI from 'openai'
 import { OpenAIImageAdapter, createOpenaiImage } from '../src/adapters/image'
 import {
   validateImageSize,
   validateNumberOfImages,
   validatePrompt,
 } from '../src/image/image-provider-options'
+import type { OpenAIImageModel } from '../src/model-meta'
 
 const testLogger = resolveDebugOption(false)
 
+/**
+ * Test-only subclass of `OpenAIImageAdapter` that exposes the real
+ * `OpenAI` SDK client's `images.generate` method to `vi.spyOn`. Using a
+ * subclass + spy (instead of replacing the whole `client` field with a
+ * stub) keeps every type real: no `as unknown as` cast, no synthetic stub
+ * type, and the original `OpenAI` instance — constructed by the adapter
+ * itself — stays in place.
+ */
+class TestOpenAIImageAdapter<
+  TModel extends OpenAIImageModel,
+> extends OpenAIImageAdapter<TModel> {
+  spyOnImagesGenerate() {
+    return vi.spyOn(this.client.images, 'generate')
+  }
+}
+
 describe('OpenAI Image Adapter', () => {
   describe('createOpenaiImage', () => {
     it('creates an adapter with the provided API key', () => {
@@ -134,7 +152,8 @@ describe('OpenAI Image Adapter', () => {
 
   describe('generateImages', () => {
     it('calls the OpenAI images.generate API', async () => {
-      const mockResponse = {
+      const mockResponse: OpenAI.Images.ImagesResponse = {
+        created: 0,
         data: [
           {
             b64_json: 'base64encodedimage',
@@ -143,22 +162,19 @@ describe('OpenAI Image Adapter', () => {
         ],
         usage: {
           input_tokens: 10,
+          input_tokens_details: { image_tokens: 0, text_tokens: 10 },
           output_tokens: 100,
           total_tokens: 110,
         },
       }
 
-      const mockGenerate = vi.fn().mockResolvedValueOnce(mockResponse)
-
-      const adapter = createOpenaiImage('gpt-image-1', 'test-api-key')
-      // Replace the internal OpenAI SDK client with our mock
-      ;(
-        adapter as unknown as { client: { images: { generate: unknown } } }
-      ).client = {
-        images: {
-          generate: mockGenerate,
-        },
-      }
+      const adapter = new TestOpenAIImageAdapter(
+        { apiKey: 'test-api-key' },
+        'gpt-image-1',
+      )
+      const mockGenerate = adapter
+        .spyOnImagesGenerate()
+        .mockResolvedValueOnce(mockResponse)
 
       const result = await adapter.generateImages({
         model: 'gpt-image-1',
@@ -178,8 +194,8 @@ describe('OpenAI Image Adapter', () => {
 
       expect(result.model).toBe('gpt-image-1')
       expect(result.images).toHaveLength(1)
-      expect(result.images[0].b64Json).toBe('base64encodedimage')
-      expect(result.images[0].revisedPrompt).toBe('A beautiful cat')
+      expect(result.images[0]!.b64Json).toBe('base64encodedimage')
+      expect(result.images[0]!.revisedPrompt).toBe('A beautiful cat')
       expect(result.usage).toEqual({
         inputTokens: 10,
         outputTokens: 100,
@@ -188,20 +204,16 @@ describe('OpenAI Image Adapter', () => {
     })
 
     it('generates a unique ID for each response', async () => {
-      const mockResponse = {
+      const mockResponse: OpenAI.Images.ImagesResponse = {
+        created: 0,
         data: [{ b64_json: 'base64' }],
       }
 
-      const mockGenerate = vi.fn().mockResolvedValue(mockResponse)
-
-      const adapter = createOpenaiImage('gpt-image-1', 'test-api-key')
-      ;(
-        adapter as unknown as { client: { images: { generate: unknown } } }
-      ).client = {
-        images: {
-          generate: mockGenerate,
-        },
-      }
+      const adapter = new TestOpenAIImageAdapter(
+        { apiKey: 'test-api-key' },
+        'gpt-image-1',
+      )
+      adapter.spyOnImagesGenerate().mockResolvedValue(mockResponse)
 
       const result1 = await adapter.generateImages({
         model: 'dall-e-3',
diff --git a/packages/typescript/ai-openai/tests/model-meta.test.ts b/packages/typescript/ai-openai/tests/model-meta.test.ts
index 648deaa87..cf599b5f7 100644
--- a/packages/typescript/ai-openai/tests/model-meta.test.ts
+++ b/packages/typescript/ai-openai/tests/model-meta.test.ts
@@ -341,8 +341,8 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
   })
 
   describe('Models WITH minimal features (Basic Models)', () => {
-    it('chatgpt-4.0 should only have streaming and base options', () => {
-      type Options = OpenAIChatModelProviderOptionsByName['chatgpt-4.0']
+    it('chatgpt-4o-latest should only have streaming and base options', () => {
+      type Options = OpenAIChatModelProviderOptionsByName['chatgpt-4o-latest']
 
       expectTypeOf<Options>().not.toExtend<OpenAIReasoningOptions>()
       expectTypeOf<Options>().not.toExtend<OpenAIStructuredOutputOptions>()
@@ -394,7 +394,7 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
 
   describe('Chat-only models WITH reasoning AND structured output but WITHOUT tools', () => {
     it('gpt-5.1-chat should have reasoning and structured output but NOT tools', () => {
-      type Options = OpenAIChatModelProviderOptionsByName['gpt-5.1-chat']
+      type Options = OpenAIChatModelProviderOptionsByName['gpt-5.1-chat-latest']
 
       expectTypeOf<Options>().toExtend<OpenAIReasoningOptions>()
       expectTypeOf<Options>().toExtend<OpenAIStructuredOutputOptions>()
@@ -404,7 +404,7 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
     })
 
     it('gpt-5-chat should have reasoning and structured output but NOT tools', () => {
-      type Options = OpenAIChatModelProviderOptionsByName['gpt-5-chat']
+      type Options = OpenAIChatModelProviderOptionsByName['gpt-5-chat-latest']
 
       expectTypeOf<Options>().toExtend<OpenAIReasoningOptions>()
       expectTypeOf<Options>().toExtend<OpenAIStructuredOutputOptions>()
@@ -502,15 +502,15 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
       expectTypeOf<'gpt-3.5-turbo'>().toExtend<Keys>()
 
       // Basic models
-      expectTypeOf<'chatgpt-4.0'>().toExtend<Keys>()
+      expectTypeOf<'chatgpt-4o-latest'>().toExtend<Keys>()
       expectTypeOf<'gpt-audio'>().toExtend<Keys>()
       expectTypeOf<'gpt-audio-mini'>().toExtend<Keys>()
       expectTypeOf<'gpt-4o-audio'>().toExtend<Keys>()
       expectTypeOf<'gpt-4o-mini-audio'>().toExtend<Keys>()
 
       // Chat-only models
-      expectTypeOf<'gpt-5.1-chat'>().toExtend<Keys>()
-      expectTypeOf<'gpt-5-chat'>().toExtend<Keys>()
+      expectTypeOf<'gpt-5.1-chat-latest'>().toExtend<Keys>()
+      expectTypeOf<'gpt-5-chat-latest'>().toExtend<Keys>()
 
       // Codex/Preview models
       expectTypeOf<'gpt-5.1-codex-mini'>().toExtend<Keys>()
@@ -551,7 +551,7 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
         OpenAIChatModelProviderOptionsByName['gpt-3.5-turbo']
       >().toHaveProperty('metadata')
       expectTypeOf<
-        OpenAIChatModelProviderOptionsByName['chatgpt-4.0']
+        OpenAIChatModelProviderOptionsByName['chatgpt-4o-latest']
       >().toHaveProperty('metadata')
     })
 
@@ -584,7 +584,7 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
         OpenAIChatModelProviderOptionsByName['gpt-3.5-turbo']
       >().toHaveProperty('store')
       expectTypeOf<
-        OpenAIChatModelProviderOptionsByName['chatgpt-4.0']
+        OpenAIChatModelProviderOptionsByName['chatgpt-4o-latest']
       >().toHaveProperty('store')
     })
 
@@ -617,7 +617,7 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
         OpenAIChatModelProviderOptionsByName['gpt-3.5-turbo']
       >().toHaveProperty('service_tier')
       expectTypeOf<
-        OpenAIChatModelProviderOptionsByName['chatgpt-4.0']
+        OpenAIChatModelProviderOptionsByName['chatgpt-4o-latest']
       >().toHaveProperty('service_tier')
     })
 
@@ -665,10 +665,10 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
         OpenAIChatModelProviderOptionsByName['gpt-4o']
       >().toHaveProperty('text')
       expectTypeOf<
-        OpenAIChatModelProviderOptionsByName['gpt-5.1-chat']
+        OpenAIChatModelProviderOptionsByName['gpt-5.1-chat-latest']
       >().toHaveProperty('text')
       expectTypeOf<
-        OpenAIChatModelProviderOptionsByName['gpt-5-chat']
+        OpenAIChatModelProviderOptionsByName['gpt-5-chat-latest']
       >().toHaveProperty('text')
     })
 
@@ -692,7 +692,7 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
         OpenAIChatModelProviderOptionsByName['gpt-4']
       >().toHaveProperty('stream_options')
       expectTypeOf<
-        OpenAIChatModelProviderOptionsByName['chatgpt-4.0']
+        OpenAIChatModelProviderOptionsByName['chatgpt-4o-latest']
       >().toHaveProperty('stream_options')
     })
   })
@@ -806,13 +806,13 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
         OpenAIChatModelProviderOptionsByName['gpt-3.5-turbo']
       >().toExtend<BaseOptions>()
       expectTypeOf<
-        OpenAIChatModelProviderOptionsByName['chatgpt-4.0']
+        OpenAIChatModelProviderOptionsByName['chatgpt-4o-latest']
       >().toExtend<BaseOptions>()
       expectTypeOf<
-        OpenAIChatModelProviderOptionsByName['gpt-5.1-chat']
+        OpenAIChatModelProviderOptionsByName['gpt-5.1-chat-latest']
       >().toExtend<BaseOptions>()
       expectTypeOf<
-        OpenAIChatModelProviderOptionsByName['gpt-5-chat']
+        OpenAIChatModelProviderOptionsByName['gpt-5-chat-latest']
       >().toExtend<BaseOptions>()
       expectTypeOf<
         OpenAIChatModelProviderOptionsByName['computer-use-preview']
@@ -821,7 +821,12 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
   })
 })
 
-// Helper types for message with specific content
+// Helper types for message with specific content using OpenAI metadata
+type OpenAITextPart = TextPart<OpenAIMessageMetadataByModality['text']>
+type OpenAIImagePart = ImagePart<OpenAIMessageMetadataByModality['image']>
+type OpenAIAudioPart = AudioPart<OpenAIMessageMetadataByModality['audio']>
+type OpenAIVideoPart = VideoPart<OpenAIMessageMetadataByModality['video']>
+type OpenAIDocumentPart = DocumentPart<OpenAIMessageMetadataByModality['document']>
 type MessageWithContent<T> = { role: 'user'; content: Array<T> }
 
 /**
@@ -838,14 +843,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -854,14 +859,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -870,14 +875,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -886,14 +891,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -902,14 +907,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -918,14 +923,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -934,14 +939,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -950,14 +955,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -966,14 +971,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -982,14 +987,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -998,14 +1003,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1014,14 +1019,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1030,14 +1035,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1046,14 +1051,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1062,14 +1067,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1078,14 +1083,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1094,14 +1099,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1110,14 +1115,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1126,14 +1131,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and ImagePart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<ImagePart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1144,14 +1149,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and AudioPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().toExtend<Message>()
     })
 
     it('should NOT allow ImagePart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<ImagePart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1160,14 +1165,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart and AudioPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().toExtend<Message>()
     })
 
     it('should NOT allow ImagePart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<ImagePart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1178,14 +1183,14 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     type Message = ConstrainedModelMessage<MakeInputModalitiesTypes<Modalities>>
 
     it('should allow TextPart', () => {
-      expectTypeOf<MessageWithContent<TextPart>>().toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAITextPart>>().toExtend<Message>()
     })
 
     it('should NOT allow ImagePart, AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<ImagePart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<VideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<DocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIImagePart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
     })
   })
 
@@ -1193,21 +1198,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
 
   describe('String and null content should always be allowed', () => {
     it('text+image models should allow string content', () => {
-      type GPT51Message = ConstrainedModelMessage<
-        OpenAIModelInputModalitiesByName['gpt-5.1']
-      >
-      type O3Message = ConstrainedModelMessage<
-        OpenAIModelInputModalitiesByName['o3']
-      >
+      type GPT51Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>>
+      type O3Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['o3']>>
 
       expectTypeOf<{ role: 'user'; content: string }>().toExtend<GPT51Message>()
       expectTypeOf<{ role: 'user'; content: string }>().toExtend<O3Message>()
     })
 
     it('text-only models should allow string content', () => {
-      type O3MiniMessage = ConstrainedModelMessage<
-        OpenAIModelInputModalitiesByName['o3-mini']
-      >
+      type O3MiniMessage = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['o3-mini']>>
 
       expectTypeOf<{
         role: 'user'
@@ -1216,9 +1215,7 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('text+audio models should allow string content', () => {
-      type GPTAudioMessage = ConstrainedModelMessage<
-        OpenAIModelInputModalitiesByName['gpt-audio']
-      >
+      type GPTAudioMessage = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-audio']>>
 
       expectTypeOf<{
         role: 'user'
@@ -1227,15 +1224,9 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('all models should allow null content', () => {
-      type GPT51Message = ConstrainedModelMessage<
-        OpenAIModelInputModalitiesByName['gpt-5.1']
-      >
-      type O3MiniMessage = ConstrainedModelMessage<
-        OpenAIModelInputModalitiesByName['o3-mini']
-      >
-      type GPTAudioMessage = ConstrainedModelMessage<
-        OpenAIModelInputModalitiesByName['gpt-audio']
-      >
+      type GPT51Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>>
+      type O3MiniMessage = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['o3-mini']>>
+      type GPTAudioMessage = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-audio']>>
 
       expectTypeOf<{
         role: 'assistant'
@@ -1256,29 +1247,25 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
 
   describe('Mixed content part validation', () => {
     it('should NOT allow mixing valid and invalid content parts', () => {
-      type GPT51Message = ConstrainedModelMessage<
-        OpenAIModelInputModalitiesByName['gpt-5.1']
-      >
+      type GPT51Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>>
 
       // TextPart + VideoPart should NOT be allowed (GPT-5.1 doesn't support video)
       expectTypeOf<
-        MessageWithContent<TextPart | VideoPart>
+        MessageWithContent<OpenAITextPart | OpenAIVideoPart>
       >().not.toExtend<GPT51Message>()
 
       // ImagePart + AudioPart should NOT be allowed (GPT-5.1 doesn't support audio)
       expectTypeOf<
-        MessageWithContent<ImagePart | AudioPart>
+        MessageWithContent<OpenAIImagePart | OpenAIAudioPart>
       >().not.toExtend<GPT51Message>()
     })
 
     it('should allow mixing valid content parts', () => {
-      type GPT51Message = ConstrainedModelMessage<
-        OpenAIModelInputModalitiesByName['gpt-5.1']
-      >
+      type GPT51Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>>
 
       // TextPart + ImagePart should be allowed
       expectTypeOf<
-        MessageWithContent<TextPart | ImagePart>
+        MessageWithContent<OpenAITextPart | OpenAIImagePart>
       >().toExtend<GPT51Message>()
     })
   })
diff --git a/packages/typescript/ai-openai/tests/openai-adapter.test.ts b/packages/typescript/ai-openai/tests/openai-adapter.test.ts
index 552793a2e..d6ec64b3c 100644
--- a/packages/typescript/ai-openai/tests/openai-adapter.test.ts
+++ b/packages/typescript/ai-openai/tests/openai-adapter.test.ts
@@ -82,8 +82,8 @@ describe('OpenAI adapter option mapping', () => {
     const chunks: StreamChunk[] = []
     for await (const chunk of chat({
       adapter,
+      systemPrompts: ['Stay concise'],
       messages: [
-        { role: 'system', content: 'Stay concise' },
         { role: 'user', content: 'How is the weather?' },
         {
           role: 'assistant',
@@ -109,7 +109,7 @@ describe('OpenAI adapter option mapping', () => {
     }
 
     expect(responsesCreate).toHaveBeenCalledTimes(1)
-    const [payload] = responsesCreate.mock.calls[0]
+    const [payload] = responsesCreate.mock.calls[0]!
 
     // Responses API uses different field names and structure
     expect(payload).toMatchObject({
diff --git a/packages/typescript/ai-react/tests/test-utils.ts b/packages/typescript/ai-react/tests/test-utils.ts
index 4393b463b..40f0b2ac9 100644
--- a/packages/typescript/ai-react/tests/test-utils.ts
+++ b/packages/typescript/ai-react/tests/test-utils.ts
@@ -24,5 +24,5 @@ import { useChat } from '../src/use-chat'
 export function renderUseChat(
   options?: UseChatOptions,
 ): RenderHookResult<UseChatReturn, UseChatOptions> {
-  return renderHook(() => useChat(options))
+  return renderHook(() => useChat(options!))
 }
diff --git a/packages/typescript/ai-react/tests/use-chat-structured-output.test.ts b/packages/typescript/ai-react/tests/use-chat-structured-output.test.ts
index c7f5955dd..04f5dff68 100644
--- a/packages/typescript/ai-react/tests/use-chat-structured-output.test.ts
+++ b/packages/typescript/ai-react/tests/use-chat-structured-output.test.ts
@@ -180,7 +180,7 @@ describe('useChat({ outputSchema }) — runtime', () => {
       ([c]) => c.type === 'CUSTOM' && c.name === 'structured-output.complete',
     )
     expect(completeCalls.length).toBe(1)
-    expect(completeCalls[0][0].value).toEqual({ object: person, raw: json })
+    expect(completeCalls[0]![0].value).toEqual({ object: person, raw: json })
 
     const deltaCalls = onChunk.mock.calls.filter(
       ([c]) => c.type === 'TEXT_MESSAGE_CONTENT',
@@ -227,13 +227,17 @@ describe('useChat() without outputSchema — runtime', () => {
     await waitFor(() => {
       expect(result.current.messages.length).toBeGreaterThan(0)
     })
-    // The return object doesn't expose partial/final at the type level — and
-    // the runtime branch in onChunk is gated on `outputSchema !== undefined`
-    // so the internal state never updates. (Runtime access is the only way
-    // to verify the no-op branch.)
-    expect(
-      (result.current as unknown as { partial?: unknown }).partial,
-    ).toEqual({})
-    expect((result.current as unknown as { final?: unknown }).final).toBeNull()
+    // The return object doesn't expose `partial`/`final` at the type level
+    // (the discriminated `UseChatReturn` only adds them when `outputSchema` is
+    // supplied), and the runtime branch in onChunk is gated on
+    // `outputSchema !== undefined` so the internal state never updates.
+    // Runtime access is the only way to verify the no-op branch. TS cannot
+    // express "this object happens to also carry these fields at runtime
+    // even though the type says it doesn't", so a single bridge cast to
+    // `unknown` is the minimum legal escape.
+    const runtimeView: { partial?: unknown; final?: unknown } =
+      result.current as unknown as { partial?: unknown; final?: unknown }
+    expect(runtimeView.partial).toEqual({})
+    expect(runtimeView.final).toBeNull()
   })
 })
diff --git a/packages/typescript/ai-react/tests/use-chat.test.ts b/packages/typescript/ai-react/tests/use-chat.test.ts
index 79cfdb638..9a536c1c7 100644
--- a/packages/typescript/ai-react/tests/use-chat.test.ts
+++ b/packages/typescript/ai-react/tests/use-chat.test.ts
@@ -1,4 +1,6 @@
-import type { ModelMessage } from '@tanstack/ai'
+import type { ModelMessage, StreamChunk } from '@tanstack/ai'
+import { EventType } from '@tanstack/ai'
+import type { SubscribeConnectionAdapter } from '@tanstack/ai-client'
 import { act, renderHook, waitFor } from '@testing-library/react'
 import { useState } from 'react'
 import { describe, expect, it, vi } from 'vitest'
@@ -74,7 +76,7 @@ describe('useChat', () => {
 
       // Message IDs are generated independently, not based on client ID
       // Just verify messages exist and have IDs
-      const messageId = result.current.messages[0].id
+      const messageId = result.current.messages[0]!.id
       expect(messageId).toBeDefined()
       expect(typeof messageId).toBe('string')
     })
@@ -92,7 +94,7 @@ describe('useChat', () => {
       })
 
       // Message IDs should have a generated prefix (not "custom-id-")
-      const messageId = result.current.messages[0].id
+      const messageId = result.current.messages[0]!.id
       expect(messageId).toBeTruthy()
       expect(messageId).not.toMatch(/^custom-id-/)
     })
@@ -310,7 +312,7 @@ describe('useChat', () => {
         expect(result.current.messages.length).toBeGreaterThan(0)
       })
 
-      expect(result.current.messages[0].id).toBe('user-1')
+      expect(result.current.messages[0]!.id).toBe('user-1')
     })
 
     it('should convert and append a ModelMessage', async () => {
@@ -329,8 +331,8 @@ describe('useChat', () => {
         expect(result.current.messages.length).toBeGreaterThan(0)
       })
 
-      expect(result.current.messages[0].role).toBe('user')
-      expect(result.current.messages[0].parts[0]).toEqual({
+      expect(result.current.messages[0]!.role).toBe('user')
+      expect(result.current.messages[0]!.parts[0]).toEqual({
         type: 'text',
         content: 'Hello from model',
       })
@@ -375,6 +377,7 @@ describe('useChat', () => {
           if (callCount === 2) {
             return chunks2
           }
+          return undefined
         },
       })
 
@@ -391,16 +394,6 @@ describe('useChat', () => {
         expect(assistantMessage).toBeDefined()
       })
 
-      const firstAssistantMessage = result.current.messages.find(
-        (m) => m.role === 'assistant',
-      )
-      const firstContent =
-        firstAssistantMessage?.parts.find((p) => p.type === 'text')?.type ===
-        'text'
-          ? (firstAssistantMessage.parts.find((p) => p.type === 'text') as any)
-              .content
-          : ''
-
       // Reload with new adapter
       rerender({ connection: adapter2 })
       await result.current.reload()
@@ -452,12 +445,6 @@ describe('useChat', () => {
         expect(result.current.messages.length).toBeGreaterThanOrEqual(2)
       })
 
-      // Create error adapter for reload
-      const errorAdapter = createMockConnectionAdapter({
-        shouldError: true,
-        error: new Error('Reload failed'),
-      })
-
       // Note: We can't easily change the adapter after creation,
       // so this test verifies error handling in general
       // The actual error would come from the connection adapter
@@ -754,7 +741,7 @@ describe('useChat', () => {
         expect(onFinish).toHaveBeenCalled()
       })
 
-      const finishedMessage = onFinish.mock.calls[0][0]
+      const finishedMessage = onFinish.mock.calls[0]![0]
       expect(finishedMessage).toBeDefined()
       expect(finishedMessage.role).toBe('assistant')
     })
@@ -778,7 +765,7 @@ describe('useChat', () => {
         expect(onError).toHaveBeenCalled()
       })
 
-      expect(onError.mock.calls[0][0].message).toBe('Test error')
+      expect(onError.mock.calls[0]![0].message).toBe('Test error')
     })
 
     it('should call onResponse callback when response is received', async () => {
@@ -930,8 +917,12 @@ describe('useChat', () => {
         })
 
         // The adapter should receive the previous conversation + new message.
-        const sentMessages = connectSpy.mock.calls[0]![0] as Array<any>
-        const userMessages = sentMessages.filter((m: any) => m.role === 'user')
+        // `connectSpy.mock.calls[0][0]` is the messages array passed to
+        // adapter.connect — typed via MockConnectionAdapterOptions.onConnect.
+        const sentMessages = connectSpy.mock.calls[0]![0] as Array<
+          ModelMessage | UIMessage
+        >
+        const userMessages = sentMessages.filter((m) => m.role === 'user')
         expect(userMessages.length).toBeGreaterThanOrEqual(2)
       })
     })
@@ -1120,39 +1111,15 @@ describe('useChat', () => {
         })
       })
 
-      it('should handle tool execution errors', async () => {
-        const toolCalls = createToolCallChunks([
-          { id: 'tool-1', name: 'testTool', arguments: '{"param": "value"}' },
-        ])
-        const adapter = createMockConnectionAdapter({ chunks: toolCalls })
-        const { result } = renderUseChat({
-          connection: adapter,
-          onToolCall: async () => {
-            throw new Error('Tool execution failed')
-          },
-        })
-
-        await result.current.sendMessage('Test')
-
-        await waitFor(() => {
-          expect(result.current.messages.length).toBeGreaterThan(0)
-        })
-
-        // Tool errors are handled by adding error output to the tool call part
-        // The error state is not set for tool execution failures
-        // Check that the message contains a tool call with error output
-        const assistantMessage = result.current.messages.find(
-          (m) => m.role === 'assistant',
-        )
-        expect(assistantMessage).toBeDefined()
-
-        if (assistantMessage) {
-          const toolCallPart = assistantMessage.parts.find(
-            (p) => p.type === 'tool-call',
-          )
-          expect(toolCallPart).toBeDefined()
-        }
-      })
+      // NOTE: A previous "should handle tool execution errors" test was deleted
+      // because it passed `onToolCall` as a useChat option. `onToolCall` is NOT
+      // part of the public `UseChatOptions` / `ChatClientOptions` surface — it
+      // is installed internally on the StreamProcessor by ChatClient (see
+      // packages/typescript/ai-client/src/chat-client.ts) and routes through
+      // the `tools` array (`AnyClientTool.execute`). The same is true of the
+      // deleted "should handle addToolResult" test below. Tool-execution error
+      // behavior is exercised in ai-client's own tests against the real
+      // public surface (`tools: [...]`).
     })
 
     describe('multiple hook instances', () => {
@@ -1185,8 +1152,8 @@ describe('useChat', () => {
         expect(result1.current.messages.length).toBe(
           result2.current.messages.length,
         )
-        expect(result1.current.messages[0].parts[0]).not.toEqual(
-          result2.current.messages[0].parts[0],
+        expect(result1.current.messages[0]!.parts[0]).not.toEqual(
+          result2.current.messages[0]!.parts[0],
         )
       })
 
@@ -1237,8 +1204,8 @@ describe('useChat', () => {
         // Both should have messages, but different ones
         expect(result1.current.messages.length).toBeGreaterThan(0)
         expect(result2.current.messages.length).toBeGreaterThan(0)
-        expect(result1.current.messages[0].parts[0]).not.toEqual(
-          result2.current.messages[0].parts[0],
+        expect(result1.current.messages[0]!.parts[0]).not.toEqual(
+          result2.current.messages[0]!.parts[0],
         )
       })
     })
@@ -1249,9 +1216,13 @@ describe('useChat', () => {
           { id: 'tool-1', name: 'testTool', arguments: '{"param": "value"}' },
         ])
         const adapter = createMockConnectionAdapter({ chunks: toolCalls })
+        // `onToolCall` is intentionally NOT passed here: it is not part of the
+        // public `UseChatOptions` surface (it's wired internally by ChatClient
+        // through the `tools` array). The previous version of this test set it
+        // via `as any` and then never exercised its result — `addToolResult`
+        // itself is the public API under test.
         const { result } = renderUseChat({
           connection: adapter,
-          onToolCall: async () => ({ result: 'success' }),
         })
 
         await result.current.sendMessage('Test')
@@ -1668,33 +1639,34 @@ describe('useChat', () => {
 
   describe('sessionGenerating', () => {
     it('should expose sessionGenerating and update from stream run events', async () => {
-      const adapter: import('@tanstack/ai-client').SubscribeConnectionAdapter =
+      // Build chunks as a typed StreamChunk array so each yielded event is
+      // checked against the AGUI discriminated union — no inline `as any`.
+      const chunks: Array<StreamChunk> = [
         {
-          subscribe: async function* (signal?: AbortSignal) {
-            yield {
-              type: 'RUN_STARTED' as const,
-              runId: 'run-1',
-              model: 'test',
-              timestamp: Date.now(),
-            }
-            yield {
-              type: 'TEXT_MESSAGE_CONTENT' as const,
-              messageId: 'msg-1',
-              model: 'test',
-              timestamp: Date.now(),
-              delta: 'Hi',
-              content: 'Hi',
-            }
-            yield {
-              type: 'RUN_FINISHED' as const,
-              runId: 'run-1',
-              model: 'test',
-              timestamp: Date.now(),
-              finishReason: 'stop' as const,
-            }
-          },
-          send: vi.fn(async () => {}),
-        }
+          type: EventType.RUN_STARTED,
+          runId: 'run-1',
+          threadId: 'thread-1',
+          timestamp: Date.now(),
+        },
+        {
+          type: EventType.TEXT_MESSAGE_CONTENT,
+          messageId: 'msg-1',
+          timestamp: Date.now(),
+          delta: 'Hi',
+        },
+        {
+          type: EventType.RUN_FINISHED,
+          runId: 'run-1',
+          threadId: 'thread-1',
+          timestamp: Date.now(),
+        },
+      ]
+      const adapter: SubscribeConnectionAdapter = {
+        subscribe: async function* (_signal?: AbortSignal) {
+          for (const chunk of chunks) yield chunk
+        },
+        send: vi.fn(async () => {}),
+      }
 
       const { result } = renderUseChat({ connection: adapter, live: true })
 
@@ -1710,25 +1682,26 @@ describe('useChat', () => {
     })
 
     it('should integrate correctly with live subscription lifecycle', async () => {
-      const adapter: import('@tanstack/ai-client').SubscribeConnectionAdapter =
+      const chunks: Array<StreamChunk> = [
         {
-          subscribe: async function* () {
-            yield {
-              type: 'RUN_STARTED' as const,
-              runId: 'run-1',
-              model: 'test',
-              timestamp: Date.now(),
-            }
-            yield {
-              type: 'RUN_FINISHED' as const,
-              runId: 'run-1',
-              model: 'test',
-              timestamp: Date.now(),
-              finishReason: 'stop' as const,
-            }
-          },
-          send: vi.fn(async () => {}),
-        }
+          type: EventType.RUN_STARTED,
+          runId: 'run-1',
+          threadId: 'thread-1',
+          timestamp: Date.now(),
+        },
+        {
+          type: EventType.RUN_FINISHED,
+          runId: 'run-1',
+          threadId: 'thread-1',
+          timestamp: Date.now(),
+        },
+      ]
+      const adapter: SubscribeConnectionAdapter = {
+        subscribe: async function* () {
+          for (const chunk of chunks) yield chunk
+        },
+        send: vi.fn(async () => {}),
+      }
 
       const { result } = renderUseChat({ connection: adapter, live: true })
 
diff --git a/packages/typescript/ai-react/tests/use-generation.test.ts b/packages/typescript/ai-react/tests/use-generation.test.ts
index 45752984d..ae3d5d19d 100644
--- a/packages/typescript/ai-react/tests/use-generation.test.ts
+++ b/packages/typescript/ai-react/tests/use-generation.test.ts
@@ -8,22 +8,28 @@ import { useTranscription } from '../src/use-transcription'
 import { useSummarize } from '../src/use-summarize'
 import { useGenerateVideo } from '../src/use-generate-video'
 import { createMockConnectionAdapter } from './test-utils'
-import type { StreamChunk } from '@tanstack/ai'
+import type { StreamChunk, TTSResult } from '@tanstack/ai'
+import { EventType } from '@tanstack/ai'
 
 // Helper to create generation stream chunks
 function createGenerationChunks(result: unknown): Array<StreamChunk> {
   return [
-    { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
     {
-      type: 'CUSTOM',
+      type: EventType.RUN_STARTED,
+      runId: 'run-1',
+      threadId: 'thread-1',
+      timestamp: Date.now(),
+    },
+    {
+      type: EventType.CUSTOM,
       name: 'generation:result',
       value: result,
       timestamp: Date.now(),
     },
     {
-      type: 'RUN_FINISHED',
+      type: EventType.RUN_FINISHED,
       runId: 'run-1',
-      finishReason: 'stop',
+      threadId: 'thread-1',
       timestamp: Date.now(),
     },
   ]
@@ -32,44 +38,61 @@ function createGenerationChunks(result: unknown): Array<StreamChunk> {
 // Helper to create video generation stream chunks
 function createVideoChunks(jobId: string, url: string): Array<StreamChunk> {
   return [
-    { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
     {
-      type: 'CUSTOM',
+      type: EventType.RUN_STARTED,
+      runId: 'run-1',
+      threadId: 'thread-1',
+      timestamp: Date.now(),
+    },
+    {
+      type: EventType.CUSTOM,
       name: 'video:job:created',
       value: { jobId },
       timestamp: Date.now(),
     },
     {
-      type: 'CUSTOM',
+      type: EventType.CUSTOM,
       name: 'video:status',
       value: { jobId, status: 'processing', progress: 50 },
       timestamp: Date.now(),
     },
     {
-      type: 'CUSTOM',
+      type: EventType.CUSTOM,
       name: 'generation:result',
       value: { jobId, status: 'completed', url },
       timestamp: Date.now(),
     },
     {
-      type: 'RUN_FINISHED',
+      type: EventType.RUN_FINISHED,
       runId: 'run-1',
-      finishReason: 'stop',
+      threadId: 'thread-1',
       timestamp: Date.now(),
     },
   ]
 }
 
-// Helper to create error stream chunks
+// Helper to create error stream chunks.
+// NOTE: The AG-UI spec for RUN_ERROR carries `message` directly on the event
+// (not nested under `error`). We emit BOTH shapes here because GenerationClient
+// supports the legacy `chunk.error.message` fallback (see generation-client.ts:
+// `chunk.message ?? chunk.error?.message`). Once that fallback is removed, the
+// `error` field can drop.
 function createErrorChunks(message: string): Array<StreamChunk> {
   return [
-    { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
     {
-      type: 'RUN_ERROR',
+      type: EventType.RUN_STARTED,
       runId: 'run-1',
-      error: { message },
+      threadId: 'thread-1',
       timestamp: Date.now(),
     },
+    {
+      type: EventType.RUN_ERROR,
+      message,
+      // Legacy shape preserved for the fallback branch in generation-client.ts.
+      // AGUIEventSchema is `passthrough` so unknown keys are allowed at runtime;
+      // the strict TS union still requires a cast on this single chunk.
+      error: { message },
+    } as StreamChunk,
   ]
 }
 
@@ -270,6 +293,7 @@ describe('useGenerateImage', () => {
 
   it('should generate images using fetcher', async () => {
     const mockResult = {
+      id: 'img-1',
       images: [{ url: 'http://example.com/img.png' }],
       model: 'dall-e-3',
     }
@@ -354,6 +378,7 @@ describe('useGenerateSpeech', () => {
 
   it('should generate speech using fetcher', async () => {
     const mockResult = {
+      id: 'tts-1',
       audio: 'base64data',
       format: 'mp3' as const,
       model: 'tts-1',
@@ -459,6 +484,7 @@ describe('useTranscription', () => {
 
   it('should transcribe audio using fetcher', async () => {
     const mockResult = {
+      id: 'trans-1',
       text: 'Hello world',
       model: 'whisper-1',
     }
@@ -507,8 +533,10 @@ describe('useSummarize', () => {
 
   it('should summarize text using fetcher', async () => {
     const mockResult = {
+      id: 'sum-1',
       summary: 'A brief summary',
       model: 'gpt-4',
+      usage: { promptTokens: 100, completionTokens: 20, totalTokens: 120 },
     }
 
     const { result } = renderHook(() =>
@@ -657,10 +685,18 @@ describe('useGenerateVideo', () => {
 
 describe('onResult transform', () => {
   it('should transform result when onResult returns a value (fetcher)', async () => {
+    // useGeneration's TOnResult generic defaults to `undefined` if not pinned
+    // (the standard Omit-plus-callback inference pattern doesn't recover it),
+    // so the callback parameter type can't infer from the fetcher's return.
+    // Pin TResult and TOnResult explicitly — no cast needed.
+    type FetcherResult = { id: string; audio: string }
+    const onResult = (raw: FetcherResult) => ({
+      playable: raw.audio.length > 0,
+    })
     const { result } = renderHook(() =>
-      useGeneration({
+      useGeneration<Record<string, any>, FetcherResult, typeof onResult>({
         fetcher: async () => ({ id: '1', audio: 'base64data' }),
-        onResult: (raw) => ({ playable: raw.audio.length > 0 }),
+        onResult,
       }),
     )
 
@@ -708,16 +744,19 @@ describe('onResult transform', () => {
   })
 
   it('should transform result from connection stream', async () => {
-    const mockResult = { id: '1', images: ['img1', 'img2'] }
+    type StreamResult = { id: string; images: Array<string> }
+    const mockResult: StreamResult = { id: '1', images: ['img1', 'img2'] }
     const chunks = createGenerationChunks(mockResult)
     const adapter = createMockConnectionAdapter({ chunks })
 
+    // The stream chunk's `value` payload is `unknown` at the type level
+    // (CUSTOM events are opaque), so TResult cannot infer from `adapter`. Pin
+    // TResult and TOnResult explicitly via the generics — no cast needed.
+    const onResult = (raw: StreamResult) => ({ count: raw.images.length })
     const { result } = renderHook(() =>
-      useGeneration({
+      useGeneration<Record<string, any>, StreamResult, typeof onResult>({
         connection: adapter,
-        onResult: (raw: { id: string; images: Array<string> }) => ({
-          count: raw.images.length,
-        }),
+        onResult,
       }),
     )
 
@@ -729,7 +768,7 @@ describe('onResult transform', () => {
   })
 
   it('should work with useGenerateSpeech transform', async () => {
-    const mockTTSResult = {
+    const mockTTSResult: TTSResult = {
       id: '1',
       model: 'tts-1',
       audio: 'base64audio',
@@ -737,12 +776,15 @@ describe('onResult transform', () => {
       contentType: 'audio/mpeg',
     }
 
+    // The hook's TOnResult generic defaults to undefined, so let's pin the
+    // callback type explicitly. TResult here is the concrete TTSResult.
+    const onResult = (raw: TTSResult) => ({
+      audioUrl: `data:${raw.contentType};base64,${raw.audio}`,
+    })
     const { result } = renderHook(() =>
-      useGenerateSpeech({
+      useGenerateSpeech<typeof onResult>({
         fetcher: async () => mockTTSResult,
-        onResult: (raw) => ({
-          audioUrl: `data:${raw.contentType};base64,${raw.audio}`,
-        }),
+        onResult,
       }),
     )
 
diff --git a/packages/typescript/ai-solid/tests/test-utils.ts b/packages/typescript/ai-solid/tests/test-utils.ts
index 28dc3bf7a..82bff2ad7 100644
--- a/packages/typescript/ai-solid/tests/test-utils.ts
+++ b/packages/typescript/ai-solid/tests/test-utils.ts
@@ -49,7 +49,7 @@ export function renderUseChat(options?: UseChatOptions) {
         }
       },
     },
-    rerender: (newOptions?: UseChatOptions) => {
+    rerender: (_newOptions?: UseChatOptions) => {
       // SolidJS doesn't have a rerender concept in the same way React does
       // The signals are already reactive, so we just return the same result
       return rendered
diff --git a/packages/typescript/ai-solid/tests/use-chat.test.ts b/packages/typescript/ai-solid/tests/use-chat.test.ts
index 2e0d43d89..f6afaef4e 100644
--- a/packages/typescript/ai-solid/tests/use-chat.test.ts
+++ b/packages/typescript/ai-solid/tests/use-chat.test.ts
@@ -72,7 +72,7 @@ describe('useChat', () => {
 
       // Message IDs are generated independently, not based on client ID
       // Just verify messages exist and have IDs
-      const messageId = result.current.messages[0].id
+      const messageId = result.current.messages[0]!.id
       expect(messageId).toBeDefined()
       expect(typeof messageId).toBe('string')
     })
@@ -90,7 +90,7 @@ describe('useChat', () => {
       })
 
       // Message IDs should have a generated prefix (not "custom-id-")
-      const messageId = result.current.messages[0].id
+      const messageId = result.current.messages[0]!.id
       expect(messageId).toBeTruthy()
       expect(messageId).not.toMatch(/^custom-id-/)
     })
@@ -308,7 +308,7 @@ describe('useChat', () => {
         expect(result.current.messages.length).toBeGreaterThan(0)
       })
 
-      expect(result.current.messages[0].id).toBe('user-1')
+      expect(result.current.messages[0]!.id).toBe('user-1')
     })
 
     it('should convert and append a ModelMessage', async () => {
@@ -327,8 +327,8 @@ describe('useChat', () => {
         expect(result.current.messages.length).toBeGreaterThan(0)
       })
 
-      expect(result.current.messages[0].role).toBe('user')
-      expect(result.current.messages[0].parts[0]).toEqual({
+      expect(result.current.messages[0]!.role).toBe('user')
+      expect(result.current.messages[0]!.parts[0]).toEqual({
         type: 'text',
         content: 'Hello from model',
       })
@@ -373,6 +373,7 @@ describe('useChat', () => {
           if (callCount === 2) {
             return chunks2
           }
+          return undefined
         },
       })
 
@@ -389,16 +390,6 @@ describe('useChat', () => {
         expect(assistantMessage).toBeDefined()
       })
 
-      const firstAssistantMessage = result.current.messages.find(
-        (m) => m.role === 'assistant',
-      )
-      const firstContent =
-        firstAssistantMessage?.parts.find((p) => p.type === 'text')?.type ===
-        'text'
-          ? (firstAssistantMessage.parts.find((p) => p.type === 'text') as any)
-              .content
-          : ''
-
       // Reload with new adapter
       rerender({ connection: adapter2 })
       await result.current.reload()
@@ -450,12 +441,6 @@ describe('useChat', () => {
         expect(result.current.messages.length).toBeGreaterThanOrEqual(2)
       })
 
-      // Create error adapter for reload
-      const errorAdapter = createMockConnectionAdapter({
-        shouldError: true,
-        error: new Error('Reload failed'),
-      })
-
       // Note: We can't easily change the adapter after creation,
       // so this test verifies error handling in general
       // The actual error would come from the connection adapter
@@ -742,7 +727,7 @@ describe('useChat', () => {
         expect(onFinish).toHaveBeenCalled()
       })
 
-      const finishedMessage = onFinish.mock.calls[0][0]
+      const finishedMessage = onFinish.mock.calls[0]![0]
       expect(finishedMessage).toBeDefined()
       expect(finishedMessage.role).toBe('assistant')
     })
@@ -766,7 +751,7 @@ describe('useChat', () => {
         expect(onError).toHaveBeenCalled()
       })
 
-      expect(onError.mock.calls[0][0].message).toBe('Test error')
+      expect(onError.mock.calls[0]![0].message).toBe('Test error')
     })
 
     it('should call onResponse callback when response is received', async () => {
@@ -1063,8 +1048,8 @@ describe('useChat', () => {
         expect(result1.current.messages.length).toBe(
           result2.current.messages.length,
         )
-        expect(result1.current.messages[0].parts[0]).not.toEqual(
-          result2.current.messages[0].parts[0],
+        expect(result1.current.messages[0]!.parts[0]).not.toEqual(
+          result2.current.messages[0]!.parts[0],
         )
       })
 
@@ -1115,8 +1100,8 @@ describe('useChat', () => {
         // Both should have messages, but different ones
         expect(result1.current.messages.length).toBeGreaterThan(0)
         expect(result2.current.messages.length).toBeGreaterThan(0)
-        expect(result1.current.messages[0].parts[0]).not.toEqual(
-          result2.current.messages[0].parts[0],
+        expect(result1.current.messages[0]!.parts[0]).not.toEqual(
+          result2.current.messages[0]!.parts[0],
         )
       })
     })
@@ -1127,9 +1112,13 @@ describe('useChat', () => {
           { id: 'tool-1', name: 'testTool', arguments: '{"param": "value"}' },
         ])
         const adapter = createMockConnectionAdapter({ chunks: toolCalls })
+        // `onToolCall` is intentionally NOT passed here: it is not part of the
+        // public `UseChatOptions` surface (it's wired internally by ChatClient
+        // through the `tools` array). The previous version of this test set it
+        // via `as any` and then never exercised its result — `addToolResult`
+        // itself is the public API under test.
         const { result } = renderUseChat({
           connection: adapter,
-          onToolCall: async () => ({ result: 'success' }),
         })
 
         await result.current.sendMessage('Test')
diff --git a/packages/typescript/ai-solid/tests/use-generation.test.ts b/packages/typescript/ai-solid/tests/use-generation.test.ts
index 45ab209a0..971344f93 100644
--- a/packages/typescript/ai-solid/tests/use-generation.test.ts
+++ b/packages/typescript/ai-solid/tests/use-generation.test.ts
@@ -9,21 +9,27 @@ import { useSummarize } from '../src/use-summarize'
 import { useGenerateVideo } from '../src/use-generate-video'
 import { createMockConnectionAdapter } from './test-utils'
 import type { StreamChunk } from '@tanstack/ai'
+import { EventType } from '@tanstack/ai'
 
 // Helper to create generation stream chunks
 function createGenerationChunks(result: unknown): Array<StreamChunk> {
   return [
-    { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
     {
-      type: 'CUSTOM',
+      type: EventType.RUN_STARTED,
+      runId: 'run-1',
+      threadId: 'thread-1',
+      timestamp: Date.now(),
+    },
+    {
+      type: EventType.CUSTOM,
       name: 'generation:result',
       value: result,
       timestamp: Date.now(),
     },
     {
-      type: 'RUN_FINISHED',
+      type: EventType.RUN_FINISHED,
       runId: 'run-1',
-      finishReason: 'stop',
+      threadId: 'thread-1',
       timestamp: Date.now(),
     },
   ]
@@ -32,44 +38,61 @@ function createGenerationChunks(result: unknown): Array<StreamChunk> {
 // Helper to create video generation stream chunks
 function createVideoChunks(jobId: string, url: string): Array<StreamChunk> {
   return [
-    { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
     {
-      type: 'CUSTOM',
+      type: EventType.RUN_STARTED,
+      runId: 'run-1',
+      threadId: 'thread-1',
+      timestamp: Date.now(),
+    },
+    {
+      type: EventType.CUSTOM,
       name: 'video:job:created',
       value: { jobId },
       timestamp: Date.now(),
     },
     {
-      type: 'CUSTOM',
+      type: EventType.CUSTOM,
       name: 'video:status',
       value: { jobId, status: 'processing', progress: 50 },
       timestamp: Date.now(),
     },
     {
-      type: 'CUSTOM',
+      type: EventType.CUSTOM,
       name: 'generation:result',
       value: { jobId, status: 'completed', url },
       timestamp: Date.now(),
     },
     {
-      type: 'RUN_FINISHED',
+      type: EventType.RUN_FINISHED,
       runId: 'run-1',
-      finishReason: 'stop',
+      threadId: 'thread-1',
       timestamp: Date.now(),
     },
   ]
 }
 
-// Helper to create error stream chunks
+// Helper to create error stream chunks.
+// NOTE: The AG-UI spec for RUN_ERROR carries `message` directly on the event
+// (not nested under `error`). We emit BOTH shapes here because GenerationClient
+// supports the legacy `chunk.error.message` fallback (see generation-client.ts:
+// `chunk.message ?? chunk.error?.message`). Once that fallback is removed, the
+// `error` field can drop.
 function createErrorChunks(message: string): Array<StreamChunk> {
   return [
-    { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
     {
-      type: 'RUN_ERROR',
+      type: EventType.RUN_STARTED,
       runId: 'run-1',
-      error: { message },
+      threadId: 'thread-1',
       timestamp: Date.now(),
     },
+    {
+      type: EventType.RUN_ERROR,
+      message,
+      // Legacy shape preserved for the fallback branch in generation-client.ts.
+      // AGUIEventSchema is `passthrough` so unknown keys are allowed at runtime;
+      // the strict TS union still requires a cast on this single chunk.
+      error: { message },
+    } as StreamChunk,
   ]
 }
 
@@ -128,7 +151,6 @@ describe('useGeneration', () => {
     })
 
     it('should track loading state during fetcher call', async () => {
-      const states: Array<boolean> = []
       let resolvePromise: (value: any) => void
 
       const { result } = renderHook(() =>
@@ -157,23 +179,28 @@ describe('useGeneration', () => {
     it('should call onProgress callback', async () => {
       const onProgress = vi.fn()
       const chunks: Array<StreamChunk> = [
-        { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
         {
-          type: 'CUSTOM',
+          type: EventType.RUN_STARTED,
+          runId: 'run-1',
+          threadId: 'thread-1',
+          timestamp: Date.now(),
+        },
+        {
+          type: EventType.CUSTOM,
           name: 'generation:progress',
           value: { progress: 50, message: 'Halfway' },
           timestamp: Date.now(),
         },
         {
-          type: 'CUSTOM',
+          type: EventType.CUSTOM,
           name: 'generation:result',
           value: { id: '1' },
           timestamp: Date.now(),
         },
         {
-          type: 'RUN_FINISHED',
+          type: EventType.RUN_FINISHED,
           runId: 'run-1',
-          finishReason: 'stop',
+          threadId: 'thread-1',
           timestamp: Date.now(),
         },
       ]
@@ -327,8 +354,12 @@ describe('useGeneration', () => {
 
   describe('error handling', () => {
     it('should require either connection or fetcher', () => {
+      // Empty options is structurally valid (both connection and fetcher are
+      // optional) but a runtime guard inside useGeneration throws. Pinning the
+      // generics explicitly avoids leaving the constraints to default to
+      // `unknown`, which trips inference on the empty literal.
       expect(() => {
-        renderHook(() => useGeneration({} as any))
+        renderHook(() => useGeneration<Record<string, unknown>, unknown>({}))
       }).toThrow('useGeneration requires either a connection or fetcher option')
     })
   })
@@ -352,6 +383,7 @@ describe('useGenerateImage', () => {
   describe('fetcher mode', () => {
     it('should generate images using fetcher', async () => {
       const mockResult = {
+        id: 'img-1',
         images: [{ url: 'http://example.com/img.png' }],
         model: 'dall-e-3',
       }
@@ -395,6 +427,7 @@ describe('useGenerateImage', () => {
   describe('connection mode', () => {
     it('should generate images using connection', async () => {
       const mockResult = {
+        id: 'img-1',
         images: [{ url: 'http://example.com/img.png' }],
         model: 'dall-e-3',
       }
@@ -425,6 +458,7 @@ describe('useGenerateImage', () => {
 
     it('should reset state after generation', async () => {
       const mockResult = {
+        id: 'img-1',
         images: [{ url: 'http://example.com/img.png' }],
         model: 'dall-e-3',
       }
@@ -465,6 +499,7 @@ describe('useGenerateSpeech', () => {
   describe('fetcher mode', () => {
     it('should generate speech using fetcher', async () => {
       const mockResult = {
+        id: 'tts-1',
         audio: 'base64data',
         format: 'mp3' as const,
         model: 'tts-1',
@@ -530,6 +565,7 @@ describe('useGenerateSpeech', () => {
   describe('stop and reset', () => {
     it('should reset state after generation', async () => {
       const mockResult = {
+        id: 'tts-1',
         audio: 'base64data',
         format: 'mp3' as const,
         model: 'tts-1',
@@ -671,6 +707,7 @@ describe('useTranscription', () => {
   describe('fetcher mode', () => {
     it('should transcribe audio using fetcher', async () => {
       const mockResult = {
+        id: 'trans-1',
         text: 'Hello world',
         model: 'whisper-1',
       }
@@ -731,6 +768,7 @@ describe('useTranscription', () => {
   describe('stop and reset', () => {
     it('should reset state after transcription', async () => {
       const mockResult = {
+        id: 'trans-1',
         text: 'Hello world',
         model: 'whisper-1',
       }
@@ -769,8 +807,10 @@ describe('useSummarize', () => {
   describe('fetcher mode', () => {
     it('should summarize text using fetcher', async () => {
       const mockResult = {
+        id: 'sum-1',
         summary: 'A brief summary',
         model: 'gpt-4',
+        usage: { promptTokens: 100, completionTokens: 20, totalTokens: 120 },
       }
       const onResult = vi.fn()
 
@@ -827,8 +867,10 @@ describe('useSummarize', () => {
   describe('stop and reset', () => {
     it('should reset state after summarization', async () => {
       const mockResult = {
+        id: 'sum-1',
         summary: 'A brief summary',
         model: 'gpt-4',
+        usage: { promptTokens: 100, completionTokens: 20, totalTokens: 120 },
       }
 
       const { result } = renderHook(() =>
@@ -1036,8 +1078,11 @@ describe('useGenerateVideo', () => {
 
   describe('error handling', () => {
     it('should require either connection or fetcher', () => {
+      // Empty options is structurally valid (both connection and fetcher are
+      // optional on UseGenerateVideoOptions) but a runtime guard inside
+      // useGenerateVideo throws.
       expect(() => {
-        renderHook(() => useGenerateVideo({} as any))
+        renderHook(() => useGenerateVideo({}))
       }).toThrow(
         'useGenerateVideo requires either a connection or fetcher option',
       )
diff --git a/packages/typescript/ai-svelte/tests/create-generation.test.ts b/packages/typescript/ai-svelte/tests/create-generation.test.ts
index fdfc50cb3..126487a5d 100644
--- a/packages/typescript/ai-svelte/tests/create-generation.test.ts
+++ b/packages/typescript/ai-svelte/tests/create-generation.test.ts
@@ -6,21 +6,27 @@ import { createTranscription } from '../src/create-transcription.svelte'
 import { createSummarize } from '../src/create-summarize.svelte'
 import { createGenerateVideo } from '../src/create-generate-video.svelte'
 import { createMockConnectionAdapter } from './test-utils'
-import type { StreamChunk } from '@tanstack/ai'
+import { EventType, type StreamChunk } from '@tanstack/ai'
 
 // Helper to create generation stream chunks
 function createGenerationChunks(result: unknown): Array<StreamChunk> {
   return [
-    { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
     {
-      type: 'CUSTOM',
+      type: EventType.RUN_STARTED,
+      runId: 'run-1',
+      threadId: 'thread-1',
+      timestamp: Date.now(),
+    },
+    {
+      type: EventType.CUSTOM,
       name: 'generation:result',
       value: result,
       timestamp: Date.now(),
     },
     {
-      type: 'RUN_FINISHED',
+      type: EventType.RUN_FINISHED,
       runId: 'run-1',
+      threadId: 'thread-1',
       finishReason: 'stop',
       timestamp: Date.now(),
     },
@@ -30,28 +36,34 @@ function createGenerationChunks(result: unknown): Array<StreamChunk> {
 // Helper to create video generation stream chunks
 function createVideoChunks(jobId: string, url: string): Array<StreamChunk> {
   return [
-    { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
     {
-      type: 'CUSTOM',
+      type: EventType.RUN_STARTED,
+      runId: 'run-1',
+      threadId: 'thread-1',
+      timestamp: Date.now(),
+    },
+    {
+      type: EventType.CUSTOM,
       name: 'video:job:created',
       value: { jobId },
       timestamp: Date.now(),
     },
     {
-      type: 'CUSTOM',
+      type: EventType.CUSTOM,
       name: 'video:status',
       value: { jobId, status: 'processing', progress: 50 },
       timestamp: Date.now(),
     },
     {
-      type: 'CUSTOM',
+      type: EventType.CUSTOM,
       name: 'generation:result',
       value: { jobId, status: 'completed', url },
       timestamp: Date.now(),
     },
     {
-      type: 'RUN_FINISHED',
+      type: EventType.RUN_FINISHED,
       runId: 'run-1',
+      threadId: 'thread-1',
       finishReason: 'stop',
       timestamp: Date.now(),
     },
@@ -61,10 +73,15 @@ function createVideoChunks(jobId: string, url: string): Array<StreamChunk> {
 // Helper to create error stream chunks
 function createErrorChunks(message: string): Array<StreamChunk> {
   return [
-    { type: 'RUN_STARTED', runId: 'run-1', timestamp: Date.now() },
     {
-      type: 'RUN_ERROR',
+      type: EventType.RUN_STARTED,
       runId: 'run-1',
+      threadId: 'thread-1',
+      timestamp: Date.now(),
+    },
+    {
+      type: EventType.RUN_ERROR,
+      message,
       error: { message },
       timestamp: Date.now(),
     },
@@ -230,6 +247,7 @@ describe('createGenerateImage', () => {
 
   it('should generate images using fetcher', async () => {
     const mockResult = {
+      id: 'img-1',
       images: [{ url: 'http://example.com/img.png' }],
       model: 'dall-e-3',
     }
@@ -302,6 +320,7 @@ describe('createGenerateSpeech', () => {
 
   it('should generate speech using fetcher', async () => {
     const mockResult = {
+      id: 'tts-1',
       audio: 'base64data',
       format: 'mp3' as const,
       model: 'tts-1',
@@ -350,6 +369,7 @@ describe('createGenerateSpeech', () => {
   it('should stop and reset', async () => {
     const gen = createGenerateSpeech({
       fetcher: async () => ({
+        id: 'tts-1',
         audio: 'base64data',
         format: 'mp3' as const,
         model: 'tts-1',
@@ -384,6 +404,7 @@ describe('createTranscription', () => {
 
   it('should transcribe audio using fetcher', async () => {
     const mockResult = {
+      id: 'tr-1',
       text: 'Hello world',
       model: 'whisper-1',
     }
@@ -431,6 +452,7 @@ describe('createTranscription', () => {
   it('should stop and reset', async () => {
     const gen = createTranscription({
       fetcher: async () => ({
+        id: 'tr-1',
         text: 'Hello world',
         model: 'whisper-1',
       }),
@@ -464,8 +486,10 @@ describe('createSummarize', () => {
 
   it('should summarize text using fetcher', async () => {
     const mockResult = {
+      id: 'sum-1',
       summary: 'A brief summary',
       model: 'gpt-4',
+      usage: { promptTokens: 1, completionTokens: 1, totalTokens: 2 },
     }
 
     const gen = createSummarize({
@@ -511,8 +535,10 @@ describe('createSummarize', () => {
   it('should stop and reset', async () => {
     const gen = createSummarize({
       fetcher: async () => ({
+        id: 'sum-1',
         summary: 'A brief summary',
         model: 'gpt-4',
+        usage: { promptTokens: 1, completionTokens: 1, totalTokens: 2 },
       }),
     })
 
diff --git a/packages/typescript/ai-svelte/tests/use-chat.test.ts b/packages/typescript/ai-svelte/tests/use-chat.test.ts
index f52539c0b..1a6c4b777 100644
--- a/packages/typescript/ai-svelte/tests/use-chat.test.ts
+++ b/packages/typescript/ai-svelte/tests/use-chat.test.ts
@@ -51,7 +51,7 @@ describe('createChat', () => {
     })
 
     expect(chat.messages).toHaveLength(1)
-    expect(chat.messages[0].role).toBe('user')
+    expect(chat.messages[0]!.role).toBe('user')
   })
 
   it('should have sendMessage method', () => {
diff --git a/packages/typescript/openai-base/tests/chat-completions-structured-output-stream.test.ts b/packages/typescript/openai-base/tests/chat-completions-structured-output-stream.test.ts
index 3b7b7ec42..638822f40 100644
--- a/packages/typescript/openai-base/tests/chat-completions-structured-output-stream.test.ts
+++ b/packages/typescript/openai-base/tests/chat-completions-structured-output-stream.test.ts
@@ -10,21 +10,32 @@
 
 import { describe, it, expect, vi, beforeEach } from 'vitest'
 import { OpenAIBaseChatCompletionsTextAdapter } from '../src/adapters/chat-completions-text'
-import type OpenAI from 'openai'
+import OpenAI from 'openai'
 import type { JSONSchema, StreamChunk } from '@tanstack/ai'
 import { resolveDebugOption, type Logger } from '@tanstack/ai/adapter-internals'
 
-let mockCreate: ReturnType<typeof vi.fn>
+/**
+ * Signature of the OpenAI SDK's `chat.completions.create`. See sibling
+ * test `chat-completions-text.test.ts` for the rationale: we narrow the
+ * union of streaming / non-streaming overloads down to a tuple the
+ * `mockImplementation` of `vi.fn` can actually accept, and return
+ * `unknown` because the test asserts on AG-UI events emitted by the
+ * adapter rather than on SDK structural types.
+ */
+type MockChatCompletionCreate = (
+  params: OpenAI.Chat.Completions.ChatCompletionCreateParams,
+  options?: OpenAI.RequestOptions,
+) => unknown
+
+let mockCreate: ReturnType<typeof vi.fn<MockChatCompletionCreate>>
 
 function makeStubClient(): OpenAI {
-  return {
-    chat: {
-      completions: {
-        create: (params: unknown, options: unknown) =>
-          mockCreate(params, options),
-      },
-    },
-  } as unknown as OpenAI
+  const client = new OpenAI({ apiKey: 'test-api-key' })
+  client.chat.completions.create = ((
+    params: OpenAI.Chat.Completions.ChatCompletionCreateParams,
+    options?: OpenAI.RequestOptions,
+  ) => mockCreate(params, options)) as typeof client.chat.completions.create
+  return client
 }
 
 class TestAdapter extends OpenAIBaseChatCompletionsTextAdapter<string> {
diff --git a/packages/typescript/openai-base/tests/chat-completions-text.test.ts b/packages/typescript/openai-base/tests/chat-completions-text.test.ts
index d0aa111a5..874887da8 100644
--- a/packages/typescript/openai-base/tests/chat-completions-text.test.ts
+++ b/packages/typescript/openai-base/tests/chat-completions-text.test.ts
@@ -1,26 +1,48 @@
 import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest'
 import { OpenAIBaseChatCompletionsTextAdapter } from '../src/adapters/chat-completions-text'
-import type OpenAI from 'openai'
+import OpenAI from 'openai'
+import { EventType } from '@tanstack/ai'
 import type { StreamChunk, Tool } from '@tanstack/ai'
 import { resolveDebugOption } from '@tanstack/ai/adapter-internals'
 
 const testLogger = resolveDebugOption(false)
 
+/**
+ * Signature of the OpenAI SDK's `chat.completions.create`. We could mirror
+ * the SDK type directly via `OpenAI.Chat.Completions['create']`, but the
+ * union of streaming / non-streaming overloads is awkward to instantiate
+ * with `mockImplementation`. A narrowed signature that accepts the request
+ * params + request options and returns `unknown` is enough for the test —
+ * actual return shapes are validated by the AG-UI events emitted from the
+ * adapter, not by SDK type structural checks.
+ */
+type MockChatCompletionCreate = (
+  params: OpenAI.Chat.Completions.ChatCompletionCreateParams,
+  options?: OpenAI.RequestOptions,
+) => unknown
+
 // Declare mockCreate at module level
-let mockCreate: ReturnType<typeof vi.fn>
+let mockCreate: ReturnType<typeof vi.fn<MockChatCompletionCreate>>
 
-/** Build a stub OpenAI client whose `chat.completions.create` defers to the
- *  module-level `mockCreate`. Reassigning `mockCreate` inside a test still
- *  takes effect because the stub looks it up at call time. */
+/**
+ * Build a real `OpenAI` SDK client and monkey-patch its
+ * `chat.completions.create` to forward to the module-level `mockCreate`.
+ * Going through a real `new OpenAI(...)` instance keeps the field type
+ * exactly `OpenAI` — no `as unknown as OpenAI` cast — and still lets tests
+ * reassign `mockCreate` between cases because the patched method looks it
+ * up at call time.
+ */
 function makeStubClient(): OpenAI {
-  return {
-    chat: {
-      completions: {
-        create: (params: unknown, options: unknown) =>
-          mockCreate(params, options),
-      },
-    },
-  } as unknown as OpenAI
+  const client = new OpenAI({ apiKey: 'test-api-key' })
+  // Monkey-patch the overloaded `create` method. The SDK's overload
+  // union makes a plain function assignment incompatible, so we pin the
+  // patched function to the inherited method's exact type — narrowing,
+  // not widening, and no `any` involved.
+  client.chat.completions.create = ((
+    params: OpenAI.Chat.Completions.ChatCompletionCreateParams,
+    options?: OpenAI.RequestOptions,
+  ) => mockCreate(params, options)) as typeof client.chat.completions.create
+  return client
 }
 
 /**
@@ -276,14 +298,14 @@ describe('OpenAIBaseChatCompletionsTextAdapter', () => {
       expect(eventTypes[0]).toBe('RUN_STARTED')
 
       // Should have TEXT_MESSAGE_START before TEXT_MESSAGE_CONTENT
-      const textStartIndex = eventTypes.indexOf('TEXT_MESSAGE_START')
-      const textContentIndex = eventTypes.indexOf('TEXT_MESSAGE_CONTENT')
+      const textStartIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_START)
+      const textContentIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_CONTENT)
       expect(textStartIndex).toBeGreaterThan(-1)
       expect(textContentIndex).toBeGreaterThan(textStartIndex)
 
       // Should have TEXT_MESSAGE_END before RUN_FINISHED
-      const textEndIndex = eventTypes.indexOf('TEXT_MESSAGE_END')
-      const runFinishedIndex = eventTypes.indexOf('RUN_FINISHED')
+      const textEndIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_END)
+      const runFinishedIndex = eventTypes.indexOf(EventType.RUN_FINISHED)
       expect(textEndIndex).toBeGreaterThan(-1)
       expect(runFinishedIndex).toBeGreaterThan(textEndIndex)
 
@@ -574,7 +596,7 @@ describe('OpenAIBaseChatCompletionsTextAdapter', () => {
       const runErrorChunk = chunks.find((c) => c.type === 'RUN_ERROR')
       expect(runErrorChunk).toBeDefined()
       if (runErrorChunk?.type === 'RUN_ERROR') {
-        expect(runErrorChunk.error.message).toBe('Stream interrupted')
+        expect(runErrorChunk.error!.message).toBe('Stream interrupted')
       }
     })
 
@@ -597,7 +619,7 @@ describe('OpenAIBaseChatCompletionsTextAdapter', () => {
       expect(chunks[0]?.type).toBe('RUN_STARTED')
       expect(chunks[1]?.type).toBe('RUN_ERROR')
       if (chunks[1]?.type === 'RUN_ERROR') {
-        expect(chunks[1].error.message).toBe('API key invalid')
+        expect(chunks[1].error!.message).toBe('API key invalid')
       }
     })
   })
@@ -680,9 +702,12 @@ describe('OpenAIBaseChatCompletionsTextAdapter', () => {
         },
       })
 
+      // `result.data` is typed as `unknown` from the schema-less call;
+      // narrow it to the shape this test produces.
+      const data = result.data as { name?: string; nickname?: string }
       // null should be transformed to undefined
-      expect((result.data as any).name).toBe('Alice')
-      expect((result.data as any).nickname).toBeUndefined()
+      expect(data.name).toBe('Alice')
+      expect(data.nickname).toBeUndefined()
     })
 
     it('throws on invalid JSON response', async () => {
@@ -933,7 +958,7 @@ describe('OpenAIBaseChatCompletionsTextAdapter', () => {
       })
 
       // Structured output call should NOT have stream_options
-      const callArgs = mockCreate.mock.calls[0]?.[0]
+      const callArgs = mockCreate.mock.calls[0]![0]
       expect(callArgs.stream).toBe(false)
       expect(callArgs.stream_options).toBeUndefined()
     })
@@ -971,12 +996,12 @@ describe('OpenAIBaseChatCompletionsTextAdapter', () => {
       }
 
       // Verify second argument contains headers and signal
-      const requestOptions = mockCreate.mock.calls[0]?.[1]
+      const requestOptions = mockCreate.mock.calls[0]![1]
       expect(requestOptions).toBeDefined()
-      expect(requestOptions.headers).toEqual({
+      expect(requestOptions!.headers).toEqual({
         'X-Custom-Header': 'test-value',
       })
-      expect(requestOptions.signal).toBe(controller.signal)
+      expect(requestOptions!.signal).toBe(controller.signal)
     })
   })
 })
diff --git a/packages/typescript/openai-base/tests/responses-structured-output-stream.test.ts b/packages/typescript/openai-base/tests/responses-structured-output-stream.test.ts
index d3c8483a3..f1b62a3f3 100644
--- a/packages/typescript/openai-base/tests/responses-structured-output-stream.test.ts
+++ b/packages/typescript/openai-base/tests/responses-structured-output-stream.test.ts
@@ -9,19 +9,31 @@
 
 import { describe, it, expect, vi, beforeEach } from 'vitest'
 import { OpenAIBaseResponsesTextAdapter } from '../src/adapters/responses-text'
-import type OpenAI from 'openai'
+import OpenAI from 'openai'
 import type { JSONSchema, StreamChunk } from '@tanstack/ai'
 import { resolveDebugOption, type Logger } from '@tanstack/ai/adapter-internals'
 
-let mockCreate: ReturnType<typeof vi.fn>
+/**
+ * Signature of the OpenAI SDK's `responses.create`. Mirrors the narrowing
+ * applied in the sibling chat-completions structured-output stream test:
+ * collapse the streaming / non-streaming overload union to a single
+ * params + options pair and return `unknown`, since the assertions live
+ * on AG-UI events, not SDK structural types.
+ */
+type MockResponsesCreate = (
+  params: OpenAI.Responses.ResponseCreateParams,
+  options?: OpenAI.RequestOptions,
+) => unknown
+
+let mockCreate: ReturnType<typeof vi.fn<MockResponsesCreate>>
 
 function makeStubClient(): OpenAI {
-  return {
-    responses: {
-      create: (params: unknown, options: unknown) =>
-        mockCreate(params, options),
-    },
-  } as unknown as OpenAI
+  const client = new OpenAI({ apiKey: 'test-api-key' })
+  client.responses.create = ((
+    params: OpenAI.Responses.ResponseCreateParams,
+    options?: OpenAI.RequestOptions,
+  ) => mockCreate(params, options)) as typeof client.responses.create
+  return client
 }
 
 class TestAdapter extends OpenAIBaseResponsesTextAdapter<string> {
diff --git a/packages/typescript/openai-base/tests/responses-text.test.ts b/packages/typescript/openai-base/tests/responses-text.test.ts
index afe3c2860..5d9f49f1a 100644
--- a/packages/typescript/openai-base/tests/responses-text.test.ts
+++ b/packages/typescript/openai-base/tests/responses-text.test.ts
@@ -1,13 +1,14 @@
 import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest'
 import { OpenAIBaseResponsesTextAdapter } from '../src/adapters/responses-text'
 import type OpenAI from 'openai'
+import { EventType } from '@tanstack/ai'
 import type { StreamChunk, Tool } from '@tanstack/ai'
 import { resolveDebugOption } from '@tanstack/ai/adapter-internals'
 
 const testLogger = resolveDebugOption(false)
 
 // Declare mockCreate at module level
-let mockResponsesCreate: ReturnType<typeof vi.fn>
+let mockResponsesCreate: ReturnType<typeof vi.fn<(...args: Array<any>) => any>>
 
 /** Build a stub OpenAI client whose `responses.create` defers to the
  *  module-level `mockResponsesCreate`. Reassigning the mock inside a test
@@ -275,14 +276,14 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
       expect(eventTypes[0]).toBe('RUN_STARTED')
 
       // Should have TEXT_MESSAGE_START before TEXT_MESSAGE_CONTENT
-      const textStartIndex = eventTypes.indexOf('TEXT_MESSAGE_START')
-      const textContentIndex = eventTypes.indexOf('TEXT_MESSAGE_CONTENT')
+      const textStartIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_START)
+      const textContentIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_CONTENT)
       expect(textStartIndex).toBeGreaterThan(-1)
       expect(textContentIndex).toBeGreaterThan(textStartIndex)
 
       // Should have TEXT_MESSAGE_END before RUN_FINISHED
-      const textEndIndex = eventTypes.indexOf('TEXT_MESSAGE_END')
-      const runFinishedIndex = eventTypes.indexOf('RUN_FINISHED')
+      const textEndIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_END)
+      const runFinishedIndex = eventTypes.indexOf(EventType.RUN_FINISHED)
       expect(textEndIndex).toBeGreaterThan(-1)
       expect(runFinishedIndex).toBeGreaterThan(textEndIndex)
 
@@ -475,7 +476,7 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
       const eventTypes = chunks.map((c) => c.type)
 
       // Should have STEP_STARTED for reasoning
-      const stepStartIndex = eventTypes.indexOf('STEP_STARTED')
+      const stepStartIndex = eventTypes.indexOf(EventType.STEP_STARTED)
       expect(stepStartIndex).toBeGreaterThan(-1)
 
       const stepStart = chunks[stepStartIndex]
@@ -1213,8 +1214,8 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
       expect(eventTypes).toContain('TEXT_MESSAGE_CONTENT')
 
       // TEXT_MESSAGE_START should be before TEXT_MESSAGE_CONTENT
-      const startIdx = eventTypes.indexOf('TEXT_MESSAGE_START')
-      const contentIdx = eventTypes.indexOf('TEXT_MESSAGE_CONTENT')
+      const startIdx = eventTypes.indexOf(EventType.TEXT_MESSAGE_START)
+      const contentIdx = eventTypes.indexOf(EventType.TEXT_MESSAGE_CONTENT)
       expect(startIdx).toBeLessThan(contentIdx)
     })
 
@@ -1315,9 +1316,9 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
         chunks.push(chunk)
       }
       const types = chunks.map((c) => c.type)
-      const startIdx = types.indexOf('TEXT_MESSAGE_START')
-      const contentIdx = types.indexOf('TEXT_MESSAGE_CONTENT')
-      const endIdx = types.indexOf('TEXT_MESSAGE_END')
+      const startIdx = types.indexOf(EventType.TEXT_MESSAGE_START)
+      const contentIdx = types.indexOf(EventType.TEXT_MESSAGE_CONTENT)
+      const endIdx = types.indexOf(EventType.TEXT_MESSAGE_END)
       expect(startIdx).toBeGreaterThanOrEqual(0)
       expect(contentIdx).toBeGreaterThan(startIdx)
       expect(endIdx).toBeGreaterThan(contentIdx)
@@ -1373,7 +1374,7 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
       const runErrorChunk = chunks.find((c) => c.type === 'RUN_ERROR')
       expect(runErrorChunk).toBeDefined()
       if (runErrorChunk?.type === 'RUN_ERROR') {
-        expect(runErrorChunk.error.message).toBe('Stream interrupted')
+        expect(runErrorChunk.error!.message).toBe('Stream interrupted')
       }
     })
 
@@ -1398,7 +1399,7 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
       expect(chunks[0]?.type).toBe('RUN_STARTED')
       expect(chunks[1]?.type).toBe('RUN_ERROR')
       if (chunks[1]?.type === 'RUN_ERROR') {
-        expect(chunks[1].error.message).toBe('API key invalid')
+        expect(chunks[1].error!.message).toBe('API key invalid')
       }
     })
 
@@ -1433,7 +1434,7 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
       const errorChunk = chunks.find((c) => c.type === 'RUN_ERROR')
       expect(errorChunk).toBeDefined()
       if (errorChunk?.type === 'RUN_ERROR') {
-        expect(errorChunk.error.message).toBe('Content policy violation')
+        expect(errorChunk.error!.message).toBe('Content policy violation')
       }
     })
 
@@ -1468,7 +1469,7 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
       expect(errorChunks.length).toBeGreaterThan(0)
       const incompleteError = errorChunks.find(
         (c) =>
-          c.type === 'RUN_ERROR' && c.error.message === 'max_output_tokens',
+          c.type === 'RUN_ERROR' && c.error!.message === 'max_output_tokens',
       )
       expect(incompleteError).toBeDefined()
     })
@@ -1504,11 +1505,11 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
 
       const errorChunk = chunks.find(
         (c) =>
-          c.type === 'RUN_ERROR' && c.error.message === 'Rate limit exceeded',
+          c.type === 'RUN_ERROR' && c.error!.message === 'Rate limit exceeded',
       )
       expect(errorChunk).toBeDefined()
       if (errorChunk?.type === 'RUN_ERROR') {
-        expect(errorChunk.error.code).toBe('rate_limit')
+        expect(errorChunk.error!.code).toBe('rate_limit')
       }
     })
   })
@@ -1775,7 +1776,7 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
       }
 
       expect(mockResponsesCreate).toHaveBeenCalledTimes(1)
-      const [payload] = mockResponsesCreate.mock.calls[0]
+      const [payload] = mockResponsesCreate.mock.calls[0]!
 
       // Verify Responses API field names
       expect(payload).toMatchObject({
@@ -1837,7 +1838,7 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
         chunks.push(chunk)
       }
 
-      const [payload] = mockResponsesCreate.mock.calls[0]
+      const [payload] = mockResponsesCreate.mock.calls[0]!
       expect(payload.input).toEqual([
         {
           type: 'message',
@@ -1905,7 +1906,7 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
         chunks.push(chunk)
       }
 
-      const [payload] = mockResponsesCreate.mock.calls[0]
+      const [payload] = mockResponsesCreate.mock.calls[0]!
       // Should have function_call, message, and function_call_output
       expect(payload.input).toEqual(
         expect.arrayContaining([

From b5d1747894ece31d074b8eab231d42f546eb636d Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:37:45 +0200
Subject: [PATCH 07/17] docs(contributing): add CONTRIBUTING.md, editorconfig,
 vscode recommendations

- CONTRIBUTING.md covering prereqs (Node 24, pnpm 11), initial setup,
  repo layout, day-to-day commands, the per-package tsconfig pattern,
  where to add unit tests, the (mandatory) E2E coverage matrix,
  changesets, PR flow, and how to add a new provider adapter. Documents
  the known gaps: .vue/.svelte SFCs are not linted today, and build
  configs are not in the `tsc` pass.
- .editorconfig with the repo's existing conventions (LF, utf-8,
  2-space, final newline).
- .vscode/extensions.json recommending eslint, prettier, vitest
  explorer, nx, svelte, vue, editorconfig.

The PR template already linked to a missing CONTRIBUTING.md; this fixes
that broken link.
---
 .editorconfig           |  15 ++++
 .vscode/extensions.json |  11 +++
 CONTRIBUTING.md         | 164 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+)
 create mode 100644 .editorconfig
 create mode 100644 .vscode/extensions.json
 create mode 100644 CONTRIBUTING.md

diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000..4250a3276
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[Makefile]
+indent_style = tab
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 000000000..89d38ce7f
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,11 @@
+{
+  "recommendations": [
+    "dbaeumer.vscode-eslint",
+    "esbenp.prettier-vscode",
+    "vitest.explorer",
+    "nrwl.angular-console",
+    "svelte.svelte-vscode",
+    "Vue.volar",
+    "EditorConfig.EditorConfig"
+  ]
+}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..8e5c1ff02
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,164 @@
+# Contributing to TanStack AI
+
+Thanks for contributing! This guide covers everything you need to get from a fresh clone to a merged PR.
+
+## Prerequisites
+
+- **Node.js**: 24 or newer (older versions break `isolated-vm`).
+- **pnpm**: 10.17.0 or newer. Use the version pinned in `packageManager` (`pnpm@11.1.1`).
+  - Recommended: install via [Corepack](https://nodejs.org/api/corepack.html). Run `corepack enable` once and pnpm is managed automatically.
+- **Git**.
+
+We don't currently use Volta/asdf/nvm files. A `.nvmrc` pins the Node version if you use nvm/fnm.
+
+## Initial setup
+
+```bash
+git clone https://github.com/TanStack/ai.git
+cd ai
+pnpm install
+pnpm run build:all   # build all public packages once so workspace deps resolve
+```
+
+`pnpm install` runs Playwright's chromium download (used by the E2E suite). If you don't need E2E, you can skip it via `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 pnpm install`.
+
+## Repository layout
+
+```
+packages/typescript/    # Public, published packages (@tanstack/ai, @tanstack/ai-openai, etc.)
+testing/                # Internal test harnesses — NOT published
+  e2e/                  # Playwright + aimock E2E suite (mandatory coverage for all changes)
+  panel/                # Stream processor visualisation panel
+examples/               # Example apps (React, Solid, Vue, Svelte, PHP, Python, vanilla)
+codemods/               # Internal codemods (not published)
+docs/                   # Documentation source
+scripts/                # Repo-level scripts (doc generation, model sync, link verification)
+```
+
+- Direct children of `packages/typescript/` are public packages (published to npm).
+- Everything under `examples/`, `testing/`, and `codemods/` is `"private": true` and excluded from build/publish.
+- The build system is **Nx** with affected-target detection.
+- The package manager is **pnpm** with workspace + catalog protocols.
+
+For deeper architecture details (adapter system, isomorphic tools, framework integrations), see `CLAUDE.md` at the repo root.
+
+## Day-to-day commands
+
+All commands are run from the repo root. Nx handles affected detection and caching.
+
+| Goal                            | Command                                       |
+| ------------------------------- | --------------------------------------------- |
+| Run unit tests (affected)       | `pnpm test:lib`                               |
+| Watch unit tests                | `pnpm test:lib:dev`                           |
+| Type-check (affected)           | `pnpm test:types`                             |
+| Lint (affected)                 | `pnpm test:eslint`                            |
+| Verify build artifacts          | `pnpm test:build`                             |
+| Format the repo                 | `pnpm format`                                 |
+| Build (affected)                | `pnpm build`                                  |
+| Build everything                | `pnpm build:all`                              |
+| Run the full CI suite locally   | `pnpm test`                                   |
+| Run the affected-PR check       | `pnpm test:pr`                                |
+| E2E suite                       | `pnpm test:e2e`                               |
+| E2E with Playwright UI          | `pnpm test:e2e:ui`                            |
+
+Working on a single package? `cd packages/typescript/<pkg>` and use its scripts directly (`pnpm test:lib`, `pnpm test:types`, etc.).
+
+## TypeScript configuration
+
+There is a single `tsconfig.base.json` at the repo root with the shared `compilerOptions`. Every package extends it and overrides only what's unique to that package (e.g. `outDir`, JSX runtime, framework lib).
+
+The standardised per-package shape is:
+
+```jsonc
+{
+  "extends": "../../../tsconfig.base.json",
+  "compilerOptions": {
+    "outDir": "dist"
+    // + package-specific overrides only
+  },
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
+}
+```
+
+Tests are included in typecheck. `vite.config.ts` / `vitest.config.ts` are not — they're tooling configs typechecked by the build tools themselves.
+
+## Adding a unit test
+
+- Place tests under `packages/typescript/<pkg>/tests/` with the suffix `.test.ts` (or `.test.tsx` for JSX).
+- Vitest's defaults discover anything matching `**/*.{test,spec}.?(c|m)[jt]s?(x)` — no per-package config is needed.
+- Tests are typechecked by `tsc` and linted by ESLint.
+
+## Adding E2E test coverage (required)
+
+**Every feature, bug fix, or behaviour change MUST have E2E coverage.** See `testing/e2e/README.md` for the full guide. Quick reference:
+
+| Change type                                | What to add                                                              |
+| ------------------------------------------ | ------------------------------------------------------------------------ |
+| New provider adapter                       | Add provider to `feature-support.ts` + `test-matrix.ts`. Tests auto-run. |
+| New feature (e.g. new generation type)     | Add to types, feature config, support matrix, fixture, spec file.        |
+| Chat / streaming bug fix                   | Test case in `chat.spec.ts` or `tools-test/`.                            |
+| Tool system change                         | Scenario in `tools-test-scenarios.ts` + spec.                            |
+| Middleware change                          | Test in `middleware.spec.ts`.                                            |
+| Client-side change (useChat etc.)          | Test covering the observable behavior change.                            |
+
+Run the suite locally with `pnpm test:e2e`. Record real LLM fixtures with `OPENAI_API_KEY=sk-... pnpm --filter @tanstack/ai-e2e record`.
+
+## Changesets
+
+Any change that ships in a published package requires a changeset. Examples, internal test harnesses, codemods, and docs do not.
+
+```bash
+pnpm changeset
+```
+
+Pick the affected packages and the bump type:
+
+- **patch**: bug fix, internal refactor, perf, docs in package, no API change.
+- **minor**: new public API, new opt-in behaviour, backwards-compatible enhancement.
+- **major**: breaking change to a published API surface. Coordinate with maintainers first.
+
+The defensive `ignore` list in `.changeset/config.json` blocks accidental publication from examples/testing/codemods even if `"private": true` is ever dropped.
+
+## Branches and commits
+
+- Branch off `main`. Name the branch after the change (`fix/openai-streaming-eof`, `feat/anthropic-cache-control`).
+- Conventional Commits aren't strictly enforced, but follow the prefixes you see in `git log`: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`, `ci:`.
+- Keep commits logical. The repo prefers a few coherent commits over one giant squash.
+
+## Pull request flow
+
+1. Push your branch and open a PR against `main`.
+2. CI runs: `pnpm test:pr` (sherif workspace check, knip dead-code, docs link verification, ESLint, unit tests, typecheck, build artifacts, build) + the full E2E suite.
+3. Address review comments.
+4. A maintainer merges. Releases are cut via Changesets — your changeset entry lands in the next release.
+
+The PR template lists the steps. The `Test plan` section is required — describe how a reviewer can verify your change.
+
+## Adding a new provider adapter
+
+The pattern lives in `packages/typescript/ai-openai/`, `packages/typescript/ai-anthropic/`, `packages/typescript/ai-gemini/`, etc. New core adapters typically:
+
+1. Create `packages/typescript/ai-<provider>/` with `package.json`, `tsconfig.json`, `src/`, `tests/`, `README.md`. Copy structure from an existing adapter.
+2. Implement tree-shakeable adapter exports under `src/adapters/` (`text.ts`, `embed.ts`, `summarize.ts`, etc.).
+3. Add `model-meta.ts` so per-model type safety works.
+4. Wire the provider into `testing/e2e/feature-support.ts` and `testing/e2e/test-matrix.ts`. Existing provider-coverage tests pick it up automatically.
+5. Record fixtures (`OPENAI_API_KEY=... pnpm --filter @tanstack/ai-e2e record`) — or write deterministic ones by hand. **No real API keys at test time.**
+6. Add a `pnpm changeset` entry.
+
+If you're building a community/third-party adapter that lives outside this repo, follow `docs/community-adapters/guide.md` instead.
+
+## Known gaps
+
+- **Vue/Svelte SFCs are not currently linted.** Our linter doesn't yet support `.vue`/`.svelte` parsers in the toolchain we use; the script blocks inside those files rely on TypeScript and tests for safety. If you're touching a `.svelte` or `.vue` file, lean on `tsc` / `svelte-check` / `vue-tsc` and explicit tests.
+- **Build configs (`vite.config.ts`, `vitest.config.ts`) are not in the `tsc` typecheck pass.** They're typechecked at build time by vite/vitest themselves. If you make changes there, run `pnpm build` or `pnpm test:lib` to surface issues.
+
+## Reporting issues / getting help
+
+- Bugs: open a GitHub issue with a minimal repro (the bug report template in `.github/issue_template/bug_report.yml` walks you through it).
+- Questions / discussions: [TanStack Discord](https://tlinz.com/discord).
+- Security: follow the disclosure process in `SECURITY.md` (if applicable) or email the maintainers directly.
+
+## Code of Conduct
+
+By participating you agree to abide by our [Code of Conduct](./CODE_OF_CONDUCT.md).

From 2f77fb728f9a42a104ac7cc691d3030a3bb0bbc3 Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Mon, 18 May 2026 11:40:14 +0000
Subject: [PATCH 08/17] ci: apply automated fixes

---
 CONTRIBUTING.md                               |  48 +--
 .../tests/anthropic-adapter.test.ts           |   5 +-
 .../ai-anthropic/tests/model-meta.test.ts     | 120 +++++--
 .../typescript/ai-anthropic/tsconfig.json     |  10 +-
 packages/typescript/ai-client/tsconfig.json   |  10 +-
 .../ai-code-mode-skills/tsconfig.json         |  10 +-
 .../typescript/ai-code-mode/tsconfig.json     |  10 +-
 packages/typescript/ai-devtools/tsconfig.json |  10 +-
 .../typescript/ai-elevenlabs/tsconfig.json    |  10 +-
 .../typescript/ai-event-client/tsconfig.json  |  14 +-
 packages/typescript/ai-fal/tsconfig.json      |  11 +-
 .../ai-gemini/tests/model-meta.test.ts        |  16 +-
 packages/typescript/ai-gemini/tsconfig.json   |  10 +-
 packages/typescript/ai-grok/tsconfig.json     |  10 +-
 packages/typescript/ai-groq/tsconfig.json     |  10 +-
 .../tests/worker.test.ts                      |  27 +-
 .../ai-isolate-cloudflare/tsconfig.json       |  19 +-
 .../typescript/ai-isolate-node/tsconfig.json  |  10 +-
 .../ai-isolate-quickjs/tsconfig.json          |  10 +-
 packages/typescript/ai-ollama/tsconfig.json   |  10 +-
 .../ai-openai/tests/model-meta.test.ts        | 308 +++++++++++++-----
 packages/typescript/ai-openai/tsconfig.json   |  10 +-
 .../typescript/ai-openrouter/tsconfig.json    |  10 +-
 packages/typescript/ai-preact/tsconfig.json   |  15 +-
 packages/typescript/ai-react-ui/tsconfig.json |  14 +-
 packages/typescript/ai-react/tsconfig.json    |  15 +-
 packages/typescript/ai-solid-ui/tsconfig.json |  14 +-
 packages/typescript/ai-solid/tsconfig.json    |  15 +-
 packages/typescript/ai-svelte/tsconfig.json   |  16 +-
 packages/typescript/ai-utils/tsconfig.json    |  10 +-
 packages/typescript/ai-vue-ui/tsconfig.json   |  14 +-
 packages/typescript/ai-vue/tsconfig.json      |  15 +-
 packages/typescript/ai/tsconfig.json          |  11 +-
 .../tests/chat-completions-text.test.ts       |   4 +-
 .../openai-base/tests/responses-text.test.ts  |   4 +-
 packages/typescript/openai-base/tsconfig.json |  10 +-
 .../preact-ai-devtools/tsconfig.json          |  10 +-
 .../react-ai-devtools/tsconfig.json           |  10 +-
 .../solid-ai-devtools/tsconfig.json           |  10 +-
 39 files changed, 450 insertions(+), 445 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8e5c1ff02..931e674bf 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -46,20 +46,20 @@ For deeper architecture details (adapter system, isomorphic tools, framework int
 
 All commands are run from the repo root. Nx handles affected detection and caching.
 
-| Goal                            | Command                                       |
-| ------------------------------- | --------------------------------------------- |
-| Run unit tests (affected)       | `pnpm test:lib`                               |
-| Watch unit tests                | `pnpm test:lib:dev`                           |
-| Type-check (affected)           | `pnpm test:types`                             |
-| Lint (affected)                 | `pnpm test:eslint`                            |
-| Verify build artifacts          | `pnpm test:build`                             |
-| Format the repo                 | `pnpm format`                                 |
-| Build (affected)                | `pnpm build`                                  |
-| Build everything                | `pnpm build:all`                              |
-| Run the full CI suite locally   | `pnpm test`                                   |
-| Run the affected-PR check       | `pnpm test:pr`                                |
-| E2E suite                       | `pnpm test:e2e`                               |
-| E2E with Playwright UI          | `pnpm test:e2e:ui`                            |
+| Goal                          | Command             |
+| ----------------------------- | ------------------- |
+| Run unit tests (affected)     | `pnpm test:lib`     |
+| Watch unit tests              | `pnpm test:lib:dev` |
+| Type-check (affected)         | `pnpm test:types`   |
+| Lint (affected)               | `pnpm test:eslint`  |
+| Verify build artifacts        | `pnpm test:build`   |
+| Format the repo               | `pnpm format`       |
+| Build (affected)              | `pnpm build`        |
+| Build everything              | `pnpm build:all`    |
+| Run the full CI suite locally | `pnpm test`         |
+| Run the affected-PR check     | `pnpm test:pr`      |
+| E2E suite                     | `pnpm test:e2e`     |
+| E2E with Playwright UI        | `pnpm test:e2e:ui`  |
 
 Working on a single package? `cd packages/typescript/<pkg>` and use its scripts directly (`pnpm test:lib`, `pnpm test:types`, etc.).
 
@@ -73,11 +73,11 @@ The standardised per-package shape is:
 {
   "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
-    "outDir": "dist"
+    "outDir": "dist",
     // + package-specific overrides only
   },
   "include": ["src", "tests"],
-  "exclude": ["node_modules", "dist"]
+  "exclude": ["node_modules", "dist"],
 }
 ```
 
@@ -93,14 +93,14 @@ Tests are included in typecheck. `vite.config.ts` / `vitest.config.ts` are not 
 
 **Every feature, bug fix, or behaviour change MUST have E2E coverage.** See `testing/e2e/README.md` for the full guide. Quick reference:
 
-| Change type                                | What to add                                                              |
-| ------------------------------------------ | ------------------------------------------------------------------------ |
-| New provider adapter                       | Add provider to `feature-support.ts` + `test-matrix.ts`. Tests auto-run. |
-| New feature (e.g. new generation type)     | Add to types, feature config, support matrix, fixture, spec file.        |
-| Chat / streaming bug fix                   | Test case in `chat.spec.ts` or `tools-test/`.                            |
-| Tool system change                         | Scenario in `tools-test-scenarios.ts` + spec.                            |
-| Middleware change                          | Test in `middleware.spec.ts`.                                            |
-| Client-side change (useChat etc.)          | Test covering the observable behavior change.                            |
+| Change type                            | What to add                                                              |
+| -------------------------------------- | ------------------------------------------------------------------------ |
+| New provider adapter                   | Add provider to `feature-support.ts` + `test-matrix.ts`. Tests auto-run. |
+| New feature (e.g. new generation type) | Add to types, feature config, support matrix, fixture, spec file.        |
+| Chat / streaming bug fix               | Test case in `chat.spec.ts` or `tools-test/`.                            |
+| Tool system change                     | Scenario in `tools-test-scenarios.ts` + spec.                            |
+| Middleware change                      | Test in `middleware.spec.ts`.                                            |
+| Client-side change (useChat etc.)      | Test covering the observable behavior change.                            |
 
 Run the suite locally with `pnpm test:e2e`. Record real LLM fixtures with `OPENAI_API_KEY=sk-... pnpm --filter @tanstack/ai-e2e record`.
 
diff --git a/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts b/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts
index 1db419993..623362212 100644
--- a/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts
+++ b/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts
@@ -35,9 +35,8 @@ vi.mock('@anthropic-ai/sdk', () => {
   return { default: MockAnthropic }
 })
 
-const createAdapter = <TModel extends 'claude-3-7-sonnet'>(
-  model: TModel,
-) => new AnthropicTextAdapter({ apiKey: 'test-key' }, model)
+const createAdapter = <TModel extends 'claude-3-7-sonnet'>(model: TModel) =>
+  new AnthropicTextAdapter({ apiKey: 'test-key' }, model)
 
 const toolArguments = JSON.stringify({ location: 'Berlin' })
 
diff --git a/packages/typescript/ai-anthropic/tests/model-meta.test.ts b/packages/typescript/ai-anthropic/tests/model-meta.test.ts
index a5f7c5bfc..7dda1b44f 100644
--- a/packages/typescript/ai-anthropic/tests/model-meta.test.ts
+++ b/packages/typescript/ai-anthropic/tests/model-meta.test.ts
@@ -567,12 +567,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -583,12 +589,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -599,12 +611,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -615,12 +633,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -631,12 +655,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -647,12 +677,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -663,12 +699,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -679,12 +721,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -695,12 +743,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -711,12 +765,18 @@ describe('Anthropic Model Input Modality Type Assertions', () => {
     it('should allow TextPart, ImagePart, and DocumentPart', () => {
       expectTypeOf<MessageWithContent<AnthropicTextPart>>().toExtend<Message>()
       expectTypeOf<MessageWithContent<AnthropicImagePart>>().toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicDocumentPart>>().toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicDocumentPart>
+      >().toExtend<Message>()
     })
 
     it('should NOT allow AudioPart or VideoPart', () => {
-      expectTypeOf<MessageWithContent<AnthropicAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<AnthropicVideoPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<AnthropicVideoPart>
+      >().not.toExtend<Message>()
     })
   })
 })
diff --git a/packages/typescript/ai-anthropic/tsconfig.json b/packages/typescript/ai-anthropic/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-anthropic/tsconfig.json
+++ b/packages/typescript/ai-anthropic/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-client/tsconfig.json b/packages/typescript/ai-client/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-client/tsconfig.json
+++ b/packages/typescript/ai-client/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-code-mode-skills/tsconfig.json b/packages/typescript/ai-code-mode-skills/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-code-mode-skills/tsconfig.json
+++ b/packages/typescript/ai-code-mode-skills/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-code-mode/tsconfig.json b/packages/typescript/ai-code-mode/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-code-mode/tsconfig.json
+++ b/packages/typescript/ai-code-mode/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-devtools/tsconfig.json b/packages/typescript/ai-devtools/tsconfig.json
index e9cd78b37..584a7975c 100644
--- a/packages/typescript/ai-devtools/tsconfig.json
+++ b/packages/typescript/ai-devtools/tsconfig.json
@@ -6,12 +6,6 @@
     "jsxImportSource": "solid-js",
     "noUnusedLocals": false
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-elevenlabs/tsconfig.json b/packages/typescript/ai-elevenlabs/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-elevenlabs/tsconfig.json
+++ b/packages/typescript/ai-elevenlabs/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-event-client/tsconfig.json b/packages/typescript/ai-event-client/tsconfig.json
index 5cf18c316..6aed8ded9 100644
--- a/packages/typescript/ai-event-client/tsconfig.json
+++ b/packages/typescript/ai-event-client/tsconfig.json
@@ -3,17 +3,9 @@
   "compilerOptions": {
     "outDir": "dist",
     "paths": {
-      "@tanstack/ai-event-client": [
-        "./src/index.ts"
-      ]
+      "@tanstack/ai-event-client": ["./src/index.ts"]
     }
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-fal/tsconfig.json b/packages/typescript/ai-fal/tsconfig.json
index 9f177f7e6..2c90ee303 100644
--- a/packages/typescript/ai-fal/tsconfig.json
+++ b/packages/typescript/ai-fal/tsconfig.json
@@ -3,13 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests",
-    "scripts"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests", "scripts"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-gemini/tests/model-meta.test.ts b/packages/typescript/ai-gemini/tests/model-meta.test.ts
index 305533358..7bc8e01aa 100644
--- a/packages/typescript/ai-gemini/tests/model-meta.test.ts
+++ b/packages/typescript/ai-gemini/tests/model-meta.test.ts
@@ -552,7 +552,9 @@ describe('Gemini Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow DocumentPart', () => {
-      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<GeminiDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -569,7 +571,9 @@ describe('Gemini Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow DocumentPart', () => {
-      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<GeminiDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -585,7 +589,9 @@ describe('Gemini Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow DocumentPart', () => {
-      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<GeminiDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -601,7 +607,9 @@ describe('Gemini Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow DocumentPart', () => {
-      expectTypeOf<MessageWithContent<GeminiDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<GeminiDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 })
diff --git a/packages/typescript/ai-gemini/tsconfig.json b/packages/typescript/ai-gemini/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-gemini/tsconfig.json
+++ b/packages/typescript/ai-gemini/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-grok/tsconfig.json b/packages/typescript/ai-grok/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-grok/tsconfig.json
+++ b/packages/typescript/ai-grok/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-groq/tsconfig.json b/packages/typescript/ai-groq/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-groq/tsconfig.json
+++ b/packages/typescript/ai-groq/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-isolate-cloudflare/tests/worker.test.ts b/packages/typescript/ai-isolate-cloudflare/tests/worker.test.ts
index d342f7aa3..3b1926343 100644
--- a/packages/typescript/ai-isolate-cloudflare/tests/worker.test.ts
+++ b/packages/typescript/ai-isolate-cloudflare/tests/worker.test.ts
@@ -225,9 +225,8 @@ describe('Worker fetch handler', () => {
     const response = await worker.fetch(request, {}, mockExecutionContext)
 
     expect(response.status).toBe(200)
-    const json = await readJson<Extract<ExecuteResponse, { status: 'error' }>>(
-      response,
-    )
+    const json =
+      await readJson<Extract<ExecuteResponse, { status: 'error' }>>(response)
     expect(json.status).toBe('error')
     expect(json.error.name).toBe('WorkerLoaderNotAvailable')
     expect(json.error.message).toContain('LOADER')
@@ -287,9 +286,8 @@ describe('Worker fetch handler', () => {
     expect(capturedOptions!.modules['main.js']).toContain('export default')
     expect(capturedOptions!.globalOutbound).toBeNull()
     expect(response.status).toBe(200)
-    const json = await readJson<Extract<ExecuteResponse, { status: 'done' }>>(
-      response,
-    )
+    const json =
+      await readJson<Extract<ExecuteResponse, { status: 'done' }>>(response)
     expect(json.status).toBe('done')
     expect(json.success).toBe(true)
     expect(json.value).toBe(42)
@@ -326,9 +324,10 @@ describe('Worker fetch handler', () => {
     const response = await worker.fetch(request, env, mockExecutionContext)
 
     expect(response.status).toBe(200)
-    const json = await readJson<
-      Extract<ExecuteResponse, { status: 'need_tools' }>
-    >(response)
+    const json =
+      await readJson<Extract<ExecuteResponse, { status: 'need_tools' }>>(
+        response,
+      )
     expect(json.status).toBe('need_tools')
     expect(json.toolCalls).toHaveLength(1)
     expect(json.toolCalls[0]!.name).toBe('fetchData')
@@ -372,9 +371,8 @@ describe('Worker fetch handler', () => {
     expect(receivedSignal!.aborted).toBe(true)
 
     expect(response.status).toBe(200)
-    const json = await readJson<Extract<ExecuteResponse, { status: 'error' }>>(
-      response,
-    )
+    const json =
+      await readJson<Extract<ExecuteResponse, { status: 'error' }>>(response)
     expect(json.status).toBe('error')
     expect(json.error.name).toBe('TimeoutError')
     expect(json.error.message).toContain('50ms')
@@ -389,9 +387,8 @@ describe('Worker fetch handler', () => {
     const response = await worker.fetch(request, {}, mockExecutionContext)
 
     expect(response.status).toBe(500)
-    const json = await readJson<Extract<ExecuteResponse, { status: 'error' }>>(
-      response,
-    )
+    const json =
+      await readJson<Extract<ExecuteResponse, { status: 'error' }>>(response)
     expect(json.status).toBe('error')
     expect(json.error.name).toBe('RequestError')
   })
diff --git a/packages/typescript/ai-isolate-cloudflare/tsconfig.json b/packages/typescript/ai-isolate-cloudflare/tsconfig.json
index 67fda246c..5219ebae6 100644
--- a/packages/typescript/ai-isolate-cloudflare/tsconfig.json
+++ b/packages/typescript/ai-isolate-cloudflare/tsconfig.json
@@ -3,20 +3,9 @@
   "compilerOptions": {
     "outDir": "./dist/esm",
     "declarationMap": true,
-    "lib": [
-      "ES2022"
-    ],
-    "types": [
-      "@cloudflare/workers-types"
-    ]
+    "lib": ["ES2022"],
+    "types": ["@cloudflare/workers-types"]
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist",
-    "worker"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist", "worker"]
 }
diff --git a/packages/typescript/ai-isolate-node/tsconfig.json b/packages/typescript/ai-isolate-node/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-isolate-node/tsconfig.json
+++ b/packages/typescript/ai-isolate-node/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-isolate-quickjs/tsconfig.json b/packages/typescript/ai-isolate-quickjs/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-isolate-quickjs/tsconfig.json
+++ b/packages/typescript/ai-isolate-quickjs/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-ollama/tsconfig.json b/packages/typescript/ai-ollama/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-ollama/tsconfig.json
+++ b/packages/typescript/ai-ollama/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-openai/tests/model-meta.test.ts b/packages/typescript/ai-openai/tests/model-meta.test.ts
index cf599b5f7..77203fd0f 100644
--- a/packages/typescript/ai-openai/tests/model-meta.test.ts
+++ b/packages/typescript/ai-openai/tests/model-meta.test.ts
@@ -826,7 +826,9 @@ type OpenAITextPart = TextPart<OpenAIMessageMetadataByModality['text']>
 type OpenAIImagePart = ImagePart<OpenAIMessageMetadataByModality['image']>
 type OpenAIAudioPart = AudioPart<OpenAIMessageMetadataByModality['audio']>
 type OpenAIVideoPart = VideoPart<OpenAIMessageMetadataByModality['video']>
-type OpenAIDocumentPart = DocumentPart<OpenAIMessageMetadataByModality['document']>
+type OpenAIDocumentPart = DocumentPart<
+  OpenAIMessageMetadataByModality['document']
+>
 type MessageWithContent<T> = { role: 'user'; content: Array<T> }
 
 /**
@@ -848,9 +850,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -864,9 +872,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -880,9 +894,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -896,9 +916,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -912,9 +938,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -928,9 +960,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -944,9 +982,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -960,9 +1004,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -976,9 +1026,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -992,9 +1048,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1008,9 +1070,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1024,9 +1092,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1040,9 +1114,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1056,9 +1136,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1072,9 +1158,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1088,9 +1180,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1104,9 +1202,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1120,9 +1224,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1136,9 +1246,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1154,9 +1270,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow ImagePart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIImagePart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIImagePart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1170,9 +1292,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow ImagePart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIImagePart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIImagePart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1187,10 +1315,18 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should NOT allow ImagePart, AudioPart, VideoPart, or DocumentPart', () => {
-      expectTypeOf<MessageWithContent<OpenAIImagePart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIAudioPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIVideoPart>>().not.toExtend<Message>()
-      expectTypeOf<MessageWithContent<OpenAIDocumentPart>>().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIImagePart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIAudioPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIVideoPart>
+      >().not.toExtend<Message>()
+      expectTypeOf<
+        MessageWithContent<OpenAIDocumentPart>
+      >().not.toExtend<Message>()
     })
   })
 
@@ -1198,15 +1334,21 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
 
   describe('String and null content should always be allowed', () => {
     it('text+image models should allow string content', () => {
-      type GPT51Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>>
-      type O3Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['o3']>>
+      type GPT51Message = ConstrainedModelMessage<
+        MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>
+      >
+      type O3Message = ConstrainedModelMessage<
+        MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['o3']>
+      >
 
       expectTypeOf<{ role: 'user'; content: string }>().toExtend<GPT51Message>()
       expectTypeOf<{ role: 'user'; content: string }>().toExtend<O3Message>()
     })
 
     it('text-only models should allow string content', () => {
-      type O3MiniMessage = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['o3-mini']>>
+      type O3MiniMessage = ConstrainedModelMessage<
+        MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['o3-mini']>
+      >
 
       expectTypeOf<{
         role: 'user'
@@ -1215,7 +1357,9 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('text+audio models should allow string content', () => {
-      type GPTAudioMessage = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-audio']>>
+      type GPTAudioMessage = ConstrainedModelMessage<
+        MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-audio']>
+      >
 
       expectTypeOf<{
         role: 'user'
@@ -1224,9 +1368,15 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('all models should allow null content', () => {
-      type GPT51Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>>
-      type O3MiniMessage = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['o3-mini']>>
-      type GPTAudioMessage = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-audio']>>
+      type GPT51Message = ConstrainedModelMessage<
+        MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>
+      >
+      type O3MiniMessage = ConstrainedModelMessage<
+        MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['o3-mini']>
+      >
+      type GPTAudioMessage = ConstrainedModelMessage<
+        MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-audio']>
+      >
 
       expectTypeOf<{
         role: 'assistant'
@@ -1247,7 +1397,9 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
 
   describe('Mixed content part validation', () => {
     it('should NOT allow mixing valid and invalid content parts', () => {
-      type GPT51Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>>
+      type GPT51Message = ConstrainedModelMessage<
+        MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>
+      >
 
       // TextPart + VideoPart should NOT be allowed (GPT-5.1 doesn't support video)
       expectTypeOf<
@@ -1261,7 +1413,9 @@ describe('OpenAI Model Input Modality Type Assertions', () => {
     })
 
     it('should allow mixing valid content parts', () => {
-      type GPT51Message = ConstrainedModelMessage<MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>>
+      type GPT51Message = ConstrainedModelMessage<
+        MakeInputModalitiesTypes<OpenAIModelInputModalitiesByName['gpt-5.1']>
+      >
 
       // TextPart + ImagePart should be allowed
       expectTypeOf<
diff --git a/packages/typescript/ai-openai/tsconfig.json b/packages/typescript/ai-openai/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-openai/tsconfig.json
+++ b/packages/typescript/ai-openai/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-openrouter/tsconfig.json b/packages/typescript/ai-openrouter/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-openrouter/tsconfig.json
+++ b/packages/typescript/ai-openrouter/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-preact/tsconfig.json b/packages/typescript/ai-preact/tsconfig.json
index 478f9b6cc..5334c001f 100644
--- a/packages/typescript/ai-preact/tsconfig.json
+++ b/packages/typescript/ai-preact/tsconfig.json
@@ -4,17 +4,8 @@
     "outDir": "dist",
     "jsx": "react-jsx",
     "jsxImportSource": "preact",
-    "lib": [
-      "ES2022",
-      "DOM"
-    ]
+    "lib": ["ES2022", "DOM"]
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-react-ui/tsconfig.json b/packages/typescript/ai-react-ui/tsconfig.json
index ec08aeb4b..c72771d3a 100644
--- a/packages/typescript/ai-react-ui/tsconfig.json
+++ b/packages/typescript/ai-react-ui/tsconfig.json
@@ -6,16 +6,8 @@
     "jsx": "react-jsx",
     "declarationMap": true,
     "composite": true,
-    "lib": [
-      "ES2022",
-      "DOM"
-    ]
+    "lib": ["ES2022", "DOM"]
   },
-  "include": [
-    "src"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-react/tsconfig.json b/packages/typescript/ai-react/tsconfig.json
index 0f90b8d47..9323c0322 100644
--- a/packages/typescript/ai-react/tsconfig.json
+++ b/packages/typescript/ai-react/tsconfig.json
@@ -3,17 +3,8 @@
   "compilerOptions": {
     "outDir": "dist",
     "jsx": "react-jsx",
-    "lib": [
-      "ES2022",
-      "DOM"
-    ]
+    "lib": ["ES2022", "DOM"]
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-solid-ui/tsconfig.json b/packages/typescript/ai-solid-ui/tsconfig.json
index f240896ee..c51d6eaf3 100644
--- a/packages/typescript/ai-solid-ui/tsconfig.json
+++ b/packages/typescript/ai-solid-ui/tsconfig.json
@@ -7,16 +7,8 @@
     "jsxImportSource": "solid-js",
     "declarationMap": true,
     "composite": true,
-    "lib": [
-      "ES2022",
-      "DOM"
-    ]
+    "lib": ["ES2022", "DOM"]
   },
-  "include": [
-    "src"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-solid/tsconfig.json b/packages/typescript/ai-solid/tsconfig.json
index 7492469d6..4abd168c9 100644
--- a/packages/typescript/ai-solid/tsconfig.json
+++ b/packages/typescript/ai-solid/tsconfig.json
@@ -4,17 +4,8 @@
     "outDir": "dist",
     "jsx": "preserve",
     "jsxImportSource": "solid-js",
-    "lib": [
-      "ES2022",
-      "DOM"
-    ]
+    "lib": ["ES2022", "DOM"]
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-svelte/tsconfig.json b/packages/typescript/ai-svelte/tsconfig.json
index 0833a339c..313245656 100644
--- a/packages/typescript/ai-svelte/tsconfig.json
+++ b/packages/typescript/ai-svelte/tsconfig.json
@@ -2,18 +2,8 @@
   "extends": "../../../tsconfig.base.json",
   "compilerOptions": {
     "outDir": "dist",
-    "lib": [
-      "ES2022",
-      "DOM"
-    ]
+    "lib": ["ES2022", "DOM"]
   },
-  "include": [
-    "src",
-    "tests",
-    "**/*.svelte"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests", "**/*.svelte"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-utils/tsconfig.json b/packages/typescript/ai-utils/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/ai-utils/tsconfig.json
+++ b/packages/typescript/ai-utils/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-vue-ui/tsconfig.json b/packages/typescript/ai-vue-ui/tsconfig.json
index 60963fbbd..06f814833 100644
--- a/packages/typescript/ai-vue-ui/tsconfig.json
+++ b/packages/typescript/ai-vue-ui/tsconfig.json
@@ -6,16 +6,8 @@
     "jsx": "preserve",
     "declarationMap": true,
     "composite": true,
-    "lib": [
-      "ES2022",
-      "DOM"
-    ]
+    "lib": ["ES2022", "DOM"]
   },
-  "include": [
-    "src"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai-vue/tsconfig.json b/packages/typescript/ai-vue/tsconfig.json
index b797eda55..55ea8ad20 100644
--- a/packages/typescript/ai-vue/tsconfig.json
+++ b/packages/typescript/ai-vue/tsconfig.json
@@ -3,17 +3,8 @@
   "compilerOptions": {
     "outDir": "dist",
     "jsx": "preserve",
-    "lib": [
-      "ES2022",
-      "DOM"
-    ]
+    "lib": ["ES2022", "DOM"]
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/ai/tsconfig.json b/packages/typescript/ai/tsconfig.json
index 0fcff08d0..575a29aab 100644
--- a/packages/typescript/ai/tsconfig.json
+++ b/packages/typescript/ai/tsconfig.json
@@ -3,13 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist",
-    "tests/**/*.test-d.ts"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist", "tests/**/*.test-d.ts"]
 }
diff --git a/packages/typescript/openai-base/tests/chat-completions-text.test.ts b/packages/typescript/openai-base/tests/chat-completions-text.test.ts
index 874887da8..fba28affe 100644
--- a/packages/typescript/openai-base/tests/chat-completions-text.test.ts
+++ b/packages/typescript/openai-base/tests/chat-completions-text.test.ts
@@ -299,7 +299,9 @@ describe('OpenAIBaseChatCompletionsTextAdapter', () => {
 
       // Should have TEXT_MESSAGE_START before TEXT_MESSAGE_CONTENT
       const textStartIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_START)
-      const textContentIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_CONTENT)
+      const textContentIndex = eventTypes.indexOf(
+        EventType.TEXT_MESSAGE_CONTENT,
+      )
       expect(textStartIndex).toBeGreaterThan(-1)
       expect(textContentIndex).toBeGreaterThan(textStartIndex)
 
diff --git a/packages/typescript/openai-base/tests/responses-text.test.ts b/packages/typescript/openai-base/tests/responses-text.test.ts
index 5d9f49f1a..0e8a34257 100644
--- a/packages/typescript/openai-base/tests/responses-text.test.ts
+++ b/packages/typescript/openai-base/tests/responses-text.test.ts
@@ -277,7 +277,9 @@ describe('OpenAIBaseResponsesTextAdapter', () => {
 
       // Should have TEXT_MESSAGE_START before TEXT_MESSAGE_CONTENT
       const textStartIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_START)
-      const textContentIndex = eventTypes.indexOf(EventType.TEXT_MESSAGE_CONTENT)
+      const textContentIndex = eventTypes.indexOf(
+        EventType.TEXT_MESSAGE_CONTENT,
+      )
       expect(textStartIndex).toBeGreaterThan(-1)
       expect(textContentIndex).toBeGreaterThan(textStartIndex)
 
diff --git a/packages/typescript/openai-base/tsconfig.json b/packages/typescript/openai-base/tsconfig.json
index 127dc2038..e2df93638 100644
--- a/packages/typescript/openai-base/tsconfig.json
+++ b/packages/typescript/openai-base/tsconfig.json
@@ -3,12 +3,6 @@
   "compilerOptions": {
     "outDir": "dist"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/preact-ai-devtools/tsconfig.json b/packages/typescript/preact-ai-devtools/tsconfig.json
index 0cb9c00df..571be78ab 100644
--- a/packages/typescript/preact-ai-devtools/tsconfig.json
+++ b/packages/typescript/preact-ai-devtools/tsconfig.json
@@ -5,12 +5,6 @@
     "jsxFactory": "h",
     "jsxFragmentFactory": "Fragment"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/react-ai-devtools/tsconfig.json b/packages/typescript/react-ai-devtools/tsconfig.json
index 1f0c39cb5..ce80fb6ff 100644
--- a/packages/typescript/react-ai-devtools/tsconfig.json
+++ b/packages/typescript/react-ai-devtools/tsconfig.json
@@ -4,12 +4,6 @@
     "jsx": "preserve",
     "jsxFactory": "solid"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }
diff --git a/packages/typescript/solid-ai-devtools/tsconfig.json b/packages/typescript/solid-ai-devtools/tsconfig.json
index 1f0c39cb5..ce80fb6ff 100644
--- a/packages/typescript/solid-ai-devtools/tsconfig.json
+++ b/packages/typescript/solid-ai-devtools/tsconfig.json
@@ -4,12 +4,6 @@
     "jsx": "preserve",
     "jsxFactory": "solid"
   },
-  "include": [
-    "src",
-    "tests"
-  ],
-  "exclude": [
-    "node_modules",
-    "dist"
-  ]
+  "include": ["src", "tests"],
+  "exclude": ["node_modules", "dist"]
 }

From 05614269dd4f5cae35ecf49e51f20d7e55a706df Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:42:43 +0200
Subject: [PATCH 09/17] chore(changesets): use ts-* glob instead of listing
 each example explicitly

---
 .changeset/config.json | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/.changeset/config.json b/.changeset/config.json
index c727b374e..367b80696 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -17,14 +17,7 @@
     "stream-processor-panel",
     "php-slim",
     "python-fastapi",
-    "ts-code-mode-web",
-    "ts-group-chat",
-    "ts-react-chat",
-    "ts-react-media",
-    "ts-react-search",
-    "ts-solid-chat",
-    "ts-svelte-chat",
-    "ts-vue-chat",
+    "ts-*",
     "vanilla-chat"
   ],
   "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {

From 30e331732424ff5b5c81a55fc533736f21d876f3 Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:48:00 +0200
Subject: [PATCH 10/17] docs: drop incorrect Node.js v24+ requirement from
 READMEs and CONTRIBUTING.md

---
 CONTRIBUTING.md                                  | 3 ---
 README.md                                        | 4 ----
 packages/typescript/ai-client/README.md          | 4 ----
 packages/typescript/ai-devtools/README.md        | 4 ----
 packages/typescript/ai-gemini/README.md          | 4 ----
 packages/typescript/ai-ollama/README.md          | 4 ----
 packages/typescript/ai-openai/README.md          | 4 ----
 packages/typescript/ai-react-ui/README.md        | 4 ----
 packages/typescript/ai-react/README.md           | 4 ----
 packages/typescript/ai/README.md                 | 4 ----
 packages/typescript/preact-ai-devtools/README.md | 4 ----
 packages/typescript/react-ai-devtools/README.md  | 4 ----
 packages/typescript/solid-ai-devtools/README.md  | 4 ----
 13 files changed, 51 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 931e674bf..5dd113612 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,13 +4,10 @@ Thanks for contributing! This guide covers everything you need to get from a fre
 
 ## Prerequisites
 
-- **Node.js**: 24 or newer (older versions break `isolated-vm`).
 - **pnpm**: 10.17.0 or newer. Use the version pinned in `packageManager` (`pnpm@11.1.1`).
   - Recommended: install via [Corepack](https://nodejs.org/api/corepack.html). Run `corepack enable` once and pnpm is managed automatically.
 - **Git**.
 
-We don't currently use Volta/asdf/nvm files. A `.nvmrc` pins the Node version if you use nvm/fnm.
-
 ## Initial setup
 
 ```bash
diff --git a/README.md b/README.md
index cd8d92350..26e3db048 100644
--- a/README.md
+++ b/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/ai-client/README.md b/packages/typescript/ai-client/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/ai-client/README.md
+++ b/packages/typescript/ai-client/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/ai-devtools/README.md b/packages/typescript/ai-devtools/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/ai-devtools/README.md
+++ b/packages/typescript/ai-devtools/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/ai-gemini/README.md b/packages/typescript/ai-gemini/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/ai-gemini/README.md
+++ b/packages/typescript/ai-gemini/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/ai-ollama/README.md b/packages/typescript/ai-ollama/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/ai-ollama/README.md
+++ b/packages/typescript/ai-ollama/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/ai-openai/README.md b/packages/typescript/ai-openai/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/ai-openai/README.md
+++ b/packages/typescript/ai-openai/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/ai-react-ui/README.md b/packages/typescript/ai-react-ui/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/ai-react-ui/README.md
+++ b/packages/typescript/ai-react-ui/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/ai-react/README.md b/packages/typescript/ai-react/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/ai-react/README.md
+++ b/packages/typescript/ai-react/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/ai/README.md b/packages/typescript/ai/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/ai/README.md
+++ b/packages/typescript/ai/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/preact-ai-devtools/README.md b/packages/typescript/preact-ai-devtools/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/preact-ai-devtools/README.md
+++ b/packages/typescript/preact-ai-devtools/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/react-ai-devtools/README.md b/packages/typescript/react-ai-devtools/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/react-ai-devtools/README.md
+++ b/packages/typescript/react-ai-devtools/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:
diff --git a/packages/typescript/solid-ai-devtools/README.md b/packages/typescript/solid-ai-devtools/README.md
index cd8d92350..26e3db048 100644
--- a/packages/typescript/solid-ai-devtools/README.md
+++ b/packages/typescript/solid-ai-devtools/README.md
@@ -49,10 +49,6 @@ A powerful, type-safe AI SDK for building AI-powered applications.
 
 ### <a href="https://tanstack.com/ai">Read the docs →</a>
 
-## Requirements
-
-- **Node.js v24+** is required to avoid compatibility issues with `isolated-vm`.
-
 ## Tree-Shakeable Adapters
 
 Import only the functionality you need for smaller bundle sizes:

From 8323a3ce1094e31d0a94a103defc89c488e0288d Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 13:50:49 +0200
Subject: [PATCH 11/17] fix: scope Node version constraint to ai-isolate-node
 (Node >= 22 for isolated-vm)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The previous "Node 24+" claim was overreaching:

- Only `@tanstack/ai-isolate-node` (via `isolated-vm`) has a Node version
  floor. Everything else in the workspace runs fine on older Node.
- `isolated-vm`'s actual `engines.node` is `>=22.0.0` (see
  https://github.com/laverdet/isolated-vm/blob/main/package.json), not 24.

Changes:
- Root package.json: drop the `node: ">=24"` entry from engines (keep the
  pnpm constraint). No global Node floor for development.
- packages/typescript/ai-isolate-node/package.json: bump `engines.node`
  from `>=18` to `>=22` to match upstream.
- packages/typescript/ai-isolate-node/README.md: same — say `>=22`, and
  add the `--no-node-snapshot` flag note for Node 20+ runtime usage.
---
 package.json                                     | 1 -
 packages/typescript/ai-isolate-node/README.md    | 3 ++-
 packages/typescript/ai-isolate-node/package.json | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/package.json b/package.json
index 8ef5fc652..0beb3c6e7 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,6 @@
   "packageManager": "pnpm@11.1.1",
   "type": "module",
   "engines": {
-    "node": ">=24",
     "pnpm": ">=11.0.0"
   },
   "scripts": {
diff --git a/packages/typescript/ai-isolate-node/README.md b/packages/typescript/ai-isolate-node/README.md
index d43640299..787e642a1 100644
--- a/packages/typescript/ai-isolate-node/README.md
+++ b/packages/typescript/ai-isolate-node/README.md
@@ -4,8 +4,9 @@ Node.js V8 isolate driver for TanStack AI Code Mode. Uses [`isolated-vm`](https:
 
 ## Requirements
 
-- Node.js >= 18
+- Node.js >= 22 (matches [`isolated-vm`'s engine constraint](https://github.com/laverdet/isolated-vm/blob/main/package.json))
 - Native compilation toolchain (the `isolated-vm` package compiles a native addon)
+- On Node.js 20.x and later, pass `--no-node-snapshot` when running `node`
 
 ## Installation
 
diff --git a/packages/typescript/ai-isolate-node/package.json b/packages/typescript/ai-isolate-node/package.json
index 0755bb1bc..77fbee8b4 100644
--- a/packages/typescript/ai-isolate-node/package.json
+++ b/packages/typescript/ai-isolate-node/package.json
@@ -20,7 +20,7 @@
   },
   "sideEffects": false,
   "engines": {
-    "node": ">=18"
+    "node": ">=22"
   },
   "files": [
     "dist",

From 05e65f1083adb14934ba44799b7c4588e349ac4d Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 14:12:27 +0200
Subject: [PATCH 12/17] chore: address CodeRabbit feedback on PR #572

- package.json: relax engines.pnpm from `>=11.0.0` to `>=10.17.0` to match
  CONTRIBUTING.md ("pnpm 10.17.0 or newer"). packageManager still pins
  pnpm@11.1.1 for corepack users.
- packages/typescript/ai-isolate-node/README.md: rewrite the
  `--no-node-snapshot` bullet so it no longer says "Node.js 20.x and later"
  alongside the "Node.js >= 22" minimum stated two bullets above. The flag
  is required by isolated-vm on every Node version we support.
- packages/typescript/ai-gemini/tests/model-meta.test.ts: the
  "thinking models should allow thinkingConfig" type-test was asserting
  `stopSequences` (a placeholder swapped in during the typecheck rot
  cleanup). Restore the original intent: assert that `thinkingConfig` is
  present on `GeminiChatModelProviderOptionsByName['gemini-2.5-pro']`.
- packages/typescript/ai-openai/tests/openai-adapter.test.ts: the test
  passes `systemPrompts: ['Stay concise']` but never checked that it
  arrived on the outbound payload. Add the missing
  `instructions: 'Stay concise'` assertion (the Responses API field the
  adapter writes `systemPrompts.join('\n')` into).

Skipped:
- packages/typescript/ai-vue-ui/tsconfig.json (and sibling -ui packages):
  CodeRabbit suggested adding `"tests"` to `include`. The *-ui packages
  have no test files on disk and use `composite: true` with `rootDir: src`,
  so widening include would point at a non-existent directory.
---
 package.json                                              | 2 +-
 packages/typescript/ai-gemini/tests/model-meta.test.ts    | 8 ++++----
 packages/typescript/ai-isolate-node/README.md             | 2 +-
 .../typescript/ai-openai/tests/openai-adapter.test.ts     | 1 +
 4 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/package.json b/package.json
index 0beb3c6e7..dd91cc05e 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
   "packageManager": "pnpm@11.1.1",
   "type": "module",
   "engines": {
-    "pnpm": ">=11.0.0"
+    "pnpm": ">=10.17.0"
   },
   "scripts": {
     "clean": "pnpm --filter \"./packages/**\" run clean",
diff --git a/packages/typescript/ai-gemini/tests/model-meta.test.ts b/packages/typescript/ai-gemini/tests/model-meta.test.ts
index 7bc8e01aa..1741568e6 100644
--- a/packages/typescript/ai-gemini/tests/model-meta.test.ts
+++ b/packages/typescript/ai-gemini/tests/model-meta.test.ts
@@ -240,12 +240,12 @@ describe('Gemini Model Provider Options Type Assertions', () => {
   })
 
   describe('Detailed property type assertions', () => {
-    it('thinking models should allow thinkingConfig in generationConfig', () => {
+    it('thinking models should allow thinkingConfig', () => {
       type Options = GeminiChatModelProviderOptionsByName['gemini-2.5-pro']
 
-      // The generationConfig should include thinkingConfig from GeminiCommonConfigOptions
-      // which intersects with GeminiThinkingOptions
-      expectTypeOf<Options>().toHaveProperty('stopSequences')
+      // gemini-2.5-pro supports thinking, so its provider options should
+      // include thinkingConfig from GeminiThinkingOptions.
+      expectTypeOf<Options>().toHaveProperty('thinkingConfig')
     })
 
     it('structured output options should have responseMimeType and responseSchema', () => {
diff --git a/packages/typescript/ai-isolate-node/README.md b/packages/typescript/ai-isolate-node/README.md
index 787e642a1..0bc982139 100644
--- a/packages/typescript/ai-isolate-node/README.md
+++ b/packages/typescript/ai-isolate-node/README.md
@@ -6,7 +6,7 @@ Node.js V8 isolate driver for TanStack AI Code Mode. Uses [`isolated-vm`](https:
 
 - Node.js >= 22 (matches [`isolated-vm`'s engine constraint](https://github.com/laverdet/isolated-vm/blob/main/package.json))
 - Native compilation toolchain (the `isolated-vm` package compiles a native addon)
-- On Node.js 20.x and later, pass `--no-node-snapshot` when running `node`
+- Pass `--no-node-snapshot` when running `node` (required by `isolated-vm` on every supported Node.js version)
 
 ## Installation
 
diff --git a/packages/typescript/ai-openai/tests/openai-adapter.test.ts b/packages/typescript/ai-openai/tests/openai-adapter.test.ts
index d6ec64b3c..8154bcad7 100644
--- a/packages/typescript/ai-openai/tests/openai-adapter.test.ts
+++ b/packages/typescript/ai-openai/tests/openai-adapter.test.ts
@@ -119,6 +119,7 @@ describe('OpenAI adapter option mapping', () => {
       max_output_tokens: 1024, // Responses API uses max_output_tokens instead of max_tokens
       stream: true,
       tool_choice: 'required', // From modelOptions
+      instructions: 'Stay concise', // systemPrompts join the Responses API `instructions` field
     })
 
     // Responses API uses 'input' instead of 'messages'

From 8dc3dd79d70e9212753c2e7e78f2727b4f89b253 Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Mon, 18 May 2026 14:35:04 +0200
Subject: [PATCH 13/17] feat(ai): systemPrompts accept { content, metadata }
 with adapter-inferred metadata typing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Extends `chat({ systemPrompts })` to accept either a plain string (existing
shape — backward compatible) or `{ content, metadata }`. The structured
form's `metadata` type is inferred from the adapter at the chat() call site
via a new `TSystemPromptMetadata` generic on `TextAdapter` — no `satisfies`
needed by callers.

- Anthropic declares `AnthropicSystemPromptMetadata` → users get
  `cache_control` autocomplete + type-checking.
- Adapters with no per-prompt metadata (OpenAI, Gemini, Ollama,
  OpenRouter, openai-base) inherit the default `never`, which makes the
  `metadata` field unusable at the call site. Passing metadata to those
  adapters is a TypeScript error.

Closes the regression introduced by removing the `modelOptions.system`
escape hatch in the audit PR — there is now a public, typed path for
attaching Anthropic `cache_control` to system prompts.

Plumbing

- New `TSystemPromptMetadata = never` generic on `TextAdapter` /
  `BaseTextAdapter`, surfaced via `'~types'['systemPromptMetadata']`.
  `TextActivityOptions.systemPrompts` is now
  `Array<SystemPrompt<TAdapter['~types']['systemPromptMetadata']>>`.
- `AnyTextAdapter` extended to 7 generic slots.
- `TextOptions.systemPrompts` (the wide internal shape adapters receive)
  is `Array<SystemPrompt>`; adapters call `normalizeSystemPrompts<...>()`
  to narrow.
- Chat engine + middleware context/config widened to carry
  `Array<SystemPrompt>` so metadata flows through to the adapter.
- OpenTelemetry middleware extracts `.content` for span events;
  per-prompt metadata is dropped from spans.
- `@tanstack/ai-event-client` mirrors the `SystemPrompt` shape locally
  (avoids a circular import with `@tanstack/ai`) and projects metadata
  away on the devtools wire.

Adapter mappings

- Anthropic reads `metadata.cache_control` and attaches it to the
  matching `TextBlockParam`.
- OpenAI / Gemini / Ollama / OpenRouter / openai-base call
  `normalizeSystemPrompts()` and join `.content` for their respective
  `instructions` / `system` / `systemInstruction` fields. (Their
  metadata type is `never`, so the field can't be set anyway.)

Tests

- ai-anthropic: new test verifies `cache_control` flows from
  `systemPrompts[i].metadata` onto the outbound `TextBlockParam`, and
  plain-string entries still produce metadata-less blocks.
- ai-openai: new test verifies mixed string + object-form input
  (without metadata) produces the expected joined `instructions`.
---
 .changeset/feat-system-prompts-metadata.md    | 73 +++++++++++++++++++
 .../ai-anthropic/src/adapters/text.ts         | 30 ++++++--
 packages/typescript/ai-anthropic/src/index.ts |  1 +
 .../src/text/text-provider-options.ts         | 31 ++++++++
 .../tests/anthropic-adapter.test.ts           | 58 +++++++++++++++
 .../src/devtools-middleware.ts                | 19 ++++-
 .../typescript/ai-gemini/src/adapters/text.ts |  9 ++-
 .../typescript/ai-ollama/src/adapters/text.ts | 11 ++-
 .../typescript/ai-openai/src/adapters/text.ts | 10 ++-
 .../ai-openai/tests/openai-adapter.test.ts    | 43 +++++++++++
 .../src/adapters/responses-text.ts            | 11 +--
 .../ai-openrouter/src/adapters/text.ts        |  7 +-
 .../ai/src/activities/chat/adapter.ts         | 13 +++-
 .../ai/src/activities/chat/index.ts           | 17 ++++-
 .../src/activities/chat/middleware/types.ts   |  5 +-
 packages/typescript/ai/src/index.ts           |  7 ++
 .../typescript/ai/src/middlewares/otel.ts     |  9 ++-
 packages/typescript/ai/src/system-prompts.ts  | 69 ++++++++++++++++++
 packages/typescript/ai/src/types.ts           | 13 +++-
 .../chat-structured-output-stream.test.ts     |  1 +
 .../typescript/ai/tests/middleware.test.ts    |  3 +-
 packages/typescript/ai/tests/test-utils.ts    |  1 +
 .../typescript/ai/tests/type-check.test.ts    |  1 +
 .../src/adapters/chat-completions-text.ts     |  7 +-
 .../src/adapters/responses-text.ts            | 11 +--
 25 files changed, 413 insertions(+), 47 deletions(-)
 create mode 100644 .changeset/feat-system-prompts-metadata.md
 create mode 100644 packages/typescript/ai/src/system-prompts.ts

diff --git a/.changeset/feat-system-prompts-metadata.md b/.changeset/feat-system-prompts-metadata.md
new file mode 100644
index 000000000..e7478bc31
--- /dev/null
+++ b/.changeset/feat-system-prompts-metadata.md
@@ -0,0 +1,73 @@
+---
+'@tanstack/ai': minor
+'@tanstack/ai-anthropic': minor
+'@tanstack/ai-event-client': patch
+'@tanstack/ai-gemini': patch
+'@tanstack/ai-ollama': patch
+'@tanstack/ai-openai': patch
+'@tanstack/ai-openrouter': patch
+'@tanstack/openai-base': patch
+---
+
+feat(ai): `systemPrompts` accept `{ content, metadata }` with adapter-inferred metadata typing
+
+`chat({ systemPrompts })` now accepts either a plain string (the existing
+shape — fully backward compatible) or `{ content, metadata }`. The `metadata`
+field's type is inferred from the adapter via a new
+`TSystemPromptMetadata` generic on `TextAdapter` / `BaseTextAdapter`:
+
+- `@tanstack/ai-anthropic` declares `AnthropicSystemPromptMetadata` →
+  users get `cache_control` autocomplete and type-checking on
+  `systemPrompts[i].metadata` for Anthropic chats.
+- Adapters with no per-prompt metadata (OpenAI, Gemini, Ollama,
+  OpenRouter, openai-base) inherit the default `never`, which makes the
+  `metadata` field unusable at the call site — passing it is a TypeScript
+  error.
+
+```ts
+import { chat } from '@tanstack/ai'
+import { anthropicText } from '@tanstack/ai-anthropic'
+
+// Anthropic — `cache_control` is autocompleted, no `satisfies` needed.
+chat({
+  adapter: anthropicText({ apiKey }, 'claude-sonnet-4-6'),
+  systemPrompts: [
+    {
+      content: 'Stable instructions — cache me.',
+      metadata: { cache_control: { type: 'ephemeral' } },
+    },
+    'Volatile per-request instruction.',
+  ],
+})
+
+// OpenAI — `metadata` field is `never`, attempting to pass it errors at compile time.
+chat({
+  adapter: openaiText({ apiKey }, 'gpt-4o-mini'),
+  systemPrompts: [
+    'Plain string.',
+    { content: 'Object form without metadata is allowed.' },
+  ],
+})
+```
+
+New exports:
+
+- `@tanstack/ai`: `SystemPrompt`, `NormalizedSystemPrompt` types and the
+  `normalizeSystemPrompts()` helper adapters use to normalize the wide
+  input shape to `{ content, metadata? }` before consumption.
+- `@tanstack/ai-anthropic`: `AnthropicSystemPromptMetadata` interface
+  (currently exposes `cache_control` for prompt caching).
+
+Internal:
+
+- New `TSystemPromptMetadata = never` generic on `TextAdapter` /
+  `BaseTextAdapter`, surfaced via `'~types'['systemPromptMetadata']`
+  for inference at the `chat()` call site.
+- Anthropic adapter reads `metadata.cache_control` and attaches it to
+  the corresponding `TextBlockParam`.
+- All other text adapters call `normalizeSystemPrompts()` and join
+  `.content` for their respective `instructions` / `system` /
+  `systemInstruction` fields.
+- `@tanstack/ai-event-client` mirrors the `SystemPrompt` shape locally
+  (avoids a circular import) and projects metadata away on the devtools
+  wire — devtools UI still receives `Array<string>`.
diff --git a/packages/typescript/ai-anthropic/src/adapters/text.ts b/packages/typescript/ai-anthropic/src/adapters/text.ts
index e08919164..077ada05c 100644
--- a/packages/typescript/ai-anthropic/src/adapters/text.ts
+++ b/packages/typescript/ai-anthropic/src/adapters/text.ts
@@ -1,4 +1,4 @@
-import { EventType } from '@tanstack/ai'
+import { EventType, normalizeSystemPrompts } from '@tanstack/ai'
 import { BaseTextAdapter } from '@tanstack/ai/adapters'
 import { convertToolsToProviderFormat } from '../tools/tool-converter'
 import { validateTextProviderOptions } from '../text/text-provider-options'
@@ -38,6 +38,7 @@ import type {
   TextOptions,
 } from '@tanstack/ai'
 import type {
+  AnthropicSystemPromptMetadata,
   ExternalTextProviderOptions,
   InternalTextProviderOptions,
 } from '../text/text-provider-options'
@@ -115,7 +116,12 @@ export class AnthropicTextAdapter<
   TProviderOptions,
   TInputModalities,
   AnthropicMessageMetadataByModality,
-  TToolCapabilities
+  TToolCapabilities,
+  // TToolCallMetadata — anthropic has no tool-call metadata round-tripping
+  unknown,
+  // TSystemPromptMetadata — narrows `systemPrompts[i].metadata` at the
+  // chat() call site so users get `cache_control` autocomplete.
+  AnthropicSystemPromptMetadata
 > {
   readonly kind = 'text' as const
   readonly name = 'anthropic' as const
@@ -335,11 +341,21 @@ export class AnthropicTextAdapter<
       temperature: options.temperature,
       top_p: options.topP,
       messages: formattedMessages,
-      system: options.systemPrompts?.length
-        ? options.systemPrompts.map(
-            (text): TextBlockParam => ({ type: 'text', text }),
-          )
-        : undefined,
+      system: (() => {
+        const normalized = normalizeSystemPrompts<AnthropicSystemPromptMetadata>(
+          options.systemPrompts,
+        )
+        if (normalized.length === 0) return undefined
+        return normalized.map(
+          (p): TextBlockParam => ({
+            type: 'text',
+            text: p.content,
+            ...(p.metadata?.cache_control && {
+              cache_control: p.metadata.cache_control,
+            }),
+          }),
+        )
+      })(),
       tools: tools,
       ...validProviderOptions,
     }
diff --git a/packages/typescript/ai-anthropic/src/index.ts b/packages/typescript/ai-anthropic/src/index.ts
index 1ba8e92b8..cc1315947 100644
--- a/packages/typescript/ai-anthropic/src/index.ts
+++ b/packages/typescript/ai-anthropic/src/index.ts
@@ -10,6 +10,7 @@ export {
   type AnthropicTextConfig,
   type AnthropicTextProviderOptions,
 } from './adapters/text'
+export type { AnthropicSystemPromptMetadata } from './text/text-provider-options'
 
 // Summarize - thin factory functions over @tanstack/ai's ChatStreamSummarizeAdapter
 export {
diff --git a/packages/typescript/ai-anthropic/src/text/text-provider-options.ts b/packages/typescript/ai-anthropic/src/text/text-provider-options.ts
index 975f29240..ed4f05746 100644
--- a/packages/typescript/ai-anthropic/src/text/text-provider-options.ts
+++ b/packages/typescript/ai-anthropic/src/text/text-provider-options.ts
@@ -4,12 +4,43 @@ import type {
   BetaToolChoiceAuto,
   BetaToolChoiceTool,
 } from '@anthropic-ai/sdk/resources/beta/messages/messages'
+import type { CacheControlEphemeral } from '@anthropic-ai/sdk/resources'
 import type { AnthropicTool } from '../tools'
 import type {
   MessageParam,
   TextBlockParam,
 } from '@anthropic-ai/sdk/resources/messages'
 
+/**
+ * Per-prompt metadata Anthropic understands on `systemPrompts` entries.
+ *
+ * Used via the structured form of `systemPrompts`:
+ *
+ * @example
+ *   import type { AnthropicSystemPromptMetadata } from '@tanstack/ai-anthropic'
+ *
+ *   chat({
+ *     adapter: anthropicText(),
+ *     model: 'claude-sonnet-4-6',
+ *     systemPrompts: [
+ *       {
+ *         content: 'Stable instructions — cache me.',
+ *         metadata: { cache_control: { type: 'ephemeral' } } satisfies AnthropicSystemPromptMetadata,
+ *       },
+ *       'Volatile per-request instruction.',
+ *     ],
+ *   })
+ */
+export interface AnthropicSystemPromptMetadata {
+  /**
+   * Anthropic prompt-caching control applied to this system prompt's
+   * `TextBlockParam`.
+   *
+   * @see https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
+   */
+  cache_control?: CacheControlEphemeral
+}
+
 export interface AnthropicContainerOptions {
   /**
    * Container identifier for reuse across requests.
diff --git a/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts b/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts
index 623362212..f1b1efe41 100644
--- a/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts
+++ b/packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts
@@ -117,6 +117,64 @@ describe('Anthropic adapter option mapping', () => {
     ])
   })
 
+  it('attaches cache_control to system TextBlockParams via systemPrompts metadata', async () => {
+    const mockStream = (async function* () {
+      yield {
+        type: 'content_block_start',
+        index: 0,
+        content_block: { type: 'text', text: '' },
+      }
+      yield {
+        type: 'content_block_delta',
+        index: 0,
+        delta: { type: 'text_delta', text: 'ok' },
+      }
+      yield {
+        type: 'message_delta',
+        delta: { stop_reason: 'end_turn' },
+        usage: { output_tokens: 1 },
+      }
+      yield { type: 'message_stop' }
+    })()
+
+    mocks.betaMessagesCreate.mockResolvedValueOnce(mockStream)
+
+    const adapter = createAdapter('claude-3-7-sonnet')
+
+    for await (const _ of chat({
+      adapter,
+      messages: [{ role: 'user', content: 'Hi' }],
+      systemPrompts: [
+        {
+          content: 'Stable instructions — cache me.',
+          // metadata is narrowed to AnthropicSystemPromptMetadata via the
+          // adapter's `~types['systemPromptMetadata']` declaration — no
+          // `satisfies` needed.
+          metadata: { cache_control: { type: 'ephemeral', ttl: '5m' } },
+        },
+        'Volatile per-request instruction.',
+      ],
+    })) {
+      // consume stream
+    }
+
+    const [payload] = mocks.betaMessagesCreate.mock.calls[0]!
+
+    // Object-form prompts attach their metadata cache_control; plain strings
+    // produce a TextBlockParam with no cache_control.
+    expect(payload.system).toEqual([
+      {
+        type: 'text',
+        text: 'Stable instructions — cache me.',
+        cache_control: { type: 'ephemeral', ttl: '5m' },
+      },
+      {
+        type: 'text',
+        text: 'Volatile per-request instruction.',
+      },
+    ])
+  })
+
   it('maps normalized options and Anthropic provider settings', async () => {
     // Mock the streaming response
     const mockStream = (async function* () {
diff --git a/packages/typescript/ai-event-client/src/devtools-middleware.ts b/packages/typescript/ai-event-client/src/devtools-middleware.ts
index e574a92c8..9acb0e2f8 100644
--- a/packages/typescript/ai-event-client/src/devtools-middleware.ts
+++ b/packages/typescript/ai-event-client/src/devtools-middleware.ts
@@ -12,6 +12,15 @@ interface DevtoolsModelMessage {
   toolCalls?: unknown
 }
 
+/**
+ * Mirrors `SystemPrompt` from `@tanstack/ai` structurally so this package
+ * doesn't import from `@tanstack/ai` (which would introduce a circular dep,
+ * see file-top comment).
+ */
+type DevtoolsSystemPrompt =
+  | string
+  | { content: string; metadata?: unknown }
+
 interface DevtoolsMiddlewareContext {
   requestId: string
   streamId: string
@@ -19,7 +28,7 @@ interface DevtoolsMiddlewareContext {
   provider: string
   model: string
   source: 'client' | 'server'
-  systemPrompts: Array<string>
+  systemPrompts: ReadonlyArray<DevtoolsSystemPrompt>
   toolNames?: Array<string>
   options?: Record<string, unknown>
   modelOptions?: Record<string, unknown>
@@ -104,7 +113,13 @@ function buildEventContext(ctx: DevtoolsMiddlewareContext) {
     model: ctx.model,
     clientId: ctx.conversationId,
     source: ctx.source,
-    systemPrompts: ctx.systemPrompts.length > 0 ? ctx.systemPrompts : undefined,
+    // Devtools wire payload is plain strings; per-prompt metadata is
+    // irrelevant for observation and would require devtools-UI changes to
+    // render. Project metadata away here so the wire shape is unchanged.
+    systemPrompts:
+      ctx.systemPrompts.length > 0
+        ? ctx.systemPrompts.map((p) => (typeof p === 'string' ? p : p.content))
+        : undefined,
     toolNames: ctx.toolNames,
     options: ctx.options,
     modelOptions: ctx.modelOptions,
diff --git a/packages/typescript/ai-gemini/src/adapters/text.ts b/packages/typescript/ai-gemini/src/adapters/text.ts
index 244b0bfe9..6e751a2ad 100644
--- a/packages/typescript/ai-gemini/src/adapters/text.ts
+++ b/packages/typescript/ai-gemini/src/adapters/text.ts
@@ -1,5 +1,5 @@
 import { FinishReason } from '@google/genai'
-import { EventType } from '@tanstack/ai'
+import { EventType, normalizeSystemPrompts } from '@tanstack/ai'
 import { BaseTextAdapter } from '@tanstack/ai/adapters'
 import { convertToolsToProviderFormat } from '../tools/tool-converter'
 import {
@@ -838,7 +838,12 @@ export class GeminiTextAdapter<
                 : undefined,
             }
           : undefined,
-        systemInstruction: options.systemPrompts?.join('\n'),
+        systemInstruction: (() => {
+          const prompts = normalizeSystemPrompts(options.systemPrompts)
+          return prompts.length > 0
+            ? prompts.map((p) => p.content).join('\n')
+            : undefined
+        })(),
         tools: convertToolsToProviderFormat(options.tools),
       },
     }
diff --git a/packages/typescript/ai-ollama/src/adapters/text.ts b/packages/typescript/ai-ollama/src/adapters/text.ts
index 2743dfb5b..3f7a252ef 100644
--- a/packages/typescript/ai-ollama/src/adapters/text.ts
+++ b/packages/typescript/ai-ollama/src/adapters/text.ts
@@ -1,4 +1,4 @@
-import { EventType } from '@tanstack/ai'
+import { EventType, normalizeSystemPrompts } from '@tanstack/ai'
 import { BaseTextAdapter } from '@tanstack/ai/adapters'
 
 import { createOllamaClient, generateId, getOllamaHostFromEnv } from '../utils'
@@ -562,9 +562,12 @@ export class OllamaTextAdapter<TModel extends string> extends BaseTextAdapter<
       options: ollamaOptions,
       messages: this.formatMessages(options.messages),
       tools: this.convertToolsToOllamaFormat(options.tools),
-      ...(options.systemPrompts?.length
-        ? { system: options.systemPrompts.join('\n') }
-        : {}),
+      ...(() => {
+        const prompts = normalizeSystemPrompts(options.systemPrompts)
+        return prompts.length > 0
+          ? { system: prompts.map((p) => p.content).join('\n') }
+          : {}
+      })(),
     }
   }
 }
diff --git a/packages/typescript/ai-openai/src/adapters/text.ts b/packages/typescript/ai-openai/src/adapters/text.ts
index a17b95267..d1d0f94ce 100644
--- a/packages/typescript/ai-openai/src/adapters/text.ts
+++ b/packages/typescript/ai-openai/src/adapters/text.ts
@@ -1,4 +1,5 @@
 import OpenAI from 'openai'
+import { normalizeSystemPrompts } from '@tanstack/ai'
 import { OpenAIBaseResponsesTextAdapter } from '@tanstack/openai-base'
 import { validateTextProviderOptions } from '../text/text-provider-options'
 import { convertToolsToProviderFormat } from '../tools'
@@ -140,10 +141,11 @@ export class OpenAITextAdapter<
       }),
       ...(options.topP !== undefined && { top_p: options.topP }),
       ...(options.metadata !== undefined && { metadata: options.metadata }),
-      ...(options.systemPrompts &&
-        options.systemPrompts.length > 0 && {
-          instructions: options.systemPrompts.join('\n'),
-        }),
+      ...(() => {
+        const prompts = normalizeSystemPrompts(options.systemPrompts)
+        if (prompts.length === 0) return {}
+        return { instructions: prompts.map((p) => p.content).join('\n') }
+      })(),
       input,
       ...(tools && tools.length > 0 && { tools }),
     }
diff --git a/packages/typescript/ai-openai/tests/openai-adapter.test.ts b/packages/typescript/ai-openai/tests/openai-adapter.test.ts
index 8154bcad7..90b805c8a 100644
--- a/packages/typescript/ai-openai/tests/openai-adapter.test.ts
+++ b/packages/typescript/ai-openai/tests/openai-adapter.test.ts
@@ -130,4 +130,47 @@ describe('OpenAI adapter option mapping', () => {
     expect(Array.isArray(payload.tools)).toBe(true)
     expect(payload.tools.length).toBeGreaterThan(0)
   })
+
+  it('accepts mixed string + object-form systemPrompts and joins .content into instructions', async () => {
+    const mockStream = createMockChatCompletionsStream([
+      {
+        type: 'response.created',
+        response: {
+          id: 'resp-mixed',
+          model: 'gpt-4o-mini',
+          status: 'in_progress',
+          created_at: 1234567890,
+        },
+      },
+      {
+        type: 'response.completed',
+        response: {
+          id: 'resp-mixed',
+          status: 'completed',
+          usage: { input_tokens: 1, output_tokens: 0 },
+        },
+      },
+    ])
+
+    const responsesCreate = vi.fn().mockResolvedValueOnce(mockStream)
+    const adapter = createAdapter('gpt-4o-mini')
+    ;(adapter as any).client = { responses: { create: responsesCreate } }
+
+    for await (const _ of chat({
+      adapter,
+      systemPrompts: [
+        'Plain string.',
+        // Object form (without metadata — OpenAI has no per-prompt metadata
+        // surface, so the `metadata` field is typed `never` and rejected
+        // at the call site).
+        { content: 'Structured.' },
+      ],
+      messages: [{ role: 'user', content: 'Hi' }],
+    })) {
+      // consume stream
+    }
+
+    const [payload] = responsesCreate.mock.calls[0]!
+    expect(payload.instructions).toBe('Plain string.\nStructured.')
+  })
 })
diff --git a/packages/typescript/ai-openrouter/src/adapters/responses-text.ts b/packages/typescript/ai-openrouter/src/adapters/responses-text.ts
index 18d6bf2ab..82b396fa2 100644
--- a/packages/typescript/ai-openrouter/src/adapters/responses-text.ts
+++ b/packages/typescript/ai-openrouter/src/adapters/responses-text.ts
@@ -1,5 +1,5 @@
 import { OpenRouter } from '@openrouter/sdk'
-import { EventType } from '@tanstack/ai'
+import { EventType, normalizeSystemPrompts } from '@tanstack/ai'
 import { BaseTextAdapter } from '@tanstack/ai/adapters'
 import { toRunErrorPayload } from '@tanstack/ai/adapter-internals'
 import { generateId, transformNullsToUndefined } from '@tanstack/ai-utils'
@@ -1553,10 +1553,11 @@ export class OpenRouterResponsesTextAdapter<
       }),
       ...(options.topP !== undefined && { topP: options.topP }),
       ...(options.metadata !== undefined && { metadata: options.metadata }),
-      ...(options.systemPrompts &&
-        options.systemPrompts.length > 0 && {
-          instructions: options.systemPrompts.join('\n'),
-        }),
+      ...(() => {
+        const prompts = normalizeSystemPrompts(options.systemPrompts)
+        if (prompts.length === 0) return {}
+        return { instructions: prompts.map((p) => p.content).join('\n') }
+      })(),
       input,
       ...(tools &&
         tools.length > 0 && {
diff --git a/packages/typescript/ai-openrouter/src/adapters/text.ts b/packages/typescript/ai-openrouter/src/adapters/text.ts
index 6878d8e19..17f14df8e 100644
--- a/packages/typescript/ai-openrouter/src/adapters/text.ts
+++ b/packages/typescript/ai-openrouter/src/adapters/text.ts
@@ -1,5 +1,5 @@
 import { OpenRouter } from '@openrouter/sdk'
-import { EventType } from '@tanstack/ai'
+import { EventType, normalizeSystemPrompts } from '@tanstack/ai'
 import { BaseTextAdapter } from '@tanstack/ai/adapters'
 import { toRunErrorPayload } from '@tanstack/ai/adapter-internals'
 import { generateId, transformNullsToUndefined } from '@tanstack/ai-utils'
@@ -1114,10 +1114,11 @@ export class OpenRouterTextAdapter<
       : ''
 
     const messages: Array<ChatMessages> = []
-    if (options.systemPrompts?.length) {
+    const systemPrompts = normalizeSystemPrompts(options.systemPrompts)
+    if (systemPrompts.length > 0) {
       messages.push({
         role: 'system',
-        content: options.systemPrompts.join('\n'),
+        content: systemPrompts.map((p) => p.content).join('\n'),
       })
     }
     for (const m of options.messages) {
diff --git a/packages/typescript/ai/src/activities/chat/adapter.ts b/packages/typescript/ai/src/activities/chat/adapter.ts
index df1c94726..e4c4dccee 100644
--- a/packages/typescript/ai/src/activities/chat/adapter.ts
+++ b/packages/typescript/ai/src/activities/chat/adapter.ts
@@ -55,6 +55,10 @@ export interface StructuredOutputResult<T = unknown> {
  * - TMessageMetadata: Metadata types for content parts (already resolved)
  * - TToolCapabilities: Tuple of tool-kind strings supported by this model, resolved from `supports.tools`
  * - TToolCallMetadata: Metadata type that round-trips with tool calls (e.g. Gemini's `thoughtSignature`)
+ * - TSystemPromptMetadata: Provider-typed metadata accepted on each
+ *   `systemPrompts[i]` entry (e.g. Anthropic `cache_control`). Defaults to
+ *   `never` — adapters without per-prompt metadata reject the `metadata`
+ *   field at the call site.
  */
 export interface TextAdapter<
   TModel extends string,
@@ -63,6 +67,7 @@ export interface TextAdapter<
   TMessageMetadataByModality extends DefaultMessageMetadataByModality,
   TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,
   TToolCallMetadata = unknown,
+  TSystemPromptMetadata = never,
 > {
   /** Discriminator for adapter kind */
   readonly kind: 'text'
@@ -80,6 +85,7 @@ export interface TextAdapter<
     messageMetadataByModality: TMessageMetadataByModality
     toolCapabilities: TToolCapabilities
     toolCallMetadata: TToolCallMetadata
+    systemPromptMetadata: TSystemPromptMetadata
   }
 
   /**
@@ -123,7 +129,7 @@ export interface TextAdapter<
  * A TextAdapter with any/unknown type parameters.
  * Useful as a constraint in generic functions and interfaces.
  */
-export type AnyTextAdapter = TextAdapter<any, any, any, any, any, any>
+export type AnyTextAdapter = TextAdapter<any, any, any, any, any, any, any>
 
 /**
  * Abstract base class for text adapters.
@@ -138,13 +144,15 @@ export abstract class BaseTextAdapter<
   TMessageMetadataByModality extends DefaultMessageMetadataByModality,
   TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,
   TToolCallMetadata = unknown,
+  TSystemPromptMetadata = never,
 > implements TextAdapter<
   TModel,
   TProviderOptions,
   TInputModalities,
   TMessageMetadataByModality,
   TToolCapabilities,
-  TToolCallMetadata
+  TToolCallMetadata,
+  TSystemPromptMetadata
 > {
   readonly kind = 'text' as const
   abstract readonly name: string
@@ -157,6 +165,7 @@ export abstract class BaseTextAdapter<
     messageMetadataByModality: TMessageMetadataByModality
     toolCapabilities: TToolCapabilities
     toolCallMetadata: TToolCallMetadata
+    systemPromptMetadata: TSystemPromptMetadata
   }
 
   protected config: TextAdapterConfig
diff --git a/packages/typescript/ai/src/activities/chat/index.ts b/packages/typescript/ai/src/activities/chat/index.ts
index 7bd20b17a..47af9b7b0 100644
--- a/packages/typescript/ai/src/activities/chat/index.ts
+++ b/packages/typescript/ai/src/activities/chat/index.ts
@@ -56,6 +56,7 @@ import type {
   ChatMiddlewareContext,
   ChatMiddlewarePhase,
 } from './middleware/types'
+import type { SystemPrompt } from '../../system-prompts'
 import type { InternalLogger } from '../../logger/internal-logger'
 import type { DebugOption } from '../../logger/types'
 import type { ProviderTool } from '../../tools/provider-tool'
@@ -102,8 +103,16 @@ export interface TextActivityOptions<
         messageMetadataByModality: TAdapter['~types']['messageMetadataByModality']
       }>
   >
-  /** System prompts to prepend to the conversation */
-  systemPrompts?: TextOptions['systemPrompts']
+  /**
+   * System prompts to prepend to the conversation.
+   *
+   * Accepts plain strings or `{ content, metadata }` objects. The `metadata`
+   * field is typed by the adapter — Anthropic narrows it to
+   * `AnthropicSystemPromptMetadata` (with `cache_control` for prompt
+   * caching), providers without per-prompt metadata reject the field
+   * entirely.
+   */
+  systemPrompts?: Array<SystemPrompt<TAdapter['~types']['systemPromptMetadata']>>
   /**
    * Tools for function calling (auto-executed when called).
    *
@@ -275,7 +284,7 @@ interface TextEngineConfig<
   TParams extends TextOptions<any, any> = TextOptions<any>,
 > {
   adapter: TAdapter
-  systemPrompts?: Array<string>
+  systemPrompts?: Array<SystemPrompt>
   params: TParams
   middleware?: Array<ChatMiddleware>
   context?: unknown
@@ -290,7 +299,7 @@ class TextEngine<
 > {
   private readonly adapter: TAdapter
   private params: TParams
-  private systemPrompts: Array<string>
+  private systemPrompts: Array<SystemPrompt>
   private tools: Array<Tool>
   private readonly loopStrategy: AgentLoopStrategy
   private toolCallManager: ToolCallManager
diff --git a/packages/typescript/ai/src/activities/chat/middleware/types.ts b/packages/typescript/ai/src/activities/chat/middleware/types.ts
index c825a696b..434e6b339 100644
--- a/packages/typescript/ai/src/activities/chat/middleware/types.ts
+++ b/packages/typescript/ai/src/activities/chat/middleware/types.ts
@@ -1,4 +1,5 @@
 import type { ModelMessage, StreamChunk, Tool, ToolCall } from '../../../types'
+import type { SystemPrompt } from '../../../system-prompts'
 
 // ===========================
 // Middleware Context
@@ -74,7 +75,7 @@ export interface ChatMiddlewareContext {
   // --- Config-derived info (may update per-iteration via onConfig) ---
 
   /** System prompts configured for this chat */
-  systemPrompts: Array<string>
+  systemPrompts: Array<SystemPrompt>
   /** Names of configured tools, if any */
   toolNames?: Array<string>
   /** Flattened generation options (temperature, topP, maxTokens, metadata) */
@@ -115,7 +116,7 @@ export interface ChatMiddlewareContext {
  */
 export interface ChatMiddlewareConfig {
   messages: Array<ModelMessage>
-  systemPrompts: Array<string>
+  systemPrompts: Array<SystemPrompt>
   tools: Array<Tool>
   temperature?: number
   topP?: number
diff --git a/packages/typescript/ai/src/index.ts b/packages/typescript/ai/src/index.ts
index 8f7c677e4..0fbbb54ee 100644
--- a/packages/typescript/ai/src/index.ts
+++ b/packages/typescript/ai/src/index.ts
@@ -104,6 +104,13 @@ export type {
 // All types
 export * from './types'
 
+// System prompts (type + normaliser used by adapters)
+export type {
+  SystemPrompt,
+  NormalizedSystemPrompt,
+} from './system-prompts'
+export { normalizeSystemPrompts } from './system-prompts'
+
 // Utility functions
 export { detectImageMimeType } from './utils'
 
diff --git a/packages/typescript/ai/src/middlewares/otel.ts b/packages/typescript/ai/src/middlewares/otel.ts
index f4e39cd2f..d4b1530f4 100644
--- a/packages/typescript/ai/src/middlewares/otel.ts
+++ b/packages/typescript/ai/src/middlewares/otel.ts
@@ -372,9 +372,14 @@ export function otelMiddleware(options: OtelMiddlewareOptions): ChatMiddleware {
         state.assistantTextBufferTruncated = false
 
         if (captureContent) {
+          // Pull out plain strings from systemPrompts; per-prompt metadata
+          // (e.g. Anthropic cache_control) is irrelevant for observability.
+          const systemPromptContents = config.systemPrompts.map((p) =>
+            typeof p === 'string' ? p : p.content,
+          )
           // Span events follow the original GenAI semconv (one event per
           // message). Backends that read events get content this way.
-          for (const sys of config.systemPrompts) {
+          for (const sys of systemPromptContents) {
             iterSpan.addEvent('gen_ai.system.message', {
               content: redactContent(sys),
             })
@@ -391,7 +396,7 @@ export function otelMiddleware(options: OtelMiddlewareOptions): ChatMiddleware {
           // (`gen_ai.input.messages`) — backends like PostHog read prompt
           // content from this attribute, not from span events.
           const inputMessages: Array<{ role: string; content: string }> = []
-          for (const sys of config.systemPrompts) {
+          for (const sys of systemPromptContents) {
             inputMessages.push({
               role: 'system',
               content: redactContent(sys),
diff --git a/packages/typescript/ai/src/system-prompts.ts b/packages/typescript/ai/src/system-prompts.ts
new file mode 100644
index 000000000..84799f67c
--- /dev/null
+++ b/packages/typescript/ai/src/system-prompts.ts
@@ -0,0 +1,69 @@
+/**
+ * A single entry in `chat({ systemPrompts: [...] })`.
+ *
+ * Accepts a plain string (the common case) or a structured object that lets
+ * providers attach typed metadata to the prompt — e.g. Anthropic
+ * `cache_control` for prompt caching, future per-prompt safety overrides for
+ * Gemini, etc.
+ *
+ * Adapters that don't recognise a given metadata field silently ignore it, so
+ * the object form is portable across providers. For type-safe per-provider
+ * metadata, narrow `TMetadata` via the provider's `<Provider>SystemPromptMetadata`
+ * interface (e.g. `AnthropicSystemPromptMetadata`).
+ *
+ * @example
+ *   // The 90% case — plain strings work everywhere.
+ *   systemPrompts: ['Be concise.', 'Cite sources.']
+ *
+ * @example
+ *   // Provider-specific metadata via the object form.
+ *   import type { AnthropicSystemPromptMetadata } from '@tanstack/ai-anthropic'
+ *
+ *   systemPrompts: [
+ *     {
+ *       content: 'Stable instructions — cache me.',
+ *       metadata: { cache_control: { type: 'ephemeral' } } satisfies AnthropicSystemPromptMetadata,
+ *     },
+ *     'Volatile per-request instruction.',
+ *   ]
+ */
+export type SystemPrompt<TMetadata = unknown> =
+  | string
+  | {
+      content: string
+      metadata?: TMetadata
+    }
+
+/**
+ * Normalised shape adapters see after the chat layer turns string entries
+ * into `{ content }` objects. Adapters call `normalizeSystemPrompts` once at
+ * the top of their option-mapping pipeline so the rest of the code only has
+ * to handle one shape.
+ */
+export interface NormalizedSystemPrompt<TMetadata = unknown> {
+  content: string
+  metadata?: TMetadata
+}
+
+/**
+ * Normalise the public `systemPrompts` shape (`Array<string | { content, metadata? }>`)
+ * to a homogenous `Array<{ content, metadata? }>`. Adapters use this so they
+ * don't have to type-narrow string vs object inline.
+ *
+ * Returns an empty array (never `undefined`) so callers can chain `.map` /
+ * `.join` without an extra null check.
+ */
+export function normalizeSystemPrompts<TMetadata = unknown>(
+  // Accept the wide public shape (`SystemPrompt<unknown>`) regardless of the
+  // caller's `TMetadata`. Adapters know their own metadata shape; the
+  // generic narrows the *output* so adapter code can read `p.metadata.X`
+  // without an additional cast.
+  prompts: ReadonlyArray<SystemPrompt> | undefined,
+): Array<NormalizedSystemPrompt<TMetadata>> {
+  if (!prompts || prompts.length === 0) return []
+  return prompts.map((p) =>
+    typeof p === 'string'
+      ? { content: p }
+      : (p as NormalizedSystemPrompt<TMetadata>),
+  )
+}
diff --git a/packages/typescript/ai/src/types.ts b/packages/typescript/ai/src/types.ts
index 24e9976b5..da7b10001 100644
--- a/packages/typescript/ai/src/types.ts
+++ b/packages/typescript/ai/src/types.ts
@@ -3,6 +3,7 @@ import type {
   StandardSchemaV1,
 } from '@standard-schema/spec'
 import type { InternalLogger } from './logger/internal-logger'
+import type { SystemPrompt } from './system-prompts'
 import type {
   BaseEvent as AGUIBaseEvent,
   CustomEvent as AGUICustomEvent,
@@ -689,7 +690,17 @@ export interface TextOptions<
   model: string
   messages: Array<ModelMessage>
   tools?: Array<Tool<any, any, any>>
-  systemPrompts?: Array<string>
+  /**
+   * System prompts to include with the request.
+   *
+   * Accepts plain strings (the common case) or `{ content, metadata }`
+   * objects that let providers attach typed metadata (e.g. Anthropic
+   * `cache_control` for prompt caching) per prompt. Providers without
+   * matching metadata support silently drop the field.
+   *
+   * @see SystemPrompt
+   */
+  systemPrompts?: Array<SystemPrompt>
   agentLoopStrategy?: AgentLoopStrategy
   /**
    * Controls the randomness of the output.
diff --git a/packages/typescript/ai/tests/chat-structured-output-stream.test.ts b/packages/typescript/ai/tests/chat-structured-output-stream.test.ts
index 9bc034eea..f743bbbac 100644
--- a/packages/typescript/ai/tests/chat-structured-output-stream.test.ts
+++ b/packages/typescript/ai/tests/chat-structured-output-stream.test.ts
@@ -60,6 +60,7 @@ function makeAdapter(opts: {
       },
       toolCapabilities: [] as ReadonlyArray<string>,
       toolCallMetadata: undefined as unknown,
+      systemPromptMetadata: undefined as never,
     },
     chatStream: () => (async function* () {})(),
     structuredOutput:
diff --git a/packages/typescript/ai/tests/middleware.test.ts b/packages/typescript/ai/tests/middleware.test.ts
index d0c2e8297..7194ee0c0 100644
--- a/packages/typescript/ai/tests/middleware.test.ts
+++ b/packages/typescript/ai/tests/middleware.test.ts
@@ -9,6 +9,7 @@ import {
   serverTool,
 } from './test-utils'
 import type { StreamChunk } from '../src/types'
+import type { SystemPrompt } from '../src/system-prompts'
 import type {
   ChatMiddleware,
   ChatMiddlewareContext,
@@ -2576,7 +2577,7 @@ describe('chat() middleware', () => {
         phase: string
         iteration: number
         maxTokens?: number
-        systemPrompts: Array<string>
+        systemPrompts: Array<SystemPrompt>
       }> = []
 
       const tool = serverTool('myTool', () => ({ ok: true }))
diff --git a/packages/typescript/ai/tests/test-utils.ts b/packages/typescript/ai/tests/test-utils.ts
index a2fbf4af0..dad3ff28f 100644
--- a/packages/typescript/ai/tests/test-utils.ts
+++ b/packages/typescript/ai/tests/test-utils.ts
@@ -172,6 +172,7 @@ export function createMockAdapter(options: {
       },
       toolCapabilities: [] as ReadonlyArray<string>,
       toolCallMetadata: undefined as unknown,
+      systemPromptMetadata: undefined as never,
     },
     chatStream: (opts: any) => {
       calls.push(opts)
diff --git a/packages/typescript/ai/tests/type-check.test.ts b/packages/typescript/ai/tests/type-check.test.ts
index 82d05e64d..f82f46d9b 100644
--- a/packages/typescript/ai/tests/type-check.test.ts
+++ b/packages/typescript/ai/tests/type-check.test.ts
@@ -37,6 +37,7 @@ const mockAdapter = {
     },
     toolCapabilities: [] as ReadonlyArray<string>,
     toolCallMetadata: undefined as unknown,
+    systemPromptMetadata: undefined as never,
   },
   chatStream: async function* () {},
   structuredOutput: async () => ({ data: {}, rawText: '{}' }),
diff --git a/packages/typescript/openai-base/src/adapters/chat-completions-text.ts b/packages/typescript/openai-base/src/adapters/chat-completions-text.ts
index 63a2f5011..3fbc726fd 100644
--- a/packages/typescript/openai-base/src/adapters/chat-completions-text.ts
+++ b/packages/typescript/openai-base/src/adapters/chat-completions-text.ts
@@ -1,4 +1,4 @@
-import { EventType } from '@tanstack/ai'
+import { EventType, normalizeSystemPrompts } from '@tanstack/ai'
 import { BaseTextAdapter } from '@tanstack/ai/adapters'
 import { toRunErrorPayload } from '@tanstack/ai/adapter-internals'
 import { generateId, transformNullsToUndefined } from '@tanstack/ai-utils'
@@ -1088,10 +1088,11 @@ export abstract class OpenAIBaseChatCompletionsTextAdapter<
     const messages: Array<ChatCompletionMessageParam> = []
 
     // Add system prompts first
-    if (options.systemPrompts && options.systemPrompts.length > 0) {
+    const systemPrompts = normalizeSystemPrompts(options.systemPrompts)
+    if (systemPrompts.length > 0) {
       messages.push({
         role: 'system',
-        content: options.systemPrompts.join('\n'),
+        content: systemPrompts.map((p) => p.content).join('\n'),
       })
     }
 
diff --git a/packages/typescript/openai-base/src/adapters/responses-text.ts b/packages/typescript/openai-base/src/adapters/responses-text.ts
index 2c41aed23..60d7ee818 100644
--- a/packages/typescript/openai-base/src/adapters/responses-text.ts
+++ b/packages/typescript/openai-base/src/adapters/responses-text.ts
@@ -1,4 +1,4 @@
-import { EventType } from '@tanstack/ai'
+import { EventType, normalizeSystemPrompts } from '@tanstack/ai'
 import { BaseTextAdapter } from '@tanstack/ai/adapters'
 import { toRunErrorPayload } from '@tanstack/ai/adapter-internals'
 import { generateId, transformNullsToUndefined } from '@tanstack/ai-utils'
@@ -1599,10 +1599,11 @@ export abstract class OpenAIBaseResponsesTextAdapter<
       }),
       ...(options.topP !== undefined && { top_p: options.topP }),
       ...(options.metadata !== undefined && { metadata: options.metadata }),
-      ...(options.systemPrompts &&
-        options.systemPrompts.length > 0 && {
-          instructions: options.systemPrompts.join('\n'),
-        }),
+      ...(() => {
+        const prompts = normalizeSystemPrompts(options.systemPrompts)
+        if (prompts.length === 0) return {}
+        return { instructions: prompts.map((p) => p.content).join('\n') }
+      })(),
       input,
       // Conditional spread: `tools: undefined` would clobber any
       // modelOptions.tools the caller set above.

From df6f675d995674ab47dbe741de8ce61cb8dcb715 Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Mon, 18 May 2026 12:57:14 +0000
Subject: [PATCH 14/17] ci: apply automated fixes

---
 packages/typescript/ai-anthropic/src/adapters/text.ts      | 7 ++++---
 .../typescript/ai-event-client/src/devtools-middleware.ts  | 4 +---
 packages/typescript/ai/src/activities/chat/index.ts        | 4 +++-
 packages/typescript/ai/src/index.ts                        | 5 +----
 4 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/packages/typescript/ai-anthropic/src/adapters/text.ts b/packages/typescript/ai-anthropic/src/adapters/text.ts
index 077ada05c..4f77890b5 100644
--- a/packages/typescript/ai-anthropic/src/adapters/text.ts
+++ b/packages/typescript/ai-anthropic/src/adapters/text.ts
@@ -342,9 +342,10 @@ export class AnthropicTextAdapter<
       top_p: options.topP,
       messages: formattedMessages,
       system: (() => {
-        const normalized = normalizeSystemPrompts<AnthropicSystemPromptMetadata>(
-          options.systemPrompts,
-        )
+        const normalized =
+          normalizeSystemPrompts<AnthropicSystemPromptMetadata>(
+            options.systemPrompts,
+          )
         if (normalized.length === 0) return undefined
         return normalized.map(
           (p): TextBlockParam => ({
diff --git a/packages/typescript/ai-event-client/src/devtools-middleware.ts b/packages/typescript/ai-event-client/src/devtools-middleware.ts
index 9acb0e2f8..37ade008d 100644
--- a/packages/typescript/ai-event-client/src/devtools-middleware.ts
+++ b/packages/typescript/ai-event-client/src/devtools-middleware.ts
@@ -17,9 +17,7 @@ interface DevtoolsModelMessage {
  * doesn't import from `@tanstack/ai` (which would introduce a circular dep,
  * see file-top comment).
  */
-type DevtoolsSystemPrompt =
-  | string
-  | { content: string; metadata?: unknown }
+type DevtoolsSystemPrompt = string | { content: string; metadata?: unknown }
 
 interface DevtoolsMiddlewareContext {
   requestId: string
diff --git a/packages/typescript/ai/src/activities/chat/index.ts b/packages/typescript/ai/src/activities/chat/index.ts
index 47af9b7b0..eb29e561f 100644
--- a/packages/typescript/ai/src/activities/chat/index.ts
+++ b/packages/typescript/ai/src/activities/chat/index.ts
@@ -112,7 +112,9 @@ export interface TextActivityOptions<
    * caching), providers without per-prompt metadata reject the field
    * entirely.
    */
-  systemPrompts?: Array<SystemPrompt<TAdapter['~types']['systemPromptMetadata']>>
+  systemPrompts?: Array<
+    SystemPrompt<TAdapter['~types']['systemPromptMetadata']>
+  >
   /**
    * Tools for function calling (auto-executed when called).
    *
diff --git a/packages/typescript/ai/src/index.ts b/packages/typescript/ai/src/index.ts
index 0fbbb54ee..dba60f076 100644
--- a/packages/typescript/ai/src/index.ts
+++ b/packages/typescript/ai/src/index.ts
@@ -105,10 +105,7 @@ export type {
 export * from './types'
 
 // System prompts (type + normaliser used by adapters)
-export type {
-  SystemPrompt,
-  NormalizedSystemPrompt,
-} from './system-prompts'
+export type { SystemPrompt, NormalizedSystemPrompt } from './system-prompts'
 export { normalizeSystemPrompts } from './system-prompts'
 
 // Utility functions

From 0e94d74e6315aadf9eac020329ce0c046bbb2bd1 Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Tue, 19 May 2026 17:25:07 +0200
Subject: [PATCH 15/17] address PR #575 review feedback
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Maps to tombeckenham's review items C1, I1–I6:

- C1 (runtime validation): `normalizeSystemPrompts` throws TypeError naming
  the offending index when an object-form entry's content isn't a string,
  so stale call sites can't stream a literal "undefined" into the model.
  New test file `packages/typescript/ai/tests/system-prompts.test.ts`
  covers the happy paths and the throw cases.

- I1 (E2E coverage): `testing/e2e/tests/system-prompt-metadata.spec.ts`
  drives the full Anthropic HTTP path with object-form systemPrompts +
  metadata.cache_control. Wire-shape assertion stays in the ai-anthropic
  unit test (aimock's journal normalises Anthropic into an OpenAI-shaped
  request and drops `cache_control`, so a journal-based assertion isn't
  reliable — the spec asserts end-to-end success instead). Required a
  test-only `systemPromptCacheControl` opt-in on `api.chat.ts` to flip
  the system prompt to object form.

- I2 (middleware widened-shape coverage): new
  `middleware.test.ts > should preserve object-form systemPrompts through
  middleware` asserts the middleware sees `Array<SystemPrompt>`, not a
  pre-flattened `Array<string>`, and that mutations preserve metadata
  through to the adapter.

- I3 (per-adapter mapping coverage): direct unit tests for
  Gemini (`systemInstruction` joined; foreign metadata dropped),
  Ollama (`messages.unshift({role:'system'})` joined; foreign metadata
  dropped), and OpenRouter (positional `{role:'system'}` message; foreign
  metadata dropped).

- I4 (OTel metadata observability): when `captureContent: true` and at
  least one entry carries metadata, the iteration span gains a
  `tanstack.ai.system_prompt.metadata` JSON attribute (positional
  per-prompt array, `null` for plain strings / no metadata). Kept off
  span events so the existing one-event-per-message GenAI semconv stays
  intact. New tests in `tests/middlewares/otel.test.ts` cover both the
  set and the absent path.

- I5 (doc/changeset wording): replaced "silently ignore" with the
  accurate "carries no meaningful value … silently dropped, never
  written to the wire" framing in `SystemPrompt`'s JSDoc, the
  `TextOptions.systemPrompts` JSDoc, and the changeset. Removed the
  misleading `satisfies AnthropicSystemPromptMetadata` from the
  `@example` (the adapter narrows the metadata field at the call site,
  so a `satisfies` cast is contradicted by the tests).

- I6 (devtools structural guard):
  `ai-event-client/tests/devtools-middleware-shape.test.ts` re-declares
  the local `DevtoolsSystemPrompt` mirror and uses `expectTypeOf` to
  assert mutual assignability with `@tanstack/ai`'s `SystemPrompt`. If
  the canonical shape gains a third variant the guard breaks at
  type-check time, forcing the maintainer to update the mirror in
  `devtools-middleware.ts`.

Suggestions S1–S5 deferred per the reviewer's "follow-up acceptable" call.
---
 .changeset/feat-system-prompts-metadata.md    | 23 ++++--
 .../tests/devtools-middleware-shape.test.ts   | 23 ++++++
 .../ai-gemini/tests/gemini-adapter.test.ts    | 42 ++++++++++
 .../ai-ollama/tests/text-adapter.test.ts      | 76 +++++++++++++++++++
 .../tests/openrouter-adapter.test.ts          | 45 +++++++++++
 .../typescript/ai/src/middlewares/otel.ts     | 19 ++++-
 packages/typescript/ai/src/system-prompts.ts  | 59 +++++++++-----
 packages/typescript/ai/src/types.ts           |  8 +-
 .../typescript/ai/tests/middleware.test.ts    | 58 ++++++++++++++
 .../ai/tests/middlewares/otel.test.ts         | 38 ++++++++++
 .../ai/tests/system-prompts.test.ts           | 66 ++++++++++++++++
 testing/e2e/src/routes/api.chat.ts            | 27 ++++++-
 .../e2e/tests/system-prompt-metadata.spec.ts  | 72 ++++++++++++++++++
 13 files changed, 526 insertions(+), 30 deletions(-)
 create mode 100644 packages/typescript/ai-event-client/tests/devtools-middleware-shape.test.ts
 create mode 100644 packages/typescript/ai/tests/system-prompts.test.ts
 create mode 100644 testing/e2e/tests/system-prompt-metadata.spec.ts

diff --git a/.changeset/feat-system-prompts-metadata.md b/.changeset/feat-system-prompts-metadata.md
index e7478bc31..21db0cf71 100644
--- a/.changeset/feat-system-prompts-metadata.md
+++ b/.changeset/feat-system-prompts-metadata.md
@@ -20,9 +20,11 @@ field's type is inferred from the adapter via a new
   users get `cache_control` autocomplete and type-checking on
   `systemPrompts[i].metadata` for Anthropic chats.
 - Adapters with no per-prompt metadata (OpenAI, Gemini, Ollama,
-  OpenRouter, openai-base) inherit the default `never`, which makes the
-  `metadata` field unusable at the call site — passing it is a TypeScript
-  error.
+  OpenRouter, openai-base) inherit the default `never`, which means the
+  `metadata` field carries no meaningful value at the call site —
+  TypeScript only accepts `undefined` there. Provider-foreign metadata
+  that reaches an adapter via JS / `as any` is silently dropped, never
+  written to the wire.
 
 ```ts
 import { chat } from '@tanstack/ai'
@@ -40,7 +42,9 @@ chat({
   ],
 })
 
-// OpenAI — `metadata` field is `never`, attempting to pass it errors at compile time.
+// OpenAI — `metadata` is `never`; only `undefined` is assignable, so the
+// field is effectively unusable. The object form without `metadata` still
+// works for portability.
 chat({
   adapter: openaiText({ apiKey }, 'gpt-4o-mini'),
   systemPrompts: [
@@ -67,7 +71,16 @@ Internal:
   the corresponding `TextBlockParam`.
 - All other text adapters call `normalizeSystemPrompts()` and join
   `.content` for their respective `instructions` / `system` /
-  `systemInstruction` fields.
+  `systemInstruction` fields. Foreign metadata that reaches them via JS
+  / `as any` is dropped (never written to the wire).
+- `normalizeSystemPrompts()` is the public API boundary and throws
+  `TypeError` (naming the offending index) for object-form entries whose
+  `content` isn't a string — preventing literal `"undefined"` from
+  reaching the model on stale call sites.
+- OpenTelemetry middleware attaches per-prompt metadata as the
+  `tanstack.ai.system_prompt.metadata` JSON span attribute when
+  `captureContent: true` and at least one entry carries metadata, so
+  observability backends can distinguish cache hit/miss for Anthropic.
 - `@tanstack/ai-event-client` mirrors the `SystemPrompt` shape locally
   (avoids a circular import) and projects metadata away on the devtools
   wire — devtools UI still receives `Array<string>`.
diff --git a/packages/typescript/ai-event-client/tests/devtools-middleware-shape.test.ts b/packages/typescript/ai-event-client/tests/devtools-middleware-shape.test.ts
new file mode 100644
index 000000000..3b09e4e44
--- /dev/null
+++ b/packages/typescript/ai-event-client/tests/devtools-middleware-shape.test.ts
@@ -0,0 +1,23 @@
+import { describe, it, expectTypeOf } from 'vitest'
+import type { SystemPrompt } from '@tanstack/ai'
+
+/**
+ * `@tanstack/ai-event-client/src/devtools-middleware.ts` intentionally
+ * duplicates the `SystemPrompt` shape locally to avoid a circular import
+ * (`@tanstack/ai-event-client` is a runtime dep of `@tanstack/ai`).
+ *
+ * Re-declare the mirror here and assert structural equality against the
+ * canonical `SystemPrompt` from `@tanstack/ai`. If `SystemPrompt` ever
+ * gains a third variant (or the existing shape changes), this guard fails
+ * at type-check time — forcing the maintainer to update the mirror in
+ * `devtools-middleware.ts` rather than silently emitting `undefined` from
+ * the projection `typeof p === 'string' ? p : p.content`.
+ */
+type DevtoolsSystemPrompt = string | { content: string; metadata?: unknown }
+
+describe('DevtoolsSystemPrompt structural mirror of SystemPrompt', () => {
+  it('the local mirror is mutually assignable with @tanstack/ai SystemPrompt', () => {
+    expectTypeOf<SystemPrompt>().toExtend<DevtoolsSystemPrompt>()
+    expectTypeOf<DevtoolsSystemPrompt>().toExtend<SystemPrompt>()
+  })
+})
diff --git a/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts b/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts
index 9f4a574e5..ead500bd0 100644
--- a/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts
+++ b/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts
@@ -131,6 +131,48 @@ describe('GeminiAdapter through AI', () => {
     ])
   })
 
+  it('joins object-form systemPrompts into systemInstruction and drops foreign metadata', async () => {
+    const streamChunks = [
+      {
+        candidates: [
+          {
+            content: { parts: [{ text: 'ok' }] },
+            finishReason: 'STOP',
+          },
+        ],
+        usageMetadata: { totalTokenCount: 1 },
+      },
+    ]
+
+    mocks.generateContentStreamSpy.mockResolvedValue(createStream(streamChunks))
+
+    const adapter = createTextAdapter()
+
+    for await (const _ of chat({
+      adapter,
+      messages: [{ role: 'user', content: 'Hi' }],
+      systemPrompts: [
+        'plain',
+        { content: 'object-form' },
+        // `metadata` on a Gemini chat is `never` at the type level; the cast
+        // models a stale call site reaching the adapter via JS / `as any`.
+        // The adapter must still produce the expected systemInstruction
+        // string and never leak the foreign field anywhere on the payload.
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
+        { content: 'with-foreign-meta', metadata: { cache_control: {} } as any },
+      ],
+    })) {
+      /* consume stream */
+    }
+
+    const [payload] = mocks.generateContentStreamSpy.mock.calls[0]!
+    expect(payload.config.systemInstruction).toBe(
+      'plain\nobject-form\nwith-foreign-meta',
+    )
+    // Foreign metadata never reaches the wire.
+    expect(JSON.stringify(payload)).not.toContain('cache_control')
+  })
+
   it('maps every common and provider option into the Gemini payload', async () => {
     const streamChunks = [
       {
diff --git a/packages/typescript/ai-ollama/tests/text-adapter.test.ts b/packages/typescript/ai-ollama/tests/text-adapter.test.ts
index f2ece1065..6bdb0222e 100644
--- a/packages/typescript/ai-ollama/tests/text-adapter.test.ts
+++ b/packages/typescript/ai-ollama/tests/text-adapter.test.ts
@@ -327,3 +327,79 @@ describe('OllamaTextAdapter.structuredOutput', () => {
     ).rejects.toThrow(/Structured output generation failed.*network down/)
   })
 })
+
+describe('OllamaTextAdapter system prompts', () => {
+  it('prepends mixed string + object-form systemPrompts as a single role:system message and drops foreign metadata', async () => {
+    chatMock.mockResolvedValueOnce(
+      asyncIterable([
+        {
+          message: { role: 'assistant', content: 'ok' },
+          done: true,
+          done_reason: 'stop',
+        },
+      ]),
+    )
+
+    const adapter = createOllamaChat('llama3.2')
+    await collectStream(
+      adapter.chatStream({
+        logger: testLogger,
+        model: 'llama3.2',
+        messages: [{ role: 'user', content: 'hi' }],
+        systemPrompts: [
+          'plain',
+          { content: 'object-form' },
+          // `metadata` on an Ollama chat is `never` at the type level; the
+          // cast models a stale call site reaching the adapter via JS / `as
+          // any`. The adapter must still join the content correctly and
+          // never leak the foreign field onto the wire.
+          // eslint-disable-next-line @typescript-eslint/no-explicit-any
+          { content: 'with-meta', metadata: { cache_control: {} } as any },
+        ],
+      }),
+    )
+
+    expect(chatMock).toHaveBeenCalledTimes(1)
+    const [payload] = chatMock.mock.calls[0]!
+    const messages = payload.messages as Array<{
+      role: string
+      content: string
+    }>
+
+    // System prompt is the first message and joins all content with '\n'.
+    expect(messages[0]).toEqual({
+      role: 'system',
+      content: 'plain\nobject-form\nwith-meta',
+    })
+    expect(messages[1]).toMatchObject({ role: 'user' })
+    // Foreign metadata never reaches the wire.
+    expect(JSON.stringify(payload)).not.toContain('cache_control')
+  })
+
+  it('omits the system message entirely when systemPrompts is empty or undefined', async () => {
+    chatMock.mockResolvedValueOnce(
+      asyncIterable([
+        {
+          message: { role: 'assistant', content: 'ok' },
+          done: true,
+          done_reason: 'stop',
+        },
+      ]),
+    )
+
+    const adapter = createOllamaChat('llama3.2')
+    await collectStream(
+      adapter.chatStream({
+        logger: testLogger,
+        model: 'llama3.2',
+        messages: [{ role: 'user', content: 'hi' }],
+      }),
+    )
+
+    const [payload] = chatMock.mock.calls[0]!
+    const roles = (payload.messages as Array<{ role: string }>).map(
+      (m) => m.role,
+    )
+    expect(roles).not.toContain('system')
+  })
+})
diff --git a/packages/typescript/ai-openrouter/tests/openrouter-adapter.test.ts b/packages/typescript/ai-openrouter/tests/openrouter-adapter.test.ts
index 3fc2ba243..f1940e263 100644
--- a/packages/typescript/ai-openrouter/tests/openrouter-adapter.test.ts
+++ b/packages/typescript/ai-openrouter/tests/openrouter-adapter.test.ts
@@ -173,6 +173,51 @@ describe('OpenRouter adapter option mapping', () => {
     expect(serialized).toHaveProperty('tool_choice', 'auto')
   })
 
+  it('prepends mixed string + object-form systemPrompts as a role:system message and drops foreign metadata', async () => {
+    const streamChunks = [
+      {
+        id: 'chatcmpl-sys',
+        model: 'openai/gpt-4o-mini',
+        choices: [{ delta: { content: 'ok' }, finishReason: 'stop' }],
+        usage: { promptTokens: 1, completionTokens: 1, totalTokens: 2 },
+      },
+    ]
+
+    setupMockSdkClient(streamChunks)
+
+    const adapter = createAdapter()
+
+    for await (const _ of chat({
+      adapter,
+      messages: [{ role: 'user', content: 'hi' }],
+      systemPrompts: [
+        'plain',
+        { content: 'object-form' },
+        // `metadata` is `never` for OpenRouter at the type level; the cast
+        // simulates a stale JS / `as any` caller. The adapter must still
+        // produce the joined system message and never leak the foreign
+        // field to the wire.
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
+        { content: 'with-meta', metadata: { cache_control: {} } as any },
+      ],
+    })) {
+      /* consume */
+    }
+
+    const [rawParams] = mockSend.mock.calls[0]!
+    const params = rawParams.chatRequest
+    const messages = params.messages as Array<{ role: string; content: string }>
+
+    // OpenRouter injects systemPrompts as a positional role:system message
+    // at the head of `messages` (not via a separate `system` field).
+    expect(messages[0]).toEqual({
+      role: 'system',
+      content: 'plain\nobject-form\nwith-meta',
+    })
+    expect(messages[1]).toMatchObject({ role: 'user' })
+    expect(JSON.stringify(params)).not.toContain('cache_control')
+  })
+
   it('streams chat chunks with content and usage', async () => {
     const streamChunks = [
       {
diff --git a/packages/typescript/ai/src/middlewares/otel.ts b/packages/typescript/ai/src/middlewares/otel.ts
index d4b1530f4..028cb2dbc 100644
--- a/packages/typescript/ai/src/middlewares/otel.ts
+++ b/packages/typescript/ai/src/middlewares/otel.ts
@@ -372,11 +372,26 @@ export function otelMiddleware(options: OtelMiddlewareOptions): ChatMiddleware {
         state.assistantTextBufferTruncated = false
 
         if (captureContent) {
-          // Pull out plain strings from systemPrompts; per-prompt metadata
-          // (e.g. Anthropic cache_control) is irrelevant for observability.
           const systemPromptContents = config.systemPrompts.map((p) =>
             typeof p === 'string' ? p : p.content,
           )
+          // Anthropic prompt-caching users need to know which prompt carried
+          // `cache_control`: it's the one attribute that explains cache
+          // hit/miss in observability. Serialise per-prompt metadata as a
+          // single JSON span attribute so backends that don't understand
+          // GenAI events can still surface it. Kept off span events to
+          // avoid breaking the one-event-per-message GenAI semconv contract.
+          const systemPromptMetadata = config.systemPrompts.map((p) =>
+            typeof p === 'string' || p.metadata === undefined
+              ? null
+              : p.metadata,
+          )
+          if (systemPromptMetadata.some((m) => m !== null)) {
+            iterSpan.setAttribute(
+              'tanstack.ai.system_prompt.metadata',
+              JSON.stringify(systemPromptMetadata),
+            )
+          }
           // Span events follow the original GenAI semconv (one event per
           // message). Backends that read events get content this way.
           for (const sys of systemPromptContents) {
diff --git a/packages/typescript/ai/src/system-prompts.ts b/packages/typescript/ai/src/system-prompts.ts
index 84799f67c..4f21974cb 100644
--- a/packages/typescript/ai/src/system-prompts.ts
+++ b/packages/typescript/ai/src/system-prompts.ts
@@ -6,26 +6,35 @@
  * `cache_control` for prompt caching, future per-prompt safety overrides for
  * Gemini, etc.
  *
- * Adapters that don't recognise a given metadata field silently ignore it, so
- * the object form is portable across providers. For type-safe per-provider
- * metadata, narrow `TMetadata` via the provider's `<Provider>SystemPromptMetadata`
- * interface (e.g. `AnthropicSystemPromptMetadata`).
+ * At the chat call site, `metadata` is narrowed by the adapter via
+ * `~types['systemPromptMetadata']`. Providers that don't declare one inherit
+ * the default `never`, which makes the field carry no meaningful value: TS
+ * only accepts `undefined` there, and provider-foreign metadata that reaches
+ * an adapter via JS / `as any` is silently dropped, never written to the
+ * wire. For type-safe per-provider metadata, refer to the provider's
+ * `<Provider>SystemPromptMetadata` interface (e.g. `AnthropicSystemPromptMetadata`).
  *
  * @example
  *   // The 90% case — plain strings work everywhere.
  *   systemPrompts: ['Be concise.', 'Cite sources.']
  *
  * @example
- *   // Provider-specific metadata via the object form.
- *   import type { AnthropicSystemPromptMetadata } from '@tanstack/ai-anthropic'
+ *   // Provider-specific metadata via the object form. No `satisfies` cast
+ *   // is needed — the adapter narrows the `metadata` field's type at the
+ *   // call site so users get autocomplete and structural checking
+ *   // automatically.
+ *   import { anthropicText } from '@tanstack/ai-anthropic'
  *
- *   systemPrompts: [
- *     {
- *       content: 'Stable instructions — cache me.',
- *       metadata: { cache_control: { type: 'ephemeral' } } satisfies AnthropicSystemPromptMetadata,
- *     },
- *     'Volatile per-request instruction.',
- *   ]
+ *   chat({
+ *     adapter: anthropicText(),
+ *     systemPrompts: [
+ *       {
+ *         content: 'Stable instructions — cache me.',
+ *         metadata: { cache_control: { type: 'ephemeral' } },
+ *       },
+ *       'Volatile per-request instruction.',
+ *     ],
+ *   })
  */
 export type SystemPrompt<TMetadata = unknown> =
   | string
@@ -52,6 +61,11 @@ export interface NormalizedSystemPrompt<TMetadata = unknown> {
  *
  * Returns an empty array (never `undefined`) so callers can chain `.map` /
  * `.join` without an extra null check.
+ *
+ * Throws a `TypeError` (naming the offending index) if an object-form entry's
+ * `content` isn't a string. Public API boundary — callers reaching this
+ * function through `as any` / external JS would otherwise stream a literal
+ * `"undefined"` into the model's system prompt with no signal.
  */
 export function normalizeSystemPrompts<TMetadata = unknown>(
   // Accept the wide public shape (`SystemPrompt<unknown>`) regardless of the
@@ -61,9 +75,18 @@ export function normalizeSystemPrompts<TMetadata = unknown>(
   prompts: ReadonlyArray<SystemPrompt> | undefined,
 ): Array<NormalizedSystemPrompt<TMetadata>> {
   if (!prompts || prompts.length === 0) return []
-  return prompts.map((p) =>
-    typeof p === 'string'
-      ? { content: p }
-      : (p as NormalizedSystemPrompt<TMetadata>),
-  )
+  return prompts.map((p, i) => {
+    if (typeof p === 'string') return { content: p }
+    if (p === null || typeof p !== 'object') {
+      throw new TypeError(
+        `systemPrompts[${i}]: expected a string or { content, metadata? }, got ${p === null ? 'null' : typeof p}`,
+      )
+    }
+    if (typeof p.content !== 'string') {
+      throw new TypeError(
+        `systemPrompts[${i}]: content must be a string, got ${typeof p.content}`,
+      )
+    }
+    return p as NormalizedSystemPrompt<TMetadata>
+  })
 }
diff --git a/packages/typescript/ai/src/types.ts b/packages/typescript/ai/src/types.ts
index d1e8fd887..a761c66f9 100644
--- a/packages/typescript/ai/src/types.ts
+++ b/packages/typescript/ai/src/types.ts
@@ -735,8 +735,12 @@ export interface TextOptions<
    *
    * Accepts plain strings (the common case) or `{ content, metadata }`
    * objects that let providers attach typed metadata (e.g. Anthropic
-   * `cache_control` for prompt caching) per prompt. Providers without
-   * matching metadata support silently drop the field.
+   * `cache_control` for prompt caching) per prompt. At the chat call site
+   * the adapter narrows `metadata`'s type via `~types['systemPromptMetadata']`
+   * — providers that don't declare one default to `never`, which makes the
+   * field carry no meaningful value (TypeScript will only accept
+   * `undefined` there). Provider-foreign metadata that reaches an adapter
+   * via JS / `as any` is silently dropped, never written to the wire.
    *
    * @see SystemPrompt
    */
diff --git a/packages/typescript/ai/tests/middleware.test.ts b/packages/typescript/ai/tests/middleware.test.ts
index 7194ee0c0..aeb5cc688 100644
--- a/packages/typescript/ai/tests/middleware.test.ts
+++ b/packages/typescript/ai/tests/middleware.test.ts
@@ -190,6 +190,64 @@ describe('chat() middleware', () => {
       expect(calls[0]!.systemPrompts).toContain('Original')
     })
 
+    it('should preserve object-form systemPrompts through middleware', async () => {
+      const { adapter, calls } = createMockAdapter({
+        iterations: [
+          [ev.runStarted(), ev.textContent('hi'), ev.runFinished('stop')],
+        ],
+      })
+
+      // Capture what the middleware sees in config.systemPrompts so we can
+      // assert the wide shape (Array<SystemPrompt>) — not a flattened
+      // Array<string> — reaches middleware code.
+      const observed: Array<unknown> = []
+
+      // Middleware reads ChatMiddlewareConfig.systemPrompts (now widened to
+      // Array<SystemPrompt>) and prepends another object-form entry. Only
+      // mutate at beforeModel so the assertion stays deterministic
+      // (onConfig fires at both init and beforeModel).
+      const middleware: ChatMiddleware = {
+        name: 'prepender',
+        onConfig: (ctx, config) => {
+          if (ctx.phase !== 'beforeModel') return undefined
+          observed.push(...config.systemPrompts)
+          return {
+            systemPrompts: [
+              { content: 'prepended', metadata: { tag: 'mw' } },
+              ...config.systemPrompts,
+            ],
+          }
+        },
+      }
+
+      const stream = chat({
+        adapter,
+        messages: [{ role: 'user', content: 'Hi' }],
+        systemPrompts: [
+          'plain-original',
+          { content: 'object-original', metadata: { caller: 'test' } },
+        ],
+        middleware: [middleware],
+      })
+      await collectChunks(stream as AsyncIterable<StreamChunk>)
+
+      // The middleware saw the wide shape: a plain string and an object
+      // with metadata, not a pre-flattened Array<string>.
+      expect(observed).toEqual([
+        'plain-original',
+        { content: 'object-original', metadata: { caller: 'test' } },
+      ])
+
+      // The adapter receives the middleware's mutation verbatim — strings
+      // stay strings, object-form entries keep their metadata, and the
+      // prepend order is preserved.
+      expect(calls[0]!.systemPrompts).toEqual([
+        { content: 'prepended', metadata: { tag: 'mw' } },
+        'plain-original',
+        { content: 'object-original', metadata: { caller: 'test' } },
+      ])
+    })
+
     it('should pipe config through multiple middlewares in order', async () => {
       const { adapter, calls } = createMockAdapter({
         iterations: [
diff --git a/packages/typescript/ai/tests/middlewares/otel.test.ts b/packages/typescript/ai/tests/middlewares/otel.test.ts
index 433b77fc1..260eeda52 100644
--- a/packages/typescript/ai/tests/middlewares/otel.test.ts
+++ b/packages/typescript/ai/tests/middlewares/otel.test.ts
@@ -435,6 +435,44 @@ describe('otelMiddleware — captureContent', () => {
     expect(asstEvt!.attributes!['content']).toBe('Hi [NUM] there')
   })
 
+  it('captureContent=true attaches systemPrompt metadata as a JSON span attribute when any entry carries metadata', async () => {
+    const { tracer, spans } = createFakeTracer()
+    const mw = otelMiddleware({ tracer, captureContent: true })
+    const ctx = makeCtx()
+
+    await runToIterationStart(mw, ctx, {
+      messages: [{ role: 'user', content: 'hi' }],
+      systemPrompts: [
+        'plain',
+        { content: 'cached', metadata: { cache_control: { type: 'ephemeral' } } },
+        { content: 'no-meta' },
+      ],
+    })
+
+    const iter = spans[1]!
+    const attr = iter.attributes!['tanstack.ai.system_prompt.metadata']
+    expect(typeof attr).toBe('string')
+    expect(JSON.parse(attr as string)).toEqual([
+      null,
+      { cache_control: { type: 'ephemeral' } },
+      null,
+    ])
+  })
+
+  it('does not attach systemPrompt metadata attribute when no entry carries metadata', async () => {
+    const { tracer, spans } = createFakeTracer()
+    const mw = otelMiddleware({ tracer, captureContent: true })
+    const ctx = makeCtx()
+
+    await runToIterationStart(mw, ctx, {
+      messages: [{ role: 'user', content: 'hi' }],
+      systemPrompts: ['plain-a', { content: 'plain-b' }],
+    })
+
+    const iter = spans[1]!
+    expect(iter.attributes!['tanstack.ai.system_prompt.metadata']).toBeUndefined()
+  })
+
   it('captureContent=false emits no message events', async () => {
     const { tracer, spans } = createFakeTracer()
     const mw = otelMiddleware({ tracer })
diff --git a/packages/typescript/ai/tests/system-prompts.test.ts b/packages/typescript/ai/tests/system-prompts.test.ts
new file mode 100644
index 000000000..d6282cab1
--- /dev/null
+++ b/packages/typescript/ai/tests/system-prompts.test.ts
@@ -0,0 +1,66 @@
+import { describe, expect, it } from 'vitest'
+import { normalizeSystemPrompts } from '../src/system-prompts'
+
+describe('normalizeSystemPrompts', () => {
+  it('returns an empty array when input is undefined', () => {
+    expect(normalizeSystemPrompts(undefined)).toEqual([])
+  })
+
+  it('returns an empty array when input is empty', () => {
+    expect(normalizeSystemPrompts([])).toEqual([])
+  })
+
+  it('wraps plain strings into `{ content }` objects', () => {
+    expect(normalizeSystemPrompts(['a', 'b'])).toEqual([
+      { content: 'a' },
+      { content: 'b' },
+    ])
+  })
+
+  it('passes object-form entries through unchanged', () => {
+    const meta = { cache_control: { type: 'ephemeral' } }
+    expect(
+      normalizeSystemPrompts([
+        { content: 'cached', metadata: meta },
+        { content: 'plain' },
+      ]),
+    ).toEqual([
+      { content: 'cached', metadata: meta },
+      { content: 'plain' },
+    ])
+  })
+
+  it('mixes plain strings and object-form in order', () => {
+    expect(
+      normalizeSystemPrompts(['first', { content: 'second' }, 'third']),
+    ).toEqual([
+      { content: 'first' },
+      { content: 'second' },
+      { content: 'third' },
+    ])
+  })
+
+  it('throws TypeError naming the offending index when object-form content is not a string', () => {
+    expect(() =>
+      // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      normalizeSystemPrompts(['ok', { metadata: {} } as any]),
+    ).toThrow(/systemPrompts\[1\]: content must be a string, got undefined/)
+
+    expect(() =>
+      // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      normalizeSystemPrompts([{ content: 42 as any }]),
+    ).toThrow(/systemPrompts\[0\]: content must be a string, got number/)
+  })
+
+  it('throws TypeError when entry is neither string nor object', () => {
+    expect(() =>
+      // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      normalizeSystemPrompts(['ok', 123 as any]),
+    ).toThrow(/systemPrompts\[1\]: expected a string or .* got number/)
+
+    expect(() =>
+      // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      normalizeSystemPrompts([null as any]),
+    ).toThrow(/systemPrompts\[0\]: expected a string or .* got null/)
+  })
+})
diff --git a/testing/e2e/src/routes/api.chat.ts b/testing/e2e/src/routes/api.chat.ts
index 2f9cb83ed..b74d493dd 100644
--- a/testing/e2e/src/routes/api.chat.ts
+++ b/testing/e2e/src/routes/api.chat.ts
@@ -56,6 +56,27 @@ export const Route = createFileRoute('/api/chat')({
         try {
           const systemPrompt = config.systemPrompt ?? DEFAULT_SYSTEM_PROMPT
 
+          // Test-only flag — when truthy, the route promotes the system
+          // prompt to object-form and attaches Anthropic `cache_control`
+          // metadata. Enables system-prompt-metadata.spec.ts to verify
+          // cache_control reaches the wire via the aimock journal.
+          const systemPromptCacheControl =
+            fp.systemPromptCacheControl === true
+              ? ({ type: 'ephemeral' as const } as const)
+              : undefined
+          const systemPrompts = systemPromptCacheControl
+            ? [
+                {
+                  content: systemPrompt,
+                  metadata: { cache_control: systemPromptCacheControl },
+                  // The route is provider-generic; the metadata type is
+                  // adapter-narrowed and only meaningful for Anthropic, so
+                  // a single bridge cast lives here at the test entry.
+                  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+                } as any,
+              ]
+            : [systemPrompt]
+
           // Two structured-output-streaming features differ only in which
           // schema they bind to. Branched per-feature so TS can pick the
           // right `chat<TSchema>()` overload without a `never` cast.
@@ -64,7 +85,7 @@ export const Route = createFileRoute('/api/chat')({
               ? chat({
                   ...adapterOptions,
                   modelOptions: config.modelOptions,
-                  systemPrompts: [systemPrompt],
+                  systemPrompts,
                   messages: params.messages,
                   threadId: params.threadId,
                   runId: params.runId,
@@ -76,7 +97,7 @@ export const Route = createFileRoute('/api/chat')({
                 ? chat({
                     ...adapterOptions,
                     modelOptions: config.modelOptions,
-                    systemPrompts: [systemPrompt],
+                    systemPrompts,
                     messages: params.messages,
                     threadId: params.threadId,
                     runId: params.runId,
@@ -88,7 +109,7 @@ export const Route = createFileRoute('/api/chat')({
                     ...adapterOptions,
                     tools: config.tools,
                     modelOptions: config.modelOptions,
-                    systemPrompts: [systemPrompt],
+                    systemPrompts,
                     agentLoopStrategy: maxIterations(5),
                     messages: params.messages,
                     threadId: params.threadId,
diff --git a/testing/e2e/tests/system-prompt-metadata.spec.ts b/testing/e2e/tests/system-prompt-metadata.spec.ts
new file mode 100644
index 000000000..bb578dcfa
--- /dev/null
+++ b/testing/e2e/tests/system-prompt-metadata.spec.ts
@@ -0,0 +1,72 @@
+import { test, expect } from './fixtures'
+
+/**
+ * End-to-end coverage for `systemPrompts: [{ content, metadata: { cache_control } }]`
+ * on the Anthropic adapter.
+ *
+ * Wire-shape coverage lives in the unit test
+ * `packages/typescript/ai-anthropic/tests/anthropic-adapter.test.ts` —
+ * `it('attaches cache_control to system TextBlockParams via systemPrompts
+ * metadata')` directly inspects the body passed to the Anthropic SDK and
+ * asserts the structured `system: [{ type: 'text', text, cache_control }]`
+ * payload. Replicating that assertion here is impossible: aimock's
+ * journal normalises Anthropic requests into an OpenAI-shaped
+ * `ChatCompletionRequest` for storage and drops unknown fields like
+ * `cache_control` in the process.
+ *
+ * What this spec covers (which the unit test cannot):
+ *  - `chatParamsFromRequestBody` accepts the request without rejecting
+ *    `forwardedProps.systemPromptCacheControl`.
+ *  - The object-form `systemPrompts` shape survives the JSON wire from
+ *    test → route → adapter without throwing (in particular,
+ *    `normalizeSystemPrompts`' runtime validation accepts the shape).
+ *  - The Anthropic SDK accepts the request as built (a malformed
+ *    `system` TextBlockParam would be rejected by the SDK or aimock).
+ *  - The stream completes with `RUN_FINISHED`, proving the full
+ *    middleware → adapter → SDK → server path is unaffected by the
+ *    presence of `metadata.cache_control`.
+ */
+test.describe('Anthropic systemPrompts metadata — wire path', () => {
+  test('object-form systemPrompts with metadata.cache_control completes end-to-end on Anthropic', async ({
+    request,
+    testId,
+    aimockPort,
+  }) => {
+    const body = {
+      threadId: 'thread-sysprompt-meta-1',
+      runId: 'run-sysprompt-meta-1',
+      state: {},
+      messages: [
+        { id: 'u1', role: 'user', content: '[chat] recommend a guitar' },
+      ],
+      tools: [],
+      context: [],
+      forwardedProps: {
+        provider: 'anthropic',
+        feature: 'chat',
+        testId,
+        aimockPort,
+        // Opt-in flag handled by `api.chat.ts` — promotes the system
+        // prompt to object-form `{ content, metadata: { cache_control:
+        // { type: 'ephemeral' } } }`. Exercising this flag with the
+        // matching aimock fixture proves the full HTTP path tolerates the
+        // structured shape end-to-end.
+        systemPromptCacheControl: true,
+      },
+    }
+    const response = await request.post('/api/chat', {
+      data: body,
+      headers: { 'Content-Type': 'application/json' },
+    })
+    expect(
+      response.ok(),
+      `expected 200, got ${response.status()}: ${await response.text()}`,
+    ).toBe(true)
+    const text = await response.text()
+    expect(text).toContain('RUN_FINISHED')
+    // No RUN_ERROR — the adapter accepted the structured system prompt
+    // and the SDK accepted the resulting `TextBlockParam` array. (See the
+    // unit test for the actual wire-shape assertion.)
+    expect(text).not.toContain('RUN_ERROR')
+  })
+})

From 7a5842060f7307da3894f94c5b32f06cafc77ce0 Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Tue, 19 May 2026 15:26:37 +0000
Subject: [PATCH 16/17] ci: apply automated fixes

---
 .../typescript/ai-gemini/tests/gemini-adapter.test.ts    | 5 ++++-
 packages/typescript/ai/tests/middlewares/otel.test.ts    | 9 +++++++--
 packages/typescript/ai/tests/system-prompts.test.ts      | 5 +----
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts b/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts
index ead500bd0..c30059fcc 100644
--- a/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts
+++ b/packages/typescript/ai-gemini/tests/gemini-adapter.test.ts
@@ -159,7 +159,10 @@ describe('GeminiAdapter through AI', () => {
         // The adapter must still produce the expected systemInstruction
         // string and never leak the foreign field anywhere on the payload.
         // eslint-disable-next-line @typescript-eslint/no-explicit-any
-        { content: 'with-foreign-meta', metadata: { cache_control: {} } as any },
+        {
+          content: 'with-foreign-meta',
+          metadata: { cache_control: {} } as any,
+        },
       ],
     })) {
       /* consume stream */
diff --git a/packages/typescript/ai/tests/middlewares/otel.test.ts b/packages/typescript/ai/tests/middlewares/otel.test.ts
index 260eeda52..632d04b6f 100644
--- a/packages/typescript/ai/tests/middlewares/otel.test.ts
+++ b/packages/typescript/ai/tests/middlewares/otel.test.ts
@@ -444,7 +444,10 @@ describe('otelMiddleware — captureContent', () => {
       messages: [{ role: 'user', content: 'hi' }],
       systemPrompts: [
         'plain',
-        { content: 'cached', metadata: { cache_control: { type: 'ephemeral' } } },
+        {
+          content: 'cached',
+          metadata: { cache_control: { type: 'ephemeral' } },
+        },
         { content: 'no-meta' },
       ],
     })
@@ -470,7 +473,9 @@ describe('otelMiddleware — captureContent', () => {
     })
 
     const iter = spans[1]!
-    expect(iter.attributes!['tanstack.ai.system_prompt.metadata']).toBeUndefined()
+    expect(
+      iter.attributes!['tanstack.ai.system_prompt.metadata'],
+    ).toBeUndefined()
   })
 
   it('captureContent=false emits no message events', async () => {
diff --git a/packages/typescript/ai/tests/system-prompts.test.ts b/packages/typescript/ai/tests/system-prompts.test.ts
index d6282cab1..5d463c149 100644
--- a/packages/typescript/ai/tests/system-prompts.test.ts
+++ b/packages/typescript/ai/tests/system-prompts.test.ts
@@ -24,10 +24,7 @@ describe('normalizeSystemPrompts', () => {
         { content: 'cached', metadata: meta },
         { content: 'plain' },
       ]),
-    ).toEqual([
-      { content: 'cached', metadata: meta },
-      { content: 'plain' },
-    ])
+    ).toEqual([{ content: 'cached', metadata: meta }, { content: 'plain' }])
   })
 
   it('mixes plain strings and object-form in order', () => {

From c3a480addd8caadaa6fe89166ec4ec7ef631ac65 Mon Sep 17 00:00:00 2001
From: Alem Tuzlak <t.zlak@hotmail.com>
Date: Tue, 19 May 2026 17:39:40 +0200
Subject: [PATCH 17/17] fix CI: ai-event-client cross-package import +
 system-prompts lint
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Two CI failures on the previous review-feedback commit, both follow-ups to
the same patch:

- `@tanstack/ai-event-client:test:types` failed because the new
  `devtools-middleware-shape.test.ts` imported `SystemPrompt` from
  `@tanstack/ai`, but `@tanstack/ai-event-client` only declares
  `@tanstack/ai` as a peerDependency. Nx's project graph therefore
  doesn't see a build edge and the `^build` predecessor for test:types
  never produces the dist files tsc needs. Adding a `workspace:*` devDep
  would close the loop but reintroduce the circular dev/runtime dep the
  current architecture is built to avoid.

  Move the structural guard test into `@tanstack/ai/tests/` instead.
  `@tanstack/ai` has no edge to ai-event-client's source for this
  assertion (the mirror gets re-declared inline), and the test now lives
  alongside the type it's guarding.

- `@tanstack/ai:test:eslint` failed on
  `@typescript-eslint/no-unnecessary-condition` at the C1 runtime checks
  inside `normalizeSystemPrompts`. TS narrows `p` to the object arm
  after the string branch, so the `p === null || typeof p !== 'object'`
  guard looks redundant to the rule even though it's deliberate
  defence-in-depth at a public API boundary. Cast through `unknown`
  to drop the narrow and re-validate without disabling the rule.

  Same treatment for the `p.content` typeof check — read `content` off
  an `unknown`-typed view of the candidate so the runtime check is
  visible to the linter without an eslint-disable.
---
 .../tests/devtools-middleware-shape.test.ts   | 23 --------------
 packages/typescript/ai/src/system-prompts.ts  | 14 ++++++---
 .../devtools-system-prompt-mirror.test.ts     | 30 +++++++++++++++++++
 3 files changed, 40 insertions(+), 27 deletions(-)
 delete mode 100644 packages/typescript/ai-event-client/tests/devtools-middleware-shape.test.ts
 create mode 100644 packages/typescript/ai/tests/devtools-system-prompt-mirror.test.ts

diff --git a/packages/typescript/ai-event-client/tests/devtools-middleware-shape.test.ts b/packages/typescript/ai-event-client/tests/devtools-middleware-shape.test.ts
deleted file mode 100644
index 3b09e4e44..000000000
--- a/packages/typescript/ai-event-client/tests/devtools-middleware-shape.test.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { describe, it, expectTypeOf } from 'vitest'
-import type { SystemPrompt } from '@tanstack/ai'
-
-/**
- * `@tanstack/ai-event-client/src/devtools-middleware.ts` intentionally
- * duplicates the `SystemPrompt` shape locally to avoid a circular import
- * (`@tanstack/ai-event-client` is a runtime dep of `@tanstack/ai`).
- *
- * Re-declare the mirror here and assert structural equality against the
- * canonical `SystemPrompt` from `@tanstack/ai`. If `SystemPrompt` ever
- * gains a third variant (or the existing shape changes), this guard fails
- * at type-check time — forcing the maintainer to update the mirror in
- * `devtools-middleware.ts` rather than silently emitting `undefined` from
- * the projection `typeof p === 'string' ? p : p.content`.
- */
-type DevtoolsSystemPrompt = string | { content: string; metadata?: unknown }
-
-describe('DevtoolsSystemPrompt structural mirror of SystemPrompt', () => {
-  it('the local mirror is mutually assignable with @tanstack/ai SystemPrompt', () => {
-    expectTypeOf<SystemPrompt>().toExtend<DevtoolsSystemPrompt>()
-    expectTypeOf<DevtoolsSystemPrompt>().toExtend<SystemPrompt>()
-  })
-})
diff --git a/packages/typescript/ai/src/system-prompts.ts b/packages/typescript/ai/src/system-prompts.ts
index 4f21974cb..5db5f3038 100644
--- a/packages/typescript/ai/src/system-prompts.ts
+++ b/packages/typescript/ai/src/system-prompts.ts
@@ -77,14 +77,20 @@ export function normalizeSystemPrompts<TMetadata = unknown>(
   if (!prompts || prompts.length === 0) return []
   return prompts.map((p, i) => {
     if (typeof p === 'string') return { content: p }
-    if (p === null || typeof p !== 'object') {
+    // Defence in depth: TypeScript narrows `p` to the object arm here, but
+    // this function is a public API boundary that callers can reach via
+    // plain JS or `as any`. Re-validate at runtime so we never stream a
+    // literal `"undefined"` into the model.
+    const candidate = p as unknown
+    if (candidate === null || typeof candidate !== 'object') {
       throw new TypeError(
-        `systemPrompts[${i}]: expected a string or { content, metadata? }, got ${p === null ? 'null' : typeof p}`,
+        `systemPrompts[${i}]: expected a string or { content, metadata? }, got ${candidate === null ? 'null' : typeof candidate}`,
       )
     }
-    if (typeof p.content !== 'string') {
+    const { content } = candidate as { content?: unknown }
+    if (typeof content !== 'string') {
       throw new TypeError(
-        `systemPrompts[${i}]: content must be a string, got ${typeof p.content}`,
+        `systemPrompts[${i}]: content must be a string, got ${typeof content}`,
       )
     }
     return p as NormalizedSystemPrompt<TMetadata>
diff --git a/packages/typescript/ai/tests/devtools-system-prompt-mirror.test.ts b/packages/typescript/ai/tests/devtools-system-prompt-mirror.test.ts
new file mode 100644
index 000000000..17ed75070
--- /dev/null
+++ b/packages/typescript/ai/tests/devtools-system-prompt-mirror.test.ts
@@ -0,0 +1,30 @@
+import { describe, it, expectTypeOf } from 'vitest'
+import type { SystemPrompt } from '../src/system-prompts'
+
+/**
+ * `@tanstack/ai-event-client/src/devtools-middleware.ts` intentionally
+ * duplicates the `SystemPrompt` shape locally as `DevtoolsSystemPrompt` to
+ * avoid a circular import (`@tanstack/ai-event-client` is a runtime dep of
+ * `@tanstack/ai`, so the devtools middleware can't depend back on
+ * `@tanstack/ai`'s types directly).
+ *
+ * Re-declare the mirror here and assert structural equality against the
+ * canonical `SystemPrompt`. The test lives in `@tanstack/ai` rather than
+ * `@tanstack/ai-event-client` because the Nx project graph would resolve
+ * a `@tanstack/ai`-importing test in `ai-event-client` only via a circular
+ * `workspace:*` dev-dep, which we deliberately avoid.
+ *
+ * If `SystemPrompt` ever gains a third variant (or the existing shape
+ * changes), this guard fails at type-check time — forcing the maintainer
+ * to update both the source mirror in `devtools-middleware.ts` and this
+ * test mirror, rather than silently emitting `undefined` from the wire
+ * projection `typeof p === 'string' ? p : p.content`.
+ */
+type DevtoolsSystemPrompt = string | { content: string; metadata?: unknown }
+
+describe('DevtoolsSystemPrompt structural mirror of SystemPrompt', () => {
+  it('the local devtools mirror is mutually assignable with SystemPrompt', () => {
+    expectTypeOf<SystemPrompt>().toExtend<DevtoolsSystemPrompt>()
+    expectTypeOf<DevtoolsSystemPrompt>().toExtend<SystemPrompt>()
+  })
+})
