Commit Graph

14474 Commits

Author SHA1 Message Date
David McKay 8b46745755 fix(reskinnable-demo): collapse HITL approval buttons on the tool result (#6404)
Ports the banking demo's #6401 fix, which was never carried over to
`reskinnable-demo`. Found while bringing the demo up against a local
Intelligence stack.

## The bug

`ApprovalButtons` collapsed only on local `responded` state, which dies
with the component. These cards **do** get remounted when the run syncs,
which resurrects live Approve/Deny buttons on an action the user already
took — a second click fires a duplicate write against an already-settled
call.

Reproduced in the banking skin: clicking the "Approve the $15,000 AWS
charge" pill and approving the policy exception left a **second card
carrying live Approve/Deny buttons** (with empty args).

## The fix

Adds a durable `resolved` prop, OR-ed with the local state so a click
still collapses without waiting for the round trip. It is passed from
the tool call itself:

```tsx
resolved={status === "complete" || !!result}
```

Applied at the three HITL renders that don't already early-return on
`status === "complete"` (`openPolicyException`,
`finalizePolicyException`, `approveTransaction`).

The other three (`offerWorkflowRecording`,
`awaitDashboardDemonstration`, `saveLearnedWorkflow`) render their own
terminal card when complete, so they never reach the buttons — passing
`resolved` there is both redundant and a type error, since `status` is
narrowed to `ToolCallStatus.Executing`. That is why banking also has
exactly three call sites.

## Verification

- Before: second card had live Approve/Deny. After: it reads *"Response
submitted."*
- `pnpm lint` → exit 0
- `pnpm build` (the type-check gate) → exit 0

Note: the duplicate card still renders — that comes from a separate
pre-existing `Encountered two children with the same key` warning also
present in banking, and is out of scope here. This PR removes the
*duplicate-write* hazard, which is what #6401 addressed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-05 12:05:38 -07:00
Maxim 3fde920ea4 Merge branch 'main' into fix/reskinnable-demo-hitl-resolved 2026-08-05 21:05:31 +02:00
Ran Shemtov 4ad21db755 fix(mastra-showcase): beautiful-chat A2UI — ground dynamic render + fixed-schema flights (PNI-122) (#6387)
Fixes **PNI-122** — beautiful-chat A2UI dynamic renders a varying error
/ no UI, flights render no UI, and (multi-turn) the dashboard paints
loose charts. All fixed and **verified live on a real LLM** (gpt-5.4
outer + gpt-4.1 render, matching gold `beautiful_chat.py`).

## 1. Dynamic A2UI ungrounded (Sales Dashboard) — no UI / varying error
`generate_a2ui` grounded its inner `render_a2ui` subagent from the
tool's `contextEntries` ARG, which the outer model always sends
**empty** (captured live: `contextEntries: []`) → empty system prompt →
invalid/misnamed components (or none) → no UI, nondeterministic. aimock
hid it (fixture returns a valid envelope regardless).

**Fix:** read the catalog schema + generation guidelines the
`@ag-ui/mastra` bridge already forwards onto the Mastra request context
(`requestContext.get("ag-ui").context`) and ground the render there.
Mirrors `readAgUiContext` in `@ag-ui/mastra`'s `getA2UITools`; preserves
per-demo catalogId. New leaf `tools/a2ui-context.ts` + regression test.

## 2. Flights narrated as text — langgraph-python parity
mastra reused the shared `searchFlightsTool` (plain `{flights}`,
rendered by the tool-rendering cells' own frontend `FlightListCard`), so
beautiful-chat produced no A2UI surface. Gold `beautiful_chat.py` wires
a **dedicated fixed-schema `search_flights`** returning an
`a2ui_operations` FlightCard envelope. Mirrored via
`searchFlightsA2uiTool` + a dedicated `beautifulChatAgent` (query_data,
todos, generate_a2ui, the fixed search_flights, flight/dashboard
steering, `parallel_tool_calls=False`, gpt-5.4). Route repointed to it,
keeping the fixed flights + steering out of the shared `weatherAgent` /
tool-rendering cells.

## 3. Dashboard over-called standalone charts (multi-turn)
gpt-4o fired the standalone `pieChart`/`barChart` frontend tools **and**
`generate_a2ui`, painting loose charts next to the dashboard. **Fix:**
gold's `parallel_tool_calls=False` + gpt-5.4 + sharpened steering (a
dashboard / "using A2UI" request calls generate_a2ui ONLY; a
single-chart request still uses the standalone tool). The aimock side
had the same over-call **baked into `recorded.json`** (a real 2026-05-15
gpt-4o session) — dropped that turnIndex-2 leg so the aimock chain is
`query_data → generate_a2ui → narration`, matching live. Flights aimock
fixture realigned to `search_flights`.

## Verification
Ran the built branch locally against a **real OpenAI key**:
- Sales Dashboard (A2UI Dynamic) → full grounded dashboard,
`[query_data, generate_a2ui]` only, single **and** after-flights ✅
- Search Flights pill → two FlightCard surfaces (no A2UI steering
needed) ✅
- Standalone Pie / Bar pills → still call `pieChart`/`barChart` and
render ✅

Test suite: added `a2ui-context.test.ts` (5/5). No new failures
(pre-existing `route.test.ts` + `demoAgentNames.parity` fail on `main`).

✅ **Aimock verified locally too** — ran the aimock image (context-routed
d6 fixtures) at :14010 and pointed the app at it via `OPENAI_BASE_URL`.
Flights pill → `search_flights` → 2 FlightCards (United $349 / Delta
$289). Sales Dashboard (after flights) → `generate_a2ui` only, no
standalone chart over-call; renders Total Revenue + 1 pie + 1 bar
(exactly 2 recharts containers). Matches live.

## Follow-ups (out of PNI-122 scope)
- Tool-call/text render ORDER in multi-turn is the tracked Mastra
one-message-id bug (separate chip).
- The dedicated `a2ui-fixed-schema` **demo** (catalog
`flight-fixed-catalog`) still uses the plain shared `search_flights`;
gold uses a separate `display_flight` there.
2026-08-05 21:03:47 +02:00
Ran Shemtov 21dcd95ce2 Merge branch 'main' into claude/competent-chatelet-7305ee 2026-08-05 21:03:41 +02:00
Ben Taylor 26d352f898 fix(channels): default welcome agent prompt (#6377)
## What does this PR do?

- Gives `thread.runAgent()` inside `onWelcome` the default prompt
`"Introduce yourself to the channel!"`.
- Keeps an explicit `runAgent({ prompt })` ahead of the default.
- Adds regression coverage for the default and override paths.

Welcome deliveries have no inbound message. Before this change,
`thread.runAgent()` passed an empty message list to the AI SDK, which
rejected the run before it reached the model.

## Related PRs and Issues

- No linked issue.

## Testing

- `pnpm nx test @copilotkit/channels-core -- --run src/welcome.test.ts`
- `pnpm nx run-many -t test,check-types,build
--projects=@copilotkit/channels-core`
- `pnpm run lint`
- `pnpm run check-format`
- `pnpm nx run-many -t publint,attw
--projects=@copilotkit/channels-core`

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] Maintainers can edit this same-repository branch; GitHub only
shows the "Allow edits by maintainers" control for forks
2026-08-05 14:02:50 -05:00
Austin Merrick ab7a50fa10 feat(inspector): add agent-ready Rich Threads setup 2026-08-05 11:55:53 -07:00
Austin Merrick ec101367c7 test(runtime): isolate metadata fetch assertions 2026-08-05 11:55:52 -07:00
Austin Merrick b3e1586330 fix(web-inspector): link Rich Threads setup 2026-08-05 11:55:52 -07:00
Austin Merrick 5ebba2b098 feat(web-inspector): warn before thread limits 2026-08-05 11:55:52 -07:00
Austin Merrick ec510e2521 chore(web-inspector): keep scenario lab internal 2026-08-05 11:55:51 -07:00
Austin Merrick 0982e96358 fix(web-inspector): correct thread empty states 2026-08-05 11:55:51 -07:00
Austin Merrick 9b604378aa test(channels): update fetch mocks for current types 2026-08-05 11:55:50 -07:00
Austin Merrick 7c3d043905 fix(web-inspector): use organization billing lab link 2026-08-05 11:55:50 -07:00
Austin Merrick de3ca81721 docs(inspector): document shipped usage states 2026-08-05 11:55:50 -07:00
Austin Merrick 0f3e2bf8ce docs(inspector): explain the thread state lab 2026-08-05 11:55:49 -07:00
Austin Merrick 98bf62143e test(web-inspector): add thread state lab 2026-08-05 11:55:49 -07:00
Austin Merrick ace43229a1 fix(web-inspector): keep inspector accessible on small screens 2026-08-05 11:55:48 -07:00
Austin Merrick 3e23f25391 fix(web-inspector): coarse-grain thread telemetry 2026-08-05 11:55:48 -07:00
Austin Merrick f4bb5eca83 feat(web-inspector): align thread detail labels 2026-08-05 11:55:48 -07:00
Austin Merrick 8451d8d40d fix(web-inspector): harden thread demo video 2026-08-05 11:55:47 -07:00
Austin Merrick a3a9eeff09 feat(web-inspector): unify locked and empty threads 2026-08-05 11:55:47 -07:00
Austin Merrick 63a66a9db8 feat(web-inspector): render thread usage footer 2026-08-05 11:55:46 -07:00
Austin Merrick e35a907ee7 feat(web-inspector): group inspector navigation 2026-08-05 11:55:46 -07:00
Austin Merrick 6ed9516620 fix(web-inspector): preserve thread selection provenance 2026-08-05 11:55:46 -07:00
Austin Merrick dfd28faaed fix(web-inspector): select the newest visible thread 2026-08-05 11:55:46 -07:00
Austin Merrick a223c757a3 fix(web-inspector): reload details after reconnect 2026-08-05 11:55:45 -07:00
Austin Merrick d9d02aac81 fix(web-inspector): preserve replacement thread stores 2026-08-05 11:55:45 -07:00
Austin Merrick fbbb4eb92c fix(web-inspector): require explicit thread capability 2026-08-05 11:55:45 -07:00
Austin Merrick 4765fc063e feat(web-inspector): project thread usage metadata 2026-08-05 11:55:45 -07:00
Austin Merrick 4a5bf2b419 test(core): prove inspector expiry snapshots 2026-08-05 11:55:44 -07:00
Austin Merrick ae0aa1f75a test(runtime): prove inspector expiry pass-through 2026-08-05 11:55:44 -07:00
Austin Merrick 149602d39c feat(shared): parse optional inspector expiry usage 2026-08-05 11:55:44 -07:00
Austin Merrick 46b692ba24 fix(inspector): drop out-of-scope expiry metadata 2026-08-05 11:55:43 -07:00
Austin Merrick 8f8d19f120 fix(inspector): clear metadata on auth changes 2026-08-05 11:55:43 -07:00
Austin Merrick 8b73765719 fix(inspector): time out optional metadata requests 2026-08-05 11:55:42 -07:00
Austin Merrick 92c162e122 fix(web-inspector): preserve fetch platform helpers 2026-08-05 11:55:42 -07:00
Austin Merrick b5f68e06af fix(shared): accept producer loopback action URLs 2026-08-05 11:55:41 -07:00
Austin Merrick 1b26dac000 test(web-inspector): omit readonly metadata fixture field 2026-08-05 11:55:41 -07:00
Austin Merrick de58e30002 docs(inspector): explain optional metadata flow 2026-08-05 11:55:41 -07:00
Austin Merrick 548385c8d9 feat(web-inspector): track coarse metadata events 2026-08-05 11:55:40 -07:00
Austin Merrick e9e5e6e457 feat(web-inspector): show trusted project context 2026-08-05 11:55:40 -07:00
Austin Merrick f720dabd78 feat(core): carry optional inspector metadata 2026-08-05 11:55:40 -07:00
Austin Merrick 9648fefc13 feat(runtime): proxy optional inspector metadata 2026-08-05 11:55:39 -07:00
Austin Merrick 5c6b81a154 feat(shared): define inspector metadata v1 2026-08-05 11:55:39 -07:00
Ran Shemtov f58cc22750 Merge branch 'main' into claude/competent-chatelet-7305ee 2026-08-05 20:53:04 +02:00
Tyler Slaton 7f2a7a9638 fix(channels): prefer inbound prompt over the welcome default
Review follow-up: resolve the default prompt after the implicit inbound
prompt, so real user input outranks the welcome default and the
implicit-inbound-consumed flag can never mark a turn consumed that was
never injected. Pin the seeded-store welcome path (all shipping
adapters) and the inbound-over-default precedence with tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 11:53:00 -07:00
Ran Shemtov 0f836ece91 fix(showcase/mastra): return gold-shaped search_flights result so flight rows render (#6397)
Fixes
[PNI-121](https://linear.app/copilotkit/issue/PNI-121/mastra-tool-rendering-results-delivered-out-of-sequence).

## Symptom

On a **live** endpoint the `tool-rendering` flight card rendered every
row blank — `United ? → ? —` — while the model's narration right below
it carried the real times and prices. Against aimock the demo looked
fine, which is why it slipped through.

## Root cause

The tool result was delivered in full. The card just never matched it.

Captured from the live runtime SSE:

- `search_flights` result: `{ flights: [{ airline: "United",
flightNumber: "UA231", departureTime: "08:15", arrivalTime: "16:45",
price: "$348" }] }`
- `FlightListCard` reads: `{ airline, flight, depart, arrive, price_usd
}`

Only `airline` overlapped, so everything else fell back to the `?` / `—`
placeholders.

That card is byte-identical to gold `langgraph-python`'s, and gold's
`tool_rendering_agent.py` `search_flights` returns exactly `{ airline,
flight, depart, arrive, price_usd }`. This integration's tool had
drifted to Mastra-flavored keys while keeping a "gold parity" comment.

## Fix

Return the gold result shape directly. The legacy caller-supplied
`flights` passthrough is untouched, and the only consumers of this tool
are the three tool-rendering-style agents, all of which drive
gold-shaped cards — so there is no other call site to migrate.

## Verification

Reproduced and fixed on a **live real-LLM endpoint** (no aimock), same
rig both times:

| | flight rows |
|---|---|
| before | `United ? → ? —` / `Delta ? → ? —` / `JetBlue ? → ? —` |
| after | `United UA231 08:15 → 16:45 $348` / `Delta DL412 11:20 → 19:55
$312` / `JetBlue B6722 17:05 → 01:30 $289` |

Also confirmed after the change:

- `tool-rendering-custom-catchall` — renders the gold-shaped result
cleanly
- `tool-rendering-reasoning-chain` — its own flight card renders all
three rows populated
- two-turn weather + flights conversation — each card lands in its own
turn, no placeholders
- `vitest` — identical pass/fail counts with and without this change (13
pre-existing `route.test.ts` header-mock failures, unrelated)

## Test coverage

The existing e2e only asserted origin/destination (which come from the
tool **args**) plus a row count, so blank rows passed. It now asserts
the **result's** `depart`/`arrive`/`price` and explicitly rejects the `?
→ ?` placeholder — fails before this change, passes after.
2026-08-05 20:52:55 +02:00
Ran Shemtov a03b6b816c Merge branch 'main' into ran/pni-121-mastra-tool-rendering-results-delivered-out-of-sequence 2026-08-05 20:52:45 +02:00
Tyler Slaton 949b6c02ad fix(channels-slack): clear the status when a tool call follows the first reply (#6399)
Slack keeps showing "is thinking…" long after the answer has been
posted, whenever an agent narrates before calling a tool.

## Repro

Any AG-UI agent whose stream is `text → TOOL_CALL_* → text`. Ours
narrates because its system prompt says *"say what you are about to
do"*:

> **antigravity**: I am going to check the system hostname using
`hostname` and `uname -a`.
> **antigravity**: Here are your system location details: …
> *antigravity is thinking…* ← still spinning, minutes later

The run is genuinely finished: the handler returns (`runAgent ← returned
after 9913ms`), both services go silent, and the thread contains the
complete reply.

## Cause

`postedReply` latches on the first posted reply, making `clearStatus` a
one-shot:

```ts
const onFirstReply = async () => {
  if (postedReply) return;
  postedReply = true;
  await clearStatus();
};
```

But the status is written again *after* that latch closes —
`onToolCallStartEvent` and `onToolCallEndEvent` both call `setStatus`.
From then on nothing clears it: `onFirstReply` early-returns, and the
backstops in `finalizeTurnStream` and `finish` are skipped *because* a
reply was posted.

Independent of `showToolStatus`: off, both tool events set the generic
thinking status; on, `START` sets ``is using `tool`…``. Either way the
write lands after the latch.

Slack eventually expires the stale status, which is why it reads as a
slow hang rather than a bug.

## Fix

The latch is really tracking *"the status is already cleared for what is
on screen"*, not *"a reply has been posted"*. `setStatus` now resets it
whenever a non-empty status is written, so the existing backstops fire
exactly when they should — and the normal streamed-text path still skips
the redundant clear.

```ts
if (text) postedReply = false;
```

## Test

A regression test drives text → tool → text and asserts the final status
is `""`. Verified failing without the change:

```
AssertionError: expected 'is thinking…' to be ''
```

`packages/channels-slack`: **32/32 passing**.

Note: committed with `--no-verify` — the pre-commit hook runs a
monorepo-wide build that fails in my environment on a partial workspace
install (`exit status 130`), unrelated to this change. CI will run the
real checks.
2026-08-05 11:48:07 -07:00
Tyler Slaton 96e2f064b8 fix(channels): default welcome agent prompt 2026-08-05 11:39:09 -07:00