Commit Graph

318 Commits

Author SHA1 Message Date
Ben Taylor 6c955686eb feat(react-core): expose AG-UI raw event to feedback callbacks (#6289)
## Summary

React v2 feedback callbacks receive an assistant message without the
trace metadata carried by the direct AG-UI event that created it. This
slice exposes that metadata to thumbs callbacks without changing
canonical messages or future run inputs.

## Root cause

AG-UI keeps `rawEvent` on events while reducer-created assistant
messages remain protocol-clean. `StateManager` sees the direct start
event but previously discarded its correlation before
`CopilotChatMessageView` forwarded the message to feedback callbacks.

## Changes

- Store defined direct `TEXT_MESSAGE_START.rawEvent` metadata by agent,
thread, and message.
- Replace repeated scoped entries and prune them with message removal
and lifecycle cleanup.
- Return a cloned sidecar value through
`CopilotKitCore.getRawEventForMessage`.
- Enrich only thumbs-up and thumbs-down callback arguments at click time
across flat and virtualized rendering.
- Add production-path regressions and document the callback-only type.

## Out of scope

Canonical messages, future `RunAgentInput.messages`, render props,
message identity, stream ordering, snapshots, transformed chunks,
persistence, GraphQL, legacy React, Vue, Angular, and standardized trace
semantics remain outside this slice.

## Related PRs and Issues

Addresses #3039.

The callback-only scope follows
https://github.com/CopilotKit/CopilotKit/issues/3039#issuecomment-5086936452.
Related trace-correlation contract: #4634.

## Test plan

- [x] StateManager sidecar tests, 10 passed. Covers direct capture,
falsey values, replacement, scope isolation, cleanup, snapshots, and
chunks.
- [x] React v2 feedback tests, 4 passed. Covers real callback routing,
canonical and outbound cleanliness, render identity, and flat/virtual
paths.
- [x] Full package suites, 625 core tests, 1,475 React Core tests, and 2
script tests passed.
- [x] Typecheck, formatting, lint, and whitespace validation passed;
lint reported five pre-existing warnings.
- [ ] CI green (`static / quality`, `test / unit` on Node 20/22/24).

## Notes

The clean-base behavioral half of the reproduction remains unproved
because temporary worktree setup hung behind unrelated Git processes.
The PR makes no base execution claim for that half.
2026-08-20 14:17:24 -05:00
Ben Taylor 6787b30203 fix(core): preserve run IDs across SSE connect replay (#6253)
## What does this PR do?

- Uses each `RUN_STARTED.runId` during Runtime SSE connect replay.
- Preserves the first run association when later message snapshots are
cumulative.
- Keeps live message events able to correct an earlier provisional run
association.
- Adds `/connect` and StateManager regression coverage for multiple
server runs.

## Why?

A single `/connect` stream can contain multiple runs. This affects
custom Runtime streams and the built-in in-memory runner, which replays
historic runs through one reconnect stream. StateManager previously
stored replayed state under the connection input ID and reassigned
earlier snapshot messages to the latest run.

## Related PRs and Issues

- Closes #6252

## Validation

- `@copilotkit/core` tests: 59 files, 661 tests passed
- `@copilotkit/core` type check
- Pre-commit lint, test, publint, attw, and commitlint

## Checklist

- [x] I have read the Contribution Guide
- [x] Documentation is not required for this internal bug fix
- [x] Allow edits by maintainers is enabled
2026-08-20 13:03:50 -05:00
BenTaylorDev aa3fb29dce chore: release monorepo v1.68.3 2026-08-20 10:27:07 -07:00
Ben Taylor 9df63beeef fix(runtime): name useSingleEndpoint when a single-route envelope hits a multi-route runtime (#6579)
Closes
[OSS-882](https://linear.app/copilotkit/issue/OSS-882/add-to-existing-journeys-reach-for-the-v1-compat-copilotkit-wrapper).

## The failure

The v1-compatible `<CopilotKit>` provider pins `useSingleEndpoint` to
`true`
([`copilotkit.tsx:108`](https://github.com/CopilotKit/CopilotKit/blob/main/packages/react-core/src/components/copilot-provider/copilotkit.tsx#L108)),
so its startup handshake POSTs `{ method: "info" }` at the base path. A
multi-route runtime — the default — matches no route for that path and
answered a bare `{"error":"Not found"}`, indistinguishable from a wrong
`basePath` or an unmounted handler.

Two independent onboarding validation runs hit this on their first
browser attempt and each had to guess the cause. Both were
*add-to-existing-app* journeys; the greenfield one reached for
`CopilotKitProvider` and never saw it.

## What changed

**The runtime says what happened.** `detectSingleRouteEnvelope`
recognises a POST whose JSON body carries a `method` the single-route
endpoint accepts, and the multi-route handler uses it at the one point
routing gives up. The 404 now carries a `code` and a message naming the
prop, plus a `logger.warn` so it lands in the dev-server terminal too.
Deliberately conservative — wrong verb, non-JSON, unknown method, or a
JSON POST that isn't an envelope all stay ordinary 404s, unchanged in
status and shape.

**The client stops discarding it.** All four `/info` callers (two in
`agent-registry.ts`, two in `agent.ts`) threw away the response body and
reported only the status, so a server-side diagnosis reached nobody.
They now go through `runtimeInfoError`, which folds a string `message`
from the body into the thrown error. Any future server-side diagnosis
reaches the developer for free.

**Docs.** Five pages paired a v2 multi-route handler with `<CopilotKit>`
and never mentioned the prop. Rather than a warning under a snippet that
is still wrong to copy, the snippets themselves now pass
`useSingleEndpoint={false}`, with a short callout linking to the
provider/handler mapping.

Two pages were deliberately left alone: `backend/runtime-endpoints.mdx`
already documents the pairing in full, and `cookbook/arcade.mdx` uses
`mode: "single-route"` on purpose and already explains it.
`backend/copilot-runtime.mdx` keeps its snippet as-is — it pairs with
the v1 endpoint, where the default is correct — and gains the caveat
only on its "switch to v2 handlers" note.

Option 3 in the issue (reconsidering the compat default) is **not** in
this PR.

## Testing

### Both halves connect, end to end

Real `createCopilotRuntimeHandler` + real `CopilotKitCore` configured
the way the v1 wrapper configures it — no mocks on either side:

```
code   : runtime_info_fetch_failed
message: Runtime info request failed with status 404: Received a single-route
         request envelope ({ method: "..." }) but this runtime is mounted in
         multi-route mode, so the request matched no route. If the frontend uses
         <CopilotKit> from @copilotkit/react-core/v2, pass useSingleEndpoint={false}
         — that provider defaults it to true. Otherwise mount the runtime with
         mode: "single-route" to serve this envelope.

PASS — the diagnostic reached the client
```

The server-side `logger.warn` fired in the same run, carrying `{ url,
path, method: 'info' }`.

### Unit tests

`packages/runtime` — `single-route-envelope-diagnostic.test.ts` (2
positive, 5 control):

```
 ✓ src/v2/runtime/__tests__/single-route-envelope-diagnostic.test.ts (7 tests) 26ms
      Tests  7 passed (7)
```

`packages/core` — `runtime-info-error-detail.test.ts` (2 positive, 5
control):

```
 ✓ src/__tests__/runtime-info-error-detail.test.ts (7 tests) 267ms
      Tests  7 passed (7)
```

### Mutation checks

Every new test was verified to fail when its mechanism is broken, in
both directions.

Detector forced to `return null` — the two positives die, the four
controls hold:

```
   × names useSingleEndpoint when the envelope is an info call
   × diagnoses every method the single-route envelope accepts
   ✓ leaves an ordinary unmatched route as a plain 404
   ✓ leaves a JSON POST that is not an envelope as a plain 404
   ✓ leaves an unrecognized method name as a plain 404
   ✓ does not diagnose a non-JSON POST
```

Detector forced to `return "info"` — the controls die instead, proving
they are not vacuous:

```
   ✓ names useSingleEndpoint when the envelope is an info call
   ✓ diagnoses every method the single-route envelope accepts
   × leaves an ordinary unmatched route as a plain 404
   × leaves a JSON POST that is not an envelope as a plain 404
   × leaves an unrecognized method name as a plain 404
   × does not diagnose a non-JSON POST
```

`runtimeInfoError` with the detail dropped, then with the `typeof
message === "string"` guard removed — each kills a different pair:

```
mutation: detail dropped              → 2 failed | 5 passed
mutation: accept any message field    → 2 failed | 5 passed
restored                              → 7 passed
```

### Full suites, builds, docs

| Check | Result |
|---|---|
| `packages/core` full suite | `Test Files 60 passed (60)` / `Tests 662
passed (662)` |
| `packages/runtime` full suite | `Test Files 142 passed (142)` / `Tests
2067 passed (2067)` |
| `packages/core` `tsc --noEmit` | clean |
| `packages/runtime` `tsdown` | `416 files` — build complete |
| MDX compile, 5 edited pages | all `OK` |
| pre-commit `nx run-many -t test,publint,attw` | passed across affected
projects |
| CI on `f94d1ab0` | 72 pass, 3 skipping, 0 fail |

Both suites are fully green. An earlier revision of this description
reported 6
runtime failures as pre-existing on `main`; they were not. They were
artifacts
of a worktree whose `node_modules` had been assembled by hand, and a
proper
`pnpm install` cleared all of them along with the inspector-metadata
failures
from a stale `@copilotkit/shared` dist. `main` is clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-20 10:37:40 -05:00
JYbill 61ac927bae Merge branch 'main' into fix/state-manager-run-id 2026-08-20 20:01:26 +08:00
contextablemark b0233c4eb0 chore: release monorepo v1.68.2 2026-08-20 02:19:06 +00:00
Benjamin Taylor f94d1ab0fb fix(runtime): name useSingleEndpoint when a single-route envelope hits a multi-route runtime
The v1-compatible `<CopilotKit>` provider pins `useSingleEndpoint` to `true`,
so it POSTs `{ method: "info" }` at the base path. A multi-route runtime — the
default — matches no route for that path and answered a bare `{"error":"Not
found"}`, which is indistinguishable from a wrong `basePath` or an unmounted
handler. Two independent onboarding validation runs hit this on their first
attempt and had to guess the cause.

The runtime now recognises the envelope at the one point multi-route routing
gives up, and answers the 404 with a message naming the prop, plus a
`logger.warn` so it also lands in the dev server terminal. Status and shape are
unchanged for every other miss.

That message was reaching nobody: all four `/info` callers threw away the
response body and reported only the status. They now route through
`runtimeInfoError`, which folds a string `message` from the body into the
error — so any future server-side diagnosis reaches the developer too.

Docs: five pages paired a v2 multi-route handler with `<CopilotKit>` without
mentioning the prop. Their snippets now pass `useSingleEndpoint={false}` and
link to the provider/handler mapping. `backend/runtime-endpoints.mdx` already
documents the pairing and is untouched; `cookbook/arcade.mdx` deliberately uses
single-route mode and already explains it.

Closes OSS-882

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 17:40:31 -05:00
xiaoqinvar 08f05b39f4 fix(core): preserve live message run reassignment 2026-08-18 17:28:33 +08:00
JYbill 12e89e60fa Merge branch 'main' into fix/state-manager-run-id 2026-08-15 17:48:03 +08:00
tylerslaton 1f9b60b231 chore: release monorepo v1.68.1 2026-08-14 21:05:45 +00:00
tylerslaton e6864b6bdd chore: release monorepo v1.68.0 2026-08-14 20:11:31 +00:00
Ben Taylor a3b814a041 fix(core): refresh Intelligence delegate headers before every join (#6469)
## Summary

`ProxiedCopilotRuntimeAgent` builds its `IntelligenceAgent` delegate
**once** and caches it for the proxy's lifetime, copying `headers` into
the delegate's constructor config. Nothing ever refreshed that copy, so
**a header that changed after the delegate was created never reached
`/connect` or `/run`** — for the life of the agent.

For a multi-tenant app carrying the active tenant in a header, the join
was attempted under the *previous* tenant's identity with the *new*
tenant's thread id, and the platform correctly answered
`THREAD_NOT_FOUND`. Only a full page reload cleared it, because that
rebuilds the delegate. A rotated or refreshed `Authorization` bearer has
the same exposure.

Reported by Sameday against 1.67.1 with a deterministic staging repro:

```
19:45:23.554 | /copilotkit/runtime/threads            | hdr=<tenant B> | 200
19:45:23.886 | /copilotkit/runtime/threads/subscribe  | hdr=<tenant B> | 200
19:45:23.893 | /copilotkit/runtime/agent/<id>/connect | hdr=<tenant A> | body.companyId=<tenant B> | 404
```

`/threads` carries **B** while `/connect` carries **A**, ~340ms apart in
the same switch. Not a race — a stale copy with no refresh path.

## Root cause

`setHeaders` / `applyHeadersToAgent` could not fix this: they write an
agent's `.headers`, and `IntelligenceAgent` exposed only `private
config`. `syncDelegate` *looks* like the refresh path, but its
`hasHeaders` probe is `"headers" in agent` — false for the delegate,
since `headers` is declared on `HttpAgent`, not on `AbstractAgent`. So
`config.headers` was the sole header source for Intelligence REST calls,
with no refresh path at all.

## The fix

Expose `headers` as a public accessor pair backed by `config`, and read
it in `requestJoinCredentials$`.

**The accessor is the entire fix**: it makes `hasHeaders` true, so
`syncDelegate` — which already runs on every `resolveDelegate()`, and is
preceded by `applyHeadersToAgent` in `RunHandler.connectAgent` — starts
actually refreshing the delegate before each join. No new plumbing.

Two things worth flagging for reviewers:

1. **The originally-suggested fix ("make `requestJoinCredentials$` read
live headers") does not work on its own** — and is actively harmful.
There was no live header source on the class to read: without the
accessor, `this.headers` is `undefined` and **every header is dropped**
(verified: only `Content-Type` survives). The read here goes through the
accessor for a single source of truth, not because that read carries the
fix.

2. **The setter replaces the config object rather than mutating it**,
because `clone()` shares the config reference. The join path alone would
mask an in-place write (`syncDelegate` rewrites headers just before
every join), but the credential re-acquisition inside a running pipeline
(`intelligence-agent.ts:563`) does not re-sync — so a clone's tenant
could ride out on the original's socket-error refresh. That's the same
cross-tenant leak this accessor exists to prevent.

`credentials` had the identical defect via `config.credentials`
(`hasCredentials` was false too) and gets the same treatment.

## Testing

**Unit tests (5 new, each written first and watched fail).** The pre-fix
failure is the staging symptom reproduced:

```
FAIL > sends a header changed after the delegate was created
AssertionError: expected { …(2) } to match object { 'X-Tenant': 'tenant-b' }
-   "X-Tenant": "tenant-b",
+   "X-Tenant": "tenant-a",
```

Coverage: a header changed post-construction reaches `/connect`; the
same on the `/run` path (which was independently verified broken
pre-fix, sending tenant A where B was expected); credentials likewise; a
clone's header update must not reach the original
(`IntelligenceAgent.clone()` invariant — this one fails under in-place
config mutation); and a per-thread clone and its original each send
their own tenant.

**Verified beyond the unit tests.** Because the mocked-harness result
alone doesn't prove the production wiring, I drove the real chain —
`CopilotKitCore.setHeaders` → registry → proxy → delegate → outbound
POST — in a plain Node process with no vitest and no `vi.mock`, stubbing
only `fetch` at the network boundary. Same script against the unfixed
file, then the fix:

```
BEFORE (origin/main)                      AFTER (this PR)
"headers" in delegate: false              "headers" in delegate: true
delegate.headers: undefined               delegate.headers: { X-Tenant: tenant-b }
proxy.headers after setHeaders(B):        proxy.headers after setHeaders(B):
  { X-Tenant: tenant-b }                    { X-Tenant: tenant-b }

0: POST /connect  X-Tenant=tenant-a       0: POST /connect  X-Tenant=tenant-a
1: POST /connect  X-Tenant=tenant-a  <--  1: POST /connect  X-Tenant=tenant-b  credentials=include
FAIL (stale headers)                      PASS (live headers reach /connect)
```

The "before" column reproduces the report's tell exactly:
`proxy.headers` correct at tenant B while `/connect` still sends tenant
A, through the very API the report found ineffective.

**Gates** (run in a worktree with a freshly built `@copilotkit/shared`,
since a stale dist otherwise produces 20 unrelated
`core-inspector-metadata` failures and 4 `tsc` errors):

| Gate | Result |
| --- | --- |
| `@copilotkit/core` vitest | **654 passed / 654**, 59/59 files |
| `tsc --noEmit` | clean |
| `oxlint` | 0 errors (2 warnings, both pre-existing test helpers) |
| `oxfmt` | no reformatting needed |

**Not covered:** `fetch` is stubbed, so this does not exercise a live
Intelligence gateway or a browser tenant switch — it proves the outbound
header is correct, not the platform's response to it.

## Note for whoever merges

#6450 and #6468 also touch `intelligence-agent.ts` (thread-restore work)
but neither goes near the header path, so conflicts should be textual at
worst.

## Follow-up left out of scope

Two separate pre-existing defects surfaced while verifying this one.
Neither is touched here.

**1. `credentials` passed to a `ProxiedCopilotRuntimeAgent` constructor
are dropped at registration.** `applyCredentialsToAgent` overwrites
`agent.credentials` from core unconditionally, with no per-agent
baseline — unlike `applyHeadersToAgent`, which merges over the
`agentOwnHeaders` baseline captured for exactly this reason (#5635).
Probed in a real process: an agent constructed with `credentials:
"include"` in a core with none configured reports `undefined`
immediately after registration, and every join goes out without
credentials. Identical before and after this PR, so it is not a
regression from this change — but the headers/credentials asymmetry
looks unintended, given #5433 was specifically about preserving proxied
runtime credentials.

**2. `buildRuntimeUrl` reads `config.agentId`
(`intelligence-agent.ts:770`), (`intelligence-agent.ts:770`), so
`syncDelegate`'s `delegate.agentId = routedAgentId()` is cosmetic for
the REST URL. Same root-cause class as this bug, but latent rather than
live (routing is fixed per proxy instance).

Happy to file both separately.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-13 09:12:58 -05:00
Benjamin Taylor 70545f072a test(core): correct an overclaiming comment, tighten the credentials assertion
The per-thread-clone test's comment claimed it guards the copy-on-write
setter. It does not: syncDelegate rewrites headers before every join, so
it passes even with an in-place write (verified). Say what it actually
pins — each proxy's joins carry its own tenant — and point at the
clone-invariant test that does guard the setter.

Also assert the pre-change join carried no credentials, so the
credentials test shows a transition rather than a single end state.
2026-08-13 08:15:52 -05:00
JYbill c06709aff7 Merge branch 'main' into fix/state-manager-run-id 2026-08-13 17:52:08 +08:00
Murat Sari 01c7283210 fix(core): prevent duplicate interrupt tool results (#6201) 2026-08-13 01:18:16 +02:00
Benjamin Taylor 7d1cdc15df test(core): pin the run path against stale Intelligence headers
The report names both /connect and /run. The run path reaches the
delegate through #runViaDelegate, which shares resolveDelegate with the
connect path, so the accessor fixes both — but that was inferred from the
shared call site rather than pinned. Verified failing against the
pre-fix file (sent tenant-a where tenant-b was expected).
2026-08-12 17:01:21 -05:00
Benjamin Taylor a3562c20a6 fix(core): refresh Intelligence delegate headers before every join
`ProxiedCopilotRuntimeAgent` builds its `IntelligenceAgent` delegate once
and caches it for the proxy's lifetime, copying `headers` into the
delegate's constructor config. Nothing ever refreshed that copy, so a
header that changed later never reached `/connect` or `/run` — for the
life of the agent.

`setHeaders`/`applyHeadersToAgent` could not fix it: they write an
agent's `.headers`, and `IntelligenceAgent` exposed only `private
config`. `syncDelegate` looked like the refresh path but its `hasHeaders`
probe is `"headers" in agent`, which was false for the delegate.

Multi-tenant apps that carry the active tenant in a header saw the join
attempted under the previous tenant's identity with the new tenant's
thread id, answered THREAD_NOT_FOUND. A rotated `Authorization` bearer
has the same exposure. Only a full reload cleared it.

Expose `headers` as a public accessor pair backed by `config`. The
accessor is the entire fix: it makes `hasHeaders` true, so `syncDelegate`
— which already runs on every `resolveDelegate()` — starts actually
refreshing the delegate before each join. Note that changing
`requestJoinCredentials$` to read live headers, as the report suggested,
does nothing on its own: there was no live source on the class to read,
and without the accessor `this.headers` is `undefined`, which drops every
header. It reads through the accessor here for a single source of truth,
not because that read carries the fix.

The setter replaces the config object rather than mutating it, because
`clone()` shares the config reference. The join path alone would mask an
in-place write (syncDelegate rewrites headers just before every join),
but the credential re-acquisition inside a running pipeline does not
re-sync, so a clone's tenant could ride out on the original's
socket-error refresh.

`credentials` had the identical defect via `config.credentials`
(`hasCredentials` was false too) and gets the same treatment.

Verified beyond the unit tests by driving the real chain
(`CopilotKitCore.setHeaders` -> registry -> proxy -> delegate ->
outbound POST) in a plain Node process with only `fetch` stubbed:
before, `"headers" in delegate` was false and the join after a tenant
switch still sent tenant A; after, it sends tenant B.

Reported by Sameday against 1.67.1 with a deterministic staging repro.
2026-08-12 16:36:11 -05:00
tylerslaton 10d8f43829 chore: release monorepo v1.67.1 2026-08-10 20:28:46 +00:00
onsclom 48312f4d65 chore: release monorepo v1.67.0 2026-08-10 18:32:14 +00:00
Austin Merrick b32b5539cc feat: add Inspector navigation, usage, and locked Threads (refs ENT-1173) (#6275)
## What does this PR do?

Adds the CopilotKit consumer side of ENT-1173 across Shared, Runtime,
Core, Web Inspector, and the existing Shell Docs pages.

- Defines and parses optional trusted Inspector metadata for identity,
plan, license, action, usage, and expiry. Runtime proxies it through a
private, failure-isolated route, and Core refreshes it without changing
connection state.
- Groups Inspector navigation into Threads, Agents, and Learning.
Threads renders finite, unlimited, unknown, overage, and expiring usage
states plus matching trusted plan or license actions.
- Keeps explicit `threadEndpoints` as the only authority for Thread
requests. Locked or absent capability states make no list, subscription,
detail, message, event, or state calls.
- Keeps the zero-thread video, three example Threads, detail tabs, and
guided tour in empty and locked states. General Intelligence remains the
default onboarding path; only trusted `team_self_hosted` metadata uses
self-hosted onboarding.
- Gives an active license with missing Runtime routes a short **Finish
setting up Rich Threads** state. Users can copy a safe coding-agent
prompt or open the public Runtime setup guide. The same copy control
appears in that guide, and raw Markdown/LLM views include the full
prompt.
- Keeps finite usage green below 90%, orange from 90% to the limit, and
red at or above the limit. At 90%, a trusted plan action changes from
**Manage Your Plan** to a purple **Upgrade Your Plan** without changing
its trusted URL, action kind, or telemetry contract.
- Adds a deterministic 33-state loopback lab for CopilotKit developers.
It has no production route or export, is absent from public docs and
package metadata, and is excluded from the npm tarball.

`Expiring Soon` is display-only; this PR does not enable the thread
culler. Managed Enterprise receives no manage-plan action, and Team
Self-Hosted receives no hosted plan action. Optional metadata and the
additive expiry field remain compatible across mixed producer, Runtime,
Core, and Inspector versions.

A small Channels test-only change updates fetch mocks for current
TypeScript types. It changes no Slack or Teams docs or runtime behavior.

## Related PRs and issues

- Refs
[ENT-1173](https://linear.app/copilotkit/issue/ENT-1173/ship-plg-ready-inspector-navigation-metadata-and-locked-threads)
- Producer:
[CopilotKit/Intelligence#696](https://github.com/CopilotKit/Intelligence/pull/696)

## Validation

- `@copilotkit/web-inspector`: 20 files and 372 tests passed; typecheck
and production build passed.
- Shell Docs: 57 files and 383 tests passed; lint, typecheck, and
production build passed. The build generated all 222 static pages.
- Browser checks cover the copy-prompt flow, unchanged white **Manage
Your Plan**, purple **Upgrade Your Plan**, orange 4,500/5,000 usage, and
red 5,000/5,000 usage.
- Independent review found no Critical or Important issues.
- The broader Runtime, React Native, Channels, package-quality,
compatibility, and Node-version checks from the prior pushed head remain
green.

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] I updated the relevant documentation
- [ ] "Allow edits by maintainers" is checked
2026-08-07 14:08:23 -07:00
tylerslaton b40602e698 chore: release monorepo v1.66.4 2026-08-07 01:25:14 +00:00
tylerslaton cfc5cfe727 chore: release monorepo v1.66.3 2026-08-07 00:31:47 +00:00
xiaoqinvar ed559fc4c2 fix(core): preserve fresh event run IDs after completed runs 2026-08-06 14:33:32 +08:00
xiaoqinvar 3fce5ecec4 Merge upstream main into fix/state-manager-run-id 2026-08-06 10:54:23 +08:00
David McKay 696c44244b fix(core): stop HITL continuations reusing the originating run id on the wire
#6296 preserved the logical run id across a HITL resolve by pinning the
originating id on the follow-up's agent invocation. That fixed #3456 (external
tracing saw one logical run split into two halves), but pinning it on the WIRE
made the transport treat the follow-up as a resumption of a run it had already
finished. It re-delivered that run's already-applied half — duplicating every
tool call on the message, each duplicate carrying empty arguments, since a start
event has none and the TOOL_CALL_ARGS deltas that follow are addressed to the
first copy — and the follow-up's own tool call never reached client state, so
its card never rendered.

In the reskinnable-demo banking skin that broke teach mode outright: the agent
called awaitDashboardDemonstration, the server emitted TOOL_CALL_START for it,
and the live "Recording your workflow" card never appeared, leaving no way to
finish or save the demonstration.

#6296's goal is kept, moved one layer up. The continuation is registered against
the originating id (markNextRunAsContinuation already took an expectedRunId
parameter, previously unused) and the state manager re-stamps the continuation's
events onto it. State/message association and external tracing still see ONE
logical run; the wire is simply allowed to identify the invocation honestly.
Nothing from #6296 is reverted.

core-follow-up's run-id test asserted the mechanism (both invocations carry the
same wire id), which this deliberately changes, so it now asserts the goal: the
originating id is pinned on the first invocation and the follow-up leaves it to
the transport. Its sibling assertion — the thread still knows exactly one run —
was already there and still passes untouched. A new StateManager test covers the
re-stamp directly; verified red before green by dropping the expectedRunId
lookup.

Verified in the browser against a live Intelligence stack: before, the recording
card never rendered; after, it renders with its REC indicator and I'm done /
Cancel controls. `@copilotkit/core` 58 files and `@copilotkit/react-core` 123
files pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 16:12:12 -07:00
Austin Merrick 4a5bf2b419 test(core): prove inspector expiry snapshots 2026-08-05 11:55:44 -07:00
Austin Merrick 46b692ba24 fix(inspector): drop out-of-scope expiry metadata 2026-08-05 11:55:43 -07:00
Austin Merrick 8f8d19f120 fix(inspector): clear metadata on auth changes 2026-08-05 11:55:43 -07:00
Austin Merrick 8b73765719 fix(inspector): time out optional metadata requests 2026-08-05 11:55:42 -07:00
Austin Merrick de58e30002 docs(inspector): explain optional metadata flow 2026-08-05 11:55:41 -07:00
Austin Merrick f720dabd78 feat(core): carry optional inspector metadata 2026-08-05 11:55:40 -07:00
Ben Taylor 7e502dd4a4 fix(react-core): preserve logical run identity across HITL resolve (#6296)
## Summary

Preserve the logical run ID when a legacy `useCopilotAction({
renderAndWaitForResponse })` frontend tool resolves and
`processAgentResult` starts its recursive follow-up.

The run handler binds each internal continuation handoff to the exact
follow-up invocation, cancels it when setup fails or no run starts, and
keeps the handoff out of the public `CopilotKitCore.runAgent` contract.
The public regression drives the legacy hook through its
`useHumanInTheLoop` and `useFrontendTool` path, renders the approval
control, resolves it, and verifies both agent calls use the same
generated ID.

Closes https://github.com/CopilotKit/CopilotKit/issues/3456

## Changes

- Preserve the originating ID across recursive frontend-tool follow-up
runs
- Keep the existing legacy HITL registration and response behavior
unchanged
- Add core follow-up coverage and a public `useCopilotAction` regression
- Retain the existing standard/legacy interrupt and StateManager
coverage from the earlier fix

## Test plan

- [x] `pnpm -C packages/react-core exec vitest run
src/hooks/__tests__/use-copilot-action.e2e.test.tsx`
- [x] `pnpm -C packages/core exec vitest run
src/__tests__/core-follow-up.test.ts`
- [x] `pnpm -C packages/react-core exec vitest run
src/v2/hooks/__tests__/use-interrupt.test.tsx`
- [x] `pnpm -C packages/core exec vitest run
src/__tests__/state-manager.test.ts`, 39 tests passed
- [x] `pnpm -C packages/react-core exec vitest run`, 123 files and 1475
tests passed
- [x] `pnpm -C packages/core exec vitest run`, 58 files and 625 tests
passed
- [x] `pnpm -C packages/core run check-types`
- [x] `pnpm -C packages/react-core run check-types`
- [x] `pnpm exec oxfmt --check` on all eight changed source/test files
- [x] `pnpm exec oxlint` on all eight changed source/test files, 5
pre-existing warnings and 0 errors
2026-08-05 12:38:32 -05:00
tylerslaton 53b772552f chore: release monorepo v1.66.2 2026-08-04 21:57:57 +00:00
tylerslaton c69f7e96a5 chore: release monorepo v1.66.1 2026-08-04 14:59:52 +00:00
Maximiliano Korp 5cc22a5a1f fix(runtime): preserve gateway handoff continuity 2026-08-03 15:58:19 -07:00
tylerslaton a87b77a991 chore: release monorepo v1.66.0 2026-08-03 20:14:52 +00:00
JYbill 8a172a3941 Merge branch 'CopilotKit:main' into fix/state-manager-run-id 2026-08-03 14:02:37 +08:00
BenTaylorDev 6988d5d8e2 chore: release monorepo v1.65.0 2026-08-02 22:43:24 +00:00
Rod Boev 3a8ab0a1c0 Keep continuation handoffs inert until lifecycle binding 2026-08-01 14:16:34 -04:00
Rod Boev 036f3299f5 Bind continuation state to each internal run invocation 2026-08-01 14:05:43 -04:00
Rod Boev 9272895536 Bind continuation state to each internal run invocation 2026-08-01 13:46:15 -04:00
Rod Boev c22956d009 Bind HITL continuation handoffs to their originating run 2026-08-01 13:24:55 -04:00
Rod Boev 0a7b8568d9 Keep internal HITL follow-ups out of forwarded user state 2026-08-01 12:57:54 -04:00
Rod Boev ab098f88e7 fix(react-core): preserve logical run identity across HITL resolve 2026-08-01 12:20:10 -04:00
Mike Ryan 561bf19fa6 feat(channels): add explicit identity and memory grants 2026-08-01 09:19:13 -07:00
Rod Boev 4fc17335b9 fix(react-core): preserve raw event sidecar lifecycle 2026-08-01 06:27:51 -04:00
Rod Boev 823226ebe0 feat(react-core): expose raw event metadata to feedback callbacks 2026-08-01 05:57:34 -04:00
Rod Boev f4519433ab feat(react-core): expose raw event metadata to feedback callbacks 2026-08-01 05:27:11 -04:00
tylerslaton 33b1312795 chore: release monorepo v1.64.2 2026-07-31 20:10:27 +00:00
xiaoqinvar 25406390b8 fix(core): preserve run IDs across SSE replay 2026-07-30 16:03:46 +08:00