Files

53 lines
2.6 KiB
YAML
Raw Permalink Normal View History

packages:
- "packages/*"
- "tools/runtime-conformance"
- "examples/v1/*"
- "examples/v2/*"
- "examples/v2/*/apps/*"
- "examples/v2/react/*"
- "examples/v2/vue/*"
- "examples/v2/angular/*"
- "examples/v2/react-native/*"
- "examples/v2/runtime/*"
- "examples/showcases/generative-ui-playground"
feat(reskinnable-demo): stream the harness into a CLI console via AG-UI subagents Makes the offsite-expenses beat legible while it runs, and gives it its own model, by taking the AG-UI subagent surface from the canary line. ## The expense analyst is now a real subagent banking gpt-5.4, temp 0 │ banking's prompt; browser frontend tools; Intelligence memory tools └─ expense-analyst gpt-5.6-sol, reasoning_effort=high │ sandboxed shell, submit_expense_report └─ merchant-researcher gpt-5.4, one per merchant, Tavily Previously the beat was a section of banking's prompt, which left nowhere to put per-beat configuration: model, effort and recursion limit are all agent-level and there was one agent. It also meant banking's ~21,000-character rulebook rode every one of the ~20 model calls the run makes, re-sending rules about markdown tables while the agent read a CSV. Reached as a `CompiledSubAgent` because a raw `SubAgent` spec has no `subagents` field and this one needs its own — the per-merchant fan-out is a headline of the beat, and a flat subagent could only research serially. Verified nesting survives: a probe showed the analyst's `task` dispatches, the researchers' `search_merchant` calls and the final report tool all reaching `astream_events`. `gpt-5.6-sol` additionally needs `use_responses_api=True`: with function tools and `reasoning_effort` it 400s on /v1/chat/completions. The first probe missed that by asking the model a question with NO tools bound — a model probe for an agent has to bind one. ## The console: one CLI window, streaming `shell/subagents/subagent-activity.tsx` subscribes to the agent's event stream and folds it into console lines. Reading `agent.messages` (the previous design) was wrong twice over: messages materialise at the `MESSAGES_SNAPSHOT`, two per run, so the pane sat still for minutes and then filled at once; and persisted messages carry no `subagentRunId`, so the harness's narration could not be told from banking's own reply. The fold is pure and idempotent — every line keyed by the id of the thing that produced it — so the same code serves the live subscription and a replay of the thread's stored events when a conversation is reopened. Three heuristics are deleted, each replaced by identity the protocol already carried: - the console's "first tool call" anchor -> the run's first `task` call, from MESSAGE order (durable; the event-derived version rendered one console per delegation on a restored thread — six, measured) - `CONSOLE_TOOL_NAMES` suppression list -> `subagentRunId` presence - `disable_streaming` on the researchers -> the canary's per-lane state `shell/subagents/subagent-message-filter.tsx` keeps subagent narration out of the conversation. It suppresses the PROSE and keeps the TOOL CALLS: an agent routinely narrates and calls a tool in one message, and returning null for the whole message hid the REPORT CARD — the run looked perfect and ended with nothing to show. Shell-level and inert for a skin whose agent has no subagents. ## Canary stack, contained to this app The subagent surface only exists on the canary line, and a released `@ag-ui/client` <= 0.0.57 rejects `SUBAGENT_*` events in the HTTP transport before any middleware runs, killing the stream. So the demo leaves the root pnpm workspace and ships its own lockfile, pinning `@copilotkit/* 1.68.3-canary` and `@ag-ui/* 0.0.59-canary` locally instead of imposing an unreleased protocol on every package in the monorepo. A 1.62.2-based canary was tried first and could not compile the app: it silently rewound the CopilotKit API five minors under a demo written against 1.67.1, and `OpenGenerativeUIActivityRenderer` (a public `/v2` export since ~1.63) was the first thing to break. `workspace:*` is not a version, so the app had no recorded lower bound on the API it needs. KNOWN GAP, deliberately not fixed here: Nx discovers projects THROUGH the pnpm workspace (there is no `workspaceLayout` in `nx.json`), so leaving it also removes the demo from the repo-wide `nx run-many -t build` and `-t check-types` sweeps. Verified — `nx show project deep-agents` and the other standalone showcases return "Could not find project". No workflow names this demo, so it is currently unbuilt and untype-checked in CI and needs its own job. Run the four gates locally until that lands. Documented in `pnpm-workspace.yaml`. ## Fixes - The run clock is keyed per run and read through an injected `ToolRuntime` instead of taking the oldest open stamp across the process. Model calls AFTER the report re-stamped the clock and that leftover became the next run's start: a two-minute run reported 333s. Now 86s reported against 98s wall clock — the gap is thread-naming and delegation, before the analyst's first model call, which is what the tile claims to measure. - `merchantKind` non-answers are rejected on the leading token, on hedging language, and over 40 characters. With no search tool the model wrote a bare "unclear"; with Tavily live it hedges in prose ("unknown (likely bookbindery/bookshop retail, but not established for this exact merchant)"), which an exact-match filter passed into a 60-character label glued to the merchant name. - `vitest` no longer externalises `@copilotkit/*`. Installing them from npm moved `src/app/layout.tsx`'s stylesheet import under `node_modules/.pnpm/`, where Node's ESM loader threw `Unknown file extension ".css"` and took out 16 suites while naming a stylesheet nobody had touched. - `agent/main.py` reads the demo's `.env` as well as its own, so `TAVILY_API_KEY` works wherever an operator puts it. Two env files to keep in sync is a trap whose failure mode is "the agent ignores a key that is plainly sitting in .env". ## Upstream finding (reported separately, not fixed here) `@copilotkit/runtime` drops `subagentRunId` when persisting messages: 2888 of 3026 stream events carry it, 0 of 53 persisted messages do. Reproduced with Intelligence removed entirely, so it is the runtime's message shape rather than the platform store — and `@copilotkit/runtime`'s dist contains no occurrence of the field at all, while `@ag-ui/core`, `ag-ui-protocol` and `@copilotkit/core` all model it. One field threaded through would let the console rebuild from message history and delete the event-replay seeding added here. `CLAUDE.md`'s appended block is generated by `next dev` (`next/dist/server/lib/generate-agent-files.js`) and committed per its own instruction to keep the tree clean. Gates: lint 0, typecheck 0, test:unit 2460 passed across 216 files, build 0. Measured end to end in Intelligence mode: 14 rows, 9 merchants researched, 6 charges filed with ids read out of real 201 bodies, totals reconciling against their own rows, 3220 events with 6 SUBAGENT_STARTED/FINISHED pairs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRubZT6AS6LCGkcE2KzcfA
2026-08-20 13:54:58 +02:00
# NOTE: `examples/showcases/reskinnable-demo` is intentionally NOT part of
# this pnpm workspace, for the same reason as `showcase/shell-dashboard`
# below: it ships its own lockfile and installs its `@copilotkit/*` and
# `@ag-ui/*` dependencies from npm rather than from `workspace:*`.
#
chore(examples): remove banking showcase in favor of reskinnable-demo The banking showcase is superseded by `examples/showcases/reskinnable-demo`, which ships the same banking experience as one of its runtime-swappable skins (alongside airline) on top of a shared shell. Keeping both means maintaining two copies of the same demo, so banking is sunset here. Removes the app and the things that referenced it: - `pnpm-workspace.yaml` — drops the workspace entry. Also fixes the adjacent NOTE, which attributed the canary AG-UI pin to "banking's agent" when it is reskinnable-demo's own Python deep agent that needs it. - `pnpm-lock.yaml` — regenerated. Only the removed importer and the peer-suffix re-keying it caused; no dependency version changes. - `examples/README.md` — the banking row becomes a reskinnable-demo row, so the successor is listed and the showcase count is unchanged. - `showcase/shell-docs/.../faq.mdx` — the Banking Assistant link retargets to reskinnable-demo instead of 404ing. - `.github/config-allowlist.txt` — drops the deleted `next.config.mjs`. Not changed: `scripts/migrate-demos.sh` and `scripts/archive-demo-repos.sh` still name `examples/showcases/banking`. Those are the already-executed one-shot manifests for the repo consolidation; the path is a historical record there, not a live reference. reskinnable-demo's `.env.example` and `docker-compose.yml` likewise still explain their +200 port offset in terms of banking's stack — the offset stays real, and "was cloned from banking" stays true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:11:48 +02:00
# It has to. Its agent is a Python deep agent whose subagents are only
feat(reskinnable-demo): stream the harness into a CLI console via AG-UI subagents Makes the offsite-expenses beat legible while it runs, and gives it its own model, by taking the AG-UI subagent surface from the canary line. ## The expense analyst is now a real subagent banking gpt-5.4, temp 0 │ banking's prompt; browser frontend tools; Intelligence memory tools └─ expense-analyst gpt-5.6-sol, reasoning_effort=high │ sandboxed shell, submit_expense_report └─ merchant-researcher gpt-5.4, one per merchant, Tavily Previously the beat was a section of banking's prompt, which left nowhere to put per-beat configuration: model, effort and recursion limit are all agent-level and there was one agent. It also meant banking's ~21,000-character rulebook rode every one of the ~20 model calls the run makes, re-sending rules about markdown tables while the agent read a CSV. Reached as a `CompiledSubAgent` because a raw `SubAgent` spec has no `subagents` field and this one needs its own — the per-merchant fan-out is a headline of the beat, and a flat subagent could only research serially. Verified nesting survives: a probe showed the analyst's `task` dispatches, the researchers' `search_merchant` calls and the final report tool all reaching `astream_events`. `gpt-5.6-sol` additionally needs `use_responses_api=True`: with function tools and `reasoning_effort` it 400s on /v1/chat/completions. The first probe missed that by asking the model a question with NO tools bound — a model probe for an agent has to bind one. ## The console: one CLI window, streaming `shell/subagents/subagent-activity.tsx` subscribes to the agent's event stream and folds it into console lines. Reading `agent.messages` (the previous design) was wrong twice over: messages materialise at the `MESSAGES_SNAPSHOT`, two per run, so the pane sat still for minutes and then filled at once; and persisted messages carry no `subagentRunId`, so the harness's narration could not be told from banking's own reply. The fold is pure and idempotent — every line keyed by the id of the thing that produced it — so the same code serves the live subscription and a replay of the thread's stored events when a conversation is reopened. Three heuristics are deleted, each replaced by identity the protocol already carried: - the console's "first tool call" anchor -> the run's first `task` call, from MESSAGE order (durable; the event-derived version rendered one console per delegation on a restored thread — six, measured) - `CONSOLE_TOOL_NAMES` suppression list -> `subagentRunId` presence - `disable_streaming` on the researchers -> the canary's per-lane state `shell/subagents/subagent-message-filter.tsx` keeps subagent narration out of the conversation. It suppresses the PROSE and keeps the TOOL CALLS: an agent routinely narrates and calls a tool in one message, and returning null for the whole message hid the REPORT CARD — the run looked perfect and ended with nothing to show. Shell-level and inert for a skin whose agent has no subagents. ## Canary stack, contained to this app The subagent surface only exists on the canary line, and a released `@ag-ui/client` <= 0.0.57 rejects `SUBAGENT_*` events in the HTTP transport before any middleware runs, killing the stream. So the demo leaves the root pnpm workspace and ships its own lockfile, pinning `@copilotkit/* 1.68.3-canary` and `@ag-ui/* 0.0.59-canary` locally instead of imposing an unreleased protocol on every package in the monorepo. A 1.62.2-based canary was tried first and could not compile the app: it silently rewound the CopilotKit API five minors under a demo written against 1.67.1, and `OpenGenerativeUIActivityRenderer` (a public `/v2` export since ~1.63) was the first thing to break. `workspace:*` is not a version, so the app had no recorded lower bound on the API it needs. KNOWN GAP, deliberately not fixed here: Nx discovers projects THROUGH the pnpm workspace (there is no `workspaceLayout` in `nx.json`), so leaving it also removes the demo from the repo-wide `nx run-many -t build` and `-t check-types` sweeps. Verified — `nx show project deep-agents` and the other standalone showcases return "Could not find project". No workflow names this demo, so it is currently unbuilt and untype-checked in CI and needs its own job. Run the four gates locally until that lands. Documented in `pnpm-workspace.yaml`. ## Fixes - The run clock is keyed per run and read through an injected `ToolRuntime` instead of taking the oldest open stamp across the process. Model calls AFTER the report re-stamped the clock and that leftover became the next run's start: a two-minute run reported 333s. Now 86s reported against 98s wall clock — the gap is thread-naming and delegation, before the analyst's first model call, which is what the tile claims to measure. - `merchantKind` non-answers are rejected on the leading token, on hedging language, and over 40 characters. With no search tool the model wrote a bare "unclear"; with Tavily live it hedges in prose ("unknown (likely bookbindery/bookshop retail, but not established for this exact merchant)"), which an exact-match filter passed into a 60-character label glued to the merchant name. - `vitest` no longer externalises `@copilotkit/*`. Installing them from npm moved `src/app/layout.tsx`'s stylesheet import under `node_modules/.pnpm/`, where Node's ESM loader threw `Unknown file extension ".css"` and took out 16 suites while naming a stylesheet nobody had touched. - `agent/main.py` reads the demo's `.env` as well as its own, so `TAVILY_API_KEY` works wherever an operator puts it. Two env files to keep in sync is a trap whose failure mode is "the agent ignores a key that is plainly sitting in .env". ## Upstream finding (reported separately, not fixed here) `@copilotkit/runtime` drops `subagentRunId` when persisting messages: 2888 of 3026 stream events carry it, 0 of 53 persisted messages do. Reproduced with Intelligence removed entirely, so it is the runtime's message shape rather than the platform store — and `@copilotkit/runtime`'s dist contains no occurrence of the field at all, while `@ag-ui/core`, `ag-ui-protocol` and `@copilotkit/core` all model it. One field threaded through would let the console rebuild from message history and delete the event-replay seeding added here. `CLAUDE.md`'s appended block is generated by `next dev` (`next/dist/server/lib/generate-agent-files.js`) and committed per its own instruction to keep the tree clean. Gates: lint 0, typecheck 0, test:unit 2460 passed across 216 files, build 0. Measured end to end in Intelligence mode: 14 rows, 9 merchants researched, 6 charges filed with ids read out of real 201 bodies, totals reconciling against their own rows, 3220 events with 6 SUBAGENT_STARTED/FINISHED pairs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRubZT6AS6LCGkcE2KzcfA
2026-08-20 13:54:58 +02:00
# representable over AG-UI on the canary line
# (`@ag-ui/* 0.0.59-canary.1786716392.0` + `@copilotkit/* 1.62.2-canary…`) —
# the released `@ag-ui/client` 0.0.57 rejects `SUBAGENT_*` events in the HTTP
# transport before any middleware runs and kills the whole stream. Pinning
# those canaries as ROOT overrides would impose an unreleased protocol on
# every package in the monorepo for one app's benefit; keeping the demo out of
# the workspace confines them to the app that needs them.
#
# ⚠ KNOWN GAP, tracked as a follow-up: Nx discovers projects THROUGH the pnpm
# workspace (there is no `workspaceLayout` in `nx.json`), so removing the demo
# here also removes it from the repo-wide `nx run-many -t build`
# (`static_compat.yml`) and `-t check-types` (`static_quality.yml`) sweeps —
# verified: `nx show project deep-agents` and the other standalone showcases
# return "Could not find project". No workflow names this demo, so it is
# currently unbuilt and untype-checked in CI. It needs its own workflow job
# (`pnpm install && pnpm build && pnpm typecheck` in its directory), which is
# NOT in this change. Run the four gates locally until that lands.
- "examples/slack"
- "examples/teams"
- "!examples/v1/_legacy"
- "showcase/scripts"
chore(showcase/harness): remove stray npm lockfile `showcase/harness` is a pnpm workspace member (pnpm-workspace.yaml), so its only install path is pnpm from the root `pnpm-lock.yaml`. Both consumers run exactly that: `showcase/harness/Dockerfile` (`pnpm install --frozen-lockfile --filter @copilotkit/showcase-harness...`) and the `harness unit suite` job in `test_unit-showcase.yml`. Nothing anywhere ran `npm ci` in this directory — no Dockerfile, workflow, or script referenced the lockfile. Because no gate ever read it, it rotted unobserved. Against a fresh regeneration it was 106 package versions stale, carried 51 packages no longer required, and was missing `axe-core` outright — which is how it surfaced: `npm ci` here failed with "Missing: axe-core@4.11.1 from lock file" for anyone who saw the file and reasonably concluded this package installs with npm. Regenerating it was the wrong fix. npm resolves a materially different tree than the one CI and prod actually run — 9 direct deps diverged, with `@hono/node-server` off by a whole major (pnpm 2.0.0 vs npm 1.19.17) — and npm cannot see the root `pnpm.overrides` block, 73 minimum-version floors with several security patches among them, because that field is pnpm-only. A working `npm ci` here would hand a developer a green install against versions that never ship, and could silently resolve below an intended security floor. The stale file was a signpost pointing the wrong way, so it is removed rather than maintained. The root `pnpm-lock.yaml` already resolves `axe-core` at 4.11.1 correctly; verified that `pnpm install --frozen-lockfile --ignore-scripts` succeeds and that axe-core 4.11.1 is present in the harness tree with no npm lockfile, and that the harness typechecks clean once the gitignored showcase fixtures are generated the way CI generates them. Adds a NOTE in pnpm-workspace.yaml recording why no npm lockfile belongs here, so the file is not re-added in good faith as it was in 671cc6ae1d. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 14:18:03 +02:00
# No npm lockfile here: installs with pnpm from the root pnpm-lock.yaml.
- "showcase/harness"
- "showcase/eval-webhook"
- "showcase/angular"
# NOTE: `showcase/shell-dashboard` is intentionally NOT part of this
# pnpm workspace. It's a flat, standalone Next.js app that ships its
# own package-lock.json and is built with `npm ci` (see its Dockerfile).
# Including it here would force it into the pnpm lockfile, which
# breaks its independent deploy path and invalidates the npm-based
# Docker build. `showcase/scripts` IS in the workspace because the
# harness package imports from it and both use pnpm.
onlyBuiltDependencies:
- better-sqlite3