12090 Commits

Author SHA1 Message Date
Ran Shemtov 5a516c827f chore: release monorepo v1.61.2 (#5696)
## Release monorepo v1.61.2

**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.61.2`
   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.61.2`
   - Creates git tag `monorepo/v1.61.2`
   - 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.61.2
2026-06-25 10:10:02 +02:00
ranst91 bb69f55c98 chore: release monorepo v1.61.2 2026-06-25 07:54:33 +00:00
Ran Shemtov 382011c79c chore: release bot-slack v0.1.0 (#5687)
## Release bot-slack v0.1.0

**Scope:** `bot-slack` | **Bump:** `minor`

---

### How this release process works

1. **This PR was created automatically** by the "release / create-pr"
workflow.
   It bumped the `bot-slack` packages to `0.1.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 `bot-slack` packages to npm at version `0.1.0`
   - Creates git tag `bot-slack/v0.1.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.
bot-slack/v0.1.0
2026-06-25 09:52:47 +02:00
Jordan Ritter f3c6447c54 fix(showcase): A2UI render-path D6 reds — a2ui-fixed-schema + declarative-gen-ui (#5694)
## Summary
Fixes the two RED A2UI D6 demos in the **built-in-agent** showcase
integration. Both are confirmed GREEN locally via the D6 control-plane
probe (`--d6 --direct --isolate`).

### a2ui-fixed-schema — React #31 crash → GREEN
**Root cause:** the showcase authors A2UI catalog defs with root
`zod@4`, but `@a2ui/web_core`'s `GenericBinder` schema scraper inspects
**Zod-3** internals (`_def.typeName==='ZodUnion'`). A zod@4 union
reports `_def.typeName===undefined` → field misclassified STATIC → the
raw `{path}` binding object reaches render → **React error #31**.
**Fix:** author this demo's catalog with a `zod-v3` (`npm:zod@3.25.76`)
alias so the binder resolves bindings (card now renders `SFO → JFK,
$289`). NOT a react-core fix.

### declarative-gen-ui — surface-missing (no paint) → GREEN
**Root cause:** the secondary-LLM prompt was far thinner than the
canonical generation guidelines, so it emitted trees that (correctly)
failed the renderer's `surfaceHasRenderableContent` paint gate. The
paint gate is correct and untouched.
**Fix:** port the canonical generation rules into the prompt, add output
validation, add catalog parity (`DataTable` + info-row), ground the
planner with sales-context, and record multi-turn aimock fixtures (4/4
turns paint).

## Red→green
- a2ui-fixed-schema: RED `Minified React error #31 {path}` → GREEN `✓
d6:built-in-agent green`, card resolves real values.
- declarative-gen-ui: RED `reason=surface-missing` → GREEN
`turnsCompleted:4, 1 passed`, all sales pills paint
(KPI/pie/bar/DataTable/status/info-row).

## Cross-regression
The shared-renderer path was checked across A2UI demos on both runtimes:
gen-ui-agent ✓, beautiful-chat 5/5 ✓, langgraph-python (v1)
a2ui-fixed-schema ✓ — no regressions.

## Code review
2 review rounds (7 agents each). Applied: a2ui factory validation
hardening (plain-object data guard, unique-id check, fail-loud on
non-string secondary-LLM return), two-arg `z.record` (zod@4 API),
index-based DataTable row key, Metric `trendValue` rendering for neutral
trend, doc corrections.

## Follow-ups (not this PR)
- **openai@5 / zod@4 peer ERESOLVE** on fresh `npm install`
(pre-existing; committed lock installs via `npm ci`).
- Cross-integration `sales-context.ts` sync (5 byte-identical copies).
- A2UI tree cycle/reachability enforcement (deferred — not a realistic
LLM-output threat; unique-id IS enforced).
- Non-string component-id edge in the unique-id guard.
- `SYSTEM_PROMPT` catalog enumeration omits `DataTable`.
- `page.tsx` docstring drift; DonutChart legend mirror; Row `align` map;
fixture match-key coupling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-24 20:41:40 -07:00
Jordan Ritter d501d233b0 fix(showcase): make built-in-agent declarative-gen-ui paint its D6 surface
The secondary-LLM prompt was far thinner than the canonical generation guidelines,
so it emitted trees that (correctly) failed the renderer's paint gate → surface-missing.
Port the canonical generation rules into the prompt, add output validation, add catalog
parity (DataTable + info-row), ground the planner with sales-context, and record
multi-turn aimock fixtures. Includes CR fixes: two-arg z.record for the DataTable rows
schema (zod@4 API), index-based DataTable row key, and Metric trendValue rendering for
neutral trend.
2026-06-24 20:25:16 -07:00
Jordan Ritter bbdcb01440 fix(showcase): resolve a2ui-fixed-schema React #31 via Zod-3 catalog defs
The showcase authors A2UI catalog defs with root zod@4, but @a2ui/web_core's
GenericBinder schema scraper inspects Zod-3 internals (_def.typeName==='ZodUnion').
A zod@4 union reports _def.typeName===undefined → misclassified STATIC → the raw
{path} binding object reaches render → React error #31. Author this demo's catalog
with a zod-v3 (npm:zod@3.25.76) alias so the binder resolves bindings. Includes CR
hardening of the shared a2ui factory validation (plain-object data guard, unique-id
check, fail-loud on non-string secondary-LLM return).
2026-06-24 20:25:16 -07:00
Maxim e27ab05634 feat(saas-demo): SaaS banking demo — Threads + teachable self-learning + Aurora UI (#5266)
## What this is
The consolidated, Jerel-owned PR for the **SaaS banking demo**
(FOR-137), built on top of the now-merged **#5180** (Maxim, FOR-138). It
continues the closed draft **#5183**, rebuilt cleanly on current `main`.

Scope: **53 files, entirely within `examples/showcases/banking` +
`examples/showcases/teach-mode`.**

<img width="1358" height="763" alt="image"
src="https://github.com/user-attachments/assets/2ad50912-077e-4a03-821b-047e487a7c8d"
/>

<img width="1600" height="894" alt="image"
src="https://github.com/user-attachments/assets/f80d894f-a24c-4d77-af83-0d1cf1369b18"
/>

<img width="800" height="451" alt="image"
src="https://github.com/user-attachments/assets/c8d6abe5-2e70-4ad1-87af-8aa6529906dc"
/>

## What's added (on top of #5180)
- 🎨 **Aurora design system** — premium light/violet fintech redesign
(lavender canvas, violet→indigo brand, gradient cards, hand-rolled SVG
statistics sparkline, Inter). Restyle-only; all wiring preserved.
- 🪟 **Chat as a docked side panel + Threads inbox** — v2 `useThreads`;
the chat is a right-docked `CopilotSidebar`; Threads live as an **inbox
button in the panel header** (conversation list, new / archive /
select).
- 🧠 **Self-learning teachable gate** — approving an over-limit
transaction is blocked with a **symptom-only** error; a human unlocks it
by filing a **justifying** policy exception; the agent gets tools +
distractors but **never the unlock recipe**. OSS mode is the default;
`CopilotKitIntelligence` is env-gated.
- 📘 **Reusable teach-mode cookbook** — `examples/showcases/teach-mode/`
(the 5-role teachable-loop contract + banking↔e-commerce mapping +
adoption checklist + recording seam + `verify-teachable-gate.sh`).
- 🗺️ **Learning-track plan** — `LEARNING-TRACK-PLAN.md`: how to make the
live learn→distill→retrieve loop work + the teachable-demo UX (suggested
prompt, inline HITL, recording vignette).

## Status / notes
- **Draft.** Runs in **OSS mode** (only `OPENAI_API_KEY`); no
Intelligence backend required.
- The **live** self-learning loop
(record→distill→`/knowledge`→fresh-agent-learns) is gated on the
react-core recording hook (`e103a19`) + an Intelligence backend — see
`LEARNING-TRACK-PLAN.md`. The teachable **mechanics** (gate + unlock)
work today and are REST-verifiable (`verify-teachable-gate.sh`).
- cc @mxmzb — consolidated demo PR per Sam's ask; builds directly on
your merged #5180.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-25 03:53:02 +02:00
GeneralJerel 7d645af274 fix: restore upstream files unintentionally rewritten by lint-fix during merge 2026-06-24 18:42:01 -07:00
GeneralJerel 9ae901ed0a Merge remote-tracking branch 'upstream/main' into jerel/saas-banking-demo
# Conflicts:
#	pnpm-lock.yaml
2026-06-24 18:23:24 -07:00
Jordan Ritter b305394b5c docs(showcase): correct gen-ui-agent PARITY_NOTES — it is GREEN, not react-core-blocked (#5693)
## Summary

Doc-only single-file correction to
`showcase/integrations/built-in-agent/PARITY_NOTES.md`. The
`gen-ui-agent` D6 cell already passes end-to-end locally, but its
PARITY_NOTES entry still documented it as RED/blocked on a `STATE_DELTA
→ useAgent` gap in `@copilotkit/react-core`. That premise is stale and
is now refuted by local D6 runs. This rewrites the entry to
GREEN/reclaimed and rescopes the surrounding section header to the
remaining A2UI render-layer demos.

## RED → GREEN proof (from the work log)

The "RED" here is documentary, not behavioral: the cell **passes**
despite the stale RED doc.

Local RED baseline (`bin/showcase test built-in-agent:gen-ui-agent --d6
--direct --isolate`):
```
[conversation-runner] turn 3/3 — assertions passed
[conversation-runner] conversation completed successfully { turnsCompleted: 3 }
  ✓ d6:built-in-agent green (44.1s)
  1 passed (44.1s)
```

Local GREEN value-test (same command, `--repeat 3`):
```
  3 passed (130.1s)
✓ Tests passed for built-in-agent:gen-ui-agent
```
3/3 stable — not a flake. The doc correction changes no runtime
behavior.

Why it works: the backend `set_steps` server-tool result is converted to
a `STATE_DELTA` `[{op:"add", path:"/steps", value:steps}]` in
`src/lib/factory/tanstack-factory.ts` (`add`, not `replace`, so
`@ag-ui/client@0.0.57` doesn't drop it as
`OPERATION_PATH_UNRESOLVABLE`). `@ag-ui/client` applies the patch and
fires `onStateChanged`; the core state-manager fans it to subscribers;
`useAgent` re-renders off `agent.state.steps`. Fully wired in published
1.61.1 — no react-core change needed.

## Key finding: there was NO config quarantine

`gen-ui-agent` was never in the manifest `not_supported_features`, never
excluded in `shared/constraints.yaml`, and
`shared/feature-registry.json` has no per-feature status field. The
harness already routes it into `runnable` and grades it green. The
**stale doc was the only artifact** — there was no executable quarantine
to lift, so this is a pure doc correction.

## The two genuinely-RED demos are out of scope

`a2ui-fixed-schema` (React #31 crash from an unresolved `{path}` A2UI
binding) and `declarative-gen-ui` (surface never paints; secondary-LLM
op-shape) are real bugs, but both belong to `@copilotkit/a2ui-renderer`
/ showcase — **not** `@copilotkit/react-core`. They are being addressed
in a separate spec and are intentionally left untouched here.

## Test plan

- [x] `oxfmt --check` on the changed file — passes (correctly formatted)
- [x] `oxlint` on the changed file — 0 warnings, 0 errors
- [x] `commitlint` on the commit message — passes (`docs(showcase):`)
- [x] D6 cell passes locally, 3/3 stable
- [ ] CI green
2026-06-24 15:35:40 -07:00
Tyler Slaton d4c58f08e8 fix(showcase/shell-dojo): runtime-derive preview backend URL (#5692)
## Problem

The CopilotKit Interactive Dojo (`showcase/shell-dojo`) built its
preview-iframe `src` from `integration.backend_url`, which
`scripts/generate-registry.ts` synthesizes into `registry.json` at
**Docker build time** (default
`showcase-{slug}-production.up.railway.app`). The value is therefore
frozen into every image regardless of environment — so the **staging
dojo iframed production integration backends**.

## Root cause

The shell (`showcase/shell`) already solved this in SU-13 (commit
`febd8bc9`, 2026-06-11): it derives each integration's backend host at
**request time** from `SHOWCASE_BACKEND_HOST_PATTERN` via
`lib/backend-url.ts`, keeping `registry.json` as the source for non-URL
metadata only. That fix was scoped to `shell` and **never ported to
`shell-dojo`** — `shell-dojo`'s `RuntimeConfig` was still empty and
`page.tsx` read the build-baked `backend_url`.

## Fix

Port the `backendHostPattern` slice of SU-13 to `shell-dojo` (nothing
else from SU-13 — the dojo has no docs-redirect middleware, posthog, or
baseUrl consumers):

- **`lib/backend-url.ts`** — verbatim copy of shell's
(`resolveBackendUrl` + the `NEXT_PUBLIC_LOCAL_BACKENDS` local-dev
override). The two apps are separate build roots with different package
managers (shell is a pnpm workspace member; shell-dojo is a standalone
`npm ci` Next app, same as shell-dashboard), so neither can import the
other's `src`, and there is no shared importable package — the same
reason `generate-registry.ts` already keeps its own copy. A drift-guard
test keeps the copy byte-identical and pins the default pattern across
`backend-url.ts` and `generate-registry.ts`.
- **`lib/runtime-config.ts`** — adds `backendHostPattern`, read from
`SHOWCASE_BACKEND_HOST_PATTERN` at request time (with the
`NEXT_PUBLIC_`-prefixed/trim fallback semantics shared with shell).
Unset → the prod default, so an unset deploy is byte-identical to today.
- **`lib/runtime-config.client.ts`** — carries the SSR sentinel
`showcase-{slug}.ssr-placeholder.invalid` + a required-field check.
- **`app/page.tsx`** — `previewUrl` now derives via
`resolveBackendUrl(...)` at request time, **gated on a `mounted` flag**
so the SSR-phase sentinel host never reaches an iframe `src`. shell-dojo
loads its registry synchronously (`getIntegrations()` in a `useMemo`,
`viewMode` defaults to `"preview"`), so unlike the shell it has no
client-`useEffect` data guard to defer the read past hydration — without
the gate, the iframe would render on first paint with the `.invalid`
sentinel host (a request to a dead domain + a flash before the real URL
swaps in).
- **`app/layout.tsx`** — comment-only; the existing generic
`JSON.stringify(config)` injection already carries the new field into
`window.__SHOWCASE_CONFIG__`.

## Ops

`SHOWCASE_BACKEND_HOST_PATTERN=showcase-{slug}-staging.up.railway.app`
is already set on the **staging dojo** Railway service (verified the
staging hostname convention against a live staging integration's
`RAILWAY_PUBLIC_DOMAIN`). **Production is intentionally left unset** =
the prod default pattern, so prod behavior is unchanged. The var is
runtime-only (images build in CI, not on Railway), so it was inert until
this lands — merging this is what flips staging off prod backends.

## Testing

- New drift-guard test (in `scripts`): `backend-url.ts` byte-identical
to shell's + default-pattern parity with `generate-registry.ts` — 2/2
pass.
- Full affected vitest run: 2110/2110 pass.
- Standalone shell-dojo Next build (`npm ci --ignore-scripts && npm run
build`) compiled + type-checked successfully.
- oxfmt clean; oxlint 0 errors.

## Notes for reviewers

- **shell-dojo is not in the pnpm workspace**, so `nx affected` does not
cover it — CI builds it via its own npm/Docker path. Verify locally with
`cd showcase/shell-dojo && npm ci && npm run build`.
- The `iframe-missing-sandbox` oxlint **warning** at `page.tsx`
pre-dates this change (the iframe does carry a `sandbox` attr; oxlint
can't see it through the variable) and is outside the diff's intent —
left untouched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-24 15:35:01 -07:00
Jordan Ritter a478692b58 docs(showcase): correct gen-ui-agent PARITY_NOTES (it is GREEN, not react-core-blocked)
The built-in-agent gen-ui-agent D6 cell already passes end-to-end locally;
the PARITY_NOTES entry that documented it as RED/blocked on a STATE_DELTA
to useAgent gap in @copilotkit/react-core was stale. The set_steps to
STATE_DELTA {op:"add", path:"/steps"} workaround merged in
tanstack-factory.ts closed that gap: @ag-ui/client applies the patch and
fires onStateChanged, the core state-manager fans it to subscribers, and
useAgent re-renders off agent.state.steps. No react-core change is needed.

Rewrites the gen-ui-agent entry to GREEN/reclaimed and rescopes the
section header to the remaining A2UI render-layer demos (a2ui-fixed-schema,
declarative-gen-ui), whose fixes belong to @copilotkit/a2ui-renderer, not
react-core. Doc-only; no config quarantine existed (gen-ui-agent was never
in manifest not_supported_features), so the cell stays a counted green.

Local RED baseline: cell passes (1 passed) despite the stale RED doc.
Local GREEN value-test: --repeat 3 => 3 passed (130.1s), stable.
2026-06-24 15:12:45 -07:00
Mark Fogle 56b51aeaef fix(showcase/shell-dojo): runtime-derive preview backend URL
The dojo's preview iframe built its src from `integration.backend_url`,
which generate-registry.ts bakes into registry.json at Docker BUILD time
(default `showcase-{slug}-production.up.railway.app`). So the staging
dojo iframed PROD integration backends — the exact staging->prod leakage
the shell's SU-13 runtime-derivation fix already prevents, but which was
never ported to shell-dojo.

Port the `backendHostPattern` slice of SU-13:
- copy shell's backend-url.ts verbatim (resolveBackendUrl + the
  NEXT_PUBLIC_LOCAL_BACKENDS local-dev override); a scripts drift-guard
  test keeps it byte-identical to the shell's and pins the default
  pattern across backend-url.ts and generate-registry.ts.
- add `backendHostPattern` to shell-dojo's RuntimeConfig (server reads
  SHOWCASE_BACKEND_HOST_PATTERN at request time; client carries the SSR
  sentinel) — the existing layout injection picks it up automatically.
- page.tsx derives previewUrl via resolveBackendUrl at request time,
  gated on a `mounted` flag so the SSR-phase sentinel host never reaches
  an iframe src (shell-dojo loads the registry synchronously, so unlike
  the shell it has no data-loading guard to defer the read past
  hydration).

Staging dojo's SHOWCASE_BACKEND_HOST_PATTERN is set to
`showcase-{slug}-staging.up.railway.app`; prod stays unset (= default
prod pattern), so prod behavior is byte-identical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 21:37:34 +00:00
Jordan Ritter eb3bb6af98 docs(showcase): correct stale aimock fixture/Dockerfile claims in RAILWAY.md (#5683)
## Summary

`showcase/aimock/RAILWAY.md` described the aimock fixture infrastructure
as it worked during an earlier migration phase, not as it works today.
The stale claims actively misled debugging. This PR corrects them to
match the real, verified infra.

## Before → After

| Claim | Before (stale) | After (correct) |
| --- | --- | --- |
| Fixture delivery (§4/§5) | Three fixtures fetched at boot from
GitHub-raw URLs: `d5-all.json`, `smoke.json`, `feature-parity.json` |
Fixtures are **baked into the image** at build time under
`/fixtures/{shared,d4,d6}`; no remote fetch |
| `d5-all.json` | Authoritative D5 bundle, re-bundled from
`harness/fixtures/d5/*` | **Gone** — a one-time migration source split
into the per-slug `showcase/aimock/d6/<slug>/` tree (the source of
truth) |
| startCommand `--fixtures` (§5) | 3 `raw.githubusercontent.com` URLs |
`--fixtures /fixtures/shared --fixtures /fixtures/d4 --fixtures
/fixtures/d6` (the baked-in dirs). Added a warning that a single
`--fixtures /fixtures` parent loads nothing |
| Runtime image (§3) | Bare `ghcr.io/copilotkit/aimock:<version>` pulled
directly | `showcase-aimock` image, `FROM
ghcr.io/copilotkit/aimock:latest` + baked fixtures, built by
`showcase_build.yml` |
| Dockerfile (§8) | "Dead code / legacy wrapper, safe to remove" |
**LIVE** — `showcase_build.yml` builds it (`dockerfile:
showcase/aimock/Dockerfile`) and it bakes `shared/`, `d4/`, `d6/` into
`/fixtures/`. Do not remove |
| Env vars (§6), references (§9) | Referenced public GitHub-raw fixture
URLs and ~5 min raw-edge cache propagation | Local baked dirs;
propagation is via image rebuild + Railway deploy |

Also documents the working Railway mutation auth path by mechanism only
(§2): account-scoped `RAILWAY_TOKEN` from the DevOps `showcase`
1Password item via GraphQL `Authorization: Bearer` — the CLI session
token is not authorized for showcase-project mutations. No token value
is in the doc.

## Verification

- `showcase/aimock/d5-all.json` does not exist; the tree is `shared/`,
`d4/`, `d6/`.
- `showcase/aimock/Dockerfile` is `FROM
ghcr.io/copilotkit/aimock:latest` + `COPY shared|d4|d6 ->
/fixtures/...`.
- `.github/workflows/showcase_build.yml` matrix entry `showcase-aimock`
builds `dockerfile: showcase/aimock/Dockerfile`, context
`showcase/aimock`.

Docs-only change. Do not merge / do not enable auto-merge.
2026-06-24 13:28:26 -07:00
Jordan Ritter 1db78ee902 fix(showcase): re-author pydantic-ai gen-ui-declarative aimock fixture (kill 503 no_fixture_match) (#5690)
## Summary
Corrects the `pydantic-ai` `gen-ui-declarative` aimock fixture. PR #5661
merged it mis-templated from `ms-agent-dotnet`: the inner secondary-LLM
blocks gated on `_design_a2ui_surface` (ms-agent's tool) instead of
pydantic-ai's actual **`render_a2ui`**, and only **1 of the 4**
declarative pills was covered (the rest were dead KPI/pie/bar/status
blocks that match no real pill). So the cell still 503'd.

Re-authored 1:1 from the canonical `langgraph-python` fixture: inner
tool **`render_a2ui`**, all **4 pills** (sales-dashboard, rep-vs-quota,
at-risk, biggest-account) as outer `generate_a2ui` + inner `render_a2ui`
+ tool-result triplets, `context: "pydantic-ai"`. Dead blocks removed.

## Effect (real-surface proven via `bin/showcase test
pydantic-ai:declarative-gen-ui --d6 --direct`)
- `no_fixture_match` 503 count **6 → 0** — the 503 is fully gone.
- **Necessary, not sufficient:** the cell still can't paint (advances
503 → `surface-missing`) due to **separate pydantic-ai integration
gaps** — missing `DataTable` renderer, `InfoRow` lacking the
`declarative-info-row` testid, and the `injectA2UITool: false` A2UI
delivery path. Filed as a follow-up (Slack `#` showcase alerts); out of
scope here.
- No-regression: `multimodal` cell still green; fixture-only change
(+187/-336, one file).

## Test plan
- [x] Real-surface red-green: `no_fixture_match` 6 → 0
- [x] Schema valid (`validateFixtures` 0 issues), no fixture shadowing
(zero delta)
- [x] Inner `render_a2ui` arguments byte-identical to canonical
langgraph-python
- [ ] CI green
2026-06-24 13:23:11 -07:00
Tyler Slaton 8489cf954d fix(slack-example): stop reactions from triggering agent (#5691)
## Problem

The Slack example currently registers an emoji-triage reaction handler,
so adding reactions can trigger an agent run.

## Why

The example should model explicit conversational triggers only.
Reactions should not start generations in this example.

## Fix

Remove the example reaction handler, reaction demo docs/tests, and Slack
manifest reaction scopes/events.

## Verification

- pnpm exec nx run slack-example:test
- pnpm exec nx run slack-example:check-types
- pnpm exec nx run slack-example:build
- rg -n
"emojiTriage|bot.onReaction|reaction_added|reaction_removed|reactions:read|reactions:write|emoji
triage" examples/slack -S
- git diff --check -- examples/slack
2026-06-24 13:11:37 -07:00
Tyler Slaton edc8a55b9e fix(slack-example): stop reactions from triggering agent 2026-06-24 13:09:53 -07:00
Jordan Ritter 52955e6335 fix(showcase): ship shared-state-read D6 cell for strands(+TS) (#5688)
## Root cause: manifest gap makes #5673 a no-op on the fleet

PR #5673 fixed the aimock D6 fixture for the `shared-state-read` cell
for the
`strands` and `strands-typescript` integrations. But that fix was a
**no-op on
the deployed fleet**, because neither integration's manifest declared a
`demos:`
entry for `shared-state-read`.

The fleet enumerates D6 cells **only** from manifest demos that have
both an `id`
**and** a `route`:
- `showcase/harness/src/cli/targets.ts` `demosForSlug()` maps
`manifest.demos` →
ids; the d6 all-pills driver derives its feature matrix from this (an
empty
  array short-circuits to a zero-cell false-green).
- `showcase/scripts/generate-registry.ts` `determineCellStatus()`: a
feature
declared in `features` but with no demo carrying a `route` → status
`unshipped`.
- `showcase/harness/src/probes/discovery/railway-services.ts`: only
demos with a
  string `id` + `route` are counted.

`shared-state-read` **was** declared as a `feature` in both manifests
and is
**not** in `not_supported_features`, and the frontend demo (`page.tsx`,
`recipe-card.tsx`, `types.ts` — byte-identical to langgraph-python)
already
exists on disk. Only the manifest `demos:` entry was missing → status
`unshipped` → the cell never ran on staging.

## The fix (mirror the gold standard)

Add the `shared-state-read` demo entry to **both** manifests, mirroring
the
gold-standard `langgraph-python` entry exactly (same id, name,
description, tags,
route, `animated_preview_url`, highlight files). The gold entry already
uses the
integration-neutral default-agent shape (no agent file in `highlight`,
just
`page.tsx` + `api/copilotkit/route.ts`), so no per-integration
adjustment was
needed.

```yaml
  - id: shared-state-read
    name: "Shared State: Read-only"
    description: "Recipe editor publishes form state via agent.setState; the agent reads the recipe context but does not mutate it (no backend tool — neutral default agent)."
    tags:
      - agent-state
    route: /demos/shared-state-read
    animated_preview_url:
    highlight:
      - src/app/demos/shared-state-read/page.tsx
      - src/app/api/copilotkit/route.ts
```

No generated artifact is committed (`registry.json` / `catalog.json` /
`constraints.json` are gitignored, regenerated at build/test time). No
hard-coded
count test needs updating: the cross-join total stays 920 cells (only
the
**status** of 2 existing cells flips `unshipped → wired`);
`generate-catalog`'s
13 tests pass.

## RED → GREEN proof (real surface, not a unit fake)

### Harness enumeration (`demosForSlug` — the exact fn the d6 driver
uses)
| Integration | RED (origin/main) | GREEN (this PR) |
|---|---|---|
| strands | count=38, includes-ssr=**false** | count=39,
includes-ssr=**true** |
| strands-typescript | count=38, includes-ssr=**false** | count=39,
includes-ssr=**true** |

### Catalog status (`generate-registry` `determineCellStatus`)
| Integration | RED (origin/main) | GREEN (this PR) |
|---|---|---|
| langgraph-python (gold) | wired (max_depth=4) | wired (max_depth=4) |
| strands | **unshipped** (max_depth=0) | **wired** (max_depth=4) |
| strands-typescript | **unshipped** (max_depth=0) | **wired**
(max_depth=4) |

### Full D6 fleet run (`bin/showcase test <slug>:shared-state-read --d6
--verbose --isolate`)
On `origin/main` these resolve `count=0` (cell absent from the run set).
With this PR:

**strands:**
```
cli.runner.resolved-targets {"target":"strands:shared-state-read","level":"d6","count":1}
fleet.control-plane.catalog-enumerated {"driverKind":"e2e_d6","discovered":1,"enqueueable":1}
✓ d6:strands/shared-state-read green (0.0s)
1 passed (0.0s)
✓ Tests passed for strands:shared-state-read
```

**strands-typescript:**
```
cli.runner.resolved-targets {"target":"strands-typescript:shared-state-read","level":"d6","count":1}
fleet.control-plane.catalog-enumerated {"driverKind":"e2e_d6","discovered":1,"enqueueable":1}
1 passed (0.0s)
✓ Tests passed for strands-typescript:shared-state-read
```

Related: #5673 (the fixture fix this PR activates on the fleet).
2026-06-24 12:34:50 -07:00
Jordan Ritter ffe50c1a96 fix(showcase): re-author pydantic-ai gen-ui-declarative aimock fixture
PR #5661 mis-templated this fixture from ms-agent-dotnet: the inner
secondary-LLM blocks used toolName "_design_a2ui_surface" (never matches
pydantic-ai, whose inner tool is render_a2ui) and only the sales-dashboard
pill had any block, so the other 3 declarative pills matched nothing and
the cell 503'd with no_fixture_match on turn 1.

Re-author 1:1 from the canonical langgraph-python fixture (identical inner
tool render_a2ui + per-pill surfaces), adapted for pydantic-ai: context
"pydantic-ai" on the outer generate_a2ui + narration entries, inner
render_a2ui entries matched by toolName alone (the agent's inner OpenAI()
client does not forward x-aimock-context). All 4 pills (sales-dashboard,
team-performance, at-risk, top-account) now get both an outer
(generate_a2ui) and inner (render_a2ui) block whose component payloads meet
each pill's probe assertion. Dead KPI/pie/bar/status blocks removed.

Real-probe proof: with this fixture the inner render_a2ui call matches and
the outer narration renders ("Here's your Q2 sales dashboard.") — the cell
advances from "Strict mode: no fixture matched / 503" to all LLM calls
matched. Remaining surface-missing failure is a non-fixture frontend/agent
A2UI delivery gap (see PR description), out of scope for this fixture fix.
2026-06-24 12:28:01 -07:00
Jordan Ritter 5f9875a6a2 fix(showcase): ship shared-state-read D6 cell for strands(+TS)
Add the shared-state-read demo entry to the strands and strands-typescript
manifests, mirroring the gold-standard langgraph-python entry. The fleet
enumerates D6 cells only from manifest demos that have both an id and a
route; shared-state-read was declared as a feature (and is not in
not_supported_features) but had no demo entry, so it resolved to status
unshipped and never ran on staging.

This makes the aimock fixture fix from #5673 actually take effect on the
fleet: both integrations now enumerate and run the shared-state-read cell
green.
2026-06-24 12:23:23 -07:00
tylerslaton f42dddc00e chore: release bot-slack v0.1.0 2026-06-24 19:10:00 +00:00
Tyler Slaton 6d9a9ecffd fix: add configurable Slack response routing (#5684)
## Summary

- Add Slack `respondTo` routing options with mention-only channel thread
replies by default.
- Keep DMs and assistant pane conversational while allowing legacy
owned-thread continuation by config.
- Update the Slack example config, manifests, docs, and Discord README
trigger wording.

## Why

Slack bots should stay quiet in channel threads unless explicitly
mentioned or configured for continuation. This makes Kite-style bots
less noisy by default while preserving the old behavior for teams that
want it.

## How

- Resolve `respondTo` once in `SlackAdapter.start()` and pass the
resolved policy into the Slack listener.
- Gate `app_mention`, `message.im`, and non-DM thread replies against
that policy.
- Add listener coverage for defaults, disabled routes, in-channel
mention replies, and legacy thread continuation.

## Test Plan

- `pnpm exec nx run @copilotkit/bot-slack:test --
src/__tests__/slack-listener.test.ts`
- `pnpm exec nx run @copilotkit/bot-slack:test`
- `pnpm exec nx run @copilotkit/bot-slack:check-types`
- `pnpm exec nx run slack-example:test`
- `pnpm exec nx run slack-example:check-types`
- targeted `pnpm exec oxfmt --check ...`
- targeted `git diff --check ...`
2026-06-24 12:07:30 -07:00
Tyler Slaton 3afb050ebe feat(bot-slack): configure response routing 2026-06-24 11:53:55 -07:00
Jordan Ritter 4a04b59d1c docs(showcase): correct stale aimock fixture/Dockerfile claims in RAILWAY.md
The showcase-aimock RAILWAY.md described fixtures as fetched from GitHub-raw
URLs at boot and called the Dockerfile dead code. Both are false and actively
misled debugging: fixtures are baked into the image at build time under
/fixtures/{shared,d4,d6}, the Dockerfile is the live image builder driven by
showcase_build.yml, and the d5-all.json bundle no longer exists (split into
the per-slug d6/ tree). Corrects sections 3, 4, 5, 6, 7, 8, 9 to match the
real infra, fixes the startCommand to load the three baked-in subdirectories,
and documents the account-scoped RAILWAY_TOKEN mutation path by mechanism.
2026-06-24 11:51:30 -07:00
Sam Julien 93ce311cfb docs: move Threads into chat UI docs (#5653)
## Summary

- Moves the canonical `/threads` guide into the **Build Chat UIs** nav
group, immediately after prebuilt components
- Keeps `/premium/threads-explained` under **Intelligence Platform** as
the architecture/persistence explanation
- Adds contextual cross-links between the Threads guide, Threads
architecture page, and relevant prebuilt chat UI docs
- Shows `Threads` in the authored framework sidebars next to their chat
UI basics

## Why

Threads are primarily discovered by developers adding saved
conversations, history, and thread switching to a chat UI. The
implementation guide belongs with chat UI docs, while the platform page
remains the deeper explanation of persistence, realtime sync, and
Enterprise Intelligence Platform backing.

## Screenshots

**Root docs navigation: `/threads` now appears with the chat UI basics,
immediately after Prebuilt Components.**

![Root docs Threads
navigation](https://raw.githubusercontent.com/CopilotKit/CopilotKit/92e68e787ec0e137124460637549b0df33929389/pr-5653/root-threads-build-chat-uis-nav.png)

**Authored framework navigation: framework-specific docs now show
Threads next to Prebuilt Components too.**

![Authored framework Threads
navigation](https://raw.githubusercontent.com/CopilotKit/CopilotKit/92e68e787ec0e137124460637549b0df33929389/pr-5653/authored-langgraph-threads-nav.png)

**Intelligence Platform navigation: the architecture page stays in the
platform section.**

![Threads architecture in Intelligence Platform
navigation](https://raw.githubusercontent.com/CopilotKit/CopilotKit/92e68e787ec0e137124460637549b0df33929389/pr-5653/threads-architecture-intelligence-nav.png)

## Validation

- `git diff --check origin/main...HEAD`
- `git diff --check`
- `npm run typecheck` from `showcase/shell-docs`
- Local route smoke checks for `/threads`, `/premium/threads-explained`,
`/prebuilt-components`, and `/prebuilt-components/chat` returned 200
- Authored framework route smoke checks returned 200
2026-06-24 11:11:33 -07:00
Sam Julien 5507c75d2d docs: add framework-scoped Threads callouts (#5651)
## Summary

- Adds a `thread_persistence_pattern` manifest flag so shared docs can
render selected-framework Threads guidance.
- Marks LangGraph Python, LangGraph TypeScript, LangGraph FastAPI, and
Google ADK with the appropriate thread persistence pattern.
- Extends `WhenFrameworkHas` support so the shared Threads guide can
show LangGraph-only and ADK-only callouts.
- Clarifies that `useThreads` manages Enterprise Intelligence Platform
thread records, not native framework stores.
- Adds framework-selected callouts to the root/shared Threads guide
without adding a third setup path.

## Notes

The new callouts intentionally avoid claiming external store listing,
lifecycle sync, migration/import tooling, or durable ADK sessions by
default. Those remain product/runtime follow-ups tracked separately.

## Validation

- `git diff --check`
- `npm run pretypecheck` in `showcase/shell-docs`
- `npm run lint` in `showcase/shell-docs` (passes with existing
warnings)
- `npm run typecheck` in `showcase/shell-docs`
- `npm run build` in `showcase/shell-docs` (passes with existing
Turbopack/NFT warning)
- Local route smoke checks:
  - `/threads` hides framework callouts
  - `/langgraph-python/threads` shows LangGraph callout only
  - `/langgraph-typescript/threads` shows LangGraph callout only
  - `/langgraph-fastapi/threads` shows LangGraph callout only
  - `/google-adk/threads` shows ADK callout only
2026-06-24 11:11:22 -07:00
Sam Julien e745322ce8 Add Inspector Threads locked state for non-Intelligence installs (#5655)
## Summary
- Adds the Inspector Threads locked state for non-Intelligence installs
with a faded full-background thread mockup, updated headline, CTA
order/styling, and production Talk to an Engineer destination.
- Adds Threads telemetry events and metadata for tab click,
locked/enabled/empty views, and CTA clicks, including
package/runtime/status fields that can be derived safely.
- Hardens adjacent inspector paths found during review: telemetry
opt-out and serialization safety, preserved realtime wsUrl on header
refresh, unknown thread endpoint status handling, stale selected-thread
rendering, announcement HTML/link safety, RUN_ERROR styling, context
value rendering, and thread-detail URL joining for trailing-slash
runtime URLs.

## Telemetry notes
Implemented derivable/safe fields: package_name, package_version,
inspector_distinct_id, posthog_distinct_id for attributed CTA URLs,
intelligence_status, thread_service_status, runtime_url_type,
runtime_mode, license_status, telemetry_disabled, cta, cta_surface, and
thread_count.

Telemetry sink allowlist checked: `CopilotKit/oss-path-to-production`
already accepts the owned `oss.inspector.*` namespace via its prefix
gate, so no sink source allowlist change is required. Added
https://github.com/CopilotKit/oss-path-to-production/pull/173 to pin the
new Inspector Threads event names in ingest tests. The package/version
metadata now reads from `packages/web-inspector/package.json` instead of
a hardcoded version string.

Not implemented because they are not currently available from safe
public inspector state:
- has_public_license_key: no explicit public boolean is exposed;
deriving from headers/config could imply token state.
- cta_variant: current UI has no variant state to distinguish.

## Validation
- NX_TUI=false pnpm nx run @copilotkit/web-inspector:check-types
--skip-nx-cache
- NX_TUI=false pnpm nx run @copilotkit/web-inspector:test
--skip-nx-cache (43 tests passed)
- NX_TUI=false pnpm nx run @copilotkit/web-inspector:build
--skip-nx-cache
- NX_TUI=false pnpm nx run @copilotkit/core:check-types --skip-nx-cache
- git diff --check
- Telemetry sink validation in
https://github.com/CopilotKit/oss-path-to-production/pull/173: `pnpm
test -- telemetry-sink-ingest.test.ts` and `pnpm build`
- 7-agent code review pass, followed by 3-agent focused confirmation
pass with no remaining findings in scope
- Pre-commit package matrix hit an unrelated @copilotkit/react-core:test
timeout in `A2UIMessageRenderer.test.tsx` during amend; targeted
web-inspector checks above passed

## Screenshot
![Inspector Threads locked
state](https://gist.githubusercontent.com/samjulien/98d0569b33990b4cf740aa14e1790614/raw/b344397d6e326e9102c4e3d90ba1a9772710e42d/inspector-threads-locked-live.svg)
2026-06-24 11:09:10 -07:00
Jordan Ritter 6c55d7909c feat(showcase): deploy strands-typescript integration to staging (#5681)
## What

Wires the `strands-typescript` showcase integration for **staging**
deployment, mirroring how the Python `strands` integration is deployed.
Provisions the Railway service and adds all repo-side deploy wiring so
the integration appears in the staging integration switcher menu.

## Why

The `strands-typescript` integration code was complete and ran locally,
but was not deployed (`deployed: false`, no Railway service), so it was
absent from the staging integration menu.

## Changes

- **manifest**: `deployed: true` so the shell lists it in the
integration menu.
- **railway-envs.ts**: new `showcase-strands-typescript` SSOT entry.
**Staging-only for now**: the prod instance is not yet provisioned, so
the entry omits the prod env and is `gateIgnore`'d (like
`harness-workers`) until it is promoted dual-env. Regenerated
`railway-envs.generated.json`.
- **showcase_build.yml** + **showcase_build_check.yml**: build-matrix
entry, change-detection filter, and dispatch option. `railway_id` is the
new Railway service id.
- **golden fixture** + **image-ref-gate inventory tests**: updated for
the new service (count 40 → 41, gateIgnore allowlist).

## Railway provisioning (done via CLI/API)

- Service `showcase-strands-typescript` created in the **showcase**
project.
  - serviceId `d6f47c8c-a0a1-4dbe-991c-50f8463fd68d`
  - staging instanceId `3f917b9f-c3f0-4d8b-96ca-7f455e06b5ba`
- staging domain `showcase-strands-typescript-staging.up.railway.app`,
health `/api/health`, restart ON_FAILURE
- staging vars: `MODEL_PROVIDER=openai`, `MODEL_ID=gpt-4o`,
`OPENAI_BASE_URL=https://aimock-staging.up.railway.app/v1`,
`OPENAI_API_KEY` (placeholder; aimock-fronted), `NODE_ENV=production`,
`NEXT_PUBLIC_BASE_URL=https://showcase.staging.copilotkit.ai`
- No Bedrock/AgentCore creds needed: like the rest of the fleet, LLM
traffic routes through the env-local **aimock** (deterministic replay),
so no real provider key is required.

## Post-merge behavior

On merge to `main`, `showcase_build.yml` builds + pushes
`ghcr.io/copilotkit/showcase-strands-typescript:latest`, redeploys the
staging service, and rebuilds the shell (picking up `deployed: true`).
After that the service is healthy and strands-typescript appears in the
staging integration menu. The image does not exist in GHCR until that
first build, so the Railway service is expected to be unhealthy until
then.

## Prod (follow-up)

Prod is intentionally not provisioned here. It will be added (dual-env,
`gateValidated: true`, `gateIgnore` removed) when the service is
promoted to prod via `showcase_promote.yml`.

## Verification

- `emit-railway-envs-json --check`: up to date
- `sync-promote-service-options --check`: dropdown up to date
(staging-only correctly excluded)
- railway/promote/emit/gate/deploy/registry vitest: 137 passing
- `oxfmt --check`: clean
- `validate-constraints strands-typescript`: valid
2026-06-24 11:04:09 -07:00
Ran Shemtov 311c47f002 Merge branch 'main' into claude/reverent-black-6ba1b9 2026-06-24 20:04:00 +02:00
Sam Julien ced9846472 fix(web-inspector): read telemetry package version from metadata 2026-06-24 10:55:49 -07:00
Ran Shem Tov d6f618dc03 fix(showcase): make default redeploy scope env-aware for staging-only services
The strands-typescript SSOT entry is ciBuilt:true but staging-only (prod
instance not yet provisioned). redeploy-env.ts's default scope was the full
CI_BUILT_SERVICES set for BOTH envs, so a staging-only ciBuilt service would
wrongly enter the prod default scope and fail a manual `redeploy-env.ts prod`
(no prod instance). Filter the default scope by env declaration (explicit
--services stays unfiltered, preserving the contract-pin that an operator can
force a named service in an env it does not declare). imageOf expansion was
already env-aware; this extends the same invariant to the base scope.

Update the inventory-lock test counts for the new service (total 40->41,
CI_BUILT 38->39, staging default scope 39->40; prod default scope stays 38 as
the staging-only service is now correctly excluded).
2026-06-24 19:54:49 +02:00
Sam Julien 9dffd143f4 fix(web-inspector): type thread telemetry props 2026-06-24 10:52:18 -07:00
Sam Julien ca59098e3a add inspector Threads PLG state 2026-06-24 10:52:18 -07:00
Ran Shemtov a2666f6fe4 fix(showcase): green strands(+TS) D6 shared-state-read + multimodal (32→34/35) (#5673)
## Summary

Greens two of the three failing D6 (e2e-full) cells for **both** the
`strands` (Python) and `strands-typescript` integrations: **32/35 →
34/35** each.

## Fixes

- **shared-state-read** — the turn-2 fixture leg wrongly pinned
`turnIndex: 0`, so the aimock matcher skipped it on turn 2 ("candidate
fixture skipped by sequence/turn state") → 404 → turn-2 `sse-missing`.
Dropped `turnIndex` to mirror the langgraph-python gold-standard fixture
(whose turn-2 leg omits it).
- **multimodal** — `sample.png/pdf/wav` were committed as **git-LFS
pointers**, so deploy/test environments without `git lfs pull` served
the ~130-byte pointer text as the uploaded file → the agent run never
started (`runsFinished=0`). Now shipped as regular binaries via a
per-integration `.gitattributes` lfs-unset + real bytes, mirroring
langgraph-python's existing convention ("must stay as regular binaries
... so deploy environments without `git lfs pull` serve the actual
files").

Both fixes verified locally: `showcase/bin/showcase test
{strands,strands-typescript} --d6 --direct --rebuild --isolate` → 34/35
each, shared-state-read + multimodal green.

## Known remaining red (out of scope here)

**gen-ui-declarative** (A2UI dynamic) stays red on both. The A2UI
surface **paints correctly** (real dashboard data), but `generate_a2ui`
never completes, so the run hangs "Running" (`runsFinished=0`). This
reproduces on **real-LLM staging** too, so it is not a fixture/aimock
artifact — it is a Strands A2UI-dynamic run-completion issue. The
fixtures and frontend are byte-identical to langgraph-python's (which
passes), pointing at the Strands adapter's auto-inject completion path.
Tracked separately for an adapter-level fix.
2026-06-24 19:48:54 +02:00
Ran Shem Tov d779f71468 feat(showcase): deploy strands-typescript integration to staging
Wire the strands-typescript showcase integration for staging deployment,
mirroring how the Python strands integration is deployed.

- manifest: flip deployed: true so the shell lists it in the integration menu
- railway-envs.ts: add showcase-strands-typescript SSOT entry (staging-only
  for now: prod instance not yet provisioned, so it omits the prod env and is
  gateIgnore'd until promoted dual-env); regenerate railway-envs.generated.json
- showcase_build.yml + showcase_build_check.yml: add the strands-typescript
  build matrix entry, change-detection filter, and dispatch option (railway_id
  is the new Railway service id)
- golden fixture + image-ref-gate inventory tests updated for the new service

Railway staging service showcase-strands-typescript provisioned
(showcase-strands-typescript-staging.up.railway.app, health /api/health,
OpenAI-via-aimock env). Prod is added later via the promote pipeline.
2026-06-24 19:39:36 +02:00
Ran Shemtov 9319a5f57a Merge branch 'main' into claude/strands-d6-green 2026-06-24 19:26:12 +02:00
Ran Shemtov a4edb83f03 fix(showcase/google-adk): all 39 in-matrix D6 cells green — restore post-tool re-invoke loop (#5676)
## What

Fixes the 6 remaining red D6 cells for the **google-adk** showcase
integration, bringing it to **39/39 on the D6 matrix** (under aimock
replay, reproduced across two independent full-matrix runs, no in-matrix
regression). See the scope/caveats section before reading this as "fully
done."

## Root cause + changes

**1. `entrypoint.sh` — remove `ADK_DISABLE_PROGRESSIVE_SSE_STREAMING=1`
(the big one).**
A/B tested in-container: with the flag set, ADK's non-progressive
aggregation path ends the agentic loop after the first tool round — no
post-tool LLM re-invoke. That broke every demo needing a second turn
after a tool result:
- `subagents` (research → writing → critique never chained past
research)
- `tool-rendering-reasoning-chain` (AAPL → MSFT)
- `shared-state-read-write` (the post-`set_notes` confirmation text)
- `tool-rendering-custom-catchall` (the post-tool narration)

The flag was added to dodge an intermittent "last event is partial"
abort on tool-rendering; the in-callback `stop_on_terminal_text` guard
(shared by every agent) is intended to cover that. See caveat 1 — that
guard's sufficiency is verified under aimock only, not against real
Gemini.

**2. `manifest.yaml` — un-skip-list `tool-rendering-reasoning-chain`.**
It was marked `not_supported` (vacuous-green) only because of the loop
gap; it passes now.

**3. `headless_complete_agent.py` — add `AGUIToolset()`.** Removing the
flag unmasked a pre-existing gap: the frontend `highlight_note` tool was
never injected/routed, so turn 3 dispatched it server-side and the
backend registry rejected it (`Tool 'highlight_note' not found`).
langgraph-python auto-injects frontend tools; ADK needs `AGUIToolset()`
in the agent's `tools` list (every other frontend-tool google-adk agent
has it).

**4. `aimock/d6/google-adk/gen-ui-interrupt.json` — re-key.** The alice
pill 503'd: its emit leg was gated `hasToolResult:false`, but the
earlier sales pill leaves a tool result in the thread (thread-global).
Re-ordered each pill's narration (`toolCallId`) leg before its emit leg
and dropped the `hasToolResult` gate, mirroring the reasoning-chain
fixture pattern.

## Verification

`showcase test google-adk --d6 --isolate` (full per-pill matrix), run
twice on separate isolated stacks:
- Both: `passed=39, failed=0, total=39, state=green`.
- The 6 previously-red cells all pass: shared-state-write,
tool-rendering-custom-catchall, subagents,
tool-rendering-reasoning-chain, gen-ui-interrupt (sales + alice),
gen-ui-headless-complete.
- No regression: all previously-passing cells (incl. all
`tool-rendering*` and A2UI: gen-ui-declarative, gen-ui-a2ui-fixed,
beautiful-chat) stay green.

## Scope and caveats (read before merging)

1. **The flag removal is verified under aimock only, NOT against real
Gemini.** `ADK_DISABLE_PROGRESSIVE_SSE_STREAMING=1` was originally added
for a *real-Gemini intermittent* "last event is partial" abort. D6 is
deterministic aimock replay and cannot reproduce that intermittent
condition, so the "0 partial-aborts" result does not prove the
`stop_on_terminal_text` guard is sufficient against real Gemini. There
is a real (unmeasured) risk this re-introduces the partial-abort on
real-LLM tool-rendering runs. Recommend a real-Gemini smoke of the
tool-rendering demos before relying on this in a real-LLM context.
2. **"39/39" is the in-matrix set, not every feature.** Three features
remain `not_supported` and are excluded from the matrix (not fixed):
`interrupt-headless`, `reasoning-default-render`,
`agentic-chat-reasoning`.
3. **Local verification only.** D6 is not CI-gated for google-adk;
evidence is two isolate runs on one machine, not an independent CI
signal.
2026-06-24 19:25:46 +02:00
Ran Shemtov 54ef8027f6 Merge branch 'main' into claude/adk-d6-non-a2ui 2026-06-24 19:25:24 +02:00
Jordan Ritter b507054f51 fix(showcase): map AG-UI multimodal content to native pydantic-ai types (fix assert_never) (#5675)
## Summary
The pydantic-ai showcase integration crashed with `assert_never` in
pydantic-ai's `_map_user_prompt` whenever AG-UI multimodal
`InputContent` (images / documents / binary, data: and url: sources)
reached the model — AG-UI content types were never normalized to the
native pydantic-ai types (`str` / `ImageUrl` / `BinaryContent` /
`DocumentUrl`) the mapper requires.

## What changed
- **`_MultimodalFlattenModel(WrapperModel)`** normalizes content at the
**model-call boundary** (overriding `request` / `request_stream` /
`count_tokens`) — deliberately NOT a `history_processor`, because that
hook persists its return into `message_history` and would leak flattened
content back to the UI.
- **Supported-type gating + degrade centralized at the single
native-type emission choke point** (instead of scattered
per-content-branch): unsupported image subtypes (HEIC/SVG/TIFF/BMP),
audio/video, and non-fetchable url attachments degrade to a text
placeholder rather than emitting a native type the OpenAI Responses
vision API rejects (which would fail the turn).
- **Mime normalized once** — strips RFC-2045 params/whitespace,
lowercases, and aliases the common non-canonical `image/jpg` →
`image/jpeg` before the allow-list (png/jpeg/gif/webp) test, so real
JPEGs are no longer silently dropped.
- Identity-based (`is`) no-op detection replaces fragile structural
`==`.

## Why it matters
Unblocks multimodal turns in the pydantic-ai showcase integration;
eliminates the `assert_never` crash and stops valid `image/jpg` JPEGs
and url-borne documents from being silently mishandled.

## Testing
- **43 unit tests** (clean pinned venv, pydantic-ai 1.0.18), red-green
proven per gap: `image/jpg` forwarded as a supported JPEG; url-media /
non-PDF-doc degrade instead of emitting an unconditional `DocumentUrl`;
parameterized mime forwarded; state-leak guard (`request_stream`
forwards flattened, not raw); `count_tokens` override; `assert_never`
provably unreachable (all flatten paths return a native type or raise).
- 9 rounds of code review (7 agents/round) to a clean confirmation round
(zero blocking findings).

## Test plan
- [ ] CI green
2026-06-24 09:57:21 -07:00
Jordan Ritter b00817d534 fix(showcase): record pydantic-ai generate_a2ui D6 fixture (staging 503 flap) (#5661)
## Summary
- The pydantic-ai `generate_a2ui` declarative D6 turn was missing an
aimock fixture, producing HTTP 503 `no_fixture_match` on staging
(pydantic-ai 503 vs ms-agent-dotnet 200 for the same turn) — a source of
dashboard flapping.
- Adds the canonical mirror fixtures (outer `generate_a2ui` + matching
inner `_design_a2ui_surface`) to
`showcase/aimock/d6/pydantic-ai/gen-ui-declarative.json`. These are
deterministic canonical mirrors matching the langgraph-python convention
— **not** a non-deterministic real-LLM recording — preserving the
mandatory LGP 1:1 parity.

## Red-green proof
- **RED:** exact failing request (`POST /v1/responses`, gpt-4.1, "Show
me my sales dashboard for this quarter.", tools=[`generate_a2ui`],
header `x-aimock-context: pydantic-ai`, strict) against the pre-fix
fixture set → **HTTP 503 `no_fixture_match`** (reproduces staging
exactly; confirmed live on staging too).
- **GREEN:** same request against the new set → **HTTP 200** SSE
emitting the `generate_a2ui` tool call; the inner `_design_a2ui_surface`
turn also returns 200 with the dashboard surface.
- Independently re-verified. `validate-on-load` clean (no fixture
shadowing); existing pydantic-ai D6 turns (KPI/pie/bar/status) still
match identically — no regression.

## Notes
- No credentials in the committed fixture — the OpenAI key was never
even resolved (canonical mirror, not a recording). Credential scan of
the diff + full blob: zero matches.

## Test plan
- [ ] CI green
- [ ] After deploy, confirm the `generate_a2ui` declarative D6 cell
flips red→green on staging
2026-06-24 09:57:17 -07:00
Jordan Ritter 6b04bb08a9 fix(showcase/harness): reliable data-copilot-running turn-done signal (kill probe false-red flaps) (#5649)
## Summary

Makes the showcase harness probe's turn-done signal **reliable**,
killing the dominant class of dashboard false-red flaps without ever
hiding a real failure.

`waitForTurnComplete` previously relied on a fragile SSE fetch-counter
conjunct that false-reds healthy demos whenever the page-side fetch
wrapper missed the runtime URL/transport. This change makes the
**`data-copilot-running` DOM attribute** (driven directly by the agent
run lifecycle, `RUN_STARTED`→true / `RUN_FINISHED`→false,
transport-independent) the **PRIMARY** done-signal, with the SSE counter
demoted to a **headless-only fallback** (headless demos never render
`CopilotChatView`, so the attribute is absent).

Design (all three preserved — no false-green, no false-red, hangs still
red):
- **Primary signal** = the `data-copilot-running` true→false
**transition** with a **stayed-stopped quiescence window** (a stop must
persist on the same run-start count for `settleMs`; a new sub-run resets
it) — so it cannot complete on an intermediate stop in a multi-step
turn.
- **SSE counter** = headless fallback only; never an OR-trigger when the
DOM signal is present.
- **`done-signal-missing` backstop** (gated on `attrPresent===true` +
`runningNow!==true`) reds a genuine painted-but-never-finished DOM turn
before the hard timeout; headless turns use their full timeout for their
only signal.

## How it was reviewed

A full 4-round `cr-loop` (7 unbiased agents/round + confirmation rounds
+ a Procedure-3 promotion audit) caught and fixed **5 distinct
correctness defects** in the implementation before merge:
- **F1** — SSE OR-trigger could complete a multi-step turn early on an
intermediate stop (false-GREEN), in both the loop and the post-loop
classifier.
- **F2** — the run-start baseline was captured *after* the message send,
killing the primary signal on fast turns (false-RED).
- **F3** — non-atomic double `surfaceReady` read per poll (latent hazard
+ wasted round-trip).
- **F4** — the surface-mount (`completeOnMount`) path had no quiescence
window (false-GREEN on intermediate stop + false-RED on a still-running
gen-UI turn).
- **F5** — the early backstop false-redded slow-but-healthy **headless**
turns (now gated on the DOM signal).

Bidirectional red-green tests for F1–F5 plus a systematic `{DOM,
headless} × {completes, lagging-recovers, genuine-hang} × {text,
surface}` completion/backstop matrix. Full harness unit suite: **3173
passed / 18 skipped / 0 failed**; `tsc --noEmit` clean; lint 0 errors;
build clean.

## Known follow-ups (NOT in this PR — pre-existing / non-blocking)

- **Theoretical edge (not reachable on real or realistically-streamed
turns):** if a run completed within a single synchronous microtask
(zero-duration), the page-side MutationObserver could miss the true edge
while `attrPresent===true` → false-red. Real LLM turns and aimock
realistic-streaming hold the attribute true across many event-loop
ticks, so the observer reliably latches it. A naive "re-add SSE fallback
for DOM-present" fix would reintroduce F1's multi-step false-green, so
it's intentionally not done here.
- **Recommended quick follow-up (latency only, no wrong verdict):**
capture `baselineBannerText` pre-`sendTurnMessage` (mirroring the
run-start/count baselines) so a fast-erroring cold-start turn fast-fails
(#5142) instead of burning the full timeout.
- **Pre-existing sse-interceptor capture/counter internals** (none
load-bearing for the new done-signal; verified STAY_IN_C by the
Procedure-3 audit): page-side counter soft-nav/multi-capture reset,
`__hk_fetchWrapped` pattern reuse + hardcoded fallback, g/y-flag
stateful RegExp, TextDecoder end-of-stream flush, bare-catch
reader-error swallow, framenav payload discard/TOCTOU,
CDP-wallTime-vs-Date.now TTFT, addInitScript/close-listener
re-registration accumulation.

## Test plan

- [x] `pnpm test` (harness) — 3173 passed / 18 skipped / 0 failed
- [x] `tsc --noEmit` exit 0, lint 0 errors, build exit 0
- [ ] Verify on staging that auth / prebuilt-sidebar / claude-sdk-tools
(and other previously-flapping cells) stop false-redding while
genuinely-broken cells stay red

Please review the replay/primary-signal approach. Not auto-merging.
2026-06-24 09:57:13 -07:00
Jordan Ritter ab76e3167b fix(showcase): harden promote-notify alerting + debt cleanup (#5674)
## Summary

Hardening + pre-existing-debt cleanup of the showcase promote-notify
Slack renderer (follow-up to #5657, scoped to deferred review items).

**Fail loud on a dropped page-the-humans alert.** The #oss-alerts
failure cross-post used to pipe the Slack API response to `/dev/null`,
so a `200`/`{"ok":false,"error":"channel_not_found"}` silently dropped
the alert that fires when a promote *failed* — on a green job nobody
would notice. Both posts now capture the response via a shared
`slack_alert_posted_ok` predicate; the #oss-alerts page fails the
renderer job loud on a dropped delivery, while the informational thread
reply stays warn-only. The predicate is mirrored byte-identically across
the live workflow and the dry-run helper.

**Debt cleanup.** Removed a dead `failed_count` var, corrected a
misleading `gha_url` comment, and added `^[0-9a-f]{6}$` validation on
the decoded blob `run_id` in the render step so a malformed run_id can't
reach Slack or the run name.

## Test plan
- [x] `promote-notify.bats` 11/11 — predicate edge cases (non-JSON,
malformed, missing/`null` ok), anti-drift parity guard (predicate
identical in both files), and call-site tests locking the #oss-alerts
fail-loud vs thread warn-only exit semantics
- [x] red→green proven: re-adding `|| true` to the #oss-alerts call-site
flips the call-site test red
- [x] shellcheck clean on the dry-run helper
2026-06-24 09:56:54 -07:00
Jordan Ritter 27b5e79a00 test(showcase): cover pydantic-ai multimodal content mapping + degrade paths 2026-06-24 09:16:07 -07:00
Ran Shem Tov c5554f317f fix(showcase/google-adk): full D6 green — restore post-tool loop, fix interrupt + headless
Brings google-adk to 39/39 D6 (reproduced across two independent full-matrix
runs, zero regressions). Four changes:

- entrypoint.sh: remove ADK_DISABLE_PROGRESSIVE_SSE_STREAMING=1. That flag's
  non-progressive aggregation path ended ADK's agentic loop after the first
  tool round (no post-tool LLM re-invoke), which broke every demo needing a
  second turn: the subagents chain (research -> writing -> critique),
  tool-rendering-reasoning-chain (AAPL -> MSFT), shared-state-read-write's
  confirmation, and the custom-catchall narration. The partial-event abort it
  guarded against is already handled in-callback by stop_on_terminal_text.
- manifest.yaml: un-skip-list tool-rendering-reasoning-chain (now passes with
  the loop restored).
- headless_complete_agent.py: add AGUIToolset() so the frontend highlight_note
  tool is injected and routed to the browser. Removing the flag unmasked this
  pre-existing gap — turn 3 dispatched highlight_note server-side and the
  backend registry rejected it. langgraph-python auto-injects frontend tools;
  ADK needs AGUIToolset() in the agent's tools list.
- aimock/d6/google-adk/gen-ui-interrupt.json: order each pill's narration leg
  (toolCallId) before its emit leg and drop the thread-global hasToolResult
  gate, so the alice pill no longer 503s after the sales pill leaves a tool
  result in the thread.
2026-06-24 18:12:17 +02:00
Jordan Ritter d56dcbbc9d fix(showcase): map AG-UI multimodal content to native pydantic-ai types at the model-call boundary
Flatten AG-UI attachment content into native pydantic-ai content types in
the OUTGOING request only, via a WrapperModel-scoped flatten rather than a
history_processor (so the flatten never persists into ctx.state.message_history
and leak into UI state). Normalize mime types, gate on supported content types,
and degrade unsupported types at the single emission choke point. Fixes the
_map_user_prompt assert_never crash on raw AG-UI multimodal content.
2026-06-24 09:03:19 -07:00
Ran Shemtov e744e363ed Merge branch 'main' into claude/strands-d6-green 2026-06-24 17:56:54 +02:00
Jordan Ritter 82523b7297 fix(showcase): harden promote-notify alerting + debt cleanup
Fail loud on a dropped #oss-alerts page: the failure-alert cross-post no longer
swallows a 200/ok:false Slack response, so a dropped page-the-humans alert reds
the renderer job instead of vanishing on a green run. The thread reply stays
warn-only. Both posts capture the response via a shared slack_alert_posted_ok
predicate, mirrored byte-identically across the live workflow and the dry-run
helper.

Debt cleanup: drop a dead failed_count var, correct a misleading gha_url comment,
and validate the decoded blob run_id against ^[0-9a-f]{6}$ in the render step so
a malformed run_id can't reach Slack or the run name.

Tests: predicate edge cases (non-JSON, malformed, missing/null ok), an anti-drift
parity guard asserting the predicate is identical in both files, and call-site
tests locking the #oss-alerts fail-loud vs thread warn-only exit semantics.
2026-06-24 08:55:53 -07:00
Ran Shem Tov cb687d7fb0 chore(showcase): bump strands adapters for A2UI-dynamic completion fix
- @ag-ui/aws-strands 0.2.2 -> 0.2.3 (strands-typescript)
- ag_ui_strands 0.2.1 -> 0.2.2 (strands)

These releases carry the A2UI-dynamic (declarative-gen-ui) run-completion fix:
the auto-injected generate_a2ui now completes after the A2UI surface paints,
so the run emits RUN_FINISHED instead of hanging 'Running'. Should green the
gen-ui-declarative D6 cell on both integrations (-> 35/35) and resolve the
real-LLM staging hang. Pending local D6 re-verify.
2026-06-24 17:16:47 +02:00
Tyler Slaton 947fe2142a fix(core): preserve agent-level headers instead of overwriting them (#5635) (#5637)
Fixes #5635.

## What

Headers set directly on an `HttpAgent` registered via
`agents__unsafe_dev_only` were silently replaced by the provider
headers. Per-agent auth headers (like an `Authorization` for a
self-hosted backend) got dropped, causing 401s.

## Why

`AgentRegistry.applyHeadersToAgent` did `agent.headers = {
...core.headers }`, a full overwrite. The run handler and the react-core
`useAgent` hook did the same. So an agent built with its own headers
lost them on registration, on every `setHeaders`, and before each
request.

## Fix

Merge instead of replace. The registry captures each agent's own headers
once (in a WeakMap, before the first apply) and rebuilds `{
...ownHeaders, ...coreHeaders }`. Core wins on key conflicts, which
keeps the existing "provider headers are authoritative" and logout/clear
behavior. All header application now routes through one method,
`CopilotKitCore.applyHeadersToAgent`, so runs never clobber per-agent
headers.

Vue and Angular benefit too: they dispatch runs through `core.runAgent`
/ `connectAgent`, so the merge is re-applied before every request.

## Tests

- core: 3 new cases in `core-headers.test.ts` (preserve, merge,
retain-across-setHeaders); existing overwrite and clear tests still
pass.
- react-core: new `use-agent-provider-headers.e2e.test.tsx` with a real
provider and an HttpAgent that has its own headers.

Verified locally: format, lint, full core + react-core suites, and both
builds.
2026-06-24 07:45:37 -07:00
Ben Taylor fbf154cb0d feat(core,react-core): add unarchiveThread to v2 thread store + useThreads (#5624)
## Summary

Adds `unarchiveThread(id)` to the v2 thread store (`@copilotkit/core`)
and the `useThreads` hook (`@copilotkit/react-core/v2`), restoring an
archived thread via the existing generic `PATCH /threads/:id { archived:
false }` update path — no new runtime endpoint. Mirrors `archiveThread`
across the store and hook.

This is the durable, architecture-independent piece extracted from the
threads-drawer effort. The drawer UI itself is being restarted as a
framework-agnostic **CopilotDrawer** (Lit web component + React/Angular
wrappers) under a separate spec; this hook method stands on its own and
is needed regardless.

## Testing

TDD. New core store test (`PATCH … { archived: false }`) and
`useThreads` hook test; full suites green (core, react-core).
2026-06-24 08:56:08 -05:00