Commit Graph

1299 Commits

Author SHA1 Message Date
copilotkit-qa-bot[bot] 17c59fd719 collect Agno persistence regression in CI 2026-08-26 14:56:06 -07:00
copilotkit-qa-bot[bot] 09f0482152 document Agno frontend-tool session storage 2026-08-26 13:43:11 -07:00
copilotkit-qa-bot[bot] 2ba50f1476 docs(google-adk): keep callback setup concise 2026-08-26 12:29:46 -07:00
copilotkit-qa-bot[bot] 1ddc8d5454 Merge remote-tracking branch 'origin/main' into codex/fac-72-google-adk-stop-callback 2026-08-26 11:11:28 -07:00
Lukas Moschitz 306ddaa5df Merge remote-tracking branch 'origin/main' into lukas/oss-903-presentation-wire-errors-notifications-to-emanate-from-and
# Conflicts:
#	packages/web-inspector/src/lib/__tests__/telemetry.test.ts
#	packages/web-inspector/src/styles/generated.css
2026-08-25 12:09:52 +02:00
Mark 4c975dad49 feat(showcase): enable LlamaIndex attachments (#6660)
## Summary

- enable the LlamaIndex multimodal Showcase demo
- update the LlamaIndex AG-UI protocol pin and its compatible
core/OpenAI adapter pins
- register the multimodal agent and refresh the integration parity notes

## Verification

- Showcase manifest and route validation passed
- LlamaIndex integration production build passed
- container dependency check passed with core 0.14.24, llms-openai
0.7.10, and protocols-ag-ui 0.4.1
- live local OpenAI smoke passed for both image and PDF attachments

## Known harness issue

The shared D6 image assertion still expects the exact contiguous phrase
`copilotkit logo`; OpenAI returned the semantically equivalent `a logo
for CopilotKit`. The browser validation confirmed one intact image
attachment and a relevant response.
2026-08-24 00:45:24 -07:00
Ran Shemtov 6f35b26614 fix(showcase): serve the CrewAI Flows plain-assistant cells with a Flow, not a crew (#6546)
## What

Eleven demos in the `crewai-crews` showcase column (labelled **CrewAI
Flows** in the UI) were served by `add_crewai_crew_fastapi_endpoint`
through a root catch-all, not by the Flow helper. This moves them onto a
real CrewAI Flow and removes the catch-all.

Affected demos: agentic-chat, gen-ui-tool-based, prebuilt-sidebar,
prebuilt-popup, chat-slots, chat-customization-css, headless-simple,
readonly-state-agent-context, agent-config, auth, voice.

## Why

`add_crewai_crew_fastapi_endpoint` wraps the crew in `ChatWithCrewFlow`,
which composes its system message with CrewAI's `build_system_message`.
That boilerplate is unconditional: it instructs the model to introduce
itself and to steer every answer back to the crew's purpose, using a
research-report example. Because the catch-all served the scaffold
research crew, those demos answered the user's question and then offered
to research the latest AI developments.

Measured against real OpenAI on `main`, first turn:

> Hey! I'm here to help you with researching cutting-edge developments
and producing detailed, actionable reports.
> The capital of France is **Paris**. If you'd like, I can also help by
generating a **current research report** on a topic of your choice.

Second turn, arithmetic question:

> 12 × 12 = 144.
> I'm here to help with researching the latest AI developments and
producing actionable reports.

Pre-seeding a hand-written `crew_description` (the existing
`_chat_flow_helpers.preseed_system_prompt`) only retargets that tail, it
does not remove it — verified on `/mcp-apps`, which is pre-seeded and
still introduces itself and offers a diagram.

## How

- New `src/agents/chat_flow.py` holds `PromptedChatFlow`, a one-turn
Flow that owns its own prompt and forwards frontend tools.
`crewai-conversational-flows` already had this class inline; it now
imports the same file, so both columns share one prompt.
- `agent_server.py` registers it at `/chat` via
`add_crewai_flow_fastapi_endpoint`, and the root catch-all registration
is gone. An unrouted agent name now fails loudly instead of landing on
someone else's backend.
- The runtime route's default target becomes `/chat`; the
`agent-config`, `auth`, and `voice` routes point there too.
- The remaining crew endpoints (`/mcp-apps`, `/byoc-hashbrown`,
`/byoc-json-render`) are untouched — each already overrides the composed
system message explicitly.
- Comments that described the removed catch-all were corrected in both
CrewAI columns.

## Verification

Against real OpenAI on the patched backend:

- `/chat` answers `Paris.` and `12 × 12 = 144.` with no purpose-reminder
tail.
- A frontend tool still round-trips: `generate_haiku` emits
`TOOL_CALL_START` / `TOOL_CALL_ARGS` / `TOOL_CALL_END`.
- `POST /` returns 404.

Python suites: 162 passed (`crewai-crews`), 164 passed
(`crewai-conversational-flows`). New coverage in `test_chat_flow.py`
(prompt contract, no crew-chat boilerplate, tool forwarding) plus a
routing contract test asserting no cell can reach a crew endpoint by
fall-through.

D6 replay: see the checklist below.

### D6 replay (local, `--d6 --direct`, warm stack)

All fourteen green: the eleven affected cells (agentic-chat,
gen-ui-tool-based, prebuilt-sidebar, prebuilt-popup, chat-slots,
chat-customization-css, headless-simple, readonly-state-agent-context,
agent-config, auth, voice) plus tool-rendering, hitl-in-chat and
shared-state-read-write as untouched controls.

gen-ui-tool-based needed the second commit: the shared probe had both
CrewAI columns off its chart-integration list, so it sent the haiku
prompt and waited for a haiku card the page cannot draw. The probe's own
unit tests still pass (11).

The conversational column's D6 was not run — it is not deployed, and its
image was not built in this session. Its Python suite passes and its
wiring mirrors the crews column line for line.
2026-08-24 09:39:53 +02:00
Mark dfe20ba05a fix(showcase): support LlamaIndex PDF attachments 2026-08-23 00:26:23 -07:00
Mark c86c97c75c feat(showcase): enable LlamaIndex attachments 2026-08-22 21:06:22 -07:00
Mike Ryan 36d9f16a26 fix(showcase): make the A2UI fixed-schema guide followable (OSS-901) (#6645)
Closes OSS-901.

## Problem

`/mastra/generative-ui/a2ui/fixed-schema` could not be followed. A
Mastra onboarding run on Codex stopped there rather than invent an API,
reporting that the guide "depends on unbundled showcase helpers."

That is true, and the mechanism is worse than the report. Region bodies
are assembled at bundle time, so what ships is invisible in a source
diff. The `backend-render-operations` marker sits on **line 1** of
`mastra/src/mastra/tools/index.ts` — put there by the marker-hoist sweep
in 34b6418 so snippets would carry their imports — and the closing
marker is at the bottom of the file. The page therefore published **all
432 lines** of the tools barrel: weather, stock price, dice, d20,
query-data, schedule-meeting, search-flights, the aimock
header-forwarding import, and

```ts
import { generateA2uiImpl, buildA2uiOperationsFromToolCall } from "@copilotkit/showcase-shared-tools";
```

`@copilotkit/showcase-shared-tools` is not a package. It is a tsconfig
`paths` entry (`mastra/tsconfig.json:23`) pointing at `./shared-tools`,
a symlink to `showcase/shared/typescript/tools`. There is nothing for a
reader to install.

Same defect on the strands page from the same sweep: 586 lines of a
1688-line `agents/agent.py`.

## What changed

**The two cells get a dedicated module for the A2UI tool**, so hoisting
the marker to the top of the file yields exactly the tool plus its own
imports. This is the shape of the reference cell
(`langgraph-typescript/src/agent/a2ui-fixed.ts`, which likewise builds
A2UI operations locally) and, on the Python side, of `gen_ui_agent.py` /
`a2ui_dynamic.py`.

| page | before | after |
| --- | --- | --- |
| mastra fixed-schema | 432 lines, 16.5 KB | 166 lines |
| strands fixed-schema | 586 lines | 171 lines |

Every line in the new snippets either installs from npm or is a visibly
local `./` / `@/` module carrying a comment about what a real app uses
instead. Mastra keeps a single operation builder — the beautiful-chat
flight tool now calls the same one. The strands cell also highlights
`tools/generate_a2ui.py` so the guide shows the helper the tool calls.

**A guard in the bundler**, because neither failure mode shows up in
review:

- any `@copilotkit/showcase-*` specifier in a published body fails the
build (corpus is at zero after this change, so no baseline);
- over 200 lines fails the build (median region is 28, p90 is 125; the
48 already over the line are baselined by `slug::region::file` and the
list only shrinks).

**The entrypoint half of the issue lands differently than I first read
it.** OSS-901 flagged `@copilotkit/runtime` +
`@copilotkit/react-core/v2` on the shared A2UI page as a v1/v2 trap. It
is not a broken pairing — v1's `CopilotRuntime` forwards `a2ui` (and
`mcpApps` / `openGenerativeUI`) straight to the v2 runtime
(`packages/runtime/src/lib/runtime/copilot-runtime.ts:414`). But #6618
landed while this branch was open and retired the v1 runtime adapter
across every showcase integration, so the page's v1 root import *was*
the stale half. The block also imported `ExperimentalEmptyAdapter` and
`copilotRuntimeNextJSAppRouterEndpoint` and used neither, so it was a
route a reader could not run. It now shows `createCopilotRuntimeHandler`
from `@copilotkit/runtime/v2` in the single-route form, matching the
rebased showcase route and `/runtime-server-adapter`, with a note that
the legacy form still works.

**On the systemic question.** A separate sweep counted ~50 regions whose
marker sits on line 1 with a matching close at end-of-file, and proposed
failing a region that spans >=90% of its file. That rule does not
survive contact with the published bodies: of 141 regions at >=90% span,
only **2** publish more than 200 lines, and 98 publish under 100 —
dedicated single-purpose files whose whole content *is* the intended
snippet. It would also flag this PR's own fix
(`strands/a2ui_generate.py` is 171/188 = 91%) and the langgraph
reference cells. Published size is the signal that separates the defect
from the pattern, which is what the guard here measures.

## Testing

**Guard catches the pre-fix tree** (restored HEAD sources, moved the new
modules aside, ran the bundler):

```
REAL EXIT=1
Region bodies importing repo-only modules:
  mastra::agentic-chat: region "weather-tool-backend" (src/mastra/tools/index.ts) imports "@copilotkit/showcase-shared-tools", ...
  mastra::agentic-chat: region "backend-render-operations" (src/mastra/tools/index.ts) imports "@copilotkit/showcase-shared-tools", ...
Region bodies over the published-snippet limit:
  strands::a2ui-fixed-schema: region "backend-render-operations" (src/agents/agent.py) publishes 586 lines (limit 200) ...
```

and passes on this branch (`bundler exit=0`, 801 demos bundled).

**Guard unit tests** —
`showcase/scripts/lib/__tests__/demo-region-guard.test.ts`, 10 passed.
Mutation-checked: raising `MAX_REGION_LINES` and short-circuiting the
alias scan fails exactly 2 of them; restoring passes 10/10.

**Showcase script suites** — `demo-region-guard`, `bundle-demo-content`,
`validate-parity`, `verify-shell-docs`, `validate-shared-symlinks`:
**151 passed (5 files)**.

**Mastra vitest** — `tests/vitest/a2ui-context.test.ts`, 5 passed. The
prompt builder lives in the dependency-free `a2ui-context.ts` so this
regression test still runs without the Mastra SDK installed, as it did
before. Mutation-checked: breaking the join fails 1 of 5.

**Strands pytest** — `tests/python/test_generate_a2ui_errors.py` 11
passed (was 1 failed / 10 passed after the move, because the happy-path
test patched `agents.agent.build_a2ui_operations_from_tool_call`;
retargeted at the new module). Whole runnable suite: **40 passed**
across `test_generate_a2ui_errors`, `test_hook_injection`,
`test_sales_state_from_args`, `test_tool_call_cap`. Mutation-checked:
stubbing out the builder call fails the happy-path test.
`test_cvdiag_boundaries` / `test_instrumentor_patch` need `starlette` /
`opentelemetry-instrumentation-threading`, absent from this venv —
unrelated to this change.

**Published snippet, rendered** (`demo-content.json` after bundling):

```
mastra snippet lines: 166 | file: src/mastra/tools/a2ui-generate.ts
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
import { generateText, tool as aiTool } from "ai";
// In your own app this is `import { openai } from "@ai-sdk/openai"`. ...
```

**Docs verification** — `verify-shell-docs.ts` produces a byte-identical
finding set with my two MDX edits toggled on and off (empty diff), so
the edits add no new findings. `component-imports`, `essential-content`
and the rest are unchanged; the suite's pre-existing failures are
untouched.

**Lint / format** — `oxfmt` on all changed TS, `oxlint` clean on the new
and edited files.

## Follow-ups (not in this PR)

- The 48 baselined regions are the same class of defect on other pages —
`strands::supervisor-delegation-tools` publishes 795 lines,
`strands::subagent-setup` 625, `ms-agent-dotnet::weather-tool-backend`
549. Each wants the same split.
- `claude-sdk-typescript/shared-tools/` and
`langgraph-typescript/shared-tools/` are real directories where symlinks
belong — the erosion `showcase/AGENTS.md` documents. Untouched here.
- Dropping the strands commit (`14c7351`) is safe on its own; it only
requires adding
`strands::backend-render-operations::src/agents/agent.py` to the guard
baseline.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-21 10:44:08 -07:00
Tyler Slaton 7bff49739e fix(runtime): replace retired Anthropic model IDs (#6616) 2026-08-21 09:06:33 -07:00
Benjamin Taylor 42a0177fe7 style: drop a stray blank line in the strands a2ui module
Reapplies the formatter fix the CI auto-format job pushed (13bed7d4),
which a rebase force-push dropped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 08:50:32 -05:00
Benjamin Taylor 38bb3f27e5 fix(showcase): give the strands A2UI tool its own module
Same defect as the mastra cell, same page: the `backend-render-operations`
marker is hoisted to the top of `agents/agent.py`, so
`/aws-strands/generative-ui/a2ui/fixed-schema` published 586 lines of a
1688-line module — the messages-snapshot wrapper, the weather/dice/query
tools, everything — instead of the A2UI tool the step is about.

Move `generate_a2ui` and its `_A2uiError` shape into
`agents/a2ui_generate.py`, which is what `gen_ui_agent.py` /
`a2ui_dynamic.py` already do for their own surfaces ("this module lives in
its own file so the surface area is reviewable in isolation"). `agent.py`
imports the tool back for the shared agent's tool list, so the wiring and
the tool id are unchanged; the published snippet is now 171 lines with its
own imports. `tools/generate_a2ui.py` joins the cell's highlighted files so
the guide also shows the helper the tool calls.

The error-handling suite patched `agents.agent.build_a2ui_operations_from_tool_call`,
which now lives on the new module — retargeted, and it still imports the
tool via `agents.agent` so the re-export stays covered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 08:42:12 -05:00
Benjamin Taylor 17385a8f6d fix(showcase): make the mastra A2UI fixed-schema snippet followable
`/mastra/generative-ui/a2ui/fixed-schema` published the entire 432-line
tools barrel, because the `backend-render-operations` marker sits at the
top of the file (the marker-hoist sweep in 34b6418 put it there so the
snippet would carry its imports). The published body therefore included
every unrelated tool plus
`import { ... } from "@copilotkit/showcase-shared-tools"` — a tsconfig
path alias to a symlink in this repo, not a package a reader can install.
A Mastra onboarding run stopped there rather than invent an API (OSS-901).

Move `generateA2uiTool` into its own module and mark the region there, so
hoisting to the top of the file yields exactly the tool plus its own
imports — the same shape as the reference cell,
`langgraph-typescript/src/agent/a2ui-fixed.ts`, which likewise builds the
A2UI operations locally instead of importing the showcase's shared tools.
The published snippet goes from 432 lines to 166, and everything in it
either installs from npm or is a visibly local `./` / `@/` module with a
comment saying what a real app would use instead.

`buildA2uiOperations` and `systemPromptFrom` replace the two shared-tools
helpers so mastra keeps a single operation builder: the beautiful-chat
flight tool now calls the same one. The prompt builder lands in the
dependency-free `a2ui-context.ts` so its regression test keeps running
without the Mastra SDK installed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 08:42:11 -05:00
Ben Taylor 1b3bf74dc8 refactor(showcase): retire the v1 runtime adapter across every integration (#6618)
Retires the v1 runtime adapter from `showcase/integrations/`. After
this, **no code under `showcase/integrations/` calls
`copilotRuntimeNextJSAppRouterEndpoint`** — 239 routes across 20
integrations.

This is the cheap path we discussed: single-route mode, which is a
genuine drop-in. **No demo page changes, no route path changes, no `GET`
exports, no new dependencies.**

## The shape

```ts
const copilotHandler = createCopilotRuntimeHandler({
  runtime,
  basePath: "/api/copilotkit-x",
  mode: "single-route",
});
...
return await copilotHandler(req);
```

**Why single-route:** these demos' frontends are `<CopilotKit
runtimeUrl="/api/copilotkit-x">` with no transport prop, and every
released provider pins the single-route transport. So single-route mode
is what the v1 adapter was already serving. Migrating to multi-route
instead would have meant editing every demo page in lockstep, for no
functional gain — nothing in the showcase probes `/info`.

**Why `createCopilotRuntimeHandler`** rather than
`createCopilotEndpointSingleRoute`: that helper is itself deprecated in
favour of the `mode` option (per the deprecated-aliases table in
`docs/backend/runtime-endpoints.mdx`), and the fetch handler needs no
`hono` dependency and composes directly with the wrappers these routes
already have.

The statement is rewritten **in place**, inside whatever wrapper it
already sat in, so `withForwardedHeaders`, the try/catch envelopes,
`wrapStreamingResponse` and `withCvdiagBackend` are untouched. 75 of
these routes construct the runtime inline in the call; rewriting in
place preserves that per-request construction exactly as v1 did. No
`runner` is added — it's optional and none of these routes passed one.

13 `copilotkit-auth/[[...slug]]` routes already use the v2 fetch handler
and are left alone; they only name v1 in comments.

## Verified

The shape was proved end-to-end **before** the rollout, in a real
running app with an untouched provider (aimock as the model backend):
`POST /api/copilotkit` → 200 twice, chat turn rendered in the browser.
It also typechecks against the exact version these integrations pin
(1.68.2).

`mastra` is the integration installed and exercised locally — 19 routes,
the `withCvdiagBackend` main route, and the only vitest suites that
touch routes. Measured against `origin/main` **in the same tree**:

| | baseline (`origin/main`) | after |
| --- | --- | --- |
| `tsc --noEmit` | errors in 10 files | errors in **9** |
| `vitest run` | 2 files / 13 tests failed, 21 passed | 2 files / 13
tests failed, 21 passed |

- **New type errors introduced: none.**
- **Fixed:** `src/app/api/copilotkit-mcp-apps/route.ts`, whose
`@ts-expect-error` was *already* unused on `main`.
- **Test-neutral:** those 13 failures are pre-existing on `main` (mostly
`extractXHeaders` dereferencing `req.headers` on a `{}` fake request).

Structural audit over all 239 routes, re-run after the pre-commit
formatter: none still imports the v1 root, calls the v1 adapter,
references `ExperimentalEmptyAdapter` or `handleRequest` in code, or is
missing `createCopilotRuntimeHandler` / `basePath` / `mode:
"single-route"`.

**CI has now built all 21 integrations green** — `showcase_build_check`
Docker-builds each changed integration and `next build` typechecks
inside it. That covers the ones I could not stand up locally, including
the non-JS backends (`spring-ai`, `ms-agent-dotnet`, `ms-agent-python`,
`ms-agent-harness-dotnet`, `langroid`, `strands`). Full run: 41 pass / 3
skip / 0 fail.

To be precise about what each gate proves: CI proves these 21 apps still
**build and typecheck**. It does not exercise a chat turn per
integration — that came from the pre-rollout live proof of the shape
itself, plus mastra's local test suite.

## Runtime verification on real cells

Docker is not running on my machine, and `bin/showcase test --d6
--direct` requires it
(`--direct` only swaps the in-process driver for the fleet
control-plane; the containers are
not optional). **So the sanctioned Iron Rule 4 probe has NOT been run**
— that gap is real and
a reviewer should weigh it. What I did instead was run a real
integration directly.

`showcase/integrations/mastra` on this branch, `npm run dev`, aimock as
the model backend.
Probing eight migrated routes with the exact envelope the released
provider sends
(`POST {basePath}` with `{"method":"info"}`) — all **200** with real
runtime payloads:

    copilotkit-multimodal          200   agents: multimodal-demo
    copilotkit-mcp-apps            200   agents: headless-complete
    copilotkit-a2ui-fixed-schema   200   agents: a2ui-fixed-schema
    copilotkit-beautiful-chat      200   agents: beautiful-chat
    copilotkit-agent-config        200   agents: agent-config-demo
    copilotkit-ogui                200   agents: open-gen-ui
    copilotkit-declarative-gen-ui  200   agents: declarative-gen-ui
    copilotkit-background-agents   200   agents: background-agents

Then three real demo cells driven in a browser, each rendering and
completing a chat turn
through its migrated route (two POSTs, both 200, assistant message
rendered):

/demos/beautiful-chat -> POST /api/copilotkit-beautiful-chat 200, 200
/demos/a2ui-fixed-schema -> POST /api/copilotkit-a2ui-fixed-schema 200,
200
/demos/multimodal -> POST /api/copilotkit-multimodal 200, 200

Deliberately spread across different route configs — plain, `a2ui`, and
a dedicated
vision-model route — rather than three variations of the same one.

### One route is 500, and it is pre-existing

`POST /api/copilotkit` (mastra's main route) returns 500 in dev:
`module-not-found` on
`./schema.js` from `src/cvdiag/cvdiag-emitter.ts`. `schema.ts` **is**
tracked and present —
Turbopack in dev just does not resolve the ESM-style `.js` specifier to
it. Proven
pre-existing by restoring **only** that file to `origin/main` and
re-probing: same 500 on the
v1 code. Its Docker build passes, which is why CI is green.

### A mistake in my own verification, recorded

My first pass at the above ran against the wrong branch — I was still on
the docs branch,
where these routes are v1, so the first six 200s I collected were the
**v1** routes. Caught it,
switched to this branch, and re-ran everything above against the
migrated code. The accidental
run was not wasted: it independently confirms the premise of this PR,
that the v1 adapter and
v2 single-route mode answer the same envelope the same way.

## Judgement call worth reviewing

27 `@ts-expect-error` directives guarded the **v1** `CopilotRuntime`
agents type ("wraps `Record` in `MaybePromise<NonEmptyRecord<...>>`").
Under `/v2` that hole is gone, which makes the directive *unused* — a
hard compile error.

I demoted them to `@ts-ignore`, which compiles whether or not the
mismatch survives in a given integration. The honest reason at the time:
19 of these apps can't be built locally, so I couldn't prove per-file
which still need a suppression, and `@ts-ignore` is what 190 sibling
files already use.

Now that CI has built all 21 green, that constraint is gone — the ~220
now-stale suppressions (all of which cite a **v1** type hole that no
longer applies) can be removed and verified by the same 21 builds. I've
left them in place here to keep this PR mechanical and reviewable; say
the word and I'll do it as a second pass.

## Two pre-existing problems found on the way

- **`npm ci` fails in `showcase/integrations/mastra`**: `Missing:
@types/http-errors@2.0.5 from lock file`. The Dockerfile uses `npm ci
--legacy-peer-deps`, which *does* succeed, so the image still builds —
but a plain `npm ci` doesn't. No manifest or lockfile is in this diff.
- **`mastra`'s vitest suite is red on `main`** — 13 failures, as tabled
above.

## What's left of the v1 entrypoint

| Surface | Before | After |
| --- | --- | --- |
| `showcase/integrations/**` | 239 | **0** |
| `examples/v1/**` | 12 | 12 (deliberately v1, never in scope) |
| everything else in `examples/` | ~61 | ~61 (not in this PR) |

Stacks cleanly with #6617 (docs) — no file overlap. It also **unblocks
the two Claude SDK quickstart pages** I had to revert there:
single-route keeps the starter file at the plain `route.ts` path, so
those pages' prose claims and `verify-shell-docs.ts` starter-path checks
stay valid, and only the fence body needs updating.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-21 08:28:17 -05:00
Ran Shem Tov b69ac14711 fix(showcase): keep the AG-UI request context on the chat Flow, and point the Channels setup at /chat
Review found two gaps in the previous commit.

`RunAgentInput.context` never reached the model. The bridge puts it on state
under `context`, but `CopilotKitState` does not declare the field, so pydantic
drops it when the endpoint validates the request into the Flow's state and the
"Application context" block rendered without it. That hollowed out the two cells
whose whole point is reading application context: readonly-state-agent-context
(now on the default `/chat` route) and agent-config. `ChatState` declares the
field so it survives validation.

Neither existing test caught it: the readonly probe only asserts the browser
request body carries its sentinel, the agent-config probe encodes the expected
value in the user message, and Flow-level unit tests bypass endpoint state
initialization. The new endpoint test drives the real FastAPI route with two
context entries and asserts both appear in the model's system message; it fails
without the declared field.

The Channels setup fragment still told readers the shared crew sits at the
server root and set `AGENT_URL` accordingly, which the removed catch-all turned
into a dead endpoint. It now points at `/chat` and says Flow rather than crew.
Migrating the consumer was preferred over restoring `/`, which would put the
silent-fallback trap back in place.

Verified: 164 and 166 Python tests pass across the two columns, the docs
setup-content tests pass (16), and readonly-state-agent-context, agent-config
and agentic-chat are green on D6 replay.
2026-08-21 10:52:54 +02:00
Mark d04643c391 chore(showcase): mark CrewAI conversational flows live 2026-08-21 00:19:45 -07:00
Benjamin Taylor e27aeb687d refactor(showcase): retire the v1 runtime adapter across every integration
Moves all 239 showcase integration routes off
`copilotRuntimeNextJSAppRouterEndpoint`, the deprecated v1 Next.js adapter, so
the v1 entrypoint has no remaining code-level users under
`showcase/integrations/`.

    const copilotHandler = createCopilotRuntimeHandler({
      runtime,
      basePath: "/api/copilotkit-x",
      mode: "single-route",
    });
    ...
    return await copilotHandler(req);

## Why single-route, and why this handler

**Single-route** because these demos' frontends are
`<CopilotKit runtimeUrl="/api/copilotkit-x">` with no transport prop, and every
released provider pins the single-route transport. Single-route mode is
therefore a drop-in for the v1 adapter: no frontend change, no path change, no
`GET` export, and nothing here probes `/info`. Migrating to multi-route instead
would have required editing every demo page in lockstep for no functional gain.

**`createCopilotRuntimeHandler`** rather than `createCopilotEndpointSingleRoute`
because that helper is itself deprecated in favour of the `mode` option (see the
deprecated-aliases table in `docs/backend/runtime-endpoints.mdx`), and because
the fetch handler needs no `hono` dependency and composes directly with the
wrappers these routes already have.

The statement is rewritten in place, inside whatever wrapper it already sat in,
so `withForwardedHeaders`, the try/catch envelopes, `wrapStreamingResponse` and
`withCvdiagBackend` are all untouched. 75 of these routes construct the runtime
inline in the call; rewriting in place preserves that per-request construction
exactly as v1 did. No `runner` is added — it is optional, and none of these
routes passed one before.

13 `copilotkit-auth/[[...slug]]` routes already use the v2 fetch handler and are
left alone; they only mention the v1 name in explanatory comments.

## Collateral

- `mastra`'s main route declared a module-level
  `const serviceAdapter = new ExperimentalEmptyAdapter()` plus a startup log
  about the adapter choice. V2 has no service adapters, so both are gone and the
  comment now explains that there is nothing to configure.
- The three `mastra` vitest suites mocked `@copilotkit/runtime` and the v1
  `{ handleRequest }` return shape; they now mock `@copilotkit/runtime/v2` and
  `createCopilotRuntimeHandler`, which returns the handler directly.
- 27 `@ts-expect-error` directives guarded the **v1** `CopilotRuntime` agents
  type ("wraps Record in MaybePromise<NonEmptyRecord<...>>"). Under `/v2` that
  hole is gone, which makes the directive unused — a hard error. They are
  demoted to `@ts-ignore`, which compiles whether or not the mismatch survives
  in a given integration, because 19 of these apps cannot be built locally to
  prove it either way. Removing all ~220 now-stale suppressions is left as
  follow-up once CI has built every integration green.

## Verified

`mastra` is the one integration installed and exercised locally (19 routes, the
`withCvdiagBackend` main route, and the only vitest suites that touch routes).
Measured against `origin/main` in the same tree:

    tsc --noEmit    baseline: errors in 10 files
                    after:    errors in  9 files
                    new errors introduced: NONE
                    fixed: src/app/api/copilotkit-mcp-apps/route.ts, whose
                           @ts-expect-error was ALREADY unused on main

    vitest run      baseline: 2 files failed, 13 tests failed, 21 passed
                    after:    2 files failed, 13 tests failed, 21 passed
                    → test-neutral; those 13 failures are pre-existing on main

Structural audit over all 239 routes: none still imports the v1 root, uses the
v1 adapter, references `ExperimentalEmptyAdapter` or `handleRequest` in code, or
is missing `createCopilotRuntimeHandler` / `basePath` / `mode: "single-route"`.

The shape itself was proved end-to-end before the rollout, in a real running
app with an untouched provider (aimock as the model backend):
`POST /api/copilotkit` -> 200 twice, chat turn rendered.

## Two pre-existing problems found on the way

- `npm ci` fails in `showcase/integrations/mastra`: `Missing:
  @types/http-errors@2.0.5 from lock file`. Its Dockerfile uses
  `npm ci --legacy-peer-deps`, which does succeed, so the image still builds —
  but a plain `npm ci` does not. Untouched here; no manifest or lockfile is in
  this diff.
- `mastra`'s vitest suite is red on `main` (13 failures, mostly
  `extractXHeaders` dereferencing `req.headers` on a `{}` fake request).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 18:59:27 -05:00
Tyler Slaton 22ca41fa1b fix(examples): default Anthropic integrations to Opus 4.8 2026-08-20 16:39:46 -07:00
copilotkit-qa-bot[bot] 7f798d557e docs(google-adk): define state-streaming stop callback 2026-08-20 13:14:31 -07:00
Ran Shem Tov f421ae6180 fix(showcase): serve the CrewAI Flows plain-assistant cells with a Flow, not a crew
The `crewai-crews` column is presented as "CrewAI Flows", but eleven of its
demos were served by `add_crewai_crew_fastapi_endpoint` through a root
catch-all: agentic-chat, gen-ui-tool-based, both prebuilt-chrome cells,
chat-slots, chat-customization-css, headless-simple,
readonly-state-agent-context, agent-config, auth and voice.

That helper wraps the crew in `ChatWithCrewFlow`, whose system message comes
from CrewAI's `build_system_message`. Its boilerplate is unconditional: it tells
the model to introduce itself and to steer every answer back to the crew's
purpose, illustrated with a research-report example. Since the catch-all served
the scaffold research crew, those cells answered the user and then offered to
research the latest AI developments. Measured on real OpenAI, turn two of a
plain arithmetic question came back as "12 x 12 = 144." followed by "I'm here to
help with researching the latest AI developments and producing actionable
reports."

Pre-seeding a hand-written crew description (the existing
`preseed_system_prompt`) only retargets that tail; the boilerplate around it
stays. Verified against the pre-seeded `/mcp-apps` crew, which still introduces
itself and offers a diagram.

Changes:
- Add `chat_flow.PromptedChatFlow`, a neutral one-turn Flow that owns its prompt
  and forwards frontend tools, and serve it at `/chat` via
  `add_crewai_flow_fastapi_endpoint`. The conversational column already had this
  class inline; it now imports the same module so both columns share one prompt.
- Point the runtime's default agent target plus the agent-config, auth and voice
  routes at `/chat`, and drop the root catch-all registration. An unrouted agent
  name now fails loudly instead of landing on someone else's backend.
- Give gen-ui-tool-based its own `gen_ui_tool_based` Flow, mirroring
  langgraph-python's dedicated graph: the cell must force a `render_*` chart call
  on the user's turn, which a neutral assistant does not do. Wired into the
  conversational registry too.
- Leave the remaining crew endpoints (`/mcp-apps`, `/byoc-hashbrown`,
  `/byoc-json-render`) alone; each already overrides the composed system message.
- Refresh the comments that described the removed catch-all.

Coverage: new `test_chat_flow.py` pins the prompt contract, the absence of
crew-chat boilerplate and frontend-tool forwarding; a routing contract test
asserts no cell can reach a crew endpoint by fall-through.
2026-08-20 12:35:05 +02:00
Jordan Ritter 069501d6dc chore(showcase): upgrade CopilotKit to 1.68.2 (lands #6576 readiness fix) 2026-08-19 20:16:28 -07:00
copilotkit-qa-bot[bot] b9d41c0e3a Merge main into codex/fac-126-strands-ts-starter 2026-08-19 11:31:21 -07:00
Benjamin Taylor 3ec309b724 docs(langgraph): fix 8 verified defects in the LangGraph onboarding docs (refs OSS-857)
Fixes defects 3, 4, 6, 7, 8, 10, 11 and 12 from the OSS-856 phase 1
validation run. Every claim below was re-verified against installed
package source or a live run, not recalled.

LangGraph quickstart (`integrations/langgraph/quickstart.mdx`):

- Route shape: a caution at the route step. The POST-only route runs the
  runtime in single-route mode, which is all chat needs; Threads and the
  Inspector need the multi-route catch-all with GET/POST/PATCH/DELETE.
  Links to the canonical runtime-endpoints section.
- Port: bare `langgraph dev` serves 2024, not 8123. Verified against both
  CLIs (`@langchain/langgraph-cli` help output, and `default=2024` in
  `langgraph_cli/cli.py`). The guide keeps `--port 8123` to stay
  consistent with every sibling page, and now says so.
- Drop `@copilotkit/react-ui` from the install list. `CopilotSidebar`
  lives in `@copilotkit/react-core/v2`; react-ui exports no `./v2` JS
  entry point and the v2 react example does not depend on it.
- Checkpointer: state the reason each tab differs. `langgraph dev` fails
  to load a graph compiled with a custom checkpointer (reproduced), while
  the FastAPI tab needs one because `ag-ui-langgraph` calls
  `graph.aget_state(...)`, which raises `ValueError: No checkpointer set`.
- Narrow the shared `uv add` line to what both tabs import, and warn that
  a project with exact pins should add them by hand.

A2UI fixed schema (`generative-ui/a2ui/fixed-schema.mdx`):

- Add the missing install step for `@copilotkit/a2ui-renderer` + `zod`,
  which the catalog/definitions/renderer snippets all import.
- Add a `StateGraph` + `ToolNode` form for developers who already have a
  hand-built graph, gated to the Python LangGraph slugs by a new
  `a2ui_agent_form` docs flag so the shared page does not show Python to
  langgraph-typescript or LangGraph code to LlamaIndex/ADK/Mastra.
- Repoint the cross-tree `/integrations/langgraph/...` link, which 301'd
  back to this same page, at the action-handler reference it promises.

Raw Markdown pipeline (`src/lib/llm-text.ts`):

- `renderPageToLlmText` never applied `filterFrameworkScopedBlocks`, so
  `/<framework>/<page>.md` emitted every `<WhenFrameworkHas>` branch with
  raw JSX tags, each carrying the one selected framework's snippet. On the
  A2UI page that produced three mutually-exclusive "how the schema is
  delivered" sections whose prose contradicted the identical code under
  each. Gate on the same framework the snippets resolve to, with a
  regression test.

Also corrects a factually wrong comment in the langgraph-python showcase
`.env.example` that claimed 8123 was the `langgraph dev` default — the
same mis-belief this ticket found in the docs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 12:19:52 -05:00
copilotkit-qa-bot[bot] bd91313517 feat: add AWS Strands TypeScript starter 2026-08-18 15:51:47 -07:00
Mark 8d32e2eaa3 fix(showcase): drop inline langgraph-ts heap cap that forced OOM restarts (#6552)
## Problem

PR #6505 added an inline `NODE_OPTIONS="--max-old-space-size=1536"` to
the `langgraph-typescript` agent launch in
`showcase/integrations/langgraph-typescript/entrypoint.sh`, intending to
bound V8 old-space on the many-core Railway host.

In staging this cap is forcing crash-restarts, not delivering savings.
Staging `showcase-langgraph-typescript` hit a V8 heap-OOM `exit 134` at
`2026-08-18T09:52:31Z` (RSS dropped `2.289 GB -> 0.902 GB` on the
crash-reset).

The cap is also structurally un-overridable. It's appended as
`${NODE_OPTIONS:+$NODE_OPTIONS }--max-old-space-size=1536`, so it is
always the *last* `--max-old-space-size` flag on the command line — and
V8 takes the last flag when the same one repeats. An operator-supplied
`NODE_OPTIONS` override therefore always loses to the inline `1536`, so
a Railway env var can't raise the ceiling for this process; only another
code change can.

## Change

Removes only the inline `--max-old-space-size=1536` addition (and its
now-stale explanatory comment) from `entrypoint.sh`, restoring the exact
pre-#6505 launch line:

```
cd /app/src/agent && PORT=8123 HOST=0.0.0.0 npm start &> >(awk '{print "[agent] " $0; fflush()}') &
```

`NODE_OPTIONS` now passes through untouched — an operator override wins
again, and with no `NODE_OPTIONS` set V8 falls back to its own default
sizing (pre-#6505 behavior).

Untouched, by design:
- Worker-recycle logic in the same entrypoint
- `langgraph-python` / `langgraph-fastapi` entrypoints and their
`MALLOC_ARENA_MAX` / `MALLOC_TRIM_THRESHOLD_` allocator tuning (also
from #6505)

`git diff --stat` confirms the diff is scoped to exactly one file:
```
showcase/integrations/langgraph-typescript/entrypoint.sh | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
```

## Local red-green proof

Reconstructed the NODE_OPTIONS composition with plain `node` (v25.8.0 —
absolute MiB numbers will vary by machine/Node version, but the
*ordering*, which is the defect, will not):

**RED — current (pre-fix) launch, operator override lost:**
```
NODE_OPTIONS="--max-old-space-size=3072 --max-old-space-size=1536" \
  node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
=> 1728
```
The operator asked for a 3072 MiB ceiling and got capped to 1728 — well
below what was requested, and the source of the crash-restart loop.

**GREEN 1/2 — fix applied, operator override now wins:**
```
NODE_OPTIONS="--max-old-space-size=3072" \
  node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
=> 3264
```

**GREEN 2/2 — fix applied, no NODE_OPTIONS set, V8 default restored
(pre-#6505 behavior):**
```
node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
=> 4288
```

## Post-merge validation gate

This PR does not attempt to prove the fix in production. Before this is
considered validated, it needs a **24h+ re-soak on a pinned image
digest** of the `showcase-langgraph-typescript` service to confirm the
OOM/exit-134 crash-restart loop is gone under real traffic.

Ref: #6505
2026-08-18 15:13:09 -07:00
Jordan Ritter f536d009c6 fix(showcase): drop inline langgraph-ts heap cap that forced OOM restarts
PR #6505 added an inline NODE_OPTIONS="--max-old-space-size=1536" to the
langgraph-typescript agent launch to bound V8 old-space on the many-core
Railway host. In production the cap is forcing crash-restarts rather than
saving memory: staging showcase-langgraph-typescript hit a V8 heap-OOM
exit 134 at 2026-08-18T09:52:31Z (RSS dropped 2.289 GB -> 0.902 GB on the
crash-reset).

The cap is also structurally broken for override: because it's appended
after ${NODE_OPTIONS:+$NODE_OPTIONS }, an operator-supplied
--max-old-space-size loses to the inline 1536 (V8 takes the last flag of
a duplicate, but the inline one is always last). A Railway env var can
raise the ceiling for the frontend process but not for the agent process
this line targets, so there's no way to dial the cap up without another
code change.

This removes only the inline --max-old-space-size=1536 addition (and its
now-stale explanatory comment) from entrypoint.sh, restoring the exact
pre-#6505 launch line so NODE_OPTIONS passes through untouched — an
operator override wins again, and with no NODE_OPTIONS set V8 falls back
to its own default sizing. Worker-recycle and the langgraph-python/
langgraph-fastapi allocator tuning (MALLOC_ARENA_MAX, MALLOC_TRIM_THRESHOLD_)
added in the same PR are untouched.

Local red-green proof (node v25.8.0, numbers will vary by machine/node
version but the ordering is the defect):

RED - current launch's NODE_OPTIONS composition, operator override lost:
  NODE_OPTIONS="--max-old-space-size=3072 --max-old-space-size=1536" \
    node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
  => 1728 (capped well below the requested 3072)

GREEN 1/2 - fix applied, operator override now wins:
  NODE_OPTIONS="--max-old-space-size=3072" \
    node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
  => 3264

GREEN 2/2 - fix applied, no NODE_OPTIONS set, V8 default restored (pre-#6505):
  node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
  => 4288

Post-merge validation gate: this needs a 24h+ re-soak on a pinned image
digest before it's considered proven in production; this PR does not
attempt that.
2026-08-18 13:58:14 -07:00
copilotkit-qa-bot[bot] c45a50fa71 docs: scope tool setup copy to Claude 2026-08-18 13:45:59 -07:00
copilotkit-qa-bot[bot] 30a8c36bc0 docs: clarify Claude tool-rendering fallback 2026-08-18 13:12:44 -07:00
github-actions[bot] 96c559bbf5 style: auto-fix formatting 2026-08-18 19:56:25 +00:00
copilotkit-qa-bot[bot] 40608dc01d docs: show Claude tool-rendering backend wiring 2026-08-18 12:53:15 -07:00
copilotkit-qa-bot[bot] 1ea70b0485 chore(showcase): refresh reviewable bot push 2026-08-18 11:53:48 -07:00
copilotkit-qa-bot[bot] 35f14ff4d0 fix(showcase): prune Claude test deps and clean snippets 2026-08-18 11:02:30 -07:00
copilotkit-qa-bot[bot] 8d01b1a368 fix(showcase): include Claude SDK tests in image 2026-08-18 10:08:28 -07:00
copilotkit-qa-bot[bot] 778dde6627 test(showcase): cover Claude SDK MCP wiring 2026-08-18 10:01:58 -07:00
copilotkit-qa-bot[bot] 0d528d57cc docs(showcase): expose Claude fixed-schema backend wiring 2026-08-18 09:48:32 -07:00
copilotkit-qa-bot[bot] eb567d44ae fix(docs): address programmatic control review feedback 2026-08-17 16:31:46 -07:00
copilotkit-qa-bot[bot] 1cc34c641a fix(docs): make programmatic control example self-contained 2026-08-17 16:09:35 -07:00
copilotkit-qa-bot[bot] 61fd3c3828 Fix Strands TypeScript sub-agent doc snippets 2026-08-17 14:50:05 -07:00
Mark 23e4709718 chore(showcase): upgrade CopilotKit to 1.68.1 (#6510)
## Summary

- advance the canonical Showcase CopilotKit pin to `1.68.1`
- apply the release consistently across all 21 integrations and the
Showcase shell
- regenerate the affected npm lockfiles, including the LangGraph
TypeScript agent lockfile and the Shell's strict peer-dependency entries

This picks up
[#5837](https://github.com/CopilotKit/CopilotKit/pull/5837), which
bounds the in-memory agent runner to prevent unbounded thread retention
and OOMs.

## Verification

- Showcase pin ratchet passes at the existing 26-failure baseline/hash
- `@copilotkit/showcase-scripts`: 2,511 tests pass
- strict Shell `npm ci --ignore-scripts` succeeds, matching the Showcase
validation workflow
- Shell unit tests pass (241/241) and its production build succeeds
- clean installs and production builds pass for Ag2, Langroid, and
Mastra
- comparison with `origin/main` found no pin-induced TypeScript
diagnostics; the standalone TypeScript failures are pre-existing and
outside the current production build gate
2026-08-17 14:27:57 -07:00
Mark db22a686cc chore(showcase): upgrade CopilotKit to 1.68.1 2026-08-15 18:46:53 -07:00
Jordan Ritter 49ab706614 perf(showcase): cap langgraph integration backend memory
Set MALLOC_ARENA_MAX=2 and MALLOC_TRIM_THRESHOLD_ on the langgraph-python and
langgraph-fastapi entrypoints to curb glibc arena fragmentation on the many-core
Railway host, and NODE_OPTIONS --max-old-space-size=1536 scoped to the
langgraph-typescript agent process (not the sibling Next.js server) to cap the
V8 heap. All values use ${VAR:-default} so explicit Railway overrides win.
2026-08-15 11:10:30 -07:00
Ran Shemtov fa13d52502 Merge branch 'main' into codex/crewai-full-d6 2026-08-14 09:37:42 +02:00
Mark f97f0768ba test(showcase): isolate CrewAI resume bridge contracts
Exercise both bridge bindings without leaking monkeypatches, and verify rejected bridge versions cannot mutate either binding.
2026-08-13 16:46:26 -07:00
Mark 2116257e1e test(showcase): harden CrewAI cancellation regressions
Use bounded dispatch and cancellation waits in both CrewAI integrations, and verify any fallback worker finishes during cleanup.
2026-08-13 16:46:14 -07:00
Mark 35aa2a34a0 fix(showcase): close CrewAI cancellation edge cases
Use AsyncOpenAI so cancellation reaches the in-flight GenerateA2UI request while retaining the thread fallback for synchronous backend tools.

Preserve cancelled versus resolved-null interrupts across pinned ag-ui-crewai 0.3.0 by encoding only resolved null as JSON null and failing loudly on version drift.

Reuse the canonical shared render_a2ui schema so the secondary request remains aligned with the shared tool contract.
2026-08-13 16:46:05 -07:00
Mark 8a6d14b29a fix(showcase): port pydantic-ai integration to v2 and restore live system prompts (#6379)
Ports `showcase/integrations/pydantic-ai` — the last pydantic-ai surface
still on v1 — to Pydantic AI v2. Refs #6364.

Three commits plus a bot formatting fix, best reviewed separately.

## 1. `chore(showcase): port pydantic-ai integration to Pydantic AI v2`

- **`requirements.txt`** → `pydantic-ai-slim[ag-ui,openai]==2.22.0`,
`ag-ui-protocol==0.1.19`. Drops the `opentelemetry-api<1.44` ceiling
from #6374; v2 resolves cleanly against otel 1.44.0, so the workaround
is no longer needed. `starlette<1.0.0` is unchanged and satisfies v2's
`>=0.46.2`.
- **9 `StateDeps` imports** move from `pydantic_ai.ag_ui` (removed in
v2) to `pydantic_ai.ui`.
- **`agent_server.py`** — `Agent.to_ag_ui()` was removed in 2.0.0, so a
`mount_agent()` helper builds the equivalent Starlette sub-app and
mounts it. The shape is deliberately identical to what v1's `AGUIApp`
produced — a Starlette app whose only route is `POST /`, named
`run_agent` — so **all 19 mount paths behave exactly as before, trailing
slashes included, and no TypeScript route file changes**.

`deps` is constructed **per request**. v1's `run_ag_ui` did `deps =
replace(deps, state=state)`, handing each run its own object; v2's
adapter does `deps.state = state`, mutating what it is given. A single
shared instance under v2 therefore lets concurrent runs overwrite each
other's state mid-run.

## 2. `fix(showcase): apply the multimodal provider gate to v2 native
content`

v2's `AGUIAdapter.load_messages` converts AG-UI attachments to native
content types *before* the model boundary; v1 delivered the raw AG-UI
part dicts. `_NATIVE_CONTENT` listed `BinaryContent` as a flatten
fixpoint, so under v2 inline attachments were waved straight through and
the entire provider gate was skipped:

- inline PDFs were no longer text-extracted, so raw bytes went to OpenAI
- unsupported image subtypes (HEIC/SVG/TIFF) were no longer degraded and
reached the provider as images, which fails the turn
- missing-mime magic-byte sniffing never ran
- `AudioUrl`/`VideoUrl` were neither fixpoints nor classifiable, so they
hit the fail-loud raise

`BinaryContent` is no longer a fixpoint. `_classify_native_content` maps
native content onto the same `(kind, scheme, mime, value)` tuple the
AG-UI classifier already produces, so **every existing gate applies
unchanged** — no gate logic was rewritten. `audio/*` and `video/*` are
named explicitly because `_kind_for` routes them to `"other"`, and a
missing mime defaults to `"image"` so the sniffer runs.

Net behaviour matches v1: a supported inline image still flattens to an
`ImageUrl` data URI, which is why most of the suite went green without
touching assertions.

Five assertions did change. They checked that state-backing content was
still AG-UI `InputContent`, which encoded v1's bridging. They now assert
the flatten's output (`ImageUrl`) never appears in state — the leak they
were written to guard. The adjacent identity and snapshot checks that
prove non-mutation are untouched.

## 3. `fix(showcase): gate url-source content and correct the v1-parity
claim`

Adversarial review of the first two commits found the gate was only half
fixed. `_NATIVE_CONTENT` still short-circuited `ImageUrl` and
`DocumentUrl`, which v2 builds from unvetted client input, so url-source
attachments bypassed the gate where v1 routed them through it:

- an `image/heic` or `image/svg+xml` url reached the provider as
`input_image`, which the Responses API rejects — failing the turn
- an `audio/mpeg` document url reached it as `input_file`
- a blank-mime inline PDF went to the image sniffer instead of text
extraction, because `load_messages` collapses `ImageInputContent` and
`DocumentInputContent` to the same bare `BinaryContent` and erases the
modality v1 defaulted on

Native content is now gated **before** the fixpoint check rather than
instead of it. `_classify_native_content` returns a tuple only when the
gate must act; `None` means provider-safe and falls through to the
fixpoint, preserving object identity. `ImageUrl` is gated rather than
rerouted so a provider-safe one keeps its identity and any explicit
`_media_type`.

It also corrected a false claim. The `mount_agent` docstring said
routing *and* behaviour were unchanged. Routing is; model input is not.
v2 defaults `manage_system_prompt='server'`, so each agent's
`system_prompt=` now reaches the model. On v1 it never did —
`_agent_graph` emitted system parts only `if not messages` and the AG-UI
bridge always supplied history — so **18 of 19 agents had silently dead
system prompts on main**. A/B on both versions with the same agent and
request: v1 sends 0 system-prompt parts, v2 sends 1. The new behaviour
is correct and kept; the docstring now says so.

## Verification

Against pydantic-ai 2.22.0, in a venv built from this branch's
`requirements.txt`:

- **52/52 Python tests pass**, up from 42/52.
`test_multimodal_content_mapping.py`'s `importorskip` pointed at the
removed `pydantic_ai.ag_ui`, which would have skipped all 43 of its
tests **green** under v2; it now targets `pydantic_ai.ui.ag_ui` and uses
the public `AGUIAdapter.load_messages` in place of the v1 private
helper.
- **16/19 mounts** return `200 text/event-stream` with `RUN_STARTED …
RUN_FINISHED` and no `RUN_ERROR`, driven through the real app with
`TestClient` using trailing-slash URLs as the TS routes do. The other
three (`/a2ui_dynamic`, `/beautiful_chat`, `/`) reach tool execution and
then fail on a raw `OpenAI()` client constructed inside a tool, which
the harness cannot intercept and aimock handles in CI.
- **Per-request deps isolation** confirmed on
`/shared_state_read_write`: state sent by one request does not appear in
the next.

`build-check (pydantic-ai)` is green on this branch, and because
`requirements.txt` changed, the cached pip layer was invalidated — so
that was a **genuine fresh resolve of pydantic-ai 2.22.0 inside the real
Dockerfile**, not a cached pass. It also confirms dropping the
`opentelemetry-api<1.44` ceiling is safe.

### D6 harness probes — run, with a baseline

The behavioural gate is the shared harness D6 probes. No CI job runs
them for showcase paths, so they were run locally on both this branch
and `main`:

| | main (v1) | this branch (v2) |
|---|---|---|
| passed | **33** / 36 | **34** / 36 |
| `reasoning-display` | ✗ `no reasoning-role message rendered within
5000ms` | ✅ **passes** |
| `gen-ui-agent` | ✗ `waitForTurnComplete … runStartCount=2,
done-signal-missing` | ✗ identical error |
| `shared-state-read` | ✗ `Strict mode: 1 candidate fixture(s) skipped
by sequence/turn state` | ✗ identical error |

```bash
cd showcase
AIMOCK_URL_LOCAL=http://localhost:4010 bin/showcase test pydantic-ai --d6 --direct --rebuild --cycle --verbose
```

**The port takes D6 from 33/36 to 34/36.** The two remaining failures
are pre-existing on `main` with byte-identical error strings — this
branch neither causes nor fixes them, and both are tracked in #6381
rather than blocking here.

`gen-ui-agent` is root-caused and is not fixture drift: that demo was
never ported to pydantic-ai. `src/agents/gen_ui_agent.py` exists in
llamaindex with a real `set_steps` tool but has no counterpart here, the
route points at `/gen_ui_tool_based/` (the chart-viz agent), and
`set_steps` is declared nowhere in the package. The fixture fabricates
`set_steps` calls the backend cannot honour, so pydantic-ai rejects the
unknown tool and exhausts its single retry. Confirmed live against real
OpenAI: the cell returns plain text, which is correct for the code as
written.

`reasoning-display` going green is the notable behavioural gain, and it
retires a documented v1 limitation. `PARITY_NOTES.md:91-97` justifies
omitting the reasoning-message branch of `use-rendered-messages.tsx` on
the grounds that "PydanticAI's AG-UI adapter does not emit reasoning
content today" — true on v1, false on v2. (That block is stale on two
further counts: it cites `@ag-ui/core@0.0.43` where `package.json` pins
0.0.57, and claims `ReasoningMessage` is not exported where it is
imported at `reasoning-block.tsx:4`.) Correcting it is tracked on #6364.

To be precise about what that proves: **v2 forwards reasoning content
where v1 dropped it.** The probe supplies the reasoning channel via its
fixture, so what is verified is the forwarding path — adapter → AG-UI
stream → frontend renderer — end to end. Whether a given model actually
emits a reasoning summary live is a separate matter and outside this
port's control: it requires a native reasoning model
(`reasoning_agent.py` defaults to `gpt-5`, overridable via
`REASONING_MODEL`) and, for summary text, a verified OpenAI
organisation. A live run here returned prose with no reasoning block,
consistent with the org-verification gate rather than anything in the
port.

Also verified: the image builds from scratch on v2. Because
`requirements.txt` changed, the cached pip layer was invalidated, so
`build-check (pydantic-ai)` in CI was a genuine fresh resolve of
pydantic-ai 2.22.0 inside the real Dockerfile — which also confirms
dropping the `opentelemetry-api<1.44` ceiling is safe.

### CI gate coverage, for the record

No CI job exercises this package's runtime behaviour on a PR, on this
branch or on `main`:

- `test / e2e / dojo` runs from the upstream `ag-ui` checkout (`ref:
main`) against upstream example agents, and filters on `packages/**` /
`sdk-python/**`
- `test_showcase-frontend-matrix.yml` is dispatch-only and builds the
integration from `base/` — a frozen-backend React baseline
- `showcase_validate.yml` asserts `tests/e2e/` exists with a minimum
spec count; it does not run it
- the package's own `tests/e2e/` (37 files) is invoked by nothing — per
`AGENTS.md` rule 1 the measuring test is the shared harness probe, so
that layer is legacy

## Remaining for #6364

Two acceptance criteria are outstanding, which is why this says Refs
rather than Closes:

- the harness D6 value-test (`bin/showcase test pydantic-ai --d6
--rebuild`), which no CI gate runs for showcase paths
- `PARITY_NOTES.md` has 6 version-dependent blocks, 4 of which were
already inaccurate against the tree before this PR; left alone
deliberately to keep this diff scoped

## Possible follow-up

`multimodal_agent.py` still reaches into three private APIs
(`pydantic_ai._run_context`, `pydantic_ai.models.wrapper`,
`pydantic_ai.models.{ModelRequestParameters,StreamedResponse}`) and
subclasses `WrapperModel`, overriding
`request`/`count_tokens`/`request_stream`. v2 adds a supported
alternative: `AbstractCapability.before_model_request`, which receives a
`ModelRequestContext` carrying `messages` and `streaming`. Migrating
would delete those private imports and ~85 lines. Deliberately not in
this PR — it fixes nothing and would obscure the review.
2026-08-13 09:59:40 -07:00
Ran Shem Tov 48a01b6203 fix(showcase): harden CrewAI probe parity 2026-08-13 00:10:36 +02:00
Ran Shem Tov 79f56d9f8e fix(showcase): finalize CrewAI D6 on official bridge 2026-08-11 22:45:04 +03:00
Ran Shem Tov 6862508eb2 Merge remote-tracking branch 'origin/main' into codex/crewai-full-d6
# Conflicts:
#	showcase/harness/Dockerfile
#	showcase/scripts/fail-baseline.json
2026-08-07 17:53:55 +03:00