Commit Graph

1776 Commits

Author SHA1 Message Date
Ben Taylor 1b028f484c fix(mastra): stop thread-scoped working memory aborting the first turn (closes OSS-1122) (#6870)
## Problem

A starter scaffolded with `copilotkit init --framework mastra` and
connected to managed Intelligence starts, accepts a chat message, and
never answers. `POST /api/copilotkit/agent/default/run` still returns
200, so the abort is only visible in the server log:

```
Agent execution failed: Error: Thread c883919e-… not found
```

## Root cause

`@ag-ui/mastra`'s `syncInputStateToWorkingMemory` writes the UI's shared
state into Mastra working memory **before** it streams a turn. That
write is unguarded and never creates the thread, because it assumes the
resource-scoped store, which upserts. Its own comment says so, and its
*remote* branch handles the opposite case explicitly ("requires the
thread to exist… create the thread and retry once").

This starter was the one Mastra agent in the repo that set
`workingMemory.scope: "thread"`. Thread scope routes the same write to
thread metadata, and `@mastra/memory` throws `Thread <id> not found`
when the thread row does not exist. On the first turn of a conversation
it never does, so the run dies before the model is called.

Managed Intelligence made that certain rather than likely:
`handlers/intelligence/run.ts` replaces the client thread id with a
platform-canonical one from `ɵacquireThreadLock`, which the Mastra store
has never seen. That also explains the two different thread ids in the
same failure.

## Evidence

Verified by running, against the starter's exact pins (`@mastra/core`
1.41.0, `@mastra/memory` 1.0.1-alpha.1, `@ag-ui/mastra` 1.1.2):

| Configuration | First-turn state sync |
| --- | --- |
| `scope: "thread"` (as shipped) | throws `Thread <id> not found`, run
aborts |
| `scope: "resource"` | writes, reads back, reaches the agent's system
message |

Resource scope keeps working memory **per conversation** here, because
the bridge derives the resource id from the thread id when no explicit
resource id is configured. Confirmed: a second thread id reads back
`null`, and schema merge semantics still work on turn 2.

## Change

- `examples/integrations/mastra` uses `scope: "resource"`, matching
every other Mastra agent in this repo, with a comment explaining why.
- A new contract test in
`scripts/__tests__/integration-intelligence-migration.test.ts` fails if
any integration starter configures thread-scoped Mastra working memory.
It asserts the mastra starter is in scope, so it cannot pass vacuously,
and it ships with five helper cases including a decoy
(`observationalMemory.scope: "thread"`, which is unrelated and must not
trip it).

This also fixes the Channel host, which drives the same agent.

## Verification

- `vitest run
scripts/__tests__/integration-intelligence-migration.test.ts` — 159
passed, and the new test is red on the unfixed starter (`expected [
'mastra/src/mastra/agents/index.ts' ] to deeply equal []`).
- `parity:check` passes, `oxlint` and `oxfmt --check` clean.

## Left undone, deliberately

The adapter's local branch is still unguarded, so a developer who
chooses thread scope hits the same abort in their own code. The fix
belongs in `@ag-ui/mastra` and mirrors what its remote branch already
does. That needs an ag-ui PR plus a release, so it is not in this
change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Updated the weather agent’s working-memory scope to support shared UI
state during the first turn of a conversation.
* Prevented conversation initialization issues caused by thread-scoped
memory.

* **Tests**
* Added validation to ensure integrations use compatible working-memory
scopes.
* Added coverage for direct, nested, resource-scoped, omitted, and
unrelated configuration cases.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 15:46:49 -05:00
Murat Sari 51f1f0f09a chore(examples): declare the web-inspector dependency in the angular demo and storybook fixes 2026-09-04 21:48:27 +02:00
Benjamin Taylor d735f67bc4 fix(mastra): stop thread-scoped working memory aborting the first turn (closes OSS-1122)
A starter scaffolded with `--framework mastra` accepted a chat message and
never answered. The run aborted server-side with `Thread <id> not found`.

`@ag-ui/mastra` writes the UI's shared state into Mastra working memory
before it streams a turn (`syncInputStateToWorkingMemory`). That write is
unguarded and never creates the thread, because it assumes the
resource-scoped store, which upserts. The starter was the one Mastra agent
in this repo that set `scope: "thread"`, which routes the same write to
thread metadata and requires the thread row to exist. On the first turn of a
conversation it does not, so `@mastra/memory` throws and the run dies before
the model is called.

Managed Intelligence made that certain rather than likely: the Intelligence
run handler swaps the client thread id for a platform-canonical one, which
the Mastra store has never seen. That is also why two different thread ids
appear in the same failure.

Verified against @mastra/core 1.41.0, @mastra/memory 1.0.1-alpha.1 and
@ag-ui/mastra 1.1.2: thread scope throws on a fresh thread, resource scope
writes, reads back, reaches the agent's system message, and stays per
conversation because the bridge derives the resource id from the thread id.

Every other Mastra agent here omits `scope`, so this aligns the starter with
them. The gate is a new contract test in the parity workflow's suite.

Left upstream: the adapter's local branch is still unguarded, so a developer
who chooses thread scope hits the same abort. Its remote branch already
creates the thread and retries. Worth a follow-up in ag-ui.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 11:45:54 -05:00
Benjamin Taylor 580d058dc5 docs(examples): cut the symptom list from the tool card header
State the Tailwind dependency and leave it there. A reader who skips the build
does not need the failure enumerated for them, and the symptoms stay on #4777
for anyone diagnosing from the other end.
2026-09-02 08:10:00 -05:00
Benjamin Taylor 9cf9c51437 docs(examples): note that the tool card needs a Tailwind build
The example tool-call card styles its header row with unprefixed Tailwind
utilities. Copied into a project that does not compile Tailwind, every class
resolves to nothing, the `<summary>` falls back to block layout, and the icons
and tool name stack in one column with the native `<details>` marker showing.
That is the layout reported in #4777, and nothing in the card says it depends
on a Tailwind build.

Add a file header recording the dependency, the two symptoms that identify it,
and the two ways out. The claude-sdk copies declare this file in
allowedDivergence, so they are annotated by hand; the rest come from
parity:sync.
2026-09-02 08:01:23 -05:00
Benjamin Taylor 2d44d3ff00 fix(agentcore): collapse the duplicate @copilotkit/shared in the lambda lock (refs OSS-1029)
The 1.70.0 repin left two copies of @copilotkit/shared in the AgentCore lambda: 1.70.0
nested under runtime, and 1.68.1 still hoisted at the top level, alongside a stale
@copilotkit/core 1.68.1.

runtime@1.70.0 pins shared to exactly 1.70.0, but the transitive @copilotkit/channels-*
0.9.0 packages ask for ^1.68.0, which the existing 1.68.1 resolution already satisfies.
A --package-lock-only bump has no reason to move a range that is already satisfied, so
npm hoists 1.68.1 for the channels packages and nests 1.70.0 under runtime. npm dedupe
does not collapse it; npm update on shared and core does.

Regenerating the lock from scratch also yields one clean copy, but sweeps 89 unrelated
packages with it -- @graphql-tools/executor 1.5.1 -> 2.0.0, @graphql-tools/utils 10 -> 11,
debug 2 -> 4, and a @types/express 5 -> 4 downgrade -- so it was rejected.

Verified: one copy of every @copilotkit and @ag-ui package in the lock afterwards, none
left on a 1.6x line, and npm install + tsc -p tsconfig.json exits 0.

Refs OSS-1029.
2026-08-31 20:23:15 -07:00
Maximiliano Korp a26767c538 fix(integrations): activate managed starters with project key 2026-08-31 20:23:15 -07:00
Maximiliano Korp 15b24e51a3 chore(examples): update CLI starters to CopilotKit 1.70.0 2026-08-31 20:23:15 -07:00
Mike Ryan f3b1ef345b fix(integrations): standardize Intelligence project key name 2026-08-31 20:23:15 -07:00
Mike Ryan f57c045f6f fix(integrations): remove AgentCore license token requirement 2026-08-31 20:23:15 -07:00
Mike Ryan 62b90dacee fix(integrations): preserve managed endpoint defaults 2026-08-31 20:23:15 -07:00
Mike Ryan d420afe494 fix(integrations): use current Intelligence name 2026-08-31 20:23:15 -07:00
Mike Ryan 18782b7f04 fix(integrations): refresh managed starter contracts 2026-08-31 20:23:15 -07:00
Mike Ryan a6af469d1e feat(integrations): align managed Intelligence starters 2026-08-31 20:23:15 -07:00
Ben Taylor f1d5d80c00 fix(examples): expose frontend tools to the ADK agent via AGUIToolset [OSS-561] (#6107)
## What & why

The **"Frontend Tools"** demo (`setThemeColor`) silently fails in
`examples/integrations/adk`: asking "set the theme to green" makes the
agent reply *"I can only help with proverbs or the weather"* and nothing
recolors.

**Root cause:** the ADK agent's tools are static `[set_proverbs,
get_weather]`. `ag_ui_adk` only injects a run's forwarded client tools
(the frontend-registered `setThemeColor`) into the LLM's tool set when
the agent's `tools` include an **`AGUIToolset`** placeholder — it swaps
that for a `ClientProxyToolset` wired to `input.tools`. Without it,
`gemini-2.5-flash` never sees `setThemeColor` and declines. (No
CopilotKit ADK example currently includes `AGUIToolset`, and the docs
don't mention it.)

## Change

```python
from ag_ui_adk import ADKAgent, add_adk_fastapi_endpoint, AGUIToolset
...
tools=[set_proverbs, get_weather, AGUIToolset()],
```

Agent-side only; no prompt change needed.

## Testing

Verified **live** (real Gemini key) via the identical change in
`examples/integrations/adk-angular` (same `agent/main.py` + `ag_ui_adk`
adapter): "Set the theme to green" now recolors the panel; before the
fix the agent refused. Because the fix is agent-side and
framework-agnostic, and `setThemeColor` was already confirmed forwarded
in the run body, the React `adk` frontend + this agent behaves
identically.

## Related

- Companion to CopilotKit/CopilotKit#6097 (the new `adk-angular` example
carries the same fix).
- Discovered while validating #6097 by live-comparing Angular vs React
ADK behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-31 07:55:10 -05:00
Ben Taylor 1a4e2c9a51 fix(examples): store Teams app icons in Git LFS (#6456)
## Summary

- normalize `examples/teams/appPackage/color.png` and `outline.png` into
Git LFS pointers
- preserve the original PNG contents and dimensions
- leave the `examples/integrations/a2a-a2ui/agent/images/` symlinks
untouched

## Root cause

The two PNGs match the repository's Git LFS attributes but were
committed as raw Git blobs. Git therefore continually cleans the working
files into LFS pointers and reports the worktree as dirty, which can
also block rebases.

## Validation

- verified both committed blobs are valid Git LFS pointers
- verified both LFS objects can be fetched from a fresh checkout of the
fork
- verified SHA-256 hashes match the original PNG contents:
- `color.png`:
`ee46987787ab5dfff4792e2df112a8d5422046296ddb1cb83fa1a85cf546d19f`
- `outline.png`:
`e653c3c3e4a700a8a46ee349463bba2169c368be803b5f48c2ae5c7ac4a7e452`
- verified image dimensions remain 192×192 and 32×32
- `MICROSOFT_APP_ID=00000000-0000-0000-0000-000000000000 NX_DAEMON=false
pnpm nx run teams-example:package --skip-nx-cache`
- independently reran previously flaky Nx test targets successfully:
  - `@copilotkit/web-inspector:test` (373 tests)
  - `@copilotkit/channels-slack:test` (389 tests)
  - `@copilotkit/vue:test` (1074 tests)
- checked against the latest upstream `main`; the affected paths are
unchanged and merge cleanly

Fixes #6420
2026-08-30 21:35:18 -05:00
Ben Taylor 478a2aac95 fix(examples): MCP Apps widgets send ui/notifications/size-changed so the host resizes the iframe (#6700)
## What

The MCP Apps example widgets report their intrinsic size with
`ui/notifications/size-change`, but both the host and the ext-apps spec
use
`ui/notifications/size-changed`:

- Host: `MCPAppsActivityRenderer` only handles `case
"ui/notifications/size-changed"` and
  reads `{ width, height }` from it to size the iframe.
- Spec: `@modelcontextprotocol/ext-apps` defines
`McpUiSizeChangedNotification` with
  `method: "ui/notifications/size-changed"` (`App.sendSizeChanged`).

Because the names differ by one letter, the host never receives the size
and the widget
iframe stays at its initial height instead of growing to fit its
content.

## Fix

Rename the notification to the spec name in the affected widgets. The
payload is unchanged
(`{ width, height }`), which is exactly what the host reads, so this is
a one-line change per
widget on the sender side only.

No host change: in JSON-RPC a notification (no `id`) must not be
answered, so the host
silently ignoring the old name is correct behavior; the bug is purely
that the widgets sent
the wrong method name.

## Affected widgets

- `examples/showcases/mcp-apps/mcp-server/apps`: flights, hotels,
kanban, trading
- `examples/showcases/generative-ui-playground/mcp-server/apps`:
calculator, flights, hotels,
  kanban, todo, trading

## Testing

Reproduced against a local run of `examples/showcases/mcp-apps` (Next
frontend + MCP server):
before, the widget iframe rendered at its initial height; after the
rename the host receives
`size-changed` and the iframe resizes to the widget content.

## A note from the contributors

From the team at MCP Apps Builders - part of our ongoing series to round
out MCP Apps host
support in CopilotKit. Opening as a draft for review.
2026-08-30 15:04:00 -05:00
Ben Taylor 57fb0e7180 docs(example): remove dead links to non-existent docs files in agentcore README (#6763)
The `examples/integrations/agentcore` README references
`docs/LOCAL_DEVELOPMENT.md` and `docs/LOCAL_DOCKER_TESTING.md`, but the
example has no `docs/` directory and neither file exists anywhere in the
example. The local-development workflow is already fully documented
inline in the "Local Development" section, so these references are dead
links.

Verified: `docs/` is absent from `examples/integrations/agentcore/`, and
a repo-wide search finds no `LOCAL_DEVELOPMENT.md` /
`LOCAL_DOCKER_TESTING.md`.
2026-08-29 21:15:02 -05:00
一片一片 8b5c6abfd6 Merge branch 'main' into docs/fix-agentcore-readme-dead-links 2026-08-29 18:43:49 +08:00
Murat Sari bb80fff40a fix(angular): align demo and Storybook versions
The Angular demo and Storybook use Angular 22.1, while @copilotkit/angular is developed against Angular 22.0. Both consumers map @copilotkit/angular directly to its source files.

That causes TypeScript to load Angular types from two dependency contexts. Angular signal types contain unique-symbol brands, so signals originating from Angular 22.0 are incompatible with otherwise equivalent signals from Angular 22.1.

Pin the demo and Storybook to Angular 22.0 so the source-linked library and its consumers share the same Angular type identity. Update pnpm-lock.yaml to keep frozen installs reproducible.

The existing unit workflow intentionally selects only packages/**, while the packed-package test does not exercise these source-linked monorepo consumers.
2026-08-29 11:45:32 +02:00
Ben Taylor 0056b6ac5e docs(examples/travel): fix broken search.py link in hook README (#6734)
The lib/hooks/README.md in the travel example links to
../../agent/travel/search.py, but the file is at
xamples/v1/travel/agent/src/search.py. Fix the relative path to
../../agent/src/search.py.
2026-08-28 22:31:35 -05:00
gdut4140 6f986a9a99 docs(example): remove dead LOCAL_DEVELOPMENT.md references in agentcore docker + validate script 2026-08-29 11:06:48 +08:00
gdut4140 ea1f2b0623 docs(example): remove dead links to non-existent docs files in agentcore README 2026-08-29 01:18:14 +08:00
Alem Tuzlak 5686a0669e Merge branch 'main' into lukas/oss-904-runtime-connection-status 2026-08-28 14:06:40 +02:00
Benjamin Taylor b18f7054af docs(react-core): state that an agent receives useAgentContext value as a JSON string (closes OSS-1003)
useAgentContext stringifies any non-string value before it leaves the
browser, and the AG-UI protocol types Context.value as a string on both
ends. An agent therefore always reads a JSON string, never the object or
array that was registered. None of the four reference pages said so; they
stopped at "serialized automatically", which reads as "the framework
handles it".

An author who believes that writes an agent that reads the object. When
the resulting shape check fails, the agent cannot distinguish "context
arrived JSON-encoded" from "no context was sent" -- the two are
identical -- so it refuses every request while the browser is registering
context correctly. That is what happened on the both-oss
langgraph-python conversion journey, where the agent's
isinstance(value, list) guard could never pass and the journey was dead
on arrival.

Each page now carries a "What the agent receives" section: the wire shape
as literal JSON, json.loads and JSON.parse examples, and a callout naming
the shape check as the trap. The value parameter description and the
Serialization behavior bullet now name the consequence for the agent
author instead of stopping at the browser half.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 12:18:14 -05:00
Mike Ryan 593fe0bc0b fix(docs): address Agent Framework review 2026-08-27 09:21:37 -07:00
Mike Ryan 6943ca8232 fix(docs): replace retired GitHub Models setup 2026-08-27 09:21:37 -07:00
copilotkit-qa-bot[bot] c6dbc485d8 Merge remote-tracking branch 'origin/main' into codex/fac-124-excalidraw-starter 2026-08-27 08:21:38 -07:00
copilotkit-qa-bot[bot] 48958500af fix(examples): align LangGraph starter runtimes 2026-08-27 08:21:29 -07:00
Alem Tuzlak 5afe7cf7ad chore(examples): add Vite Vue Inspector check app 2026-08-27 13:01:37 +02:00
Alem Tuzlak 42d3c92fbd chore: merge origin/main into tyler/default-browser-inspector 2026-08-27 12:09:27 +02:00
moonturbo 1d06f5af51 docs(examples/travel): fix broken search.py link in hook README 2026-08-27 09:43:26 +08:00
copilotkit-qa-bot[bot] db752715aa fix(examples): preserve integration Docker parity 2026-08-26 16:25:33 -07:00
copilotkit-qa-bot[bot] 9294bbad06 test(examples): scope FAC-124 lifecycle coverage 2026-08-26 16:23:09 -07:00
copilotkit-qa-bot[bot] 618363f013 fix(examples): make Excalidraw MCP starter deterministic 2026-08-26 15:40:45 -07:00
copilotkit-qa-bot[bot] 70f15d6ead Merge remote-tracking branch 'origin/main' into codex/fac-127-ms-agent-stable-apis 2026-08-26 12:56:16 -07:00
copilotkit-qa-bot[bot] 0b854047e2 fix(ms-agent-python): preserve Azure AD auth 2026-08-26 12:55:46 -07:00
Maxim 9a103a0348 chore(examples): put the AgentCore example on uv projects (#6672)
## What

Converts `examples/integrations/agentcore` from unlocked
`requirements.txt` files to uv projects (`pyproject.toml` + `uv.lock`),
matching every other Python integration example in this repo.

## Why

The example already used uv as an *installer* — the agent images are
built from `ghcr.io/astral-sh/uv` and ran `uv pip install -r
requirements.txt` — but nothing was locked, so each image build
re-resolved transitive dependencies against whatever PyPI had that day.

That had already drifted into a hard break. `langgraph==1.0.10rc1`
resolved alongside a `langgraph-prebuilt` that reads `ExecutionInfo` off
`langgraph.runtime`, which 1.0.x does not export, so the LangGraph agent
raised `ImportError` at container start.

## The migration

- Both agents get a `pyproject.toml` + `uv.lock`; the Dockerfiles
install with `uv sync --locked` and run out of `/app/.venv`.
- LangGraph agent moves to `langgraph==1.1.6` / `langchain==1.2.15`, the
pair used by `examples/integrations/langgraph-python`, which resolves
the import failure. `langchain` was previously `>=0.3.0` while the code
uses the 1.x `create_agent` API.
- Four packages that shipped code imports directly were declared nowhere
and survived only as transitives: `boto3` (both agents, via
`agents/utils/ssm.py`), `PyJWT` (langgraph, via `agents/utils/auth.py`),
`langchain-core` (langgraph, via `tools/todos.py`), `botocore` (root,
via `scripts/utils.py`). All now declared; no resolved version changed.
- `aws-opentelemetry-distro` moves from a loose second `uv pip install`
into the locked set.
- The example root gets a project for the `scripts/` helpers. Their
`requirements.txt` listed the dependencies but nothing installed it, so
`uv run scripts/test-agent.py` — the command that script's own docstring
gives — failed on a missing `requests`.
- Deploy and local-dev scripts call `uv run` instead of bare `python3`;
preflight checks for `uv` rather than `python3`.

## Terraform

The docker-mode image hash read `patterns/<pattern>/requirements.txt`,
`patterns/utils`, a root-level `gateway/` and `tools/`, and a root
`pyproject.toml` — none of which exist here. `filesha256` on a missing
file is a plan-time error. Repointed at `agents/<pattern>` and
`agents/utils`, now hashing `pyproject.toml` and `uv.lock`.

The hash then had to exclude the virtualenv the migration creates:
`fileset(pattern_dir, "**/*.py")` saw 3114 files instead of 5, and the
computed hash differed depending on whether a developer had ever run the
agent locally — feeding `replace_triggered_by` and forcing a runtime
replacement. Measured: `5f9a98ef…` with a venv present vs `bacab1e1…`
without, on identical committed sources. The fix filters `.venv/` and
`venv/` and produces the clean-checkout digest in both cases.

## Review

Five review rounds plus a promotion audit, and nine defects this
migration introduced were found and fixed before merge. Each fix was
verified by running the thing, not by reading it:

- The image hash sweeping the local virtualenv (above).
- The undeclared direct dependencies (above).
- `scripts/test-agent.py` piped the child's output and never drained it,
deadlocking the agent, while the startup-timeout branch blocked forever
on a read — the only channel carrying uv's lockfile-drift error.
- `--local` treated any listener on port 8080 as the agent, so a foreign
process produced "Agent started successfully" while the real child died.
Adopting a running process is now explicit opt-in.
- The documented invocation contract had drifted across the two READMEs
and both scripts' usage text; a single reconciliation pass now owns all
of them, and every documented command was executed to confirm it works.
- The Terraform README named the CloudFormation deploy script, which
cannot read a Terraform deployment.
- Two `.env.example` entries parsed as their own trailing comment text
under Docker Compose.
- The build context shipped 898 MB of local-only artifacts (measured);
now 11 kB.
- Assorted comment and message inaccuracies, including a container env
block whose comment attributed a runtime-critical variable to uv.

## Repository hygiene

Two fixes the pre-merge gates surfaced rather than the review rounds:

- `oxfmt` on the example README and `tofu fmt` on the Terraform locals
file. The README break was introduced by this branch; the Terraform one
predates it but sits in a file this branch edits.
- The Terraform ignore rules were anchored to the top level, so the
provider cache `terraform init` writes beside every *nested* module was
fully stageable — a measured 834 MB one `git add -A` from being
committed. Switched to unanchored patterns, matching what this branch
already did for the virtualenv layout. Verified with `git check-ignore`
that the nested cache and lock file are now covered, tfstate and tfvars
still are, and no tracked file is caught by the wider patterns.

## Not addressed

Roughly 90 further findings are real but pre-existing and belong to four
follow-up subjects, listed in full in the review ledger:

- **Terraform module repair** — `terraform validate` fails on five
undeclared resources, so this module cannot plan at all. Zip mode
references an entry point and a packager directory that do not exist.
- **test-agent AG-UI correctness** — the request body fails
`RunAgentInput.model_validate` on both agents, and the response decoder
parses a pre-AG-UI format, so failures print nothing and exit 0.
- **README accuracy** — a `docs/` directory that does not exist, a wrong
Node floor, a teardown block whose second command never runs.
- **Deploy-script hardening** —
`infra-terraform/scripts/deploy-frontend.py` requires a Terraform output
nothing declares, so it exits 1 every run; the README now says so rather
than presenting it as a working path.

## Verification

Both images built for `linux/arm64` and the agent module imported inside
each, after every fix cycle. `uv lock --check` clean on all three
projects. Every documented command executed from its documented
directory. The virtualenv hash filter, the build-context reduction, the
pipe deadlock, the port-adoption fix and the env-file parsing were each
verified by measurement with before/after output. No repo CI job builds
or lints this example, so these local runs are the only coverage that
exists.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-26 21:36:43 +02:00
Ben Taylor 9e488f7a51 test(examples): gate the starters' Intelligence wiring block on one shape (closes OSS-982) (#6716)
**Merge order: #6711#6718 → this PR.**

#6718 rewrites `identifyUser` in the same 22 blocks and is a sibling of
this branch, not stacked on it, so the two overlap on the same lines.
Landing the gate last means it ratchets on the finished shape and avoids
a conflict. If this PR goes first instead, #6718 goes red until it moves
all 22 sites together — which is the gate working, but noisier.

Stacked on #6711 — merge that first. This branch descends from it, so
the diff below carries its commit too; GitHub drops those once #6711
lands.

Basing this PR on `main` rather than on #6711's branch is deliberate: 17
of 35 workflows filter `pull_request: branches: [main]`, including the
one this PR extends, so a PR based on the 981 branch would not run the
check it adds.

## Problem

The marked block that wires managed Intelligence is the region a hosted
reader copies verbatim, and nothing checked it. Both gaps are
deliberate, not accidental:

- `examples/integrations/_parity/manifest.json` lists
`src/app/api/copilotkit/**` under `allowedDivergence` for every instance
it tracks. What parity does hold byte-identical is the demo frontend: 54
verbatim paths of example canvas, todo columns and charts.
- No `examples/integrations/*/docker-compose.test.yml` sets
`COPILOTKIT_LICENSE_TOKEN`. The wiring is a ternary on that variable, so
all 13 smoke-tested starters take the else arm. The `intelligence:` arm
has never executed in CI, in any starter.

The cost was already visible. The block's code was byte-identical in 21
of 22 starters, but its warning comment had drifted into five variants
and the two `ms-agent-framework-*` starters shipped the `demo-user` stub
with no warning at all. Comment drift is harmless by itself; it is the
tracer showing nothing held the region still, and it is how the
localhost default of #6711 survived in all 22 copies at once.

## Change

`scripts/validate-intelligence-wiring-block.ts` greps the opening
marker, compares every site against the north-star starter, and fails on
the first line that differs. Two normalisations keep it usable:

- The block is dedented, because `agentcore` nests it two levels deeper
— its runtime is a Lambda handler, not a Next.js route.
- The else arm's runner name is masked, because `agentcore` runs
`AgentCoreRunner` in front of a Bedrock AgentCore session where an
in-process runner has nothing to run. `EXPECTED_RUNNER` holds that one
exception, so a runner swapped in by accident still fails.

Everything else, comment text included, must match to the byte. Then the
warning is unified at all 22 sites on the fullest existing wording,
which also says the id must exist in Intelligence or thread operations
can fail.

It compares against the north star rather than a literal kept in the
script, so improving the block means editing `langgraph-python` and
running the other 21 to match.

## What it does and does not guarantee

It is a shape gate, not a content gate: 22 identically wrong copies
still pass. What it guarantees is that a fix reaches all of them or
none. The check passes on day one — 21 of 22 already matched on code —
so it is a ratchet, not a migration.

## Verification

Mutating a real starter three ways, each caught:

| Mutation | Reported as |
| --- | --- |
| Dropped one comment line | `line 15 differs from the north star`, exit
1 |
| \`InMemoryAgentRunner\` → \`SomeOtherRunner\` | `else arm uses
SomeOtherRunner; expected InMemoryAgentRunner` |
| Reintroduced \`?? \"http://localhost:4201\"\` | `line 6 differs`, both
sides shown |

The third matters: the #6711 regression is now caught at a second site,
independent of the env-name validator.

Commands run, all exit 0:

- `pnpm exec vitest run
scripts/__tests__/validate-intelligence-wiring-block.test.ts
scripts/__tests__/validate-intelligence-env-names.test.ts` — 30 passed
- `pnpm check:intelligence-wiring-block` — `All 22 Intelligence wiring
sites match langgraph-python.`
- `pnpm check:intelligence-env-names` — unaffected, still canonical
- `pnpm parity:verify`
- `oxfmt --check`, `oxlint`, and `tsc --noEmit --strict` on the new pair

Two tests guard the gate against going vacuous: one asserts at least 22
marker files are discovered, so an empty violation list cannot pass on
an empty file list.

Not run locally: the lefthook pre-commit suite, which fails
environmentally in a worktree without per-package installs (`sh: vite:
command not found`). This diff touches no package source.

## Not covered

Enrolling the `intelligence:` arm in the smoke path. It needs a license
token in CI secrets and an endpoint reachable from the compose network —
a different size of job, tracked separately.
2026-08-26 14:36:24 -05:00
Maxim 888a70e169 Merge branch 'main' into chore/agentcore-uv 2026-08-26 21:28:39 +02:00
Ben Taylor 4b73ce3c83 fix(examples): stop overriding the managed Intelligence URL defaults (closes OSS-981) (#6711)
## What does this PR do?

`CopilotKitIntelligence` is built to be correct when the caller says
nothing: omitting `apiUrl`/`wsUrl` resolves to
`https://api.intelligence.copilotkit.ai` and
`wss://realtime.intelligence.copilotkit.ai`, and its docstring says so
outright — *"leaving both unset is always correct against it."*

Every starter's runtime route defeated that default:

```ts
apiUrl: process.env.INTELLIGENCE_API_URL ?? "http://localhost:4201",
wsUrl:
  process.env.INTELLIGENCE_GATEWAY_WS_URL ?? "ws://localhost:4401",
```

With the variables unset — the correct configuration for a managed user
— the `??` supplies localhost and the runtime aims at a local stack that
is not running. This is the artifact `copilotkit init` clones, so it is
the first thing a new managed user runs.

The starter's own `.env.example` already warns about exactly this
failure, two files away:

> `INTELLIGENCE_API_URL` and `INTELLIGENCE_GATEWAY_WS_URL` point at a
self-hosted or local Intelligence deployment only — leave them unset
when using managed Intelligence, or the channel host and runtime will
try to reach a local stack that usually is not running.

So the documentation was right and the code contradicted it.
`channel-host.mts`, in the same directories, already had the correct
shape.

### The fix

**22 runtime wiring sites** (20 route handlers, `adk-angular/server.ts`,
and the AgentCore Lambda) now use the conditional spread these starters
already use in `channel-host.mts`, so a self-hosted override still works
and the managed default applies when absent:

```ts
...(process.env.INTELLIGENCE_API_URL
  ? { apiUrl: process.env.INTELLIGENCE_API_URL }
  : {}),
```

No hosted URL is written into the examples — the library already owns
them, so this is a deletion.

**3 `.env.example` files** (`agent-spec`, `llamaindex`, `mcp-apps`) set
the same values *uncommented*. Two do it directly beneath a comment
telling the reader to leave them unset, and an `.env.example` is copied
to `.env`, so these were the remaining route to a localhost value once
the code default was gone. Commented out to match the other nineteen
starters; `agent-spec` had no explanation at all and gets the standard
one.

**A guard**, added to the existing
`scripts/validate-intelligence-env-names.ts` rather than a new script —
it already polices the canonical Intelligence key name and the two dead
hosts, and its workflow is deliberately unfiltered so it sees every
README, example and skill. Two rules: `managedUrlFallback` (a `??`/`||`
default on either variable) and `managedUrlEnvFileAssignment` (an
uncommented env-example assignment). The rule is the *pattern*, not the
literal, so a staging host substituted for localhost fails the same way.

Five files legitimately want a local target and are allowlisted with
their reasons: the `playwright.config.ts` and `.env.example` of the
banking and reskinnable-demo showcases (own vendored compose ports
7050/7053 and 7250/7253, own seeded org keys) and
`agentcore/docker/.env.example` (the documented local development
stack). Resolving those to the managed hosts would aim an offline test
suite at production.

`scripts/__tests__` has no general runner, so the workflow runs this
test file explicitly, following the `plugin-skills-check.yml` precedent
— otherwise a rule that silently stopped matching would leave the check
passing on an empty result.

## Related PRs and Issues

- Closes OSS-981.
- Supersedes the canceled ENT-922, whose blocker ("do not invent hosted
URLs; rewrite once the managed env contract is final") no longer
applies: the contract shipped as `MANAGED_INTELLIGENCE_API_URL` /
`MANAGED_INTELLIGENCE_WS_URL`, and the fix removes a fallback rather
than adding a URL.
- ENT-949 shipped a warning for this class of mistake, but
`warnOnPartialHostOverride` only fires on a *partial* override — both
values defaulting to localhost together is not partial, so nothing
warned.

## Verification

- `pnpm exec vitest run
scripts/__tests__/validate-intelligence-env-names.test.ts` — 13 passed.
Written first: the rules were red before they existed, then reported
**48 violations across 24 files** for the code rule and **10 across 5**
for the env-file rule; the fixes took both to green.
- `pnpm check:intelligence-env-names` — exit 0.
- `oxfmt --check` and `oxlint` over all 25 touched files — clean.
- The spread typechecks under `strict` + `exactOptionalPropertyTypes`,
the setting that would reject `apiUrl: string | undefined`.
- The marked wiring block stays byte-identical across 21 of 22 starters
(`agentcore` differs only in its runner), and no `localhost` remains
inside any marked block.
- Not run locally: the 13 starter Next builds. `test_smoke-starter.yml`
typechecks the route handlers in CI on this PR.

### Out of scope

`agentcore/docker/docker-compose.yml` keeps its
`${INTELLIGENCE_API_URL:-http://localhost:4201}`: it is compose
substitution in the documented local-dev stack, not shipped runtime
code. Separately that default cannot work anyway — inside the bridge
container `localhost` is the container's own loopback — but that is a
different bug.

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] "Allow edits by maintainers" is checked

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-26 14:28:28 -05:00
Maxim f8e13e675c Remove the banking showcase in favor of reskinnable-demo (#6683)
## What

Sunsets `examples/showcases/banking`. It is superseded by
`examples/showcases/reskinnable-demo`, which ships the same banking
experience as one of its runtime-swappable skins (alongside airline) on
top of a shared shell. Keeping both means maintaining two copies of the
same demo.

160 files deleted, plus the five places that pointed at the app:

| File | Change |
| --- | --- |
| `pnpm-workspace.yaml` | Drops the workspace entry. Also fixes the
adjacent NOTE, which attributed the canary AG-UI pin to "banking's
agent" when it is reskinnable-demo's own Python deep agent that needs
it. |
| `pnpm-lock.yaml` | Regenerated (−919/+12). The 12 additions are
peer-suffix re-keying caused by removing the importer — banking pinned a
different `eslint`/`vitest` peer combination. No dependency version
changes. |
| `examples/README.md` | The banking row becomes a reskinnable-demo row,
so the successor is listed and the showcase count is unchanged. |
| `showcase/shell-docs/src/content/docs/faq.mdx` | The "Banking
Assistant" link retargets to reskinnable-demo instead of 404ing. |
| `.github/config-allowlist.txt` | Drops the deleted `next.config.mjs`.
|

Note that banking was a real pnpm workspace member using `workspace:*`
deps, unlike reskinnable-demo, which sits deliberately outside the
workspace with its own lockfile. That is why the root lockfile has to be
regenerated here.

## Deliberately not changed

- `scripts/migrate-demos.sh` and `scripts/archive-demo-repos.sh` still
name `examples/showcases/banking`. Those are the already-executed
one-shot manifests for the repo consolidation; the path is a historical
record in them, not a live reference.
- `reskinnable-demo`'s `.env.example` and `docker-compose.yml` still
explain their +200 port offset in terms of banking's stack. The offset
stays real, and "was cloned from banking" stays true.
- The `banking` mentions in `test_reskinnable-demo.yml` refer to
reskinnable-demo's **banking skin**, not this app.

## Verification

- `.github/scripts/check-config-allowlist.sh` passes.
- A full `pnpm install` agrees with the regenerated lockfile (no further
diff).
- The lockfile-only regen and the full install produce identical output.

The `test-and-check-packages` pre-commit hook fires on any
`pnpm-lock.yaml` change, so it ran `test,publint,attw` across all 25
packages. Four suites failed locally — `sqlite-runner`, `web-inspector`,
`vue`, `react-core` — in a worktree installed with `--ignore-scripts`,
which skips `better-sqlite3`'s native build. This change touches no
package source, so CI is the gate on those; please confirm they are
green here before merging.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-26 21:27:16 +02:00
copilotkit-qa-bot[bot] 7a24a2d855 fix(ms-agent-python): migrate starter to stable APIs 2026-08-26 12:09:08 -07:00
Benjamin Taylor 314f1ca55d fix(examples): stop overriding the managed Intelligence URL defaults (closes OSS-981)
CopilotKitIntelligence resolves apiUrl/wsUrl to the managed hosts when they are
omitted, and its own docstring says leaving both unset is always correct against
the managed service. Every starter's runtime route supplied
`?? "http://localhost:4201"` instead, so a managed reader who copied the block
got a runtime aimed at a local stack that is not running -- the failure the
starter's own .env.example warns about two files away.

Replace the fallbacks with the conditional spread these same starters already use
in channel-host.mts, so a self-hosted override still works and the managed
default applies when it is absent. Three .env.example files also set the values
uncommented, two of them directly under a comment telling the reader to leave
them unset; comment those out to match the other nineteen starters.

Guard both shapes in validate-intelligence-env-names.ts, which already polices
the canonical Intelligence key name and hosts and runs unfiltered on every PR.
The rule is the pattern rather than the literal, so a staging host substituted
for localhost fails the same way. Local e2e harnesses and demo stacks that
genuinely target a local deployment are allowlisted with their reasons.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 12:56:36 -05:00
copilotkit-qa-bot[bot] e21af7f5c2 Merge main into FAC-128 Slack manifest fix
# Conflicts:
#	pnpm-lock.yaml
2026-08-26 09:53:09 -07:00
Alem Tuzlak 93861b428d fix(web-inspector): polish inspector chrome, threads, and dark mode 2026-08-26 09:25:41 -07:00
Benjamin Taylor 84dd86f2ed test(examples): gate the starters' Intelligence wiring block on one shape (closes OSS-982)
The marked block that wires managed Intelligence is the region a hosted reader
copies verbatim, and nothing checked it. Both gaps were deliberate: the parity
manifest lists `src/app/api/copilotkit/**` under `allowedDivergence` for every
instance it tracks, and no `docker-compose.test.yml` sets
`COPILOTKIT_LICENSE_TOKEN`, so every smoke-tested starter takes the else arm and
the `intelligence:` arm has never run in CI.

The cost was already visible. The block's code was byte-identical in 21 of 22
starters, but its warning comment had drifted into five variants and the two
`ms-agent-framework-*` starters shipped the `demo-user` stub with no warning at
all. That drift is how the localhost default of OSS-981 survived in all 22
copies at once.

Add `scripts/validate-intelligence-wiring-block.ts`, which greps the opening
marker, compares every site against the north-star starter, and fails on the
first line that differs. Two normalisations keep it usable: the block is
dedented, because `agentcore` nests it deeper, and the else arm's runner name is
masked, because `agentcore` runs `AgentCoreRunner` in front of a Bedrock session
where an in-process runner has nothing to run. Everything else, comment text
included, must match to the byte.

Then unify the warning at all 22 sites on the fullest wording, which also says
the id must exist in Intelligence or thread operations can fail.

The check passes on day one, so it is a ratchet rather than a migration. It is a
shape gate, not a content gate: 22 identically wrong copies still pass. What it
guarantees is that a fix reaches all of them or none.

Not covered: enrolling the `intelligence:` arm in the smoke path. That needs a
license token in CI and a reachable endpoint from the compose network, and is
tracked separately.
2026-08-26 11:16:00 -05:00
Benjamin Taylor 8483f434f7 fix(examples): stop overriding the managed Intelligence URL defaults (closes OSS-981)
CopilotKitIntelligence resolves apiUrl/wsUrl to the managed hosts when they are
omitted, and its own docstring says leaving both unset is always correct against
the managed service. Every starter's runtime route supplied
`?? "http://localhost:4201"` instead, so a managed reader who copied the block
got a runtime aimed at a local stack that is not running -- the failure the
starter's own .env.example warns about two files away.

Replace the fallbacks with the conditional spread these same starters already use
in channel-host.mts, so a self-hosted override still works and the managed
default applies when it is absent. Three .env.example files also set the values
uncommented, two of them directly under a comment telling the reader to leave
them unset; comment those out to match the other nineteen starters.

Guard both shapes in validate-intelligence-env-names.ts, which already polices
the canonical Intelligence key name and hosts and runs unfiltered on every PR.
The rule is the pattern rather than the literal, so a staging host substituted
for localhost fails the same way. Local e2e harnesses and demo stacks that
genuinely target a local deployment are allowlisted with their reasons.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 09:59:23 -05:00
Lukas Moschitz 9726bae8f3 chore(demo): let the v2 react demo target a standalone runtime process
The demo mounts the runtime as its own Next route handler, so app and runtime
share one process. Restarting the runtime restarts the dev server and reloads
the page, which re-runs the startup handshake and hides any mid-session
connection behaviour under observation.

Read the runtime URL from NEXT_PUBLIC_COPILOTKIT_RUNTIME_URL when it is set, so
the demo can be pointed at a runtime running as a separate process (e.g.
examples/v2/runtime/express). Unset, behaviour is unchanged.
2026-08-26 13:25:11 +02:00
Alem Tuzlak 1983c07ccf fix(examples): add missing zod for the OpenRouter demo-server
@ai-sdk/openai imports zod/v4 at runtime. The Angular OpenRouter
demo-server did not declare that peer, so chat failed on Windows pnpm.
2026-08-26 12:20:08 +02:00