Commit Graph

14820 Commits

Author SHA1 Message Date
Mike Ryan 62bc9df49d fix(channels): make render batches replay stable 2026-07-29 09:00:18 -07:00
Mike Ryan 87e904d822 chore(channels): remove obsolete changeset 2026-07-29 09:00:18 -07:00
Mike Ryan f84aa5ac64 fix(channels): back off render batch retries 2026-07-29 09:00:18 -07:00
Mike Ryan 35bf81fccb fix(channels): preserve frame-key message refs 2026-07-29 09:00:18 -07:00
Mike Ryan f0a9435bde test(channels-intelligence): bound delta-count latency 2026-07-29 09:00:18 -07:00
Mike Ryan ac1e51a0af fix(channels-intelligence): bound stalled render lanes 2026-07-29 09:00:17 -07:00
Mike Ryan 119f6e38d2 fix(channels-intelligence): retry immutable render batches 2026-07-29 09:00:17 -07:00
Mike Ryan f8d700c523 feat(channels-intelligence): batch managed render output 2026-07-29 09:00:17 -07:00
Sam Julien 10b87af572 docs: organize Channels guides by provider and framework (#6193)
## Summary

- Make Slack and Microsoft Teams the production-ready Channels choices
in the top provider picker, with framework-aware routes under
`/slack/...` and `/teams/...`.
- Put ten task-oriented guides inside every provider/framework journey
and remove the standalone Channels overview from navigation.
- Restore the global Channels SDK reference at `/reference/channels`,
including 34 current core, UI, state, transcript, and direct-adapter
entries.
- Add the complete CopilotKit Intelligence setup walkthrough, product
screenshot, and a stable architecture-diagram slot that Mike's final
artwork can replace in place.
- Qualify Discord and WhatsApp correctly: their direct adapters already
ship, while managed Intelligence support is coming soon.

## Why

Developers should choose their chat provider and agent framework first,
then stay in that context while they build and operate the integration.
The previous structure mixed provider guides, an extra overview layer,
and stale provider-specific reference pages, making it hard to find the
supported path or understand which behavior was managed versus
developer-operated.

This update keeps the guide journey provider-specific while returning
API material to the normal global Reference surface. It also documents
operational boundaries that matter in production instead of adding pages
for their own sake.

## How

- Reuse provider-aware MDX across Slack, Teams, and all 19 public
agent-framework integrations; the built-in agent keeps the shorter route
without a framework segment.
- Organize the sidebar into Getting started, Build, Production, and API
reference with guides for Intelligence, tools, rich and interactive
messages, commands and reactions, files, state, persistence,
transcripts, and operations.
- Pin the verified `@copilotkit/channels@0.4.0` and
`@copilotkit/runtime@1.64.1` pair and align the copy with current SDK
source plus live Intelligence behavior.
- Document managed capabilities and provider-specific realities,
including active/standby runtimes, optional hosted endpoint defaults,
output-free turn finalization, Slack manifest scopes, Teams attachment
shapes and consent, delivery acceptance semantics, and durable state
requirements.
- Preserve useful direct-adapter discoverability for Slack, Teams,
Discord, Telegram, and WhatsApp without restoring obsolete symbol pages.
- Add one-hop redirects for retired routes and cover navigation,
framework selection, raw-doc URLs, search, reference discovery, and
sitemap output.

Validation:

- Full docs suite: 51 files / 348 tests
- Typecheck
- Lint with no errors (existing baseline warnings only)
- Production build: 222 static pages
- Live HTTP checks: Slack Intelligence, Teams + Mastra files, Slack rich
messages, and direct-adapter reference all return 200
- Independent read-only correctness passes against the current Channels
SDK, Runtime, Intelligence, and every public framework setup

Linear:
https://linear.app/copilotkit/issue/OSS-615/channels-sdk-documentation-audit
2026-07-29 08:50:10 -07:00
Markus Ecker 2d7f188b29 feat(vue): mirror React's useAgent thread scoping, remove thread cloning
Ports PR #6141's React contract to Vue and deletes the per-thread cloning Vue
used instead.

Cloning is gone: cloneForThread, getOrCreateThreadClone, getThreadClone and the
module-level globalThreadCloneMap. Those clones were reachable only through a
WeakMap, components had to look them up to find the agent actually in use, and
nothing tied a clone's lifetime to the scope that created it.

In its place, the same two-shape contract React now has:

  useAgent()                                       // shared registry agent
  useAgent({ agentId })                            // shared registry agent
  useAgent({ agentId, runtimeAgentId, threadId })  // private proxied agent

UseAgentProps becomes a base plus a two-branch union, so every partial set —
{ agentId, threadId }, { agentId, runtimeAgentId }, { runtimeAgentId, threadId }
— is a compile error, with the same three runtime guards and the same messages as
React for callers TypeScript doesn't reach. Vue's branches take
MaybeRefOrGetter where React takes plain values; the shapes are otherwise
identical.

Thread resolution mirrors React exactly: an explicit `threadId` prop wins,
otherwise the chat configuration's thread gated on `hasExplicitThreadId`, so a
ThreadsProvider-minted placeholder UUID never overwrites the agent's own.

Two Vue-specific details, both load-bearing:

- The pin watcher's first source is `() => agent.value`, not `agent`. Vue sets
  `forceTrigger` when any array watch source is a shallow ref, which would re-run
  the pin on every `triggerRef(agent)` — i.e. every streamed message — and re-pin
  the inherited thread over one CopilotChat had deliberately set for the chat it
  renders. Two suites cover this ("uses the explicit agentId and threadId over
  inherited configuration").
- CopilotChat assigns `agent.threadId` inside its /connect watcher rather than a
  separate one, because CopilotKitCore.connectAgent reads that field
  synchronously to decide whether a restore is fresh; a later assignment would
  let /connect address the previous thread. React does the same, in the same
  place.

CopilotChatMessageView resolves the registry agent directly instead of consulting
the clone map, and reads `copilotkit.agents` so it recomputes when the registry
changes.

Tests: use-agent-thread-isolation.test.ts covered clone semantics that no longer
exist; use-agent-thread-pinning.test.ts replaces it with the new invariants —
one instance per agentId, config-thread pinning gated on explicitness, and all
three all-or-nothing guards. Four component suites used getThreadClone purely as
a lookup and now read from the registry. MockMCPProxyAgent recorded addMessage
only inside its clone() override, so those assertions passed only because
cloning existed; the recording moves onto the class. clone() itself is left
intact everywhere, since CopilotKitCore's SuggestionEngine still clones agents
(packages/core/src/core/suggestion-engine.ts).

Call-site enumeration: cloneForThread and getOrCreateThreadClone were
module-private, zero references. getThreadClone and globalThreadCloneMap were
used by CopilotChatMessageView (rewritten) and 4 test files (retargeted); zero
remain, including in prose. useAgent's other callers, use-capabilities and
use-interrupt, pass `{ agentId }` only and match the unscoped branch unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 16:40:31 +02:00
Tyler Slaton 70d5a1636c fix(react-core): honor threadId prop on useAgent (#6141)
## Problem

`UseAgentProps` (`packages/react-core/src/v2/hooks/use-agent.tsx`)
exposed only `{ agentId?, updates?, throttleMs? }` — there was **no
`threadId`**. Yet the shipped V2 React Native demo calls:

```ts
const { agent } = useAgent({ agentId: "default", threadId });
```

(`examples/v2/react-native/demo/src/ChatScreen.tsx`)

Because the prop didn't exist on the type, it was **silently ignored**.
The demo's `threadId` state — and its "New Chat" reset
(`setThreadId(generateThreadId())`) — never reached the agent. The demo
has no `<CopilotChatConfigurationProvider>` in its tree (see `App.tsx`),
which was the *only* source the hook read threadId from, so the agent
ran under its own auto-minted UUID the whole time. A misleading API: the
demo advertised a supported prop that did nothing.

## Fix

Accept an optional `threadId` on `UseAgentProps` and honor it.
Resolution precedence:

1. An explicit `threadId` prop wins — lets headless callers (e.g. React
Native) scope the run to a thread with no chat-configuration provider in
the tree.
2. Otherwise fall back to the surrounding chat configuration's threadId,
gated on `hasExplicitThreadId` exactly as before.

The threadId still lands on `agent.threadId`, which
`ProxiedCopilotRuntimeAgent` uses to address `/agent/run`,
`/agent/connect`, and `/agent/stop`.

## Backward compatibility

Fully backward compatible: `threadId` is optional, and when omitted the
behavior is byte-for-byte unchanged (config-sourced,
`hasExplicitThreadId`-gated). No demo change is needed — the RN demo's
existing `useAgent({ agentId, threadId })` call now works as it always
appeared to.

## Tests

Extends the existing threadId-propagation contract test
(`packages/react-core/src/__tests__/threadid-propagation.contract.test.tsx`)
with the prop path:

- honors an explicit `threadId` prop with **no**
`CopilotChatConfigurationProvider` (the RN demo scenario)
- prefers the `threadId` prop over the chat configuration's threadId
- re-syncs `agent.threadId` when the prop changes

The pre-existing config-sourced invariants remain covered and unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-29 07:23:58 -07:00
Maxim 50e0f939b9 fix(a2ui-renderer): hoist the export test's entry import out of the test body
Follow-up to 85223276fa, which fixed the ordering bug but introduced a timing
one. Importing the source entry inside the test body meant the dynamic import
transformed the whole renderer graph (lit, markdown-it, zod) while vitest's 5s
default testTimeout was running. On a warm local cache that took ~890ms and
passed; CI, cold, took 5039ms and failed:

  × filterCatalog package export > is reachable from the package entry 5039ms
    → Test timed out in 5000ms.

Moving the import to module scope pays that cost during collection, which is
not bounded by testTimeout, and leaves the assertion synchronous.

Verified under CI-like conditions this time — both vite caches moved aside AND
dist/ removed: 16/16 pass, and the test file goes from 5059ms to 4ms with the
graph cost showing up as collect 3.57s instead.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-29 16:11:20 +02:00
Markus Ecker 4c2dd14f40 Merge branch 'main' into fix/useagent-threadid 2026-07-29 16:06:33 +02:00
Alem Tuzlak d4314dd66a fix(showcase): unbreak gen-ui-agent and declarative-json-render on a real LLM (#6228)
## What does this PR do?

Two `built-in-agent` demos were broken against a real model while their
D5/D6 rows stayed **green** — `d5:built-in-agent/gen-ui-agent`,
`d5:built-in-agent/byoc` and both `e2e:` rows all pass. Neither failure
is reachable under aimock, so the fixtures could never have caught them
(`showcase/GOTCHAS.md` #8). Both root causes were confirmed against the
live OpenAI API.

### 1. `gen-ui-agent` stopped mid-plan on every run

`@tanstack/ai`'s `chat()` applies `maxIterations(5)` when no
`agentLoopStrategy` is passed (`@tanstack/ai@0.35.0`,
`src/activities/chat/index.ts`: `config.params.agentLoopStrategy ||
maxIterationsStrategy(5)`). Nothing errors when the budget runs out —
the run just ends. `GEN_UI_AGENT_PROMPT` scripts **7** `set_steps` calls
(1 initial + in_progress/completed per step × 3) plus a closing message,
so the walk died two calls short with the last step pinned at `pending`
and no narration.

Captured from the staging SSE stream:

```
TOOL_CALL_START: 5,  STATE_DELTA: 5,  TEXT_MESSAGE_*: 0
call 5 (final): step1 completed, step2 completed, step3 pending
```

Reproduced locally with the real model, the real prompt and the real
`set_steps` tool:

| budget | `set_steps` calls | final statuses | narration |
|---|---|---|---|
| default (5) | 5 | `completed, completed, pending` | **none** |
| `maxIterations(25)` | 7 | `completed, completed, completed` | 333
chars |

Every demo factory now passes the shared `DEMO_AGENT_LOOP_STRATEGY` (25
— several times the longest scripted walk, still bounded, since each
iteration is a model call). The two non-streaming tool-free `chat()`
calls (`subagent-tools`, `a2ui-factory`'s secondary designer) keep the
default: they have no loop to exhaust.

### 2. `declarative-json-render` rendered nothing at all

`RUN_STARTED` → `RUN_FINISHED`, zero events between, no console error,
no error banner.

`text.format: { type: "json_object" }` has a server-side precondition
that the word "json" appear in the request's `input`. The adapter sends
`systemPrompts` as `instructions` and only `messages` as `input`, so
with the JSON directive living solely in `SYSTEM_PROMPT` the API
rejected every single run:

```
400 Response input messages must contain the word 'json' in some form
    to use 'text.format' of type 'json_object'.   (param: input)
```

The directive now rides in `messages` — as `role: "user"`, because
`TanStackChatMessage` admits only `user | assistant | tool` and the
runtime deliberately hoists system messages into `systemPrompts`, the
very half that is not input. It is invisible in the UI (the chat renders
from AG-UI events, not from what the backend sends the model).
`json_object` enforcement is kept; verified live that the run then
streams a complete, `JSON.parse`-able spec.

That 400 was **invisible** because the hand-rolled converters forward a
whitelist of chunk types and dropped `RUN_ERROR` — every one except
`reasoning-factory`. The `type: "tanstack"` factories were already fine
(the runtime's `convertTanStackStream` rethrows, `tanstack.ts:419`), so
the four `type: "custom"` converters now call the shared
`throwOnRunError`. This is why a fleet-wide silent failure went
unnoticed, and it is fixed independently of the JSON-mode bug.

### 3. The progress card stopped claiming completion it doesn't have

`InlineAgentStateCard` printed `All ${total} steps complete` whenever
`status === "complete"`, ignoring the step data — so a truncated run
announced completion above a list that visibly showed step 3 unstarted,
which is what made an agent stopping early read as a UI glitch. The
wording now derives from the steps (`describeProgress`, extracted as a
pure function so it is testable without a DOM), a stalled run says so,
and the check-mark icon is gated on the data too.

## Verification

- 18 new unit tests, all green: agent-loop budget sized off the prompt
itself, `throwOnRunError`, the `json_object` input precondition +
converter behaviour, and the card's wording across running / done /
stalled / empty
- `oxlint` 0 warnings 0 errors on the changed dirs; `oxfmt` clean
- Live end-to-end runs against real OpenAI for both root causes (tables
above)
- Pre-existing and unrelated: this integration is not a pnpm-workspace
member, so `tsc --noEmit` here reports 73 errors from version skew in a
standalone install (`gpt-5.4` outside the pinned adapter's model union,
`@ag-ui/client` not exposed as a direct dep). Both hit untouched files
and untouched lines; my two real type errors were fixed. CI runs vitest
only in `showcase/scripts` and `showcase/harness`, so these tests are
developer-local, same as the pre-existing `tanstack-factory.test.ts`
beside them.

## Related PRs and Issues

- Sibling real-LLM-vs-aimock fix: #6226
- Same class as #6224 (ms-agent .NET real-LLM demo defects)

## Checklist

- [x] I have read the Contribution Guide
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation (`showcase/GOTCHAS.md` — two new entries)
- [x] "Allow edits by maintainers" is checked

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-29 15:54:47 +02:00
Alem Tuzlak bcf43311d6 fix(showcase/ms-agent-dotnet): surface shared-state-read-write chat replies
Deterministic pill replies (greet / remember / weekend) were emitted as
AgentRunResponseUpdate with Contents only and no Role. The AG-UI .NET host
maps assistant text into TEXT_MESSAGE_* only when Role == Assistant, so the
client showed empty chat while the server still ran.

Set Role = ChatRole.Assistant on those updates, harden LatestUserText via
message.Text, and broaden pill matching for the staging suggestion copy.
2026-07-29 15:50:56 +02:00
renovate[bot] fce904deaa chore(deps): update docker/login-action action to v4.6.0 (#6229)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [docker/login-action](https://redirect.github.com/docker/login-action)
| action | minor | `v4.5.2` → `v4.6.0` |

---

### Release Notes

<details>
<summary>docker/login-action (docker/login-action)</summary>

###
[`v4.6.0`](https://redirect.github.com/docker/login-action/compare/v4.5.2...v4.6.0)

[Compare
Source](https://redirect.github.com/docker/login-action/compare/v4.5.2...v4.6.0)

</details>

---

### Configuration

📅 **Schedule**: (in timezone America/Los_Angeles)

- Branch creation
  - "before 9am every weekday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/CopilotKit/CopilotKit).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
2026-07-29 13:50:49 +00:00
David McKay ce0576d7d1 Merge branch 'main' into fix/useagent-threadid 2026-07-29 06:50:17 -07:00
Alem Tuzlak 62d1dc1619 fix(showcase/ms-agent-dotnet): ground declarative-gen-ui charts in sales data
Secondary A2UI design call (injectA2UITool:false path) never saw frontend
App Context, so PieChart/BarChart shipped with empty data arrays ("No data
available") and DataTables rendered blank rows while Metrics invented
placeholders.

Bake the Vantage Threads Q2 dataset + composition rules (from sales-context.ts)
and non-empty chart/table examples into DeclarativeGenUiDesignSystemPrompt.
Coerce string chart values to numbers. Tighten outer agent to not dump the
dashboard as prose.
2026-07-29 15:47:56 +02:00
Maxim 85223276fa fix(a2ui-renderer): stop the filterCatalog export test depending on its own dist
The export test self-imported the package by name:

  const mod = await import("@copilotkit/a2ui-renderer");

which resolves through node_modules to dist/. Nothing guarantees dist/ exists
when the test runs: nx.json sets test.dependsOn to ["^build"], and the caret
means *dependencies'* builds, not the project's own. Under `nx run-many` the
scheduler ran a2ui-renderer:test before a2ui-renderer:build, so the import
failed with "Failed to resolve entry for package @copilotkit/a2ui-renderer".
Standalone runs passed only because an earlier build had left dist/ populated.

Nx reported the task as flaky, which it was not — it was order-dependent. The
same root cause failed check-types, since tsc resolves the dynamic import to
dist/index.d.mts.

Importing the source entry instead keeps what the test is actually for (that
src/index.ts -> react-renderer/index.ts -> ./filter-catalog re-export chain is
intact, so callers can import filterCatalog) while making it hermetic. The
package.json "exports" mapping is already covered by this package's publint and
attw targets.

Verified with dist/ deleted: 16/16 pass and check-types is clean. Both
`nx run-many -t test` and `-t check-types` across core, react-core, runtime,
web-inspector and a2ui-renderer now pass with --skip-nx-cache.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-29 15:36:14 +02:00
github-actions[bot] 66b6d3fef3 style: auto-fix formatting 2026-07-29 13:33:01 +00:00
Alem Tuzlak 5c89395dc8 fix(showcase): unbreak gen-ui-agent and declarative-json-render on a real LLM
Two built-in-agent demos were broken against a real model while their D5/D6
rows stayed green, because aimock exercises neither failure. Both root causes
were confirmed against the live OpenAI API.

gen-ui-agent stopped mid-plan on every run. `@tanstack/ai`'s `chat()` applies
`maxIterations(5)` when no `agentLoopStrategy` is passed, and nothing errors
when the budget runs out — the run just ends. GEN_UI_AGENT_PROMPT scripts 7
`set_steps` calls (1 initial + in_progress/completed per step x 3) plus a
closing message, so the walk died two calls short with the last step pinned at
`pending` and no narration. Reproduced with the real model and the real prompt:

  default budget -> 5 calls, "completed, completed, pending", no message
  maxIterations(25) -> 7 calls, all completed, 333-char summary

Every demo factory now passes the shared DEMO_AGENT_LOOP_STRATEGY (25 —
several times the longest scripted walk, still bounded). The two non-streaming
tool-free `chat()` calls keep the default: they have no loop to exhaust.

declarative-json-render rendered nothing at all: RUN_STARTED -> RUN_FINISHED,
no events, no console error, no banner. `text.format: { type: "json_object" }`
has a server-side precondition that the word "json" appear in the request
`input`, but the adapter sends `systemPrompts` as `instructions` and only
`messages` as `input` — so with the JSON directive living solely in
SYSTEM_PROMPT the API rejected every run with

  400 Response input messages must contain the word 'json' in some form to
      use 'text.format' of type 'json_object'.   (param: input)

The directive now rides in `messages` (as `user`, since TanStackChatMessage
admits no `system` role and the runtime hoists system messages into
systemPrompts — the half that is not input). json_object enforcement is kept;
verified live that the run then streams a complete, JSON.parse-able spec.

That 400 was invisible because the hand-rolled converters forward a whitelist
of chunk types and dropped RUN_ERROR — every one except reasoning-factory. The
`type: "tanstack"` factories were fine (the runtime's converter rethrows), so
the four `type: "custom"` converters now call the shared throwOnRunError.

Also: the gen-ui-agent progress card announced "All N steps complete" whenever
the RUN ended, ignoring the step data, so a truncated run read as a UI glitch
instead of an agent that stopped early. The wording is now derived from the
steps (`describeProgress`, extracted pure so it is testable without a DOM) and
a stalled run says so.

Both gotchas recorded in showcase/GOTCHAS.md.
2026-07-29 15:30:37 +02:00
renovate[bot] 4875d6d1f2 chore(deps): update docker/login-action action to v4.6.0 2026-07-29 13:28:39 +00:00
Maxim fa40e0424b Merge remote-tracking branch 'origin/blitz/glass-inspector/integration' into blitz/glass-inspector/integration 2026-07-29 15:28:16 +02:00
Alem Tuzlak 7030ea7b0f fix(showcase): settle mcp-apps D5/D6 on the full iframe cascade (#6226)
## What does this PR do?

Fixes a fleet-wide false red on `mcp-apps` D5/D6: red on all 18
integrations that support the feature since `first_failure_at`
2026-07-28 23:03Z, while the demos rendered correctly by hand.

**Root cause.** The `completeOnMount` gate added in d70d48a561 named the
`mcp-app-iframe` testid, which only Angular's `copilot-mcp-apps-widget`
declares. `react-core` and `vue` build the sandbox iframe imperatively
(`document.createElement("iframe")`) with no testid, so the settle gate
could never be satisfied — every React/Vue integration timed the turn
out at 30s with `reason=surface-missing` and never reached
`assertIframePresent`, whose `iframe[sandbox]` fallback would have
passed. `crewai-crews` and `langroid` stayed green only because they
skip the feature (`errorClass: "skipped-incapable"`).

Verified against live staging (`showcase-built-in-agent-staging`, after
clicking the "Sketch a system diagram" pill):

```
oldGate_testIdOnly: 0     <- what the probe waited for
newGate_cascade:    1     <- the surface that was there all along
allIframes: [{ sandbox: "allow-scripts allow-same-origin allow-forms", testid: null, hasSrcdoc: true }]
```

**Fixed on both sides of the contract:**

1. **Product** — `react-core` and `vue` `MCPAppsActivityRenderer` now
set `data-testid="mcp-app-iframe"` and `title="Interactive MCP
application"` on the host-created iframe, matching Angular. Pinned by a
new test in each package, so dropping the attribute fails in the package
that owns it rather than silently reddening the fleet a day later.

2. **Harness** — `completeOnMount` accepts CSS `selectors` alongside
`testIds`, so the probe settles on the cascade its own module doc and
assertion already declare:

   ```ts
completeOnMount: { selectors: ['[data-testid="mcp-app-iframe"],
iframe[sandbox]'] }
   ```

`querySelectorAll` unions comma-separated branches, so one entry
expresses "any conforming form of this surface" while the
conjunctive-across-entries and `minNewMounts` delta semantics stay
exactly as before; `testIds: ["x"]` is now sugar for `selectors:
['[data-testid="x"]']`, so every other probe is untouched. This half
matters on its own: the integrations pin
`@copilotkit/react-core@1.61.2`, so a testid-only fix would leave 18
cells red until a release plus a fleet redeploy.

Also: a `completeOnMount` spec naming no surface now throws instead of
burning the whole turn budget and reporting a misleading
`surface-missing`. The trap is recorded in `showcase/GOTCHAS.md` next to
the sibling `copilot-assistant-message` testid gotcha.

## Verification

- harness `conversation-runner.test.ts` + `d5-mcp-apps.test.ts` —
101/101, including new red-green pairs: a `selectors` cascade greens, a
never-mounting cascade still reds `surface-missing`, a leftover-only
surface still reds, an empty spec fails loud
- `@copilotkit/vue` `MCPAppsActivityRenderer.test.ts` — 6/6
- `@copilotkit/react-core` `MCPAppsActivityRenderer.e2e.test.tsx` —
17/17
- `oxfmt` clean, `check-types` clean on both packages
- Pre-existing and unrelated (fail identically on an untouched worktree
on Windows): harness `typecheck` wants the gitignored generated
`showcase/shell/src/data/frontend-catalog.json`; 6 `src/probes` tests
assert POSIX path separators

## Related PRs and Issues

- Regressed by #6212-era commit d70d48a561 ("test(showcase): add
deterministic Angular parity audit")

## Checklist

- [x] I have read the Contribution Guide
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation (`showcase/GOTCHAS.md`)
- [x] "Allow edits by maintainers" is checked

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-29 15:27:16 +02:00
Maxim 1e575233e6 test(banking): make the memory-recall e2e approval loop actually completable
The approval loop could never pass, independent of the demo's behavior:

  for (let step = 0; step < 4; step++) {
    const approve = page.getByRole("button", { name: /^approve$/i });
    await approve.first().click({ timeout: 30_000 }).catch(...)
  }

Two compounding problems. The recall path emits at most three HITL cards
(openPolicyException -> finalizePolicyException -> approveTransaction) but the
loop demanded four, so the last iteration always waited on a card that never
arrives. And the per-click timeout (30s) equalled the whole test budget
(playwright.config.ts sets no `timeout`, so Playwright's 30s default applied),
so the first miss consumed the entire test and the `.catch()` fallback to the
other APPROVE_LABELS was unreachable dead code.

Now: poll every label for the next visible approve control, treat "no card
left" as flow completion rather than a timeout, keep a runaway guard that is
explicitly not the expected card count, and give the test a budget that can
actually hold one agent turn plus the closing server poll.

Confirmed against a local run (aimock + the docker Intelligence stack): the
agent recalls the procedure, files the EXC-BOARD-APPROVED exception, and
approves the charge, and the "Record a workflow?" card never appears. The
header's "verify on first green run" notes are updated to record what that
run settled and what it did not.

The spec still fails at its closing assertion: PUT /api/v1/transactions/t-3
{status:"approved"} keeps returning 422, i.e. store.hasApprovedException() is
false, so the over-limit gate is never lifted even though the (fixture-scripted)
agent text claims it was. That is pre-existing and out of scope here — this PR
touches no part of the approval path (lib/store, the exceptions/transactions
routes, copilot-context, components/wow are all untouched). Left failing rather
than skipped so it stays visible.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-29 15:27:08 +02:00
lukasmoschitz 20cb3ab3a6 fix(showcase): align langgraph-typescript to langgraph-python north star (#6196)
## Summary

Brings the **langgraph-typescript** showcase integration to D6 parity
with the north-star **langgraph-python** (OSS-583). The frontend + demo
set were already aligned; this PR fixes the behavior gaps so the D6 grid
is honest.

**Final local D6: 39/39 green** (all cells the north star wires),
verified serially from the harness worker logs. Two of the fixes were
genuine TypeScript-runtime bugs that aimock's scripted replay had masked
as "green".

## Fixes

| Cell | Root cause | Fix |
|---|---|---|
| gen-ui-open, gen-ui-open-advanced | stale `turnIndex:0` on leg-1
tool-call fixtures → turnIndex-relaxed re-serve loop
(`done-signal-missing`) | `turnIndex:0` → `hasToolResult:false` (mirror
LGP) |
| reasoning-display | `@langchain/openai@1.4.4` streaming Responses
converter collapses reasoning + answer to the same content-block index →
answer swallowed (`text-unstable`) | `disableStreaming:true` (forces the
non-streaming converter → separate blocks); documented streaming
trade-off in PARITY_NOTES |
| tool-rendering | langchain-js streamed-chunk reassembly leaves a
tool-call-with-content only under `additional_kwargs.tool_calls` →
`shouldContinue` routes to `__end__`, no card |
`normalizeAssistantMessage()` promotes it to a clean `AIMessage` |
| frontend-tools-async | stale bare `turnIndex:0` duplicate fixture →
re-emit loop | remove the stale fixture (same class is red on LGP too —
flagged) |
| a2ui-recovery | fixture prompt drift (still LGP's prompt) + inner
`render_a2ui` sub-agent invoked config-less so `x-test-id` isn't
forwarded → flaky heal | retarget prompt to the
langgraph-typescript-unique one + `wrapModelCall`/`wrapToolCall` + ALS
header forwarding (mirror mastra) |
| multimodal | `@ag-ui/langgraph` collapses every attachment to an
`image_url` data-URL; `rewritePart` had no `image_url` branch → a PDF
was forwarded as an image → OpenAI 400 | add an `image_url` branch
routing on the data-URL MIME (image → pass through; PDF → extract text
via `pdf-parse`), mirroring langgraph-python |

## Verification
- D6 run serially against aimock (real durations from
`showcase-harness-pool-worker-1`, not the CLI's "0.0s"); the two
previously-flaky cells (frontend-tools-async, a2ui-recovery) verified
with 4–6 consecutive green runs.
- multimodal PDF upload + the fixed cells confirmed live against real
OpenAI.

## Known items (documented in `showcase/GOTCHAS.md`, out of this PR's
scope)
- **mcp-apps Excalidraw** is a masked-green cell: `gpt-4o-mini` (kept,
D6-green) emits malformed Excalidraw `create_view` JSON live → black
canvas. `gpt-5.4` fixes it live but reds aimock D6, because the **TS
MCP-Apps middleware doesn't act on aimock's replayed responses-path
tool-call** (fixture is byte-identical to LGP; LGP's Python runtime
mounts the iframe). The real fix is a TS-runtime/`@copilotkit/runtime`
change + then gpt-5.4 — follow-up.
- **multimodal** needs the image built with `git lfs pull` (its sample
attachments are LFS-tracked and baked, not mounted); a build without LFS
ships pointers and reds it. Build-layer follow-up.
- **frontend-tools-async** stale fixture is fleet-wide — the same
deletion is needed on langgraph-python (its D6 is red for the same
reason).

## Scope
Only `integrations/langgraph-typescript/`, its aimock fixtures, and
`showcase/GOTCHAS.md`. langgraph-python (the north star) was not
touched.
2026-07-29 14:57:04 +02:00
Tyler Slaton a130dfc430 fix: remove all changesets (#6230)
Recently we made a few commits that let in some changesets. As a result,
agents now frequently try to add them to every change that gets made to
CopilotKit. Likely this was just an old branch and review didn't catch
them getting merged in.

Immediate remediation is to just remove the folder and make this commit
message so future agents can find the decision in commit history.
2026-07-29 05:48:20 -07:00
Lukas Moschitz 3f0a7bda05 fix(showcase/lgt): copy manifest.yaml into runtime image
The x-pathname middleware added in this branch activates layout.tsx's
request-time readFileSync(cwd/manifest.yaml) in generateMetadata. Without
the manifest in the runner stage, every /demos page 500s with ENOENT once
middleware sets the header. Mirrors langgraph-python's Dockerfile and
satisfies scripts/__tests__/runtime-manifest-copy.test.ts.
2026-07-29 14:46:50 +02:00
Tyler Slaton 1e5ba689e0 fix: remove all changesets
Recently we made a few commits that let in some changesets.
As a result, agents now frequently try to add them to every
change that gets made to CopilotKit. Likely this was just an
old branch and review didn't catch them getting merged in.

Immediate remmediation is to just remove the folder and make
this commit message so future agents can find the decision
in commit history.

Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-07-29 08:46:22 -04:00
Lukas Moschitz f1513e3554 docs(showcase/lgt): fix reasoning-agent fallback-model comment (gpt-5-mini) 2026-07-29 14:34:19 +02:00
Lukas Moschitz 3100b3ea80 docs(showcase/lgt): fix recovery-agent ALS-store comment (wrapModelCall, not beforeAgent) 2026-07-29 14:34:19 +02:00
Lukas Moschitz aa685b3957 fix(showcase/lgt): stop mcp-apps route leaking error message/stack to client
The mcp-apps POST catch block returned the raw error message and stack
to the client and logged nothing server-side, leaking internal paths and
library versions to anyone who could hit /api/copilotkit-mcp-apps. Mirror
the sibling copilotkit/route.ts hardening: log full details server-side
under a randomUUID correlation id and return only the id plus a generic
message with status 500.
2026-07-29 14:34:19 +02:00
Lukas Moschitz b1838b9de6 fix(showcase/lgt): add x-pathname middleware for per-demo titles (LGP parity) 2026-07-29 14:34:19 +02:00
github-actions[bot] 12ff61f74b style: auto-fix formatting 2026-07-29 11:40:41 +00:00
Lukas Moschitz 8f6123a5ec Merge remote-tracking branch 'origin/main' into lukas/oss-583-align-langgraph-typescript-showcase-demos-and-code
# Conflicts:
#	showcase/GOTCHAS.md
2026-07-29 13:38:42 +02:00
Lukas Moschitz 5683528f09 docs(showcase): document mcp-apps Excalidraw masked-green (gpt-4o-mini vs gpt-5.4)
mcp-apps is aimock-green but live-degraded: gpt-4o-mini emits malformed Excalidraw
create_view elements JSON (stray trailing }) -> MCP JSON.parse fails -> black
canvas live. gpt-5.4 fixes it live but reds aimock D6 because the TS MCP-Apps
middleware doesn't act on aimock's REPLAYED responses-path create_view tool call
(never mounts the iframe; fixture is byte-identical to LGP, LGP's Python runtime
mounts it — so TS-runtime-specific, not a fixture issue). Kept gpt-4o-mini to hold
D6 green; the real fix is a TS MCP-Apps-middleware/@copilotkit runtime change +
then gpt-5.4. Flagged as follow-up.
2026-07-29 13:30:15 +02:00
Lukas Moschitz 72ad5396c7 fix(showcase): langgraph-typescript multimodal handles PDF attachments (no 400)
The @ag-ui/langgraph converter collapses EVERY attachment (image and document)
into a LangChain image_url data-URL, so a PDF reached rewritePart as an
image_url part and hit neither the image nor document branch -> passed through
unchanged -> sent to gpt-4o as an image -> OpenAI 400 'Invalid MIME type. Only
image types are supported.' (The existing document-branch pdf-parse code was
dead — the part never arrives as 'document'.)

Add an image_url branch to rewritePart that routes on the data-URL MIME (mirrors
langgraph-python's multimodal_agent): image/* passes through unchanged; any
non-image (application/pdf) is flattened to text via the existing pdf-parse path
instead of being forwarded as an image. Source-only, no dep/model change.

multimodal D6 still green (PNG path unchanged); PDF upload verified live (text
extracted, no 400).
2026-07-29 13:30:15 +02:00
Alem Tuzlak ef7eae5136 fix(showcase/ms-agent-dotnet): Instructions wiring + hashbrown/json-render/gen-ui/state demos (#6227)
## Summary

Fixes more **ms-agent-dotnet** (Agent Framework) staging failures
against a real LLM.

### Root cause (load-bearing)

`ChatClientAgent` ctor is `(chatClient, instructions, name, description,
tools, …)`.

Almost every agent in this integration passed the system prompt as
**`description:`** (metadata only). The model received **null
instructions**, so:

| Demo | Symptom |
|------|---------|
| shared-state-read-write | Pills appear to do nothing / no set_notes |
| declarative-hashbrown | Empty — frontend JSON parser rejects prose |
| declarative-json-render | Wall of text instead of rendered UI |
| declarative-gen-ui | Wall of text + invented `DashboardCard` on later
pills |

### Fixes

1. **Global**: `description:` → `instructions:` for every
ChatClientAgent system prompt in `ms-agent-dotnet/agent`.
2. **Hashbrown + json-render**: also set `ChatResponseFormat.Json` (same
contract as langgraph-python's `response_format=json_object`).
3. **declarative-gen-ui**: catalog-specific secondary design prompt
(Card, not DashboardCard/FlightCard) + stricter outer agent (always call
`generate_a2ui`, one short sentence).
4. **shared-state-streaming**: add feature to `manifest.yaml`
`features:` so the shell no longer shows **Backend fixture unavailable**
for a demo that is already wired end-to-end.

### shared-state-streaming note

You *were* supposed to be able to open that link if the feature is
supported — the page existed under `demos/` but was missing from
`features:`, so the shell treated it as a non-runnable cell. That is
fixed. (D6 fixture content for this slug is still thin vs LGP; live LLM
path is the product path.)

## Test plan

- [x] `dotnet test` SharedStateAgent.Tests 79/79 (Docker SDK 9)
- [ ] Staging after deploy:
- [ ] `/react/ms-agent-dotnet/shared-state-read-write/preview` — all
three pills respond; Remember something updates notes
- [ ] `/react/ms-agent-dotnet/shared-state-streaming/preview` — cell
loads (not fixture-unavailable); document streams
- [ ] `/react/ms-agent-dotnet/declarative-hashbrown/preview` — pills
paint metrics/charts
- [ ] `/react/ms-agent-dotnet/declarative-json-render/preview` — pills
paint MetricCard/charts not raw text
- [ ] `/react/ms-agent-dotnet/declarative-gen-ui/preview` — all four
pills paint A2UI without DashboardCard error / wall of text
2026-07-29 13:08:06 +02:00
Alem Tuzlak f57151990f fix(showcase/ms-agent-dotnet): wire system prompts to Instructions + demo repairs
Root cause across nearly every ChatClientAgent: system prompts were passed as
`description:` (agent metadata) instead of `instructions:` (the actual system
message). ChatClientAgent(instructions, name, description, …) therefore ran
with null instructions, so models ignored tool guidance and BYOC JSON demos
emitted prose.

Fixes reported staging failures:
- shared-state-read-write pills: instructions now reach the model + stronger set_notes guidance
- declarative-hashbrown / declarative-json-render: instructions + ChatResponseFormat.Json (LGP parity)
- declarative-gen-ui: catalog-specific design prompt (no DashboardCard), stronger outer agent
- shared-state-streaming: feature was demo-only in the manifest → shell "Backend fixture unavailable"; added to features

Verified: unit suite 79/79 in Docker SDK 9.
2026-07-29 13:00:08 +02:00
Alem Tuzlak 9d8916a9d9 fix(showcase): settle mcp-apps D5/D6 on the full iframe cascade
The `completeOnMount` gate added in d70d48a561 named the `mcp-app-iframe`
testid, which only Angular's `copilot-mcp-apps-widget` declared. react-core
and vue build the sandbox iframe imperatively with no testid, so every
React/Vue integration timed the turn out at 30s with
`reason=surface-missing` and never reached `assertIframePresent` — whose
`iframe[sandbox]` fallback would have passed. D5 + D6 `mcp-apps` went red on
all 18 integrations that support the feature (first_failure_at 2026-07-28
23:03Z) while the demos rendered correctly by hand.

Fixed on both sides of the contract:

- react-core and vue now set `data-testid="mcp-app-iframe"` and a `title` on
  the host-created iframe, matching Angular. Pinned by a test in each package.
- `completeOnMount` accepts CSS `selectors` alongside `testIds`, so the probe
  settles on the same cascade its module doc and assertion already use
  (`[data-testid="mcp-app-iframe"], iframe[sandbox]`). A comma-joined entry is
  one conjunctive surface whose branches `querySelectorAll` unions, so the
  delta/`minNewMounts` semantics are unchanged and `testIds` is now sugar for
  the equivalent selector. This half greens the fleet on the next sweep
  without waiting for a package release, since the integrations pin
  @copilotkit/react-core 1.61.2.

A spec naming no surface now throws instead of burning the turn budget and
reporting a misleading `surface-missing`.

Verified against live staging: after clicking the pill, the old gate matched
0 elements and the cascade matched 1 (the sandboxed iframe was there all
along). Also recorded in showcase/GOTCHAS.md.
2026-07-29 12:34:38 +02:00
Alem Tuzlak 75fc766fff fix(showcase): repair ms-agent .NET real-LLM demo defects (#6224)
## Summary

Fixes staging click-through failures on **ms-agent-dotnet** and
**ms-agent-harness-dotnet** demos. Same class of bug as #6200 (GOTCHAS
#8): aimock D6 was green while real LLMs failed.

### Root causes & fixes

| Demo | Symptom | Fix |
|------|---------|-----|
| beautiful-chat Sales Dashboard | `Catalog not found: sales_dashboard`
| Force page-registered `catalogId`; stronger secondary design prompt |
| declarative-gen-ui KPI / pie / bar / status | Loader never resolves;
`without a type`; `SummaryCard` missing `id` | Sanitize + normalize flat
A2UI components; drop invalid entries; force
`declarative-gen-ui-catalog` |
| shared-state-read-write Remember something | Notes panel never updates
| AsyncLocal store write misses (tool EC); mirror writes + read
fallback; wire dead deterministic reply path for the pill |
| subagents left panel | Chat works, side UI empty | Same AsyncLocal
store bug for `state.delegations` |
| open-gen-ui-advanced calculator / ping host | Form/input calculator;
ping no-ops | System prompt for clickable keypad + `notifyHost` /
`evaluateExpression` wiring |
| beautiful-chat calculator | Buttons do nothing | OGUI guidance:
`type=button`, no `form`, click handlers |

### Voice auth error

Not a code defect in the voice route:
`GuardedOpenAITranscriptionService` correctly fails when
`OPENAI_API_KEY` is missing on the **Next.js** process. Staging needs
that env var on the showcase frontend service (transcription hits real
OpenAI, not aimock).

### MCP Excalidraw empty iframe

Left as follow-up — likely external MCP host / sandbox CSP; no
agent-side bug found in wiring.

## Test plan

- [x] `dotnet test` ms-agent-dotnet (79/79) in Docker SDK 9 — includes
new A2UI force-catalog / type-as-key / drop-invalid tests
- [x] harness agent build + cvdiag tests (5/5)
- [ ] Staging click-through after deploy:
- [ ] `/react/ms-agent-dotnet/beautiful-chat` — Sales Dashboard paints;
calculator interactive
- [ ] `/react/ms-agent-harness-dotnet/declarative-gen-ui` — all four
pills paint without A2UI errors
- [ ] `/react/ms-agent-harness-dotnet/shared-state-read-write` —
Remember something updates notes
- [ ] `/react/ms-agent-harness-dotnet/subagents` — left panel shows
running/completed delegations
- [ ] `/react/ms-agent-harness-dotnet/open-gen-ui-advanced` — calculator
keypad + ping host
- [ ] Voice: confirm `OPENAI_API_KEY` present on staging frontend, then
mic works
2026-07-29 11:51:26 +02:00
Alem Tuzlak f58d24109a fix(showcase): repair ms-agent .NET real-LLM demo defects
Staging click-through on ms-agent-dotnet / ms-agent-harness-dotnet hit
several GOTCHAS #8 defects: aimock D6 was green while live LLMs failed.

A2UI (beautiful-chat sales dashboard, declarative-gen-ui pills):
- Force the page-registered catalogId (models invent "sales_dashboard").
- Sanitize/normalize flat components; salvage type-as-key nests; drop
  entries missing id/component (SummaryCard without id, charts without type).
- Strengthen secondary design prompts with the flat catalog contract.

Shared state + subagents side panels:
- Tool invocation drops AsyncLocal set by SetActiveThread, so writes landed
  in the global slot while snapshots keyed by AgentSession/AgentThread.
  Mirror writes and fall back on read (same pattern as D5ParityAgents).
- Wire the dead TryBuildDeterministicReply path for the "Remember something"
  pill so notes update without relying on the model calling set_notes.

Open generative UI advanced + beautiful-chat calculator:
- Prompt for clickable keypad (not form/submit) and notifyHost ping wiring.

Verified: ms-agent-dotnet unit suite 79/79 green in Docker SDK 9; harness
agent builds clean and cvdiag tests 5/5.
2026-07-29 11:42:32 +02:00
Markus Ecker 4cbca9ebe5 docs(react-core): document useAgent threadId and runtimeAgentId
The reference page's Parameters section covered only `agentId` and `updates`, so
both props this branch adds were undocumented.

Adds an entry for each, and notes on `agentId` that passing `runtimeAgentId`
makes it required and turns it into a name the hook registers an agent under
rather than one it retrieves.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 11:27:57 +02:00
Markus Ecker acdd9a9ef5 fix(react-core): enforce useAgent thread-scoping props at the type level
UseAgentProps left `agentId`, `runtimeAgentId`, and `threadId` independently
optional, so every unsafe or pointless combination compiled and only
`threadId`-without-`runtimeAgentId` was caught — at runtime, on render. Given
the bug this branch fixes was a silently-ignored `threadId` prop, the type is
where it should have been caught.

Split UseAgentProps into a base plus a two-branch union so exactly two shapes
are valid:

  useAgent()                                       // shared agent
  useAgent({ agentId })                            // shared agent
  useAgent({ agentId, runtimeAgentId, threadId })  // private agent, pinned thread

Every partial combination is now a compile error, each for its own reason.
`threadId` alone would scope a thread onto a shared singleton (the original
review finding). `runtimeAgentId` without `threadId` registers a private agent
that behaves like the shared one, minus nothing but a registration and a local
id to keep unique. And without an explicit `agentId`, the proxy registers under
the chat configuration's agentId or DEFAULT_AGENT_ID — ids that already belong
to real agents — which either throws `already registered` or silently shadows
one, depending on whether runtime discovery has landed.

The runtime throws stay as backstops for callers TypeScript doesn't cover (plain
JS, `as any`, props widened to `string | undefined` at a call boundary), and now
cover all three cases, each failing before any registration happens.

Adds use-agent-types.test.tsx pinning the compile-time half of the contract
across the accept/reject matrix, plus contract tests for the two new throws. The
`@ts-expect-error` on each deliberately-bad call doubles as an assertion that the
type still rejects it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 11:27:17 +02:00
Lukas Moschitz fda8743dd5 docs(showcase): GOTCHAS — langgraph-typescript streaming/LFS edge cases + fleet follow-ups
Record the durable findings from OSS-583:
- langgraph-typescript per-framework notes: langchain-js streaming-reassembly bugs
  (reasoning index-collision -> disableStreaming; tool-call+content reassembly ->
  normalizeAssistantMessage), a2ui-recovery inner-render header forwarding via
  ALS/wrapToolCall (mirrors mastra), and multimodal's LFS-asset build requirement.
- 'What Was Green But Still Wrong' #8: single-pass sweeps hide flaky cells and
  aimock-green can mask a real backend bug -> re-run for stability + verify the
  right graph runs.
- Known fleet-wide follow-ups: the frontend-tools-async stale turnIndex fixture
  reds the north star too (needs the same deletion in langgraph-python); image
  builds must git lfs pull so multimodal ships real assets not LFS pointers.
2026-07-29 09:42:41 +02:00
Tyler Slaton c5d0881380 Merge remote-tracking branch 'origin/main' into agent/oss-615-channel-docs 2026-07-28 23:30:25 -04:00
Tyler Slaton 1c87fe9b79 docs: expand Channels guides and API reference 2026-07-28 23:30:15 -04:00
Tyler Slaton cc825c7c99 chore: release monorepo v1.64.1 (#6214)
## Release monorepo v1.64.1

**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.64.1`
   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.64.1`
   - Creates git tag `monorepo/v1.64.1`
   - 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.64.1
2026-07-28 18:53:06 -07:00
Tyler Slaton e711ff8e00 docs(channels): restore global reference 2026-07-28 21:03:55 -04:00
tylerslaton 028a5adc9d chore: release monorepo v1.64.1 2026-07-28 17:48:23 -07:00