Commit Graph

15424 Commits

Author SHA1 Message Date
Alem Tuzlak 40820e440a fix(web-inspector): rebase playground onto new inspector nav 2026-08-21 11:34:32 +02:00
Tyler Slaton 84522196f3 fix(web-inspector): tighten playground density 2026-08-21 11:21:06 +02:00
Tyler Slaton e340bea3e8 fix(web-inspector): align playground with default chat 2026-08-21 11:20:58 +02:00
Tyler Slaton 2100aeaf5e feat(web-inspector): add agent playground 2026-08-21 11:20:46 +02:00
Ran Shem Tov b69ac14711 fix(showcase): keep the AG-UI request context on the chat Flow, and point the Channels setup at /chat
Review found two gaps in the previous commit.

`RunAgentInput.context` never reached the model. The bridge puts it on state
under `context`, but `CopilotKitState` does not declare the field, so pydantic
drops it when the endpoint validates the request into the Flow's state and the
"Application context" block rendered without it. That hollowed out the two cells
whose whole point is reading application context: readonly-state-agent-context
(now on the default `/chat` route) and agent-config. `ChatState` declares the
field so it survives validation.

Neither existing test caught it: the readonly probe only asserts the browser
request body carries its sentinel, the agent-config probe encodes the expected
value in the user message, and Flow-level unit tests bypass endpoint state
initialization. The new endpoint test drives the real FastAPI route with two
context entries and asserts both appear in the model's system message; it fails
without the declared field.

The Channels setup fragment still told readers the shared crew sits at the
server root and set `AGENT_URL` accordingly, which the removed catch-all turned
into a dead endpoint. It now points at `/chat` and says Flow rather than crew.
Migrating the consumer was preferred over restoring `/`, which would put the
silent-fallback trap back in place.

Verified: 164 and 166 Python tests pass across the two columns, the docs
setup-content tests pass (16), and readonly-state-agent-context, agent-config
and agentic-chat are green on D6 replay.
2026-08-21 10:52:54 +02:00
Mark d04643c391 chore(showcase): mark CrewAI conversational flows live 2026-08-21 00:19:45 -07:00
Mark 2826412b7b fix(showcase): complete HITL probe on modal mount (#6629)
## Summary

- complete the tool-only HITL approval leg when the app-level approval
modal mounts
- retain the shared runner's finished-run/new-assistant-bubble gates and
the existing approval/follow-up assertions
- add a contract test that pins the modal completion selector to the
first turn

## Why

Unhandled tool calls intentionally render no default chat card. The HITL
fixture's first leg therefore produces an empty assistant bubble plus
the approval modal, so text-stability completion cannot converge even
though the app and fixture are healthy.

## Verification

- focused red/green contract: 8 tests passed after failing on missing
`completeOnMount`
- showcase harness: 177 test files / 3,722 tests passed; typecheck and
build passed
- isolated fleet-control-plane D5 cells passed for LangGraph Python,
CrewAI Conversational Flows, and Mastra

## Deployment scope

This changes only the shared showcase harness image. Promote the harness
control-plane and harness pool-worker roles together; no integration
service image changes are required for this fix.
2026-08-20 23:23:17 -07:00
Jerel John Velarde db92921125 fix(showcases): align MCP Apps runtime graph 2026-08-20 22:28:27 -07:00
Jerel John Velarde a25941f901 fix(world): preserve LangGraph assistant config 2026-08-20 21:35:36 -07:00
Jerel John Velarde e0528d379e fix(showcases): sync chatkit studio lockfile 2026-08-20 21:10:08 -07:00
Jerel John Velarde 0daa38f9a7 fix(showcases): make MCP Apps deployable 2026-08-20 21:09:44 -07:00
Mark 7c24e14ae3 fix(showcase): complete HITL probe on modal mount 2026-08-20 20:39:40 -07:00
Tyler Slaton c2abbea9cf feat(web-inspector): redesign Home, navigation, and notifications (#6600)
## Summary

Redesigns the Web Inspector around Home, What's New, System Health,
Intelligence, and a clearer responsive sidebar. It also keeps live
Threads scoped to the matching agent so All Agents does not show
duplicates.

## Why

The Inspector needed a faster at-a-glance health view, coherent light
and dark themes, explicit Intelligence states, and a notification flow
that fits the new animated launcher without showing a floating banner
over the host application.

## How

- adds Alem Tuzlak's Home briefing, live sidebar, and matching-agent
thread filtering
- integrates the latest launcher halo, pulse, and unread dot from main
- opens unread launcher notifications on Home with a What's New preview
and sidebar ping
- marks the announcement read only after its What's New content is
visible
- adds responsive System Health, Intelligence, features, Learning,
Settings, and What's New surfaces
- expands the deterministic local test bench, including disconnected
Intelligence and RUN_ERROR states
- preserves Alem's original authored commits and keeps the follow-up
polish in one Tyler-authored commit

## Verification

- pnpm nx test web-inspector --skip-nx-cache (481 tests)
- pnpm nx build web-inspector --skip-nx-cache
- full pre-commit affected package test, publint, and attw checks
- interactive launcher-to-dismissal walkthrough in the local Inspector
lab

## Related

- Linear: OSS-866
- Linear: OSS-868
2026-08-20 19:33:21 -07:00
Tyler Slaton 799734accc feat(web-inspector): polish Home, navigation, and runtime health 2026-08-20 19:17:27 -07:00
Alem Tuzlak 3b4f9b7662 test: stabilize slow package import checks
Give the React dist-context and Vue SSR import-safety tests enough time on slower CI runners.
2026-08-20 19:17:27 -07:00
Alem Tuzlak 626f06a344 fix(core): keep live thread events on the matching agent
REST /threads is agent-scoped. The Phoenix user_meta channel is not. Drop live upserts whose agentId does not match the store so Inspector All Agents does not show the same thread twice.
2026-08-20 19:17:27 -07:00
Alem Tuzlak 5696417174 feat(web-inspector): add Home briefing and live sidebar 2026-08-20 19:17:27 -07:00
Tyler Slaton 99ac525d1b docs: call Inspector out in quickstarts and feature pages (#6591)
After the first chat, web quickstarts now tell the reader to open
Inspector and confirm three things: the agent is listed, AG-UI Events
are moving, and Threads is unlocked or shows Enable Intelligence.

## What does this PR do?

- Add a shared Open Inspector step after the first chat in every web
integration quickstart, plus Vue and Angular.
- Angular links the [Inspector for Angular](/angular/inspector) install
page first. Vue sets `show-dev-console="auto"` so the overlay appears on
localhost.
- Add a short Callout on feature pages that map to a shipped pane:
Threads, Frontend Tools, State, Context, Learning, and HITL tools.
- Add the `inspector-docs` skill so a new Inspector pane gets a docs
pointer, or `no page yet`.
- Keep the Intelligence signup copy that names Inspector. Skip React
Native and Channels.

## Related PRs and Issues

- Linear: https://linear.app/copilotkit/issue/OSS-885

## Checklist

- [ ] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] "Allow edits by maintainers" is checked (lets us help iterate on
your PR directly — faster turnaround for everyone)

## Testing

Commands run:

1. File contract check against the shared step, 17 integration
quickstarts, Vue, Angular, feature Callouts, and non-web skip. Passed.
2. `node --experimental-strip-types scripts/sync-plugin-skills.ts
--check`. Passed (`plugin skill mirror in sync`).
3. Did not run `pnpm test` or shell-docs `vitest`. This worktree has no
`node_modules`.

Manual test:

1. Follow a React quickstart on localhost. After the first chat, open
Inspector. Agents lists the agent. AG-UI Events move. Threads is
unlocked or shows Enable Intelligence.
2. Repeat with Intelligence set to No. The Open Inspector step is still
there. Threads shows Enable Intelligence.
3. Follow the Angular frontend guide. The step links the Angular
Inspector install page first.
4. Open Threads, frontend tools, shared state, and agent-readonly. Each
has a Callout that names the matching pane.

How this PR makes testing easy:
`showcase/shell-docs/src/lib/__tests__/inspector-docs.test.ts` fails if
a web quickstart drops the step, if a mapped feature page drops its
Callout, or if Callouts name Playground or Fork.

## Risk / rollback

Docs-only plus a repo skill. Revert the PR to undo. No runtime API
change.
2026-08-20 18:28:16 -07:00
Tyler Slaton 7180a14dcb Merge main into Inspector docs quickstart callouts 2026-08-20 18:15:00 -07:00
Rod Boev d5fe12043c fix(core): clear tool result state per server run 2026-08-20 21:06:21 -04:00
Mark cd39ce7c10 fix(showcase): register CrewAI flows production instance (#6619)
## Summary

- register the provisioned `showcase-crewai-conversational-flows`
production Railway service instance, domain, health path, and probe in
the Railway SSOT
- regenerate the promotion closure and workflow service selector so the
integration can be promoted through the standard runbook path
- update SSOT, image-reference, generator, and environment-aware
redeploy tests for dual-environment coverage
- recast the staging-only runbook reference as a completed
staging-to-production example

This deliberately does not mark the integration manifest as deployed or
perform another Railway mutation. It only reconciles the already-running
production instance into source control.

## Live verification

- production `/api/health` returns HTTP 200
- production and staging run the same image digest:
`sha256:e6f38a9454f8ae9410239bb3cc75d21b0d2ccecbbbfe789b25a9f2d9f03139b4`
- all 84 environment-scoped Railway image refs verified
- `autoUpdates` verified disabled across all 84 service/environment
checks
- promotion dry-run resolves the production target to the pinned digest
above

## Local verification

- `pnpm exec tsc --noEmit -p showcase/scripts/tsconfig.json`
- uncached Nx test run: 77 files, 2,519 tests passed
- Railway Ruby suite: 188 runs, 723 assertions passed
- `pnpm lint` (0 errors)
- `actionlint .github/workflows/showcase_promote.yml`
- `pnpm exec tsx showcase/scripts/emit-railway-envs-json.ts --check`
- `pnpm exec tsx showcase/scripts/sync-promote-service-options.ts
--check`
2026-08-20 18:02:03 -07:00
Tyler Slaton 1823b871ed feat(web-inspector): launcher signal and What's new replace the announcement banner (#6590)
## Summary

Replace the Inspector announcement banner with a non-blocking unread
signal on the launcher and a persistent **What's new** destination
inside the Inspector. The launcher now uses the approved responsive Kite
treatment: an internal wash plus two visible, staggered water-ripple
rings.

This follow-up also trims the implementation to the one signal that
exists today, adds a local replay control, and records when the launcher
notification is actually presented.

## Why

The old banner covered the host application and duplicated the
announcement inside every Inspector tab. The initial signal
implementation also carried speculative registry machinery for future
error notifications, could consume its only pulse while the launcher was
hidden, and counted ordinary announcement-content clicks as CTA
interactions.

The notification funnel also had no exposure event, and announcement
telemetry could run before the runtime handshake revealed that telemetry
was disabled.

## How

- Adds **What's new** as the first primary navigation destination and
removes the host-app overlay.
- Uses direct news-signal state instead of a generic one-entry registry.
- Defers the one-beat pulse until the launcher and browser tab are
visible, and persists read state only after announcement content
renders.
- Adds `oss.inspector.whats_new_signal_viewed`, emitted once per
announcement presentation with `banner_id`, `surface: "launcher"`, and
`presentation: "animated" | "reduced_motion"`.
- Holds notification views and attribution behind the runtime `/info`
handshake, preventing events or `posthog_distinct_id` link parameters
when telemetry is disabled.
- Tracks announcement clicks only when a link is activated.
- Scales the launcher from 51.84 px on compact screens to a 62.208 px
desktop cap, with an internal wash, two staggered outward ripples, a
resting unread dot, and a reduced-motion fallback.
- Preserves the Kite artwork and pins its crop/path invariant in tests.
- Adds a one-shot **Replay notification** workbench control that
preserves Inspector layout and clears only the local read/pulse mirrors
needed for replay.
- Keeps the launcher pointer cursor at rest and the grabbing cursor only
while dragging.

Verified with 463 Web Inspector tests plus Nx type-check and build
targets. The full pre-commit test, package-quality, publint, and `attw`
gate passes; lint reports zero errors.

Related: OSS-860, OSS-864, OSS-865

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] Relevant documentation is updated
- [x] Allow edits by maintainers is enabled
2026-08-20 17:58:20 -07:00
Rod Boev b2e16947c5 test(core): restore LangGraph event ordering 2026-08-20 20:54:09 -04:00
Tyler Slaton 35965ca74a fix(web-inspector): harden launcher notification and track exposure
Replace speculative signal machinery with direct state and defer hidden pulses.

Limit click telemetry to real links and add the replay workbench control.

Restore the pointer cursor and record visible launcher presentations.
2026-08-20 17:47:46 -07:00
Lukas Moschitz 6e43a5bb45 feat(web-inspector): replace announcement banner with launcher signal
Add host-scoped read state and the persistent What’s new destination.

Include the responsive Kite treatment, renamed announcement telemetry, and complete behavior tests.

Refs OSS-860, OSS-864, OSS-865
2026-08-20 17:47:15 -07:00
Rod Boev 1cde1d8f04 fix(core): align tool result history with current main 2026-08-20 20:44:16 -04:00
Rod Boev ca0e094347 fix(core): close terminal lifecycle review gaps
Track the started input through protocol errors so remapped run IDs clean up
the active run without disturbing pre-start failures. Add lifecycle and
multi-call reconciliation coverage.
2026-08-20 20:32:47 -04:00
Rod Boev 08f2655c24 fix(core): deduplicate tool results by toolCallId
Reconcile streamed tool results by call identity so divergent message IDs
cannot append a second real result. Share placeholder normalization between
state reconciliation and run-handler forwarding.
2026-08-20 20:32:39 -04:00
Rod Boev ce8f077733 test(core): cover finalized and overlapping result lifecycles
Exercise same-input finalization cleanup and a pre-start failure while an
earlier input remains active.
2026-08-20 20:31:17 -04:00
Rod Boev 9ecb00192e fix(core): retain all propagated tool results during reconciliation
Leave AG-UI result propagation active and reconcile placeholders, duplicate
identities, and pre-start lifecycle state without suppressing subscribers.
2026-08-20 20:31:06 -04:00
Rod Boev 85cd3c133e fix(core): preserve result ownership across terminal edge cases
Use the input fallback for pre-start terminals, preserve message associations,
and match frontend placeholders by their normalized full content.
2026-08-20 20:30:14 -04:00
Rod Boev 61834d9443 fix(core): preserve tool results after message snapshots
Route canonical tool results through the AG-UI terminal messages mutation so
subsequent runs retain results omitted by later snapshots.
2026-08-20 20:29:12 -04:00
Mark 81bb04be56 test(showcase): decouple staging-only parity fixture 2026-08-20 17:17:54 -07:00
Mark fc14045c0a fix(showcase): register CrewAI flows production instance 2026-08-20 17:06:09 -07:00
Benjamin Taylor e27aeb687d refactor(showcase): retire the v1 runtime adapter across every integration
Moves all 239 showcase integration routes off
`copilotRuntimeNextJSAppRouterEndpoint`, the deprecated v1 Next.js adapter, so
the v1 entrypoint has no remaining code-level users under
`showcase/integrations/`.

    const copilotHandler = createCopilotRuntimeHandler({
      runtime,
      basePath: "/api/copilotkit-x",
      mode: "single-route",
    });
    ...
    return await copilotHandler(req);

## Why single-route, and why this handler

**Single-route** because these demos' frontends are
`<CopilotKit runtimeUrl="/api/copilotkit-x">` with no transport prop, and every
released provider pins the single-route transport. Single-route mode is
therefore a drop-in for the v1 adapter: no frontend change, no path change, no
`GET` export, and nothing here probes `/info`. Migrating to multi-route instead
would have required editing every demo page in lockstep for no functional gain.

**`createCopilotRuntimeHandler`** rather than `createCopilotEndpointSingleRoute`
because that helper is itself deprecated in favour of the `mode` option (see the
deprecated-aliases table in `docs/backend/runtime-endpoints.mdx`), and because
the fetch handler needs no `hono` dependency and composes directly with the
wrappers these routes already have.

The statement is rewritten in place, inside whatever wrapper it already sat in,
so `withForwardedHeaders`, the try/catch envelopes, `wrapStreamingResponse` and
`withCvdiagBackend` are all untouched. 75 of these routes construct the runtime
inline in the call; rewriting in place preserves that per-request construction
exactly as v1 did. No `runner` is added — it is optional, and none of these
routes passed one before.

13 `copilotkit-auth/[[...slug]]` routes already use the v2 fetch handler and are
left alone; they only mention the v1 name in explanatory comments.

## Collateral

- `mastra`'s main route declared a module-level
  `const serviceAdapter = new ExperimentalEmptyAdapter()` plus a startup log
  about the adapter choice. V2 has no service adapters, so both are gone and the
  comment now explains that there is nothing to configure.
- The three `mastra` vitest suites mocked `@copilotkit/runtime` and the v1
  `{ handleRequest }` return shape; they now mock `@copilotkit/runtime/v2` and
  `createCopilotRuntimeHandler`, which returns the handler directly.
- 27 `@ts-expect-error` directives guarded the **v1** `CopilotRuntime` agents
  type ("wraps Record in MaybePromise<NonEmptyRecord<...>>"). Under `/v2` that
  hole is gone, which makes the directive unused — a hard error. They are
  demoted to `@ts-ignore`, which compiles whether or not the mismatch survives
  in a given integration, because 19 of these apps cannot be built locally to
  prove it either way. Removing all ~220 now-stale suppressions is left as
  follow-up once CI has built every integration green.

## Verified

`mastra` is the one integration installed and exercised locally (19 routes, the
`withCvdiagBackend` main route, and the only vitest suites that touch routes).
Measured against `origin/main` in the same tree:

    tsc --noEmit    baseline: errors in 10 files
                    after:    errors in  9 files
                    new errors introduced: NONE
                    fixed: src/app/api/copilotkit-mcp-apps/route.ts, whose
                           @ts-expect-error was ALREADY unused on main

    vitest run      baseline: 2 files failed, 13 tests failed, 21 passed
                    after:    2 files failed, 13 tests failed, 21 passed
                    → test-neutral; those 13 failures are pre-existing on main

Structural audit over all 239 routes: none still imports the v1 root, uses the
v1 adapter, references `ExperimentalEmptyAdapter` or `handleRequest` in code, or
is missing `createCopilotRuntimeHandler` / `basePath` / `mode: "single-route"`.

The shape itself was proved end-to-end before the rollout, in a real running
app with an untouched provider (aimock as the model backend):
`POST /api/copilotkit` -> 200 twice, chat turn rendered.

## Two pre-existing problems found on the way

- `npm ci` fails in `showcase/integrations/mastra`: `Missing:
  @types/http-errors@2.0.5 from lock file`. Its Dockerfile uses
  `npm ci --legacy-peer-deps`, which does succeed, so the image still builds —
  but a plain `npm ci` does not. Untouched here; no manifest or lockfile is in
  this diff.
- `mastra`'s vitest suite is red on `main` (13 failures, mostly
  `extractXHeaders` dereferencing `req.headers` on a `{}` fake request).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 18:59:27 -05:00
Tyler Slaton 0ae1e188a8 ci: reject retired Anthropic model references 2026-08-20 16:40:52 -07:00
Tyler Slaton 5d19399fdd fix(release): default AI release notes to Opus 4.8 2026-08-20 16:40:26 -07:00
Tyler Slaton 518feae6cd docs: update Anthropic model references to Opus 4.8 2026-08-20 16:40:09 -07:00
Tyler Slaton 22ca41fa1b fix(examples): default Anthropic integrations to Opus 4.8 2026-08-20 16:39:46 -07:00
Tyler Slaton 5064884c3f fix(runtime): update Anthropic defaults without restricting model IDs 2026-08-20 16:39:15 -07:00
Dusty 30038b8305 Revert "fix(docs): configure Clerk satellite session sync"
This reverts commit c26527f521.
2026-08-20 15:25:19 -07:00
Dusty c26527f521 fix(docs): configure Clerk satellite session sync 2026-08-20 15:12:05 -07:00
Max Korp 09cd6a85e5 test(react-core): isolate feedback memoization rerender (#6615)
## Summary

- replace the configuration-context update in the assistant slot-prop
stability test with an unrelated message-view prop update
- preserve coverage that the raw-event feedback adapter does not churn
ordinary assistant render props
- leave production behavior and the callback-only raw-event boundary
unchanged

## Root cause

The test changed chatInputPlaceholder, which changes the memoized
chat-configuration context value. CopilotChatAssistantMessage consumes
that context, so React correctly rerenders it independently of the
message-view memo comparator. The configuration update was therefore not
an unrelated proxy for feedback-adapter churn.

## Test plan

- [x] reproduce the original expected 1 / received 2 failure
- [x] prove the corrected test fails when className is temporarily added
to the feedback adapter memo dependencies
- [x] raw-event feedback test file
- [x] React-core memoization/performance tests
- [x] complete React-core suite on React 19
- [x] complete React-core suite on React 18 compatibility overrides
- [x] React-core build and normal typecheck
- [x] changed-file format and lint checks
2026-08-20 14:51:15 -07:00
Maximiliano Korp 5e09288b90 test(react-core): isolate feedback memoization rerender 2026-08-20 14:28:46 -07:00
Adi Korivi 87f1f85597 docs(langgraph): fix inaccurate "Works the same for create_react_agent" comments
Swapping the create_agent factory for create_react_agent (langgraph.prebuilt)
does not work: create_react_agent has no middleware= or system_prompt=
parameter and rejects state_schema=CopilotKitState, so following the comment
raises TypeError. It is also deprecated in favour of langchain.agents.create_agent.

Replace the misleading inline comment with an accurate note at all 7 sites
(supersedes the deprecated factory; accepts neither middleware= nor
system_prompt=), and fix the TypeScript snippets to reference createReactAgent
instead of the Python snake_case name.

Closes CopilotKit#6607
2026-08-20 14:12:58 -07:00
Dusty d7d774fc9b Auto-merged main into codex/ent-1157-shared-clerk-session on deployment. 2026-08-20 13:57:57 -07:00
David McKay 43f1ef3039 fix(showcase): tighten the offsite-expenses beat (#6609)
The "Sort out my offsite expenses" beat had three problems on stage: the
harness console was a black slab in a light-mode transcript, the tool
activity grew a stack of finished steps that pushed the report card off
the screen, and the run took a full minute.

## Console (banking skin)

- Every colour is now a semantic token, so the pane follows the app into
dark or light. It was `bg-ink` with `text-white/45`-style overlays,
which only ever looked right in one mode.
- **Collapsed by default.** The status strip still carries the live
state ("3 agents working"), so the run reads as alive while closed.
- Still the **full** log when open. It is the detail view, and windowing
it as well left two lines and nowhere to read the rest.

## Tool activity (shell, affects all skins)

- Rolls to the last two lines; older ones are **removed**, not
collapsed.
- Registration is a **layout** effect, and that is load-bearing. A new
line renders before it is registered, and registering is what evicts the
oldest, so with a passive effect the browser painted the in-between
state: three rows for one frame on every tool call, and again when the
end-of-run `MESSAGES_SNAPSHOT` remounts every line at once. Measured per
animation frame over a full run — 12,734 frames, never more than two,
one `1->2` transition.
- A shared registry rather than something simpler because CopilotKit
renders one component per tool call and owns the container. CSS
`:nth-last-child` needs siblings and the lines had one parent each;
mount-order counters drift across the snapshot remount.

Reviewers should know this one is **not** scoped to banking. Most beats
emit one or two tool calls so it is a no-op for them, but a beat
emitting three or four would now show only its last two.
`VISIBLE_TOOL_ACTIVITY` is a single constant if we want it higher.

## Agent: 1m 0s -> ~45s

- **Research is gated on the offsite dates.** A charge dated outside the
window is settled by its date whatever the merchant turns out to be, so
half the researcher dispatches were buying nothing. Travel on the
adjacent days is still kept in scope.
- **Filings go out in one command** instead of one `curl` per row. The
researchers already ran concurrently, so halving them bought almost
nothing — the serial per-row round-trips through the model were most of
the wall clock.
- Fetch and verify are one command; there is nothing to decide between
the halves.
- Analyst reasoning effort defaults to `medium`, overridable with
`BANKING_EXPENSE_EFFORT`.

## Filing is idempotent

The batching made this necessary rather than optional: the script got
run twice and every charge was filed twice, so the report card claimed
six filings while the ledger held twelve. A duplicate here is a
reimbursement claimed twice.

The script now writes `filed.json` and exits early if it already exists.
That marker is cleared once per run, because the workspace is a fixed
directory shared by every run and a stale marker would convince the next
demo it had already filed and post nothing at all — the same bug wearing
the opposite mask, and a quieter one, since a run that files nothing
still writes a confident report.

Deduping server-side on merchant+amount would have been wrong: **Hotel
Verrano legitimately appears twice at the identical $318.55** for the
two nights of the offsite.

## Verification

Run against a live Intelligence stack, not unit tests alone:

- Six rows filed, all `status=pending`, stable across 60s of polling.
- Present in the Pending Approval queue with their notes and
approve/decline actions.
- Report card: 14 rows read, 6 merchants researched, $2,377.15
reimbursable.
- Console checked in both themes (panel `#f9f8fc` light / `#1f1c2c`
dark, text inverting with it).

`lint`, `typecheck`, `test:unit` (2460 passed) and `build` all green,
re-run after rebasing onto current main.

Does this change make anything in `.claude/skills/reskin/` wrong,
incomplete, or misleading? No — nothing there documents the harness
console, the tool-activity renderer, or the analyst prompt.
2026-08-20 13:34:14 -07:00
copilotkit-qa-bot[bot] 90a35cdb7c fix(react-core): stabilize feedback button callbacks 2026-08-20 13:19:38 -07:00
copilotkit-qa-bot[bot] 7f798d557e docs(google-adk): define state-streaming stop callback 2026-08-20 13:14:31 -07:00
David McKay f3f32aafff fix(showcase): tighten the offsite-expenses beat
The "Sort out my offsite expenses" beat had three problems on stage: the
harness console was a black slab in a light-mode transcript, the tool
activity grew a stack of finished steps that pushed the report card off
the screen, and the run took a full minute.

Console (banking skin):
- Every colour is now a semantic token, so the pane follows the app into
  dark or light instead of being hardcoded dark. It was `bg-ink` with
  `text-white/45`-style overlays, which only ever looked right in one mode.
- Collapsed by default. The status strip still carries the live state, so
  the run reads as alive while closed.
- Still the FULL log when open. It is the detail view, and windowing it as
  well left two lines and nowhere to read the rest.

Tool activity (shell, all skins):
- Rolls to the last two lines; older ones are REMOVED, not collapsed.
- Registration is a layout effect, and that is load-bearing. A new line
  renders before it is registered, and registering is what evicts the
  oldest, so with a passive effect the browser painted the in-between
  state: three rows for one frame on every tool call, and again when the
  end-of-run MESSAGES_SNAPSHOT remounts every line at once. Measured per
  animation frame over a full run: 12,734 frames, never more than two.
- A shared registry rather than something simpler because CopilotKit
  renders one component per tool call and owns the container. CSS
  `:nth-last-child` needs siblings and the lines had one parent each;
  mount-order counters drift across the snapshot remount.

Agent (run time 1m 0s -> ~45s):
- Research is gated on the offsite dates. A charge dated outside the
  window is settled by its date whatever the merchant turns out to be, so
  half the researcher dispatches were buying nothing. Travel on the
  adjacent days is still kept in scope.
- Filings go out in one command instead of one curl per row. The
  researchers already ran concurrently, so the serial per-row round-trips
  through the model were most of the wall clock, not the research.
- Fetch and verify are one command; there is nothing to decide between
  the halves.
- Analyst reasoning effort defaults to medium, overridable with
  BANKING_EXPENSE_EFFORT.

Filing is idempotent, which the batching made necessary: the script got
run twice and every charge was filed twice, so the report card claimed six
filings while the ledger held twelve. The script now writes `filed.json`
and exits early if it exists. That marker is cleared once per run, because
the workspace is a fixed directory shared by every run and a stale marker
would convince the next demo it had already filed and post nothing at all
— the same bug wearing the opposite mask, and a quieter one, since a run
that files nothing still writes a confident report.

Deduping server-side on merchant+amount would have been wrong: Hotel
Verrano legitimately appears twice at the identical 318.55 for the two
nights of the offsite.

Does this change make anything in .claude/skills/reskin/ wrong,
incomplete, or misleading? No. Nothing there documents the harness
console, the tool-activity renderer, or the analyst prompt; its only
matches for "console" are `console.error` in unrelated template code.

Verified on the real path against a live Intelligence stack: six rows
filed, all status=pending, stable across 60s of polling, and present in
the Pending Approval queue with their notes and approve/decline actions.
2026-08-20 13:09:25 -07:00