mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
4f58ceaf00
## What & why Resolves [OSS-132](https://linear.app/copilotkit/issue/OSS-132). Investigated with systematic-debugging; every conclusion verified against the **real** OpenAI Responses API. **Net change: a TanStack version bump only.** No showcase schema change. - `@tanstack/ai` `0.18.0` → `0.35.0` - `@tanstack/ai-openai` `0.9.1` → `0.15.6` - `package-lock.json` regenerated (Dockerfile uses `npm ci --legacy-peer-deps`) ## The bug The built-in-agent showcase 400s on every prompt against real OpenAI. The state tools (`AGUISendStateSnapshot` / `AGUISendStateDelta` / `set_steps`) declare arbitrary payloads as `z.any()`, which serializes to a **typeless** JSON-Schema property (`{ "description": ... }`, no `"type"`). The old `@tanstack/openai-base`'s `isStrictModeCompatible()` only screened for `oneOf/allOf/not/$ref/$defs`, so it missed the missing `type`, sent the tool with `strict: true`, and OpenAI rejected it: ``` 400 Invalid schema for function 'AGUISendStateSnapshot': In context=('properties','snapshot'), schema must have a 'type' key. ``` This was **masked in production** because the deployed showcase runs against aimock, which replays fixtures without validating the request schema — a raw `curl` to prod returns a clean `RUN_FINISHED`, green for the wrong reason. The ticket's original framing (zod3/zod4 drift → typeless *root*, `got "None"`) was already fixed by the zod-4 migration; this is the same symptom one layer down (typeless *property*). ## The fix is upstream `@tanstack/ai-openai@0.15.6` (via `@tanstack/openai-base@0.9.2`) fixes `isStrictModeCompatible`: it now detects typeless / `z.any()` properties and sends `strict: false`. OpenAI accepts typeless properties under `strict: false` — so `z.any()` works again with no schema change on our side. (`@tanstack/ai-openai@0.15.5` also dropped `@tanstack/ai-client` from its peerDependencies, so no `ai-client` dep is added.) ## Verification (real OpenAI, gpt-4o) | Probe | Result | |---|---| | Typeless property, `strict: true` (raw OpenAI) | **400** — `schema must have a 'type' key` | | Typeless property, `strict: false` (raw OpenAI) | **ACCEPTED** — confirms it was the strict flag, not the schema | | `z.any()` tool on old adapter (0.9.1/0.15.4) | adapter sends `strict: true` → **400** | | `z.any()` tool on new adapter (0.15.6) | adapter sends **`strict: false`** → **ACCEPTED**, model calls the tool | | All 3 `z.any()` state tools attached, new adapter | **ACCEPTED**, no 400 | ## Not covered here The showcase's aimock + Playwright e2e suite was **not** run locally (this worktree has no installed toolchain). CI runs it on this PR; please confirm the gen-ui / shared-state demos still pass before merge. --- _Branch history shows an interim `z.string()` workaround that was reverted once the upstream fix shipped; the net diff is the version bump only. Squash-merge recommended._
Built-in Agent (TanStack AI) Showcase
CopilotKit's BuiltInAgent in factory mode with TanStack AI as the LLM backend.
The agent runs in-process inside the Next.js API route — there is no separate agent server process to start (unlike the LangGraph TypeScript variant which spawns langgraph-cli on port 8123).
Quick Start
Prerequisites
- Node.js 18+
- An OpenAI API key
Setup
- Clone & install dependencies
npm install
- Set environment variables
Create a .env.local file from .env.example:
cp .env.example .env.local
Then fill in your OPENAI_API_KEY:
OPENAI_API_KEY=sk-...
NEXT_PUBLIC_COPILOTKIT_AGENT=default
- Start the dev server
npm run dev
Open http://localhost:3000 to see the demo index.
Build
npm run build
Architecture
- Agent Factory: See
src/lib/factory/tanstack-factory.tsfor theBuiltInAgentwiring and TanStack AI integration. - Tools: Defined in:
src/lib/factory/state-tools.ts— state management toolssrc/lib/factory/server-tools.ts— server-side toolssrc/lib/factory/subagent-tools.ts— sub-agent tools
- API Route:
src/app/api/copilotkit/[[...slug]]/route.tshandles the AG-UI protocol.
Next Steps
Phase 3+ will add individual demo pages under src/app/demos/.