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._