mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
codex/fac-83-react-native-headless-metro
15497 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
91ee17f26b | chore(release): refresh public API manifest | ||
|
|
589d59f96a | fix(react-native): make headless bundles Metro-safe | ||
|
|
addd3f8831 |
fix(react-core): honor chatInputToolbarAddButtonLabel in the add menu tooltip (#6771)
## Problem
The add-menu ("+") button in `CopilotChat` renders its tooltip from a
hardcoded string, so `labels.chatInputToolbarAddButtonLabel` retitles
the **menu item** but leaves the **tooltip** in English:
```tsx
<CopilotChat labels={{ chatInputToolbarAddButtonLabel: "上传附件" }} />
// menu item → "上传附件" ✅
// tooltip → "Add attachments /" ❌
```
That blocks full localization of the chat UI unless you replace the
entire add-button slot just to change one string.
`packages/react-core/src/v2/components/chat/CopilotChatInput.tsx:1330`
(before):
```tsx
<span>Add attachments</span>
```
## Why this is a bug, not a design choice
Two independent signals say the hardcoded string was an oversight:
1. **Every other tooltip in the v2 chat surface is already
label-driven** — `CopilotChatInput.tsx:1186` renders
`<p>{labels[labelKey]}</p>`, and `CopilotChatUserMessage.tsx:303` /
`CopilotChatAssistantMessage.tsx:255` both render `<p>{title}</p>`. The
add-menu button was the only hardcoded tooltip in the package.
2. **Angular already does it the right way** —
`packages/angular/src/lib/components/chat/copilot-chat-tools-menu.ts:183`
derives the same tooltip from `chatInputToolbarAddButtonLabel`. React
was the outlier.
## Change
One-line fix: the tooltip now reads the existing label.
```tsx
<span>{labels.chatInputToolbarAddButtonLabel}</span>
```
I deliberately **reused `chatInputToolbarAddButtonLabel`** rather than
adding the `chatInputToolbarAddButtonTooltip` key the issue also
floated:
- It matches what Angular already ships, so this closes a parity gap
instead of opening a new one.
- A second key adds public API surface for a case nobody has actually
hit (menu item and tooltip needing to differ). It can be added later as
a non-breaking addition if a real need shows up.
- The default label is already `"Add attachments"`
(`CopilotChatConfigurationProvider.tsx:22`), so **the rendered default
text is unchanged** — no visual or snapshot regression.
The `/` shortcut glyph stays hardcoded: it is a key name, not prose.
## Out of scope (flagging, not fixing)
The React default for this label (`"Add attachments"`) differs from
Vue's and Angular's (`"Add photos or files"` —
`packages/vue/src/v2/providers/types.ts:6`,
`packages/angular/src/lib/chat-config.ts:30`). That is a pre-existing
cross-framework inconsistency; changing it here would silently alter
someone's default string, so I left it alone. Vue's add button has no
tooltip at all, so it needs no counterpart change.
## Testing
**1. New test fails without the fix (mutation-checked, not a
self-fulfilling probe).**
Run against the unfixed source, the assertion catches the hardcoded
string:
```
FAIL src/v2/components/chat/__tests__/CopilotChatInput.test.tsx > CopilotChatInput
> uses the configured add button label for the add menu tooltip
AssertionError: expected 'Add attachments/' to contain 'Upload attachment'
Expected: "Upload attachment"
Received: "Add attachments/"
```
Worth noting: my first draft of this test used `user.hover()` +
`findByRole("tooltip")` and failed for the *wrong* reason (no tooltip
ever rendered). This suite mocks `@radix-ui/react-tooltip` to a
passthrough (`src/v2/__tests__/setup.ts:92`), so tooltip content renders
eagerly and there is no real open/close or `role="tooltip"`. The
committed test asserts on `[data-slot="tooltip-content"]` scoped to the
add button's tooltip root, which is the convention this mock implies —
and it demonstrably fails on unfixed code, as shown above.
**2. Target file green with the fix — 56/56.**
```
✓ src/v2/components/chat/__tests__/CopilotChatInput.test.tsx (56 tests) 1050ms
Test Files 1 passed (1)
Tests 56 passed (56)
```
**3. Full `@copilotkit/react-core` suite: no regressions.** Baseline at
clean `HEAD` vs. this branch, same worktree, same command:
| | Tests | Passed | Failed |
|---|---|---|---|
| `HEAD` (unfixed) | 1514 | 1505 | 7 |
| This branch | 1515 | **1506** | 7 |
Exactly +1 test and +1 pass — my added test — with the identical 7
failures on both sides. Those 7 pre-existing failures are in
`CopilotChatView.pinToSend.test.tsx`, `use-pin-to-send.test.tsx`, and
three `src/v1-deprecated/hooks/__tests__/` files; none touch the add
button or labels.
**4. Typecheck — zero errors in the touched files.**
`tsc --noEmit` reports 21 pre-existing errors in this worktree, all in
the inspector/threads family (`use-inspector-thread-override.ts`,
`inspector-thread-override.test.tsx`, `CopilotKitInspector.tsx`,
`CopilotKitProvider.tsx`, `use-threads.tsx`,
`CopilotChatMessageView.tsx`, `CopilotChat.tsx`). None in
`CopilotChatInput.tsx` or its test:
```
$ tsc --noEmit 2>&1 | grep -c 'CopilotChatInput'
0
```
**5. Pre-commit hooks passed in full** (not bypassed — no
`--no-verify`):
```
✔️ check-binaries (0.04 seconds)
✔️ lint-fix (2.16 seconds)
✔️ check-intelligence-env-names (7.97 seconds)
✔️ test-and-check-packages (52.53 seconds)
✔️ commitlint (0.61 seconds)
```
`test-and-check-packages` runs `nx run-many -t test,publint,attw` for
the affected package, so react-core's `test`, `publint`, and `attw` all
passed. Formatting applied with `oxfmt`.
Fixes #6750
|
||
|
|
4edbbc3f28 |
fix(react-core): honor chatInputToolbarAddButtonLabel in the add menu tooltip
The add-menu ("+") button's tooltip hardcoded the string "Add attachments",
so `labels.chatInputToolbarAddButtonLabel` only retitled the menu item and
the tooltip stayed English. That blocked full localization of CopilotChat
without replacing the whole add-button slot.
Every other tooltip in the v2 chat surface is already label-driven, and the
Angular implementation already derives this tooltip from the same label, so
this was an oversight rather than a deliberate split.
The "/" shortcut glyph stays hardcoded — it is a key name, not prose.
Fixes #6750
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
d692f25852 |
feat(runtime): expose Learning Container selector (#6767)
## What does this PR do? Adds `getLearningContainerId` to `CopilotKitIntelligence` so developers can assign Intelligence Threads to Learning Containers without a theta-prefixed Runtime option. The selector receives: - The resolved application `user`. - The parsed AG-UI `input` for the run. - The `agentId` and the `web` or `channel` surface. Web runs pass the exact parsed `RunAgentInput`. Channel runs build the same canonical input that the AgentRunner receives. Channels also carry the resolved application user through the core and Intelligence adapter boundaries. The Runtime validates the selected stable ID and sends only that ID with the existing Thread create or lock call. Intelligence stays responsible for project scope, entitlements, Container lookup, and the one-time Thread binding. Persisted AG-UI events remain the source for Learning snapshots. The old `ɵlearning` Runtime option remains as a deprecated fallback. The Runtime rejects configurations that set both APIs. ## Why? Learning Container assignment is an Intelligence SDK concern. Developers also need the resolved user and complete run input to select a Container from application data without reading raw transport details. ## Related PRs and Issues - Refs [ENT-1149](https://linear.app/copilotkit/issue/ENT-1149/enable-projects-to-learn-from-agent-runs-and-publish-reusable-skills) - Related design: #6746 ## Validation - GitHub CI: 53 passed, 3 skipped - `pnpm nx run-many -t test,check-types,build -p @copilotkit/runtime @copilotkit/channels-core @copilotkit/channels-intelligence` - `pnpm nx run-many -t publint,attw,check-dts -p @copilotkit/runtime @copilotkit/channels-core @copilotkit/channels-intelligence` - `pnpm lint` (0 errors; existing warnings remain) - `npm run typecheck` and `npm run build` in `showcase/shell-docs` - `npm test` in `showcase/shell-docs` has one pre-existing failure at `inspector-docs.test.ts:141`: the tracked Threads callout contains `Playground`. ## 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] Maintainer edits are available because this PR uses a branch in the main repository |
||
|
|
28c5208596 |
docs: document reading AG-UI context in a Pydantic AI agent (#6768)
## Problem Pydantic AI's AG-UI adapter reads `messages`, `tools`, `state`, `thread_id` and `resume` off `RunAgentInput`, and nothing else. `context` — the field `useAgentContext` travels on — is never passed to the agent. Nothing errors when it is dropped. There is no warning and no console message, so an agent that received none of the page's entries still answers confidently about them. A developer who wires `useAgentContext` against a Pydantic AI agent gets a well-formed answer about data the agent never had. Verified against `pydantic-ai-slim` 2.33.0 and current upstream `main`: zero references to `run_input.context` across all nine modules in `pydantic_ai/ui/ag_ui/`. ## Why there was no page The omission is deliberate upstream, not a bug. [pydantic/pydantic-ai#7105](https://github.com/pydantic/pydantic-ai/issues/7105) was closed as completed by [#7106](https://github.com/pydantic/pydantic-ai/pull/7106): `run_input` is public, so `adapter.run_input.context` has always worked, and auto-injecting client-submitted text into `instructions` would let a prompt injection inherit operator authority. Upstream documented the route instead of adding API. What was missing was a CopilotKit page saying any of this. `useAgentContext`'s reference page documents the frontend hook only, and the four existing `agent-app-context` pages cover built-in-agent, langgraph, mastra and microsoft-agent-framework. ## What's here `pydantic-ai/agent-app-context.mdx`, the fifth such page, wired into the integration's App Control nav after `shared-state`. Two details the page pins down, both verified against a running agent rather than adapted from a sibling page: - **`value` is a string, not your object.** `useAgentContext` calls `JSON.stringify` before the run leaves the browser, and AG-UI types `Context.value` as a string on both ends. `json.loads` is required, and a shape check like `isinstance(entry.value, list)` can never pass. A failed check is indistinguishable from context never being sent, which is what makes this one expensive. - **`from_request`, not `dispatch_request`.** The one-line `AGUIAdapter.dispatch_request(request, agent=agent)` used elsewhere in these docs parses the request internally, leaving no `run_input` to build `deps` from. The context route needs the two-step form. The page also carries upstream's trust rule: entries reach the model as tool output, never as `instructions`, and facts the *server* established are what belong in instructions. ## Verification The documented `agent.py`, served over real HTTP with AG-UI request bodies shaped exactly as the runtime sends them: | Case | Result | |---|---| | Asks about the shared entries | Answers from them, all three colleagues | | Asks about someone never sent | Declines, and names exactly the three the page did send | | `context` arrives empty | Reports an empty list rather than inventing one | Suite: **480 passed / 2 failed**. Both failures (`inspector-docs`, `llm-text` mastra tool-rendering) reproduce identically on pristine `origin/main` content — confirmed by reverting both files and re-running. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
9acc242f34 |
docs: document reading AG-UI context in a Pydantic AI agent
Pydantic AI's AG-UI adapter reads `messages`, `tools`, `state`, `thread_id` and `resume` off `RunAgentInput`, and nothing else. `context` -- the field `useAgentContext` travels on -- is never passed to the agent, and nothing errors when it is dropped, so an agent that received none of the page's entries still answers confidently about them. That omission is deliberate upstream (pydantic/pydantic-ai#7105, closed by #7106): entries are client-submitted, so the adapter leaves it to the application to decide what to trust, and `run_input` is public for exactly this purpose. What was missing on our side was a CopilotKit page saying so. Add `pydantic-ai/agent-app-context.mdx`, the fifth such page, alongside built-in-agent, langgraph, mastra and microsoft-agent-framework, and wire it into the integration's App Control nav. Two details the page pins down, both verified against a running agent rather than adapted from a sibling page: - `useAgentContext` JSON-stringifies `value` and AG-UI types `Context.value` as a string on both ends, so `json.loads` is required and a shape check like `isinstance(entry.value, list)` can never pass. - The one-line `AGUIAdapter.dispatch_request(request, agent=agent)` used elsewhere in these docs parses the request internally, leaving no `run_input` to build `deps` from. The page uses the two-step `from_request` form instead. The page also carries upstream's trust rule: entries reach the model as tool output, never as `instructions`, so a prompt injection cannot inherit operator authority. Verified: the documented `agent.py` served over HTTP answers from the shared entries, names exactly what the page did send when asked about a colleague it did not, and reports an empty list when `context` arrives empty. Suite is 480 passed / 2 failed, both failures identical on pristine origin/main. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
4ccae6fe20 |
fix(react-native): keep the polyfill imports in the built barrel (closes OSS-1002) (#6744)
## The bug
`src/polyfills.ts` is five side-effect-only imports plus
`installStreamingFetch()`. The published barrel was 195 bytes:
```js
// node_modules/@copilotkit/react-native/dist/polyfills.mjs — 1.69.2
import { t as installStreamingFetch } from "./streaming-fetch-BnQh3vBz.mjs";
installStreamingFetch();
export { };
```
Every React Native app following the documented setup died on its first
runtime call:
```
E ReactNativeJS: '[CopilotKit] Error (runtime_info_fetch_failed):',
[ReferenceError: Property 'ReadableStream' doesn't exist]
```
## Root cause
The `sideEffects` field, but not in the way it first looks. It is
correct for *consumers* and wrong for *this package's own build*:
```json
"sideEffects": ["./dist/index.*", "./dist/headless.*", "./dist/polyfills.*", "./dist/polyfills/**/*"]
```
tsdown/rolldown reads the package's own `sideEffects` while bundling and
matches it against **source** paths. `src/polyfills/streams.ts` matches
none of those `dist` globs, so it is declared side-effect-free — a hard
assertion that lets rolldown drop the import without analysing the
`globalThis` assignments inside.
Reproduced in isolation at the pinned tsdown (0.20.3):
| `sideEffects` | built barrel |
|---|---|
| `["./dist/polyfills.*", "./dist/polyfills/**/*"]` | `export { };` —
empty |
| same + `["./src/polyfills.*", "./src/polyfills/**/*"]` | `import
"./polyfills/streams.mjs";` |
| field absent | `import "./polyfills/streams.mjs";` |
**Wider than the ticket recorded:** `dist/index.mjs` and
`dist/headless.mjs` also had zero polyfill code, so the package's
advertised auto-install on first import did not happen either. Not
RN-specific in principle — but I surveyed every package at `origin/main`
and this is the only one exposed. The other `sideEffects` arrays
(`react-core`, `react-ui`, `react-textarea`) are `["**/*.css"]`, which
matches source and works.
## The fix
Add matching `./src/**` globs. Barrel goes 195B → 362B with all five
imports; `headless.mjs` now leads with `import "./polyfills.mjs"`.
## The test, and why the existing one didn't catch this
`src/__tests__/polyfills.test.ts` has ~20 assertions covering all five
groups and was green the whole time — it imports `"../polyfills"`, the
TypeScript **source**, which vitest transpiles without bundling and
therefore without tree-shaking. It exercises a graph the published
package does not contain.
So the new check runs against `dist/`. Two things it has to get right to
be honest:
- **Node ships these globals natively.** Asserting `ReadableStream` is
"defined" after import passes on an empty barrel. The probe clears all
nine first, emulating Hermes.
- **The two formats need different treatment.** CJS is executed for real
in a child realm. ESM is checked structurally — it cannot be executed
here because `encoding.mjs` takes a named import from CommonJS
`text-encoding`, which Metro rewrites to a `require()` but bare Node ESM
rejects.
It is wired into `build`, so a dead barrel fails the build rather than
reaching npm — which matters, because this shipped through a fully green
suite.
## Docs
Added the `Property 'ReadableStream' doesn't exist` symptom to
troubleshooting, which previously covered only the inverse case (a
polyfill *conflict*).
I deliberately left the reference docs' "auto-installs on first import"
claims and the crypto import-order callout alone: both become **true**
once the build is fixed, and I verified the auto-install behaviourally.
## Verification
- **Red/green proven, not assumed:** reverted the `sideEffects` change,
rebuilt → 5/5 groups FAIL in both formats. Restored → 5/5 PASS. There is
also a test for a *single* group regressing, which a whole-barrel
assertion would wave through.
- **Packed tarball** (`pnpm pack`) verified behaviourally: all nine
globals install.
- 289 vitest + 26 script tests pass; `check-types` clean; `attw` green;
`publint` clean apart from a pre-existing `repository.url` suggestion;
oxfmt/oxlint clean.
- Added `{projectRoot}/scripts/**` to the package's `test` inputs and
confirmed cache invalidation (19/19 cached → 18/19 after touching the
verifier); without it, editing the verifier alone would restore a cached
pass.
**Not verified:** the on-device round trip — no emulator in this
environment. The bare-realm equivalent passes on the packed tarball.
## Follow-up worth its own ticket
`dist/polyfills/encoding.mjs` uses a named import from CommonJS
`text-encoding`. Metro handles it; a true-ESM consumer would not.
Pre-existing and not RN-facing, so left out of this change.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
9e27e10830 | feat(runtime): expose Learning Container selector | ||
|
|
15d4fa0e04 |
fix(telemetry): stamp sampling metadata and emitter markers on every event (#6749)
Closes OSS-1017, OSS-1018, OSS-1019.
Runtime volume can't currently be counted from the telemetry data alone.
Three separate reasons, all in the two `TelemetryClient`s, all fixed
here.
## What was wrong
**OSS-1017 — v2 samples but doesn't say so.**
`packages/runtime/src/v2/runtime/telemetry/telemetry-client.ts` gates
anonymous events at 5% and lets identified callers through at 100%, then
sends without stamping `sampleRate` / `sampleWeight`. The v1 client has
computed that block for a while; v2 never did. Measured in PostHog
(project 26816, `oss.runtime.copilot_request_created`), the share of
runtime volume arriving unweightable was 1.1% in May, 12.2% in June,
20.2% in July, 24.4% in August — roughly doubling each month. It has
already produced wrong GTM numbers: raw counts understate real volume
10–18× *and* overstate growth (+211% vs a true +128% Jan→Jul), because
the sampled/unsampled mix drifts as v2 adoption rises.
**OSS-1018 — identified v2 events aren't detectable downstream.** The
telemetry id travels as the `X-CopilotKit-Telemetry-Id` header, not an
event property, so whether an event was sampled at 5% or captured at
100% wasn't recoverable from the event. Consumers had to probe for
whatever identity fields happened to be present, which only ~2.7% of v2
events carry.
**OSS-1019 — v1 writes every event twice.** `capture()` sends to both
`lambdaClient.send()` and `segment.track()`, so one request becomes two
PostHog rows with nothing marking them as copies. Both prior dedupe
attempts produced wrong numbers: a "≥ 1.60 dual-emits" version cutoff is
wrong (1.59.5 dual-emits too — it added ~13M phantom requests to June),
and Segment-only drops the entire v2 runtime (19.5M in August).
## What changed
A new `packages/shared/src/telemetry/sampling.ts` holds
`computeSamplingMeta`, and both clients call it. The v1 client's inline
block is replaced by that call with identical output, so the
pre-existing v1 tests act as the regression check that the extraction is
behavior-preserving. v2 passes the result in `globalProperties`, the
slot the sink already spreads into the event and the same one v1 uses —
so both emitters are now identical on the wire.
`telemetry_identified` is carried explicitly rather than inferred from
`sampleWeight === 1`. Under `COPILOTKIT_TELEMETRY_SAMPLE_RATE=1`
anonymous events also weigh 1, and weight alone stops separating the
populations.
For the dual-write, per the issue's option 3 plus a dedupe key —
additive only, both transports keep flowing:
| property | value |
| -- | -- |
| `telemetry_emitter` | `v1-shared` \| `v2-runtime` |
| `telemetry_transport` | `segment` \| `lambda` |
| `telemetry_event_id` | one uuid per v1 `capture()`, identical on both
copies |
v2 doesn't carry an event id — it has a single transport, so there's
nothing to dedupe.
## The counting rule this enables
Drop v1's lambda copy, keep everything else, and sum the stamped weight:
```sql
sumIf(sampleWeight, NOT (telemetry_transport = 'lambda' AND telemetry_emitter = 'v1-shared'))
```
Note for whoever runs the next month-close: **this release breaks the
existing runbook query.** It isolates v2 with `NOT
JSONHas(properties,'sampleRate')`, which matches nothing once v2 starts
stamping `sampleRate` — `v2_runtime` would silently read zero and total
volume would lose ~24%. The runbook has been updated with an
era-agnostic query that gives the same answer either side of the
release; historical events don't get backfilled, so the old inference
path stays as the fallback for pre-fix data.
## Testing
Run from the worktree with `@copilotkit/shared` built so the runtime
resolves the real helper rather than a mock.
**`packages/shared` — 35 passed (35)**, including all 20 pre-existing v1
tests, unchanged. New `sampling.test.ts` (5) covers both branches, the
`sampleRate=1` collision that motivates the explicit flag, and an
empty-string telemetry id. New cases in `telemetry-client.test.ts` (4)
cover both copies sharing one `telemetry_event_id`, a fresh id per
capture, the emitter marker on both copies, and `telemetry_identified`
tracking the gate branch.
```
✓ src/telemetry/sampling.test.ts (5 tests)
✓ src/telemetry/lambda-client.test.ts (6 tests)
✓ src/telemetry/telemetry-client.test.ts (24 tests)
Test Files 3 passed (3)
Tests 35 passed (35)
```
**`packages/runtime` v2 telemetry — 37 passed (37)**, covering the new
client suite plus the four pre-existing license/telemetry integration
files:
```
✓ src/v2/runtime/telemetry/__tests__/telemetry-client.test.ts (6 tests)
✓ src/v2/runtime/telemetry/__tests__/global-properties.test.ts (6 tests)
✓ src/v2/runtime/telemetry/__tests__/instance-created.test.ts (5 tests)
✓ src/v2/runtime/__tests__/telemetry.test.ts (15 tests)
✓ src/v2/runtime/__tests__/sse-license-telemetry.integration.test.ts (1 test)
✓ src/v2/runtime/__tests__/sse-license-env-fallback.integration.test.ts (1 test)
✓ src/v2/runtime/__tests__/license-telemetry-endpoints.integration.test.ts (3 tests)
Tests 37 passed (37)
```
One pre-existing assertion changed: `global-properties.test.ts` asserted
`globalProperties` equals `{}` when the caller sets none, which is wrong
by design now that sampling metadata always rides there. Rewritten to
pin the exact key set, which preserves the original intent (nothing of
the caller's is added) and is strictly stronger.
**Mutation-checked** — each new test was verified to fail when its
mechanism is broken, then the mutation reverted and green confirmed:
| mutation | result |
| -- | -- |
| `effectiveSampleRate` always `= sampleRate` (drop identified branch) |
shared 2 failed, runtime 1 failed |
| `telemetry_identified` hardcoded `false` | shared 3 failed, runtime 1
failed |
| v1 event id hoisted per-client instead of per-capture | shared 1
failed |
| both v1 copies stamped `transport: "lambda"` | shared 1 failed |
| v2 drops the sampling block from `globalProperties` | runtime 4 failed
|
| *(reverted)* | shared 35/35, runtime 17/17 |
**Build/lint** — `tsdown` clean for both `@copilotkit/shared` (115
files) and `@copilotkit/runtime` (414 files); `oxfmt` applied; `oxlint`
reports 0 errors. The one warning on new code
(`consistent-function-scoping` on a test-local `jwtWith`) is the same
pattern the existing v1 test file already uses at
`telemetry-client.test.ts:42`.
Not run locally: the pre-commit `test-and-check-packages` hook, which
builds the whole monorepo and fails in this worktree on packages that
were never installed there (`core`, `sdk-js`, `channels-ui`) —
environmental, unrelated to these files. Leaving that to CI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
d7b536ba79 |
docs: complete predictive-state tool lifecycle (#6762)
## Summary - replace the incomplete Python custom-graph examples on the LangGraph and Deep Agents predictive-state pages with a complete `StateGraph` lifecycle - execute backend tool calls through `ToolNode`, persist `observed_steps`, and append the matching `ToolMessage` via `ToolRuntime.tool_call_id` before looping back to the model - preserve frontend-action interception and add source, visual-render, and LLM-render regression coverage for both routes ## Validation - `npx vitest run src/lib/__tests__/predictive-state-tool-lifecycle.test.ts` (2 passed) - `npm run typecheck` - `npm run build` - compiled both exact published Python snippets against the showcase dependency versions without calling a model provider - exercised the tool branch without a provider and verified state persistence plus the matching tool-call ID Linear: https://linear.app/copilotkit/issue/FAC-74/deep-agents-state-streaming-docs-python-custom-graph-tool-call-hangs |
||
|
|
67945e2641 | Merge remote-tracking branch 'origin/main' into codex/fac-74-tool-lifecycle | ||
|
|
61d232ec63 | docs: complete predictive-state tool lifecycle | ||
|
|
f87aeaa904 |
docs: correct four pages that contradict shipped code, and document copilotkit verify (#6760)
## What
Five defects from the onboarding sweeps that share one shape: **a page
states something the library stopped doing, or never said something the
library requires.** Grouped because they are the same failure class and
the files do not overlap; each is independently revertable.
| Issue | Defect | Fix |
|---|---|---|
| OSS-936 | `getLocalAgents({ mastra })` does not compile | `resourceId`
added at 6 doc sites |
| OSS-948 | Angular Inspector page teaches a mount that now destroys the
framework's own element | page rewritten; lying snippet deleted |
| OSS-950 | Nothing says the Angular runtime is its own process, or how
to move it off 8200 | `PORT` documented |
| OSS-953 | `copilotkit verify` documented nowhere | added to the shared
CLI snippet |
| OSS-944 | the a2ui flight example is copied as an application | domain
marked illustrative |
## Corrections to the issues as filed
Three tickets were wrong on a load-bearing detail. Recording these
because each changed the fix:
- **OSS-936 — "the docs may be right and the type over-strict".** They
are not. `resourceId` is Mastra's memory-scoping key, required
identically on `GetLocalAgentsOptions`, `GetLocalAgentOptions` **and**
`GetRemoteAgentsOptions`. `@ag-ui/mastra`'s own `registerCopilotKit`
resolves it per request as `requestContext.get(MASTRA_RESOURCE_ID_KEY)
?? fallback`. Defaulting it silently would put every user in one memory
scope. So the snippets were wrong, not the type.
- **OSS-948 — "Vue has no Inspector documentation at all".** It does.
`docs/inspector.mdx` already documents the auto-mount for React, Vue and
Angular, `enableInspector`, and the fact that an explicit `true` cannot
override the production gate. The *only* wrong page was the Angular
override, which shadowed that correct shared content. No Vue page was
needed.
- **OSS-950 — "`agent-only` used `COPILOT_RUNTIME_PORT`, so a mechanism
exists".** That variable appears **zero times in CopilotKit and zero
times in Intelligence**. The real knob is `PORT`, which `angular.mdx`
already passed to `server.ts` without ever telling the reader.
## Found while fixing, not filed separately
- **#6663 left a sixth broken fence** in a file it edited — the tracing
example at `copilot-runtime.mdx:127` also omits `resourceId`.
- **`react-native.mdx` named the wrong default.** It implied `verify`
defaults to `:8200`; the CLI defaults to
`http://localhost:3000/api/copilotkit`.
- **A shipped skill taught a non-existent export.**
`skills/copilotkit-debug/references/agent-debugging.md` showed `import {
CopilotKitWebInspector } from "@copilotkit/web-inspector"`. That symbol
is not exported — `index.ts` exports the tag, not a wrapper. This is
exactly OSS-891's failure mode, so it is fixed here.
- **The Angular Inspector page had drifted three separate ways**, not
one: the manual mount, the `does not depend on that package` claim,
*and* a navigation table (`Threads / Agents / Learning`) contradicting
the shared page's `Home / Workbench / Inspect`. That is why the page is
now thin and points at `/inspector` instead of restating it.
## Deliberately not in this PR
- **The a2ui domain swap (OSS-944's other half).** The docs side is one
file, but the example lives in **21 showcase cells / 264 files / 20 e2e
specs**, 106 of which contain `flight`. It also wants the post-OSS-942
re-run to say whether it is still needed. Only the illustrative-domain
callout is here.
- **The three Mastra example files** (`examples/canvas/mastra`,
`examples/canvas/mastra-pm`, `examples/integrations/mastra`).
`examples/integrations/mastra/src/agent.ts:13` carries `//
@ts-expect-error` over exactly this call, so fixing it requires removing
the suppression — but that example's typecheck is **already red on
main** for unrelated `@mastra/core` `Memory` type errors, so the change
cannot be verified. Left for a PR that fixes the example build.
- **OSS-935 / OSS-891.** 935 needs a canonical-route decision plus
redirect infra; 891 is a CI gate, not docs.
## Testing
Worktree at `origin/main` `4b3b1cd88e`.
**1. The Mastra type claim — proved by compiling, both directions.**
`@ag-ui/mastra@1.1.2`, `@mastra/core`, NodeNext + strict:
```
OLD getLocalAgents({ mastra }) -> exit 1
old.ts(4,45): error TS2741: Property 'resourceId' is missing in type
'{ mastra: Mastra<...> }' but required in type 'GetLocalAgentsOptions'.
NEW getLocalAgents({ mastra, resourceId: "user-1" }) -> exit 0
```
**2. Every changed MDX compiles**, and the gate is mutation-checked:
```
OK frontends/angular/inspector.mdx OK integrations/mastra/copilot-runtime.mdx
OK frontends/angular.mdx OK integrations/mastra/background-tasks.mdx
OK frontends/react-native.mdx OK .../shared-state/in-app-agent-read.mdx
OK snippets/shared/cli/cli.mdx OK .../shared-state/in-app-agent-write.mdx
OK generative-ui/a2ui/fixed-schema.mdx OK .../shared-state/predictive-state-updates.mdx
all compiled
mutation: append an unclosed <Callout>
-> FAIL Expected a closing tag for `<Callout>` (76:1-76:37) # the gate is live
```
**3. shell-docs suite — 456/458.**
```
Test Files 3 failed | 59 passed (62)
Tests 2 failed | 456 passed (458)
```
Both failures are **pre-existing on `origin/main`**, proved by reverting
every file in this PR to `origin/main` in place and re-running:
```
baseline (origin/main content + origin/main tests):
x inspector-docs > Inspector Callout snippets name the shipped pane <- "Playground"
x llm-text > canonical tool-rendering example for mastra
Tests 2 failed | 66 passed (68)
```
`open-inspector-pane-threads.mdx` says "copy it into a Playground
scratch session" while the test forbids `/\bPlayground\b/` across that
directory. **`main` is red on this today** — worth a look independently
of this PR. The three remaining failed *files* cannot start in this
worktree (`@clerk/nextjs`, jsdom); they are environment, not content.
**4. The two new Angular guards are mutation-checked** — neither is
self-fulfilling:
```
mutation A: re-add "does not depend on that package" to inspector.mdx
-> x the Angular Inspector page does not teach a manual mount
mutation B: recreate open-inspector-step-angular.mdx
-> x Angular uses the shared Open Inspector step, not a manual-mount variant
restored -> both pass
```
**5. One test caught a real repo rule I had broken.**
`angular-docs-content > keeps published Angular docs standalone and
canonical` forbids naming another frontend in Angular docs; my first
draft said "behaves exactly like React and Vue". Reworded, now green
(7/7).
**6. Doctest gating unchanged.** Extraction reports **22** fences on
this branch — exactly the count #6663 established. No fence added or
lost. (The Mastra fences edited here are not gated: they reference
`@/mastra`, which cannot resolve in the extraction directory.)
**7. Pre-commit gates, run manually:**
```
check:intelligence-env-names Intelligence env var names and hosts are canonical. exit 0
check:plugin-skills plugin skill mirror in sync
oxfmt --check All matched files use the correct format.
oxlint Found 0 warnings and 0 errors.
commitlint found 0 problems, 1 warnings
```
**8. Interaction with the one overlapping open PR.** #6712 (`refs
OSS-977`) touches `react-native.mdx` and `inspector-docs.test.ts` too.
`git merge-tree` reports no conflict, and I merged it locally and ran
the tests — **both PRs' tests pass together** (21/22, the 22nd being the
pre-existing Playground failure):
```
✓ Inspector states that it needs a browser and React Native has none (#6712)
✓ the React Native page lists the missing Inspector among its limitations (#6712)
✓ the Angular Inspector page does not teach a manual mount (this PR)
✓ Angular uses the shared Open Inspector step, not a manual-mount variant (this PR)
```
Merge order does not matter.
Refs OSS-936, OSS-948, OSS-950, OSS-953, OSS-944.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
465abb0239 |
docs: correct four pages that contradict shipped code, and document verify
Five onboarding-sweep defects that share one shape: a page states something the
library stopped doing, or never said something the library requires.
Mastra `resourceId` (OSS-936) — `getLocalAgents({ mastra })` does not typecheck
against `@ag-ui/mastra`; `resourceId` is required. It is Mastra's memory-scoping
key, required identically on the local, single-agent and remote option types, so
the snippets were wrong rather than the type over-strict. Fixed at all six doc
sites, including the tracing example that #6663 left behind.
Angular Inspector (OSS-948) — `@copilotkit/angular@0.4.0` ships the auto-mount
with a pinned `@copilotkit/web-inspector`. The Angular Inspector page still
taught a hand-written mount whose unconditional `DestroyRef.onDestroy` tears out
the element the framework now owns. Rewritten as a thin migration page that
points at `/inspector` instead of restating it, and the Angular Open Inspector
snippet — which asserted "Angular does not mount Inspector by default" — is
deleted in favour of the shared one every other web frontend already uses.
Angular runtime port (OSS-950) — say plainly that the runtime is its own
process, and name `PORT` as the way to move it off 8200. `COPILOT_RUNTIME_PORT`
appears nowhere in either repo and is not the mechanism.
`copilotkit verify` (OSS-953) — documented nowhere in the product docs. Added to
the shared CLI snippet, stating what `--round-trip` cannot prove: it records the
answer's character count and tool-call names, never its text, and proves an
agent answered under the declared id, not which deployment. React Native now
links that section rather than restating it, and its claim that the CLI defaults
to `:8200` is corrected to the real default, `:3000`.
A2UI flight example (OSS-944, part) — mark the domain illustrative on the page
the onboarding graph is mandated to fetch. The domain swap itself is not here:
it is 106 files across 21 showcase cells and wants the post-OSS-942 re-run
first.
Also fixes a shipped skill that taught `import { CopilotKitWebInspector }`, an
export that does not exist (OSS-891's failure mode, found in passing).
Two new tests guard the Angular claims, both mutation-checked.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
4b3b1cd88e |
chore: release angular v0.4.0 (#6758)
## Release angular v0.4.0 **Scope:** `angular` | **Bump:** `minor` --- ### How this release process works 1. **This PR was created automatically** by the "release / create-pr" workflow. It bumped the `angular` packages to `0.4.0` and generated AI-enhanced release notes. 2. **CI runs on this PR** — the full test suite (unit tests, lint, type checks, build) must pass before merging. This is the review gate. 3. **Review the release notes** in `release-notes.md` in this PR. If a Notion draft was created, you can edit the release notes there before merging. 4. **When this PR is merged**, the `release / publish` workflow automatically: - Builds all packages - Publishes the `angular` packages to npm at version `0.4.0` - Creates git tag `angular/v0.4.0` - Creates a GitHub Release with the final release notes ### Before merging - [ ] CI is green (tests, lint, types, build) - [ ] Version bumps look correct - [ ] Release notes are accurate (edit in Notion if a draft was created) --- > **Do not merge until CI is fully green.** The full test suite runs automatically on this PR.angular/v0.4.0 |
||
|
|
bf1bb98765 | chore: release angular v0.4.0 | ||
|
|
8469e72b30 |
feat(web-inspector): copy stored threads into Playground from Threads (#6642)
Inspector Threads now has **Try from here**. One click copies a stored thread into a Playground scratch session. The stored thread does not change. If the copy fails, Inspector stays on Threads and keeps the current Playground scratch. Example tour threads and locked Threads do not show the button. ## What does this PR do? Adds **Try from here** on a real stored thread in Inspector Threads. One click copies messages and thread state into a Playground scratch session. The stored thread does not change. If the copy fails, Inspector stays on Threads and keeps the current Playground scratch. Example tour threads and locked Threads do not show the button. ## Related PRs and Issues - Linear: OSS-873 - Playground base: https://github.com/CopilotKit/CopilotKit/pull/6580 (merged) ## 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 ## Testing **Commands run** 1. Rebased `feat/oss-873-try-from-here` onto `origin/main` and resolved 6 conflict files. 2. `npx nx run @copilotkit/web-inspector:test` — 626 tests passed (after the stale-result guard). 3. `npx nx run @copilotkit/web-inspector:check-types` — passed. **Manual test** 1. Open Inspector on localhost with Intelligence on, so a real stored thread exists. 2. Open that thread. Confirm **Try from here** is in the thread header. 3. Click **Try from here**. Confirm Inspector opens Playground with the copied messages and the stored thread is unchanged. 4. Open an example tour thread. Confirm **Try from here** is not shown. 5. Force a copy failure (disconnect runtime). Confirm Inspector stays on Threads and the prior Playground scratch is unchanged. **How this PR makes testing easy** - `packages/web-inspector/src/__tests__/inspector-navigation.spec.ts` covers the button, copy path, failure path, and a stale click that must not overwrite Playground. - `packages/web-inspector/src/lib/__tests__/telemetry.test.ts` covers `oss.inspector.threads_try_from_here_clicked`. ## Risk / rollback Risk is limited to Inspector Threads and Playground. A revert of this PR removes the button and the new telemetry event. No runtime protocol change. ## Public API change New Inspector telemetry export and event name: **Before** ```ts trackThreadsTabClicked(props); ``` **After** ```ts trackThreadsTabClicked(props); trackThreadsTryFromHereClicked({ ...props, outcome: "success" }); ``` `CpkThreadInspector` also emits a `tryFromHere` custom event when the user clicks the button. |
||
|
|
5a191c8e36 |
fix(web-inspector): put Try from here next to Expand all
Move the button onto the messages toolbar, on the right of Expand all and Collapse all, with a top-right arrow. |
||
|
|
ec146f6721 | fix(web-inspector): drop stale Try from here results | ||
|
|
d6812e41c8 |
fix(core): report the runtime connection status from the last actual contact (#6706)
Closes OSS-904.
## The problem
`CopilotKitCore.runtimeConnectionStatus` was set only by the `/info`
handshake, which runs **once on connect**. If the runtime became
unreachable after that, the status stayed `connected` indefinitely —
measured two independent ways against `examples/v2/react/demo` and
recorded in the ticket.
The failure was not lost, it was filed in the wrong drawer: it arrived
as `agent_run_failed`, indistinguishable from an agent bug. So
everything downstream inherited the wrong answer — System Health
reported healthy, the launcher error signal could not fire for the most
common real symptom ("it worked a minute ago"), and a customer `onError`
handler written to separate wiring problems from agent problems got the
wrong classification.
## What this changes
The status now reports **the outcome of the last actual contact with the
runtime**.
A failed runtime request — or silence past a per-request watchdog —
triggers **one** bounded confirmation request. If nothing answers, the
status moves to `error` and the failure is emitted through the existing
wiring error code, so customers already handling startup wiring failures
pick up the mid-session case without changing a line. A subsequent
successful request re-syncs and clears it.
Crucially, **the conversation survives**. The transition does not
discard runtime knowledge, so the agent backing an open chat is the same
instance, its messages stay on screen, and submitting stays possible —
which matters because submitting is what restores the status.
No polling, no heartbeat, no retry loop. Every timer is bound to one
request and dies with it.
## Decisions worth knowing when reviewing
- **Reactive in both directions.** A heartbeat would put permanent
background traffic into every embedding application; a retry loop mostly
races a user who is about to retry anyway. The cost is stated rather
than hidden: while nothing is happening, nothing is detected.
- **Status change is separated from discarding knowledge.** The only
pre-existing code that set `error` also cleared `remoteAgents`. That is
right at startup and destructive mid-session, because conversation state
lives on the agent instance. Four sites now hold this invariant up
together; each carries a comment saying so.
- **The trigger is deliberately permissive, and the check is the
arbiter.** A request that received a successful response never triggers
a check; user cancellation never does; everything else may. Defining the
trigger precisely would mean maintaining a status-code list that is
complete only for the deployment topologies someone thought of.
- **Silence counts.** A server can refuse (fails fast) or hang (accepts
and never answers). A stopped dev server refuses; a container
mid-rollout, a half-switched deploy and a dropped tunnel hang. Only
bounding the check does not help, because no check starts — hence the
per-request watchdog. It observes only and never cancels the request.
- **The rule is stated by destination, not by call site**, so a runtime
route added later inherits the behaviour. Excluded: the Intelligence
realtime endpoint (a different service — reporting its outage as
"runtime unreachable" would be a false diagnosis), endpoints belonging
to the customer, and the stop request.
- **Recovery may prune, under two conditions**: the runtime must have
reported at least one agent, and the agent must carry no conversation
state. An empty list is the signature of a runtime that has not finished
registering.
- **"Answered but refused" keeps the error status and gets a different
message.** An expired token means the app cannot work, so red is right;
telling the reader "unreachable" would send them to check ports and
containers.
## Deliberately not delivered
- Detecting an outage, or a recovery, while the application is idle.
- Recovery by opening the Threads view: every binding withholds thread
requests until the status is already connected, so nothing is sent while
it is red. The thread plumbing still earns its place for *detection*.
- A signal for the Intelligence realtime endpoint failing while the
runtime is healthy — a real gap, and its own ticket.
- Memory and suggestion routes adopting the instrumented fetch.
- A new status value or a new error code.
## Costs this introduces
`error` now means two things — "never connected, no agents" and "lost
mid-session, agents intact". Documented on the enum. And because the
status can now change mid-session at all, an outage costs some churn
that did not exist before: the memory list and the Inspector's thread
list are cleared and refetched, and where the chat owns its run-activity
store it is stopped and restarted. All of it is paid on a user-caused
transition, never while idle.
## Testing
Four independent reviewers audited an earlier revision of this branch;
the ten defects they reproduced are fixed and each is pinned by a test
that was red first. A mutation audit of 110 mutants killed 90; the
surviving holes were closed in the round after.
The connection-health suites carry 72 tests. Request counting is a
first-class assertion throughout, because several decisions are
*absences* — no polling, no retry loop, one check per burst, no traffic
while red — and an absence is only testable by counting. Those tests use
fake timers advancing ten minutes; that boundary is documented where it
lives, since anything slower is invisible to them.
Verified by hand in a browser with the runtime running as its own
process, so the page outlives it: a refusing runtime, a hanging runtime,
recovery, an agent added during an outage, an agent deleted during an
outage. `performance.timeOrigin` was checked throughout to prove the
page never reloaded and the result was not an artefact of a fresh
handshake.
## Follow-ups this leaves behind
Three of these deserve their own ticket. None blocks this PR; all three
are consequences of where its scope was drawn, and they are listed here
so the boundary is explicit rather than implied.
### 1. A signal for the Intelligence realtime endpoint
In Intelligence mode the browser gets its chat events from a **second
service** at its own address; the runtime is only asked for the
credentials. If that service fails while the runtime is healthy, this
change correctly reports the runtime as reachable — and the user
experiences exactly the silence this ticket exists to remove.
It is excluded here on purpose: folding it into the runtime status would
report "runtime unreachable" about a healthy runtime, and a false
diagnosis costs more debugging time than no signal. It needs its own
signal, which is a presentation decision as much as a detection one.
### 2. Memory routes onto the instrumented fetch
The memory store still builds with the global fetch, so its
runtime-bound requests are invisible to connection health. Two costs: a
genuine failure there is a signal we discard, and a success there cannot
restore the status.
The asymmetry is what makes this worth fixing rather than leaving:
memory is the surface most disrupted by a status transition (its list is
cleared and refetched) and currently the one least able to contribute.
The change itself is small — that module already takes its request
function as an injected dependency.
### 3. Consumers should key on what they need, not on the status value
Several consumers treat "status is not connected" as "discard
everything": the memory list, the Inspector's thread list, and the
chat's run-activity store. That was harmless while the status could not
change after page load. It can now, so every outage costs churn that did
not exist before.
This is the same mistake this PR fixes three times *inside* core — a
guard bound to a state instead of to the thing it protects. The
principle was applied internally and not to these consumers. That makes
the churn listed under "Costs" above **deferred rather than inherent**,
and it is the largest of the three follow-ups: three consumers in three
packages, each with its own risk, which is why it was kept out of this
PR.
### Two smaller items
- The launcher error signal on `main` carries a comment stating the
limitation this change removes ("a runtime that dies after the page
loaded … raises nothing … closing that gap means a re-probe in the
core"). It becomes false when this lands and should be corrected then.
- `packages/web-inspector/src/styles/generated.css` is build output
under version control and re-dirties the tree on every build. Unrelated
to this PR, but the Tailwind source glob scans test files, so any prose
comment containing a utility word (`fixed`, `hidden`, `visible`,
`block`) silently changes the committed CSS. Narrowing the glob would
remove the class of problem.
Full specification, including the interview decisions and every
revision: `OSS-904-PRD.md`.
|
||
|
|
c71dcfbb12 | style: auto-fix formatting | ||
|
|
95285be33b | feat(web-inspector): copy stored threads into Playground from Threads | ||
|
|
1cb76928ad |
Turn the Home Intelligence card into an install path (#6740)
## Why The Inspector said what Intelligence *is* and linked out to a signup page. Of ~1,655 Inspector opens in 90 days, **under 100 clicked any CTA**. This replaces the feature list with an argument, and the outbound link with an install that happens in the editor the developer is already in. This is the unfinished half of OSS-867, whose body asks for exactly this: *"If a capability requires Intelligence, detail why and include a video demonstrating that feature working end-to-end."* ## What changed **A four-slide argument, paired to the picture beside it.** Each slide carries two sentences and the visual they describe: your users' threads → the pattern inside them → the skill file → what it compounds into. An earlier draft sold Threads in prose while animating Learning; bound together they read as one chain, and `meeting-scheduling/SKILL.md` recurs through all four so the closing diagram is checkable rather than decorative. Condensed from the six-phase animation on the Intelligence home page — not screen-recorded. A ported version is themeable, stays sharp, and costs no asset weight; the original also runs 21.4s and opens on the agent booking the wrong meeting, a poor first frame for a card arguing for the product. **A copy-prompt button instead of a link out.** It hands the CLI's own onboarding prompt to a coding agent. Every previous Intelligence CTA opened a new tab into a signup form, which is where developers drop out. It carries the CLI's `onboarding_run_id`, so `oss.inspector.home_prompt_copied` can be joined to `cli.onboarding.completed` on the Intelligence side. `home_cta_clicked` only ever proved that someone clicked a link — this is the first event that can show whether an install followed. **Section anatomy mirrors System Health** (header band, rule, content), so the action sits in the same top-right slot the status pill and renew link already use, and the panel keeps one section shape throughout. ## Correctness of the claims The copy was checked against the product's own surfaces, and two claims did not survive: - **Skills are not applied at run time.** Candidates land at `pending_review`, a human approves, and the published set is pulled down with `copilotkit skills download`. Nothing reads published skills during a run. The slide says approve → pull in → the next run starts from what worked. - **Insights were missing**, and with them the evidence link that makes Learning credible: every Insight cites the Threads and messages behind it. Also: *Rich Threads* is the product's name for the durable ones, and the distinction is the whole sale next to a Threads tab full of local ones that die on reload. "Your users" means the app's end users — which is what the platform means too (`identifyUser` resolves one user per request; a thread carries `end_user_id`, renamed from `user_id` because the old name *"caused repeated misdiagnosis"*). ## Behaviour worth reviewing - The story advances **only while Home is visible and the document is not hidden**. A debugging tool should not hold a repeating timer behind a closed panel. - Slide motion is horizontal and derived from each slide's index relative to the active one, so clicking a tab backwards animates backwards with no stored direction to fall out of sync. - Copied state **expires after 4s** so the button invites a second press; a failed copy **does not**, because that state is the only place the prompt is selectable by hand. - Three modes, not two: a lapsed plan keeps the renew link and never sees an install prompt. - The rotating copy is hidden from assistive tech (it would announce four times a loop); one stable sentence is exposed in its place and is test-covered so it cannot quietly rot. ## Deliberate omissions **No third-party coding-agent logos on the button**, unlike the Intelligence app. That app is a private hosted surface; this package ships inside other people's sites, and vendoring Anthropic's and OpenAI's marks is not a call to make quietly. The helper line names the agents in text. Deferred and worth discussing separately: ordering the Home sections by state (health first when something is broken, Intelligence first when nothing is), and putting the same button in the locked Learning and Threads tabs, where intent is highest. ## Verification 617 tests pass, `check-types` clean, oxlint 0 errors. Verified live in both themes: all four slides, uniform 16px padding on every slide, card height stable across slides, copy success **and** failure paths, and the header band unchanged at 76px when the copied hint appears. The reset behaviour is mutation-checked — the file records which mutation each test does and does not catch. |
||
|
|
5686a0669e | Merge branch 'main' into lukas/oss-904-runtime-connection-status | ||
|
|
1dfc5cdafa | refactor(core): remove OSS-904 design comments | ||
|
|
a7191e2a12 | fix(core): bound recovery /info hang and tighten OSS-904 comments | ||
|
|
b8b35b736c |
fix(packages): declare the MIT SPDX license on five published packages (#6511)
Five packages publish to npm with no `license` field, so registry metadata and automated license scanners report them as **Unknown**: ``` @copilotkit/agentcore-runner published=1.68.1 license=<NONE> @copilotkit/core published=1.68.1 license=<NONE> @copilotkit/sqlite-runner published=1.68.1 license=<NONE> @copilotkit/voice published=1.68.1 license=<NONE> @copilotkit/web-inspector published=1.68.1 license=<NONE> ``` The repo is MIT (see `LICENSE`) and every other published `@copilotkit/*` package already declares it — these five were simply missed. This adds `"license": "MIT"` to each, positioned before `"repository"` to match the sibling packages. ## Why Reported downstream in #2860, where a corporate procurement scan refused packages whose license it could not resolve. That class of scanner reads the `license` field from registry metadata; a `LICENSE` file in the repo is not enough, and these packages ship no `LICENSE` file either. **Correcting the record on that issue while I am here:** the `@ag-ui/*` packages named in the original report are *not* affected. Every version the reporter’s scanner flagged already carries `"license": "MIT"`: ``` @ag-ui/client@0.0.42 MIT @ag-ui/core@0.0.37 MIT @ag-ui/core@0.0.42 MIT @ag-ui/encoder@0.0.42 MIT @ag-ui/langgraph@0.0.20 MIT @ag-ui/proto@0.0.42 MIT ``` `@ag-ui/core` has declared MIT since at least 0.0.35. An earlier triage note on #2860 attributed the failure to a missing SPDX field upstream; that was wrong, and why their scanner reported `Unknown` for `@ag-ui/*` is still unexplained. This PR fixes the part that is genuinely defective on our side. ## Testing Metadata-only; no source, build, or runtime change. - Confirmed the five missing fields against the live registry with `npm view <pkg> license` (output above), and confirmed the other published `@copilotkit/*` packages (`runtime`, `react-core`, `react-ui`, `shared`, `sdk-js`, `angular`, `channels`, `channels-core`) already report `MIT`. - Enumerated every non-private `packages/*/package.json` on `origin/main` to confirm these five are the complete set missing the field. - Each edited file re-parsed with `json.load` and reports `MIT`. - The `sync-lockfile` pre-commit hook resolved all 71 workspace projects against the edited manifests without error. Placement matches `packages/shared/package.json`, where `"license"` immediately precedes `"repository"`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
dccfb6bb14 |
docs: add inspector-workbench skill for agent Inspector UI work (#6737)
When an agent is asked to fix Inspector UI, it must start the standalone lab and take screenshots. This PR adds `skills/inspector-workbench/SKILL.md` next to `inspector-docs`. `AGENTS.md` and `CLAUDE.md` point at it, so CopilotKit employee sessions load it by default. ## What does this PR do? - Adds the `inspector-workbench` skill. The default host is `nx run @copilotkit/web-inspector:dev:standalone` at `http://127.0.0.1:5177`. - Requires a screenshot after each visual change. Screenshot files go in `.inspector-workbench/` (gitignored), not the repo root. - Cross-links `inspector-docs` when a pane is added, renamed, or removed. - Registers the slug in `RESERVED_LIFECYCLE_SLUGS` so `pnpm sync:plugin-skills` does not delete the skill. ## Related PRs and Issues None. ## 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 (lets us help iterate on your PR directly — faster turnaround for everyone) ## Testing 1. Commands run: - `pnpm check:plugin-skills` passed (`plugin skill mirror in sync`). - `pnpm exec vitest run scripts/__tests__/sync-plugin-skills.test.ts` passed. - Full package tests were not run. This change is agent instructions plus the reserved-slug list. 2. Manual test: 1. Open `skills/inspector-workbench/SKILL.md`. 2. Confirm the default command is `nx run @copilotkit/web-inspector:dev:standalone`. 3. Ask an agent to fix Inspector UI. Confirm it starts the lab and takes a screenshot before it claims the UI is done. 3. How this PR makes testing easy: the reserved-slug unit test now includes `inspector-workbench`. CI `plugin-skills-check` will run on this path. ## Risk / rollback Low. This is agent instruction plus a gitignore folder. Revert the PR to undo. |
||
|
|
669132d731 |
fix(web-inspector): stop lit's part marker from failing the usage-footer test
The assertion searched footer.outerHTML for "241" to prove the unclamped thread count never reaches the user. outerHTML also carries lit's part markers, which lit builds as `lit$` + nine digits from Math.random(), regenerated per process. Roughly one process in a hundred rolls a marker containing those digits and fails the assertion with no relation to what the footer rendered — this run drew lit$924125892$. Comments are stripped before the check. Visible text and attributes still count, so a genuine leak in an aria-label is caught exactly as before, and the stripping is asserted so it cannot silently stop working. Not introduced here: the same dice roll could hit any change to this package. The other outerHTML assertions in the suite compare two strings from the same process and share a marker, so they were never exposed. |
||
|
|
1efdf37a40 |
feat(web-inspector): report which story step a developer opens by hand (refs OSS-867)
The rail's four tabs reported nothing. Adds oss.inspector.home_story_beat_selected, carrying the step as a property rather than one event per label: the labels are expected to move as the story is iterated, and per-label events would retire with them. beat_index rides along so a reorder can be judged against where people actually click. Only a press reports. The story also advances on its own every few seconds, and reporting that would emit one event per idle developer per beat and bury the handful of real interactions under a metronome — asserted, not assumed. |
||
|
|
cb94614f42 |
fix: preserve sibling state in CopilotKit middleware (#6748)
## Summary - follow up on the post-merge review of #6747: LangChain projected each `wrapModelCall` request through that middleware's own schema, which stripped `agentName` owned by the sibling Deep Agents middleware - preserve sibling-owned fields at the shared CopilotKit middleware boundary while retaining the existing `exposeState` default-off and allowlist behavior - add a real `createAgent` regression that proves `agentName: "Mochi"` reaches the model system prompt The docs merged in #6747 need no further copy change; this fixes the shared runtime boundary they exercise. ## Validation - reproduced RED on merged `main`: the real model received only the original system prompt - focused regression GREEN - `pnpm nx test @copilotkit/sdk-js` (118 passed) - `pnpm nx check-types @copilotkit/sdk-js` - `pnpm nx build @copilotkit/sdk-js` - pre-commit package, publint, attw, binary, formatting, and environment-name checks Fixes [FAC-66](https://linear.app/copilotkit/issue/FAC-66/deep-agents-ts-interrupt-based-docs-do-not-persistuse-agent-name). |
||
|
|
6ccff843c7 |
fix(telemetry): stamp sampling metadata and emitter markers on every event
The v2 runtime client gated anonymous events at 5% and let identified callers through at 100%, then sent without recording which branch the event took. A quarter of runtime volume — 24.4% in August and roughly doubling each month — arrived carrying no record of its own sampling, so it could not be weighted from the data alone. Downstream had to hardcode a x20 assumption, which both understates real volume and overstates growth as the sampled/unsampled mix drifts. Extract the v1 client's sampling block into shared/telemetry/sampling so the two clients cannot drift again, and call it from both. Identified events weigh 1, anonymous ones 1/sampleRate. Carry telemetry_identified explicitly rather than letting consumers infer identity from sampleWeight === 1: under COPILOTKIT_TELEMETRY_SAMPLE_RATE=1 anonymous events also weigh 1 and the two populations stop being distinguishable. The v1 client also sends every capture to both Segment and the lambda sink, so one request produces two rows with nothing marking them as copies. Stamp telemetry_emitter, telemetry_transport, and a per-capture telemetry_event_id shared by both copies, making the dedupe explicit instead of inferred from $lib. Both transports keep flowing. Refs OSS-1017, OSS-1018, OSS-1019 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
ed315ac592 | fix: preserve structured system messages when exposing state | ||
|
|
d385b9290e | test: assert structured system message content safely | ||
|
|
f17d0509db | fix: preserve system prompt text when exposing state | ||
|
|
2f1c4c9332 | fix: preserve sibling middleware state for exposure | ||
|
|
6a3c7c4df4 |
docs: persist Deep Agents interrupt names (#6747)
## Summary - complete the Python and TypeScript Deep Agents interrupt setup so the chosen name persists in graph state - expose only the name field to the model and explain how it should use that state after resume - keep both public interrupt guides in parity and test authored, rendered, and LLM-text output ## Validation - `npx vitest run src/lib/__tests__/deepagents-interrupt-docs.test.ts` (3 passed) - `npm run typecheck` - `npm run build` - full shell-docs suite: 478/479 passed; the remaining Mastra tool-rendering import assertion is pre-existing and unrelated Fixes [FAC-66](https://linear.app/copilotkit/issue/FAC-66/deep-agents-ts-interrupt-based-docs-do-not-persistuse-agent-name). Also covers FAC-67, which already duplicates FAC-66. |
||
|
|
a1c7146739 | docs: persist Deep Agents interrupt names | ||
|
|
b8492e2b70 |
docs(vue): document the generative-UI path and publish it in the Vue sidebar (closes OSS-1005) (#6743)
## Problem Vue 3 is a documented frontend and generative UI is the capability that turns a chat box into the product — every completing showcase cell's proof is a *card*, not a paragraph. But no page described how a tool result becomes a rendered surface in Vue. A showcase run pairing AWS Strands with Vue reached exactly that point, correctly refused to invent a rendering path, and said so: > "The official Vue documentation also does not document Strands generative-UI rendering, so none was invented or claimed." It shipped a text answer. Vue has 2 recorded runs against Next.js's 42 — the least-covered frontend is also the one where the most valuable capability was undocumented, and those reinforce each other. ## The capability was never missing `packages/vue` already ships the whole surface: `useRenderTool`, `useDefaultRenderTool`, `A2UIMessageRenderer`, `A2UISurfaceActivityRenderer`, `OpenGenerativeUIRenderer`, `MCPAppsActivityRenderer`, a full `src/v2/components/a2ui/` catalog and adapter, e2e coverage, and two working demo pages under `examples/v2/vue/demo/`. Notably it is React-free *by design* — the A2UI code carries comments explaining it duplicates small helpers specifically to avoid pulling `@copilotkit/a2ui-renderer`'s React dependencies. So this is a docs task, not an SDK one. ## But the gap was structural, not editorial This is the part worth reviewing carefully, because it's why a guide file alone would not have fixed anything. **Sidebar.** `getFrontendQuickstartNavTree()` gated its guides branch on `id === "angular"`. Angular gets its 8 guides; every other frontend got an empty array plus a "Guides coming soon" placeholder. The new test's red-check shows Vue's entire sidebar: ``` AssertionError: expected [ '/vue', …(2) ] to include '/vue/guides/generative-ui' ``` Three URLs. **Routing.** `resolveFrontendDocPage()` serves `/<frontend>/<slug>` only from a `frontends/<frontend>/<slug>` variant file, or from a doc whose nearest `meta.json` declares `frontend: universal`. `generative-ui/meta.json` declares no policy at all, so `/vue/generative-ui/*` resolves **not-found**. Those pages weren't merely React-flavored for a Vue reader — they were unreachable in the Vue namespace. The irony: `concepts/meta.json` **is** universal, and it holds `generative-ui-overview`. A Vue developer could reach the page explaining *what* generative UI is, and no page showing *how*. ## Changes | File | Change | | --- | --- | | `docs/frontends/vue/guides/generative-ui.mdx` | New. The guide. | | `lib/frontend-page-content.ts` | `VUE_GUIDE_PAGES` + a `FRONTEND_GUIDE_PAGES` lookup replacing the `id === "angular"` branch, so a frontend's guides are data rather than a conditional. Angular's tree is unchanged. | | `docs/frontends/vue.mdx` | The missing "Where to go next" pointer. | | `lib/__tests__/frontend-options.test.ts` | Three tests. | The guide covers `useRenderTool`, `useDefaultRenderTool`, `useFrontendTool` with a renderer, A2UI (provider-level and catalog-on-provider), Open Generative UI, and MCP Apps — written from `packages/vue` source and the in-repo demos, not translated from the React docs. Two things it states deliberately: - **It does not depend on the agent framework.** The reporting run read the absence as Strands-specific. Generative UI reads AG-UI tool calls; nothing changes when you swap the agent. The guide says so up front. - **`useRenderTool` and `useFrontendTool` do not hand their renderers the same props.** The former normalizes to `parameters` + a string-union status; the latter passes through to core with `args` + the `ToolCallStatus` enum. A renderer written for one silently draws nothing in the other. Verified in source, not inferred. ### One note on the link form The quickstart links the guide as `/vue/guides/generative-ui`, not the relative `guides/generative-ui` that `angular.mdx` uses. `resolveDocsHref` returns any non-root-relative href untouched, and `next.config.ts` sets no `trailingSlash` — so the relative form would resolve against `/vue` and land on `/guides/generative-ui`, which doesn't exist. A test pins the authored href and asserts it both survives rewriting and resolves. (`angular.mdx:241` uses the relative form and looks like it has the same problem; not touched here.) ## Verification - `frontend-options.test.ts` — 25/25. **Red-checked twice**: commenting out the single nav wiring line fails the sidebar test; reverting the href to the relative form fails the link test. Both can actually fail. - Full `shell-docs` suite — 475/476. The one failure (`llm-text.test.ts`, mastra tool-rendering) **reproduces on unmodified `origin/main`** with these changes reverted. Pre-existing, unrelated. - `tsc --noEmit` clean. `oxfmt --check` and `oxlint` clean. - Search index regenerated: the page parses and is indexed at `href: "/vue/guides/generative-ui"`, section "Frontends". ## Deliberately out of scope 1. **No Vue redirect map.** Angular's `ANGULAR_DOC_REDIRECTS` maps ~20 `generative-ui/*` slugs onto its guides, so `/angular/generative-ui/tool-rendering` lands somewhere useful. `/vue/generative-ui/tool-rendering` still 404s. That's a policy decision about how much React IA to mirror into Vue. 2. **Backend-scoped variant.** On `/vue/<backend>`, `resolveDocsHref` rewrites cross-section links — `/generative-ui/a2ui`, `/generative-ui/mcp-apps`, `/inspector` — into that prefix, where they resolve not-found. This follows from those sections having no `frontend:` policy, is the same for every non-Angular frontend page today, and is not introduced here. The sidebar link to the guide is correct in both contexts. 3. **`FRONTEND_REFERENCE_SLUGS.vue` left alone — but please look at it.** Vue's sidebar "Reference docs" link points at `"reference"`, the **React** reference, despite a complete 25-page `/reference/vue` tree existing and registered in `reference-items.ts`. It's pinned by an assertion at `frontend-options.test.ts:538`, so it looks deliberate. If it's an oversight it compounds this exact bug — a Vue developer sent to the React reference cannot find `useRenderTool`'s Vue signature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
cb6004051d |
docs(react-core): state that an agent receives useAgentContext value as a JSON string (closes OSS-1003) (#6742)
## Problem `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 the browser half: - `/reference/v2/hooks/useAgentContext` — "Object values are serialized automatically." - `/reference/react-native/hooks/useAgentContext` — the same sentence. - `/reference/vue/hooks/useAgentContext` — "Non-string values are serialized with `JSON.stringify` automatically." - `examples/v2/docs/reference/use-agent-context.mdx` — "Can be any serializable value." "Serialized automatically" reads as *the framework handles it*, not *your agent gets a string and must parse it*. No page mentioned `json.loads`, `JSON.parse`, or what the agent side receives. ## Why it matters An author who believes that writes an agent that reads the object. When the shape check fails, the agent cannot distinguish "context arrived JSON-encoded" from "no context was sent" — the two are byte-identical — so it refuses every request while the browser is registering context perfectly. That is what happened on the `both-oss::langgraph-python::nextjs` conversion journey (OSS-1003). The agent guarded on `isinstance(entry["value"], list)`, which the protocol can never satisfy, so its success path was unreachable on every real run and the journey was dead on arrival. Reproduced directly against that graph: ``` A wire shape (value = JSON string) -> "...context is missing." B object shape (value = list) -> resolved correctly C no context at all -> identical to A ``` ## Change Each of the four pages gains a `## What the agent receives` section: - the wire shape shown as literal JSON - `json.loads` (Python) and `JSON.parse` (TypeScript) agent-side examples - a callout naming the shape check as the trap, and why a failed check is indistinguishable from absent context The `value` parameter description and the `Serialization` behavior bullet on each page now name the consequence for the agent author and link to that section, instead of stopping at the browser half. Docs only — no source or runtime behavior changes. ## Verification - All four files parse-check clean: balanced code fences, balanced JSX, anchor targets present and linked. - `Callout` is globally registered (`showcase/shell-docs/src/lib/mdx-registry.tsx:263`), so no per-file import is needed. - `shell-docs` `llm-text.test.ts`: **10 failed | 32 passed** both with and without these edits — identical, so this change introduces nothing. Those 10 are pre-existing `claude-sdk`/`google-adk` content assertions that fail on stale generated data in a fresh worktree. - `.mdx` is outside lefthook's `lint-fix` glob, so oxfmt/oxlint do not reformat these files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
6d2f7708b3 |
chore: release monorepo v1.69.3 (#6741)
## Release monorepo v1.69.3 **Scope:** `monorepo` | **Bump:** `patch` --- ### How this release process works 1. **This PR was created automatically** by the "release / create-pr" workflow. It bumped the `monorepo` packages to `1.69.3` and generated AI-enhanced release notes. 2. **CI runs on this PR** — the full test suite (unit tests, lint, type checks, build) must pass before merging. This is the review gate. 3. **Review the release notes** in `release-notes.md` in this PR. If a Notion draft was created, you can edit the release notes there before merging. 4. **When this PR is merged**, the `release / publish` workflow automatically: - Builds all packages - Publishes the `monorepo` packages to npm at version `1.69.3` - Creates git tag `monorepo/v1.69.3` - Creates a GitHub Release with the final release notes ### Before merging - [ ] CI is green (tests, lint, types, build) - [ ] Version bumps look correct - [ ] Release notes are accurate (edit in Notion if a draft was created) --- > **Do not merge until CI is fully green.** The full test suite runs automatically on this PR.v1.69.3 |
||
|
|
a768047532 |
docs(vue): document the generative-UI path and publish it in the Vue sidebar (closes OSS-1005)
Vue 3 is a documented frontend and generative UI is the capability that turns a chat box into the product, but no page described how a tool result becomes a rendered surface in Vue. A run pairing AWS Strands with Vue reached that point, correctly refused to invent a rendering path, and shipped a text answer instead. The capability was never missing. packages/vue ships useRenderTool, useDefaultRenderTool, A2UIMessageRenderer, A2UISurfaceActivityRenderer, OpenGenerativeUIRenderer, a full a2ui/ catalog and adapter, e2e coverage, and two working demo pages. Only the docs were absent. They were absent structurally, not editorially. getFrontendQuickstartNavTree gated its guides branch on `id === "angular"`, so every other frontend got an empty list plus a "Guides coming soon" placeholder -- Vue's whole sidebar was three URLs. Routing matched: resolveFrontendDocPage serves /<frontend>/<slug> only from a frontends/<frontend>/ variant or a section marked `frontend: universal`, and generative-ui/meta.json declares no policy, so /vue/generative-ui/* resolved not-found. concepts/meta.json IS universal, so a Vue reader could reach the page explaining what generative UI is and no page showing how. Add the guide, and replace the Angular identity check with a FRONTEND_GUIDE_PAGES lookup so a frontend's guides are data rather than a branch. Angular's tree is unchanged. The guide is written from packages/vue source and the in-repo demos rather than translated from React, states up front that none of this depends on the agent framework, and documents that useRenderTool and useFrontendTool do not hand their renderers the same props -- `parameters` plus a string-union status versus `args` plus the ToolCallStatus enum -- so a renderer written for one silently draws nothing in the other. The quickstart's link to the guide is the fully-qualified /vue/guides/generative-ui rather than the relative form angular.mdx uses. resolveDocsHref returns non-root-relative hrefs untouched and next.config sets no trailingSlash, so `guides/generative-ui` would resolve against /vue and land on /guides/generative-ui. A test pins the authored href and asserts it both survives rewriting and resolves. Not addressed here: Vue has no equivalent of ANGULAR_DOC_REDIRECTS, so /vue/generative-ui/* still 404s rather than landing on this guide, and on the backend-scoped variant of the page (/vue/<backend>) resolveDocsHref rewrites cross-section links like /generative-ui/a2ui and /inspector into that prefix, where they do not resolve. Both follow from the missing `frontend:` policy rather than from this guide. Separately, FRONTEND_REFERENCE_SLUGS.vue points at the React reference despite a complete /reference/vue tree; it is pinned by a test assertion, so it is left alone here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
84dea7bfbb |
fix(react-native): keep the polyfill imports in the built barrel (closes OSS-1002)
`src/polyfills.ts` is five side-effect-only imports. The `sideEffects` globs only matched `./dist/**`, and rolldown matches that field against SOURCE paths while bundling, so every `src/polyfills/*.ts` was declared pure and dropped. Every published version through 1.69.2 shipped a 195-byte barrel installing nothing but streaming fetch, so an app following the documented setup died on its first runtime call with `Property 'ReadableStream' doesn't exist`. `dist/index.mjs` and `dist/headless.mjs` lost the same imports, so the package's advertised auto-install on first import did not happen either. Add matching `./src/**` globs. The barrel goes 195B to 362B with all five imports, and `headless.mjs` now leads with `import "./polyfills.mjs"`. `src/__tests__/polyfills.test.ts` stayed green throughout this, because it imports the source, which is never bundled and so is never tree-shaken. Add `scripts/verify-polyfill-barrel.mjs`, which checks `dist/` instead. It clears the nine globals first (Node ships them natively and Hermes does not, so asserting they are merely "defined" would pass on an empty barrel), then executes the CJS barrel in a child realm and checks the ESM barrel structurally. ESM cannot be executed here: the encoding polyfill takes a named import from CommonJS `text-encoding`, which Metro rewrites to a require() but bare Node ESM rejects. The check runs from `build`, so a dead barrel fails the build rather than reaching npm. Also document the `ReadableStream doesn't exist` symptom in troubleshooting, where only the inverse case (a polyfill *conflict*) was covered before. Verified: reverting the sideEffects change and rebuilding turns the check red in both formats, 5 of 5 groups; restoring it turns it green. A behavioural check on the packed tarball installs all nine globals. 289 vitest + 26 script tests pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
8617f5b76b | chore: release monorepo v1.69.3 | ||
|
|
3b09f97107 |
fix(docs): replace retired GitHub Models setup (#6730)
## What does this PR do? - Replaces the retired GitHub Models setup in the Microsoft Agent Framework .NET starter with direct OpenAI. - Updates the live .NET guides to the current Agent Framework AG-UI hosting, session, state, and response APIs. - Pins quickstart packages to the versions tested by the starter. - Adds a recursive retired-guidance guard and runs it in docs CI for docs or starter-only changes. GitHub Models was fully retired on July 30, 2026, so the published setup can no longer work. ## Related PRs and Issues - Companion CLI cleanup: https://github.com/CopilotKit/Intelligence/pull/1029 ## Validation - `npm exec -- vitest run src/lib/__tests__/ms-agent-dotnet-provider.test.ts` (5 tests passed) - `npm run typecheck` - `npm run lint` (existing warnings only) - `npm run build` - `pnpm run validate:model-names` - Workflow syntax and formatting checks passed. - `docker build -f docker/Dockerfile.agent agent` - `docker compose -f docker-compose.test.yml config` - Compiled all nine full .NET guide examples against the pinned Agent Framework and AG-UI packages. - TestServer proof returned `200 text/event-stream` and emitted the expected `STATE_SNAPSHOT` through `WithMetadata(streamOptions)`. - Full shell-docs test run: 469 tests passed; one unrelated existing Mastra fixture test failed in `llm-text.test.ts`. ## 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 (lets us help iterate on your PR directly — faster turnaround for everyone) |
||
|
|
593fe0bc0b | fix(docs): address Agent Framework review | ||
|
|
6943ca8232 | fix(docs): replace retired GitHub Models setup | ||
|
|
f6f2dc4bb6 |
fix(examples): make Excalidraw MCP starter deterministic (#6729)
## Summary - pin all active LangGraph Python and LangGraph FastAPI starter runtimes to the published `copilotkit==0.1.96` lifecycle fix and compatible `ag-ui-langgraph==0.0.43` / `ag-ui-protocol==0.1.19` versions - add bounded Excalidraw guidance to the LangGraph Python starter: one `create_view` call, unique IDs, labeled shapes, arrows, one final camera update, and a one-sentence response - retain lifecycle regression coverage in the Python SDK, where the real intercepted-tool implementation is owned and tested; starter smoke builds verify both consumer environments resolve the released fix ## Release sequence This is the second FAC-124 PR. #6728 merged first, and `copilotkit==0.1.96` is verified live on PyPI with the lifecycle materialization and duplicate-suppression code. This starter PR should merge next. After it merges, the final PR will update the Intelligence catalog/provenance to this merge commit. Linear: https://linear.app/copilotkit/issue/FAC-124/langgraph-py-cli-starter-excalidraw-mcp-pill-is-nondeterministic ## Validation - `uvx --from uv==0.8.24 uv lock --check` — LangGraph Python and LangGraph FastAPI locks - `docker build -f docker/Dockerfile.agent -t fac-124-langgraph-python-final agent` — passed with `copilotkit==0.1.96` - `docker build -f docker/Dockerfile.agent -t fac-124-langgraph-fastapi-final agent` — passed with `copilotkit==0.1.96` - `pnpm parity:check` — passed; LangGraph FastAPI 84 ok, 0 errors - `git diff --check` The Railway production image previously installed the corrected Python pins and compiled the Next.js frontend; local export stopped only when the Docker host ran out of disk while copying the standalone bundle. |