7393 Commits

Author SHA1 Message Date
Ben Taylor bf8aca7ee7 chore: release monorepo v1.56.4 (#4332)
## Release monorepo v1.56.4

**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.56.4`
   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.56.4`
   - Creates git tag `monorepo/v1.56.4`
   - 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.56.4
2026-04-27 15:21:16 -05:00
BenTaylorDev f19afade44 chore: release monorepo v1.56.4 2026-04-27 15:05:59 -05:00
Jordan Ritter 84d90deb1a feat(showcase/google-adk): port langgraph-python demos to fill dashboard column (#4318)
## Summary

Brings the **Google ADK** column on
https://dashboard.showcase.copilotkit.ai/#coverage from 8 wired cells
(parity_tier `minimal`) up to **35 wired cells** (parity_tier `partial`)
— using `langgraph-python` (38/39) as the reference. All ports use real
Google ADK + Gemini 2.5 Flash agents wired through `ag-ui-adk`; nothing
is stubbed.

### Backend

- `src/agent_server.py` refactored from a single shared `LlmAgent`
mounted at `/` to one `ADKAgent` per demo at `/<agent_name>`, driven by
a new `src/agents/registry.py` source-of-truth (with an `AgentSpec`
dataclass for `predict_state` / `emit_messages_snapshot` kwargs).
- 18 new per-demo agent modules covering reasoning (Gemini thinking
mode), tool-rendering (4 variants), HITL (in-chat + in-app),
shared-state (read-write + per-token streaming via
`PredictStateMapping`), multi-agent supervisor, A2UI dynamic +
fixed-schema, BYOC, open-gen-ui (basic + advanced), agent-config,
readonly-context, multimodal, beautiful-chat, plus the existing
recipe-themed shared-state-read.

### Frontend

- `src/app/api/copilotkit/route.ts` now maps each agent name to its
matching backend path.
- 6 dedicated runtime routes for demos that need bespoke runtime config:
- `copilotkit-auth` — V2 `createCopilotRuntimeHandler` with an
`onRequest` 401 gate
- `copilotkit-declarative-gen-ui` and `copilotkit-a2ui-fixed-schema` —
`a2ui.injectA2UITool: false` because the agents own their own A2UI tools
- `copilotkit-byoc-hashbrown`, `copilotkit-byoc-json-render`,
`copilotkit-ogui` (shared by open-gen-ui + advanced)
- 26 new / replaced demo pages with their helper components.

### Manifest

`showcase/packages/google-adk/manifest.yaml` declares 35 features (was
8). `pnpm generate-registry` validates clean.

### Skipped (intentional)

- `gen-ui-interrupt`, `interrupt-headless` — depend on LangGraph's
`interrupt()` graph primitive; ADK has no direct equivalent. The
high-level `useHumanInTheLoop` case is covered via `hitl-in-chat`.
- `mcp-apps` — `ag_ui_adk` does support `MCPToolset`, but a working
MCP-driven UI demo is a separate chunk; left for follow-up.

## Test plan

- [x] `pnpm generate-registry` validates manifest end-to-end (Catalog:
reference = langgraph-python with 37 wired features; google-adk now at
35/39 wired)
- [x] `npx tsc --noEmit` in `showcase/packages/google-adk` — no new
errors (pre-existing `byoc-json-render/registry.tsx` and
`shared-state-write/page.tsx` errors untouched)
- [x] Python syntax: `ast.parse` over every file in `src/agents/` — all
parse cleanly
- [ ] Local smoke test: `pnpm dev` in `showcase/packages/google-adk`,
hit each new `/demos/*` route, verify L2/L3 health
- [ ] Railway deploy: confirm health probes go green and dashboard
column lights up

## Caveats worth knowing before deploy

1. **Per-token streaming** in `shared-state-streaming` uses
`PredictStateMapping(stream_tool_call=True)`. Per `ag_ui_adk` docs, true
per-token argument streaming requires Gemini 3+ via Vertex AI; on Gemini
2.5 Flash this should still work but at chunk-level granularity.
2. **Subagents** uses direct `genai.Client.models.generate_content`
calls inside each delegation tool, not ADK's native `sub_agents` /
`AgentTool`. Functionally equivalent for the demo; a follow-up could
refactor to ADK-native multi-agent.
3. **A2UI fixed-schema** has an inline `_build_flight_operations` helper
instead of importing `copilotkit.a2ui`. The `copilotkit` Python SDK
isn't in `requirements.txt` for this package — adding it later and
refactoring is straightforward.
4. **`/agents/state` collision**: `ag_ui_adk.add_adk_fastapi_endpoint`
hardcodes `POST /agents/state` regardless of the `path` arg. With N
agents mounted, only the first registered agent's state endpoint is
reachable. Most demos don't use it; `headless-complete` could.
5. **Beautiful-chat** is intentionally minimal vs. the langgraph-python
sibling's richer canvas/layout split.
2026-04-27 13:03:59 -07:00
github-actions[bot] b7dce5c1b4 style: auto-fix formatting 2026-04-27 19:54:21 +00:00
Alem Tuzlak 3daa7dbba0 fix: align google-adk starter with packages — route rewrite, deps, sample_agent
Rewrite starter route.ts to use HttpAgent (matching packages pattern),
fix default port to 8123, add full 37-agent list including sample_agent,
add missing @ag-ui/client dependency, register sample_agent in registry.
2026-04-27 12:52:53 -07:00
Alem Tuzlak 9c5a0ac850 fix: correct OGUI instructions, sandbox regex, and ternary precedence
Update open-gen-ui agent instructions to emit HTML directly instead
of fenced blocks (the runtime's generateSandboxedUi tool handles
rendering). Tighten sandbox evaluateExpression regex to reject **
exponentiation. Fix ternary operator precedence in 3 agent files
where string concatenation bound tighter than the conditional.
2026-04-27 12:52:53 -07:00
Alem Tuzlak ba5bf65881 fix: handle promise rejections in google-adk demo pages
Replace swallowed .catch(() => {}) with console.error logging in
headless-simple, headless-complete, and shared-state-read demos.
2026-04-27 12:52:53 -07:00
Alem Tuzlak f282a1674e fix: harden google-adk route error handling and add auth catch-all
Remove stack trace leaks from error responses, replace @ts-ignore
with @ts-expect-error, hoist CopilotRuntime to module scope, and
add [[...slug]] catch-all for the V2 auth endpoint so sub-route
requests don't 404.
2026-04-27 12:52:53 -07:00
Alem Tuzlak d8a208297d refactor(google-adk): track strip-prior-block in inject callbacks
Round 5 review surfaced a fragility in the empty-write guard. The
`if not new_text` short-circuit added in Round 4 correctly avoids
clobbering the LlmAgent static `instruction=` field when there's
nothing to inject — but if a prior callback DID embed a block in the
existing Content and the user has since cleared state, the early
return leaves the stale block in place because we never write the
stripped result back.

In practice this is unreachable: `_INSTRUCTION` is non-empty for all
three agents, so `original_text` after stripping always retains at
least the static instruction. But the explicit `stripped_prior_block`
flag makes the invariant honest if anyone ever wires up an LlmAgent
with an empty `instruction=` and removes the implicit dependency on
the static instruction being non-empty.
2026-04-27 12:52:53 -07:00
Alem Tuzlak ebb9247ccb style(google-adk): drop unnecessary {} fallback in state spreads
eslint-plugin-unicorn no-useless-fallback-in-spread — spreading
undefined into an object literal is a no-op, so '?? {}' is redundant.
Functionally identical, silences the lint warning.
2026-04-27 12:52:53 -07:00
Alem Tuzlak 5d3269c113 fix(google-adk): preserve static instruction + persisted notes
Two related issues surfaced in Round 4 review of the ADK showcase:

1. The before-model callbacks in agent_config_agent,
   readonly_state_agent_context_agent, and shared_state_read_write_agent
   guarded the empty-write branch with `if not new_text and original is
   None`. That missed the case where `original` is a non-None Content
   with empty text — possible after stripping a prior block that was
   the entire Content. In that branch the callback wrote
   Content(text=""), clobbering the LlmAgent's static `instruction=`.
   Tightened the guard to `if not new_text: return None`.

2. The shared-state-read-write seed effect spread the observed agent
   state but unconditionally assigned `notes: []`, wiping any
   backend-persisted notes when the user landed without persisted
   preferences. Falls back to `agentState?.notes ?? []` instead.
2026-04-27 12:52:52 -07:00
Alem Tuzlak d1d5a936b1 fix(showcase/google-adk): CR Round 3 — splice prior block, fail-loud guards, sanitize errors, spread state writes
Round 3 confirmation found bugs Round 2's fixes left behind in the same
files. All fixes target subject-scoped + load-bearing concerns.

bucket (a) findings:

A1 (strip-prior-block content loss): all three before-model-callback
agents (\`agent_config_agent\`, \`readonly_state_agent_context_agent\`,
\`shared_state_read_write_agent\`) sliced
\`original_text[end_idx + len(END_MARKER):]\` to remove the prior
injected block. That dropped content from index 0 to sig_idx as well —
fine for the steady-state pattern where our block is at position 0,
but if any other middleware ever prepends content to system_instruction
between turns, that prefix would be silently lost. Splice instead:
\`original_text[:sig_idx] + original_text[end_idx + len(END_MARKER):]\`.

A2 (empty-block + empty-original still rewrites system_instruction):
when both \`block\` is None and \`original\` is None, the callbacks were
still writing \`Content(role="system", parts=[Part(text="")])\`,
overwriting whatever the LlmAgent's \`instruction=\` field would have
contributed. Added an early return for that case so the static
instruction passes through.

A3 (sub-agent error message exposes raw exception text):
\`_invoke_sub_agent\` was raising
\`_SubAgentError(f"sub-agent call failed: {exc.__class__.__name__}: {exc}")\`.
\`{exc}\` for genai HTTP errors can include URLs, request IDs, partial
credentials, and quota details. The error string lands in
\`state["delegations"][i].result\` and ships to the public Railway
deploy. Sanitized to surface only \`exc.__class__.__name__\` to clients;
\`logger.exception\` keeps the full trace + str(exc) server-side.

A4 (agent.setState seed/handler effects clobber unrelated state keys):
\`agent.setState({ config: INITIAL_CONFIG })\` and the matching prefs
seed/handlers replaced the whole state object rather than merging. If
the runtime adds any other keys (e.g. \`copilotkit\` for the read-only
context middleware, future framework additions), they were wiped on
every config write. Now spread the observed state on every write.

A5 (\`_build_prefs_block\` missing the empty-recognized-keys guard): a
truthy prefs dict containing only unrecognized keys (schema drift /
forward-extension UI prop) would still emit a block consisting only of
\`[SIG, "Tailor every response to these preferences. ADDR_USER_BY_NAME"]\`,
i.e. directives without directives. Added the same
\`if len(lines) == 1: return None\` guard already present in
\`agent_config_agent._format_config\` and
\`readonly_state_agent_context_agent._format_context\`.

Bucket (b) defensive items applied:

- subagents \`_invoke_sub_agent\` parts extraction: dropped the redundant
  \`if content is not None\` ternary; \`getattr(None, "parts", None)\`
  already returns the default.

Starter regenerated.

Call-site enumeration:
- splice path inside \`_inject_config\`/\`_inject_context\`/
  \`_inject_preferences\`: signature unchanged; only callers are the
  matching LlmAgent before_model_callback bindings.
- \`_SubAgentError\` constructor message format changed (still str
  argument): consumers stringify it via str(exc); behaviour unchanged
  apart from the redacted exception body.
- \`agent.setState\` payloads in agent-config + shared-state-read-write
  pages: consumed only by the matching runtime route per page; the
  spread shape is a superset of the prior shape, so backend callbacks
  see the same fields plus any pre-existing keys (which they already
  read defensively).
- \`_build_prefs_block\` early-return: only consumer is
  \`_inject_preferences\` in the same module; new return path is None,
  same as the existing \`not prefs\` early return.
2026-04-27 12:52:52 -07:00
Alem Tuzlak 6323ccf205 fix(showcase/google-adk): CR Round 2 — fix bugs introduced by Round 1 + remaining bucket (a) cleanups
Round 2 (confirmation) surfaced bugs in code my Round 1 fixes touched.

bucket (a) findings:

- subagents_agent._update_delegation: dropped the synthetic
  \`sub_agent: "unknown"\` fallback I added in Round 1. The frontend's
  \`Delegation.sub_agent\` union is
  \`research_agent | writing_agent | critique_agent\`; an "unknown" value
  fell through SUB_AGENT_BADGE_CLASS / SUB_AGENT_LABEL maps and rendered
  as \`undefined\` text + className. Now we log loudly and skip — no row
  beats a malformed row.

- subagents_agent._invoke_sub_agent: cleaned up the
  \`getattr(content, "parts", None) or [] if content is not None else []\`
  ternary. \`getattr(None, ...)\` already returns the default, so the
  outer conditional was dead.

- agent_config_agent._format_config: added \`if len(lines) == 1: return None\`
  guard before appending CONFIG_END_MARKER. A truthy config dict with no
  recognized keys (schema drift / future-extension forwardedProps) was
  emitting a meaningless [SIGNATURE, END_MARKER] block telling the LLM
  to "Honour every directive above" with zero directives. Mirrors the
  same guard in readonly_state_agent_context_agent._format_context.

- delegation-log.tsx: added STATUS_BADGE_CLASS + STATUS_LABEL maps and
  a status-derived border-color so running/completed/failed entries are
  visually distinguishable. Without this, my Round 1 backend fix that
  actually emits all three states had no UI signal — every entry was
  the same muted gray. Now: amber spinner + "running…" while the
  sub-agent works, emerald on completion, red on failure.

- hitl-in-app/page.tsx: added an unmount cleanup that rejects every
  still-pending approval (with reason "user navigated away before
  responding") so the agent's tool-call promises never orphan when
  the user leaves the page mid-approval. Also added \`key={head.id}\`
  on ApprovalDialog so any future local state in the dialog component
  is per-request rather than leaking from one approval to the next as
  the head rotates.

- tool-rendering-custom-catchall: aligned the renderer's status type
  with what the runtime + page actually emit. The runtime's
  DefaultRenderProps status enum is
  \`"inProgress" | "executing" | "complete"\` and the page collapses both
  pre-completion variants to "executing"; there is no "incomplete"
  state today. The renderer's \`"incomplete"\` branch was unreachable
  dead code from a copy-paste of an older type. Narrowed the prop type
  to \`"executing" | "complete"\` and dropped the dead branch.

- manifest.yaml highlight arrays: 7 demos with dedicated runtime
  routes (a2ui-fixed-schema, declarative-gen-ui, byoc-json-render,
  byoc-hashbrown, auth, open-gen-ui, open-gen-ui-advanced) were
  pointing at the unified \`src/app/api/copilotkit/route.ts\` instead
  of their own dedicated route file. Documentation drift the showcase
  tooling uses to render source listings — pointed each at its real
  route. Also added \`src/app/demos/auth/demo-token.ts\` to the auth
  highlight list so the bundled demo-token note is visible alongside
  the page.

bucket (b) cheap items applied:

- AgentSpec.predict_state: \`Iterable\` → \`Sequence\`. A one-shot
  generator passed by mistake would empty after the first request;
  Sequence forces a re-iterable container. Module-level lists already
  satisfy this contract.

Starter regenerated to keep drift-check green.

Call-site enumeration:
- \`STATUS_BADGE_CLASS\`, \`STATUS_LABEL\`, \`ENTRY_BORDER_BY_STATUS\`
  (new): private to \`delegation-log.tsx\`.
- \`pendingQueueRef\` (new): private to hitl-in-app/page.tsx unmount cleanup.
- \`_update_delegation\` signature unchanged; only the missing-entry
  branch behaviour changed (no longer appends).
- \`AgentSpec.predict_state\` widened constraint
  (Iterable→Sequence): only consumed in agent_server.py's
  ADKAgent construction; passing a list still satisfies Sequence.
- CustomCatchallRendererProps.status narrowed
  (executing|complete|incomplete → executing|complete): only
  consumer is the page in the same demo folder; it now passes a
  matching union.
2026-04-27 12:52:52 -07:00
Alem Tuzlak 8804c5d0e0 fix(showcase/google-adk): wire OGUI runtime + boost streaming + state-hydration race + cheap (b) cleanups
CR Round 1 remaining bucket (a) findings + cheap (b) items:

A1 (streaming claim alignment): \`shared_state_streaming_agent.py\` no
longer carries an empty \`GenerateContentConfig()\` with comments that
claimed it enabled per-token streaming. Per-token streaming is driven
by (i) \`PredictStateMapping(stream_tool_call=True)\` set on the
ADKAgent middleware and (ii) the new
\`streaming_function_call_arguments=True\` kwarg added to the AgentSpec
+ agent_server.py wiring. The kwarg degrades gracefully on google-adk
< 1.24.0 with a UserWarning per the upstream contract.

A8 (useEffect race): both \`agent-config/page.tsx\` and
\`shared-state-read-write/page.tsx\` previously seeded INITIAL_* with
empty deps on mount, which fired BEFORE the runtime hydrated agent.state
on a page reload — overwriting backend-persisted config/preferences with
defaults. Replaced with a \`seededRef.current\` flag that gates the seed
to a single emission AFTER agent.state has been observed at least once.
Effect now correctly lists \`agent\` + \`agentState\` deps (no eslint
disable).

A9 (notes-card stable key): \`shared-state-read-write/notes-card.tsx\`
\`key={i}\` for plain-string lists used pure positional identity.
Replaced with \`key={i}::\${note}\` so DOM identity tracks both
position and content — agent rewrites of the notes list no longer
attach scroll/selection state to the wrong row.

A10 (hitl-in-app concurrent approvals): replaced
\`useState<ApprovalRequest | null>\` with a queue. Gemini's parallel
tool-call paths can fire \`request_approval\` more than once before the
first resolves; the previous single-slot state orphaned the first
promise (the agent waited forever). Queue head renders, every approval
resolves in arrival order, removal is filter-by-id-safe under
concurrent resolves.

A13 (OGUI runtime config): \`copilotkit-ogui/route.ts\` was missing
\`openGenerativeUI: { agents: [...] }\` on the CopilotRuntime. Without
it the OpenGenerativeUIMiddleware never engaged, so the
\`generateSandboxedUi\` tool calls from \`open_gen_ui\` /
\`open_gen_ui_advanced\` never converted to activity events and the
sandboxed iframe stayed empty. Verified the langgraph-python sibling
configures it the same way.

A14 (booked_schema parity): every sibling integration loads
\`BOOKED_SCHEMA = a2ui.load_schema(...)\` for parity even though the
A2UI Python SDK does not yet accept \`action_handlers\` for swap-on-
click; google-adk's \`a2ui_fixed_agent.py\` was the only package to
ship the JSON without loading it. Added the load + manifest highlight
entries.

A15 (handleClearNotes stale closure): same file as A9. Both handlers
now read latest agent state via the closure-fresh \`agentState\`
rather than the destructured \`preferences\` / \`notes\` snapshots that
went stale under rapid concurrent edits.

Bucket (b) cheap items applied:
- \`agent_server.py\`: \`reload=True\` → env-gated via UVICORN_RELOAD,
  so production runs aren't burning CPU on file-watching.
- \`agent_server.py\` /agents/state docstring: now explicitly names the
  FIRST registered agent (\`_simple_chat\`-shared demos work; bespoke-
  LlmAgent demos store sessions in their own ADKAgent's service that
  /agents/state doesn't reach — STATE_DELTA via useAgent still works).
- \`registry.py\`: stale "Already-implemented demos" header dropped;
  \`_SIMPLE_CHAT_INSTRUCTION\` rewritten to be tool-agnostic so the
  hint matches every demo that shares this agent (frontend-tools,
  headless-simple's \`show_card\`, etc.).
- \`tool-rendering-custom-catchall/page.tsx\`: \`: any\` cast on render
  args replaced with inferred types + an explicit status-narrow at the
  call site.
- \`voice/page.tsx\`: empty \`input={{}}\` prop removed — was overriding
  CopilotChat's default input slot with no override at all.
- \`byoc-json-render\` page+route: agent name renamed to
  \`byoc-json-render-demo\` (kebab + \`-demo\` suffix) to match
  sibling \`byoc-hashbrown-demo\` / \`a2ui-fixed-schema\` /
  \`auth-demo\` convention.

Starter regenerated to keep drift-check green.

Call-site enumeration:
- \`AgentSpec.streaming_function_call_arguments\` (new field): only
  consumed in agent_server.py's \`ADKAgent(...)\` construction.
- \`SHARED_STATE_STREAMING_PREDICT_STATE\`: re-exported, signature
  unchanged.
- \`AGENT_REGISTRY\` shared-state-streaming entry now passes
  streaming_function_call_arguments=True; no other callers.
- \`byoc-json-render-demo\` agent string: only consumed in the
  matching dedicated route + the corresponding page.tsx; both
  updated together.
2026-04-27 12:52:52 -07:00
Alem Tuzlak 0d86bab891 docs(showcase/google-adk): correct stale path + wiring claims in demo doc-comments
CR Round 1 bucket (a) finding A12: doc-comments referenced files and
wiring patterns that don't match the actual code in this package.

- a2ui-fixed-schema/page.tsx: \`src/agents/a2ui_fixed.py\` →
  \`src/agents/a2ui_fixed_agent.py\` (actual filename)
- declarative-gen-ui/page.tsx: \`src/agents/a2ui_dynamic.py\` →
  \`src/agents/declarative_gen_ui_agent.py, which re-exports the
  generate_a2ui tool defined in src/agents/main.py\`
- auth/demo-token.ts: header referenced \`use-demo-auth.ts\` (no such
  file in this package); now points at \`./page.tsx\` and adds a
  reminder that the constant ships into the browser bundle.
- open-gen-ui/page.tsx: rewrote to describe the actual two-pronged
  wiring — \`openGenerativeUI\` on the runtime AND on the provider —
  rather than just naming the runtime; the prior single-source claim
  obscured the activity-renderer activation that lives on \`<CopilotKit>\`.
- byoc-hashbrown/page.tsx: removed \"Wave 4a\" internal sequencing
  label; \"langgraph-python agent\" → \"Google ADK byoc_agent\".
- byoc-json-render/page.tsx: \"the LangGraph agent\" → \"the Google
  ADK byoc_agent\"; \"Wave 4a's hashbrown demo\" → \"the
  byoc-hashbrown demo\".

Comments-only change. No behavioural impact.

Call-site enumeration: doc-comments are leaf changes; no symbols
added, removed, or renamed; no call sites to enumerate.
2026-04-27 12:52:39 -07:00
Alem Tuzlak 1bf78426f0 fix(showcase/google-adk): inject-callbacks fail-loud + strip-stale-block on bad state + agent-config docstring
CR Round 1 bucket (a) findings A6, A7, A11:

A6 (silent no-op on malformed state): all three before-model-callback
agents (agent_config, readonly_state_agent_context, shared_state_read_write)
imported `logging.getLogger(__name__)` but never called the logger when
the frontend sent a non-dict / non-list payload. Schema drift was
indistinguishable from "user hasn't set anything yet". Now log
\`logger.warning(...)\` with the observed type so the regression surfaces
server-side.

A7 (readonly-context: early returns leave stale prior block): when
\`state["copilotkit"]\` or \`state["copilotkit"]["context"]\` was the
wrong shape, \`_inject_context\` returned without reaching the
strip-prior-block path — any context block injected on a previous turn
would stay embedded in \`system_instruction\` indefinitely. Now coerce
malformed state to \`raw_entries = []\` so the strip path always runs.

A11 (agent_config docstring stale): top-of-file docstring listed only
\`tone/expertise/response_length\` but the impl + frontend also handle
\`language\`. Updated.

Also extracted the trailing-sentence end markers into module-level
constants (\`CONFIG_END_MARKER\`, \`CONTEXT_END_MARKER\`,
\`PREFS_END_MARKER\`) so the strip logic and the \`_format_*\` builders
can't drift apart from a one-place edit. Added a warning log when a
signature is present but the end marker is missing — previously the
strip silently no-op'd and prior blocks would stack on subsequent turns.

Call-site enumeration:
- \`CONFIG_END_MARKER\`, \`CONTEXT_END_MARKER\`, \`PREFS_END_MARKER\`
  (new): private to their respective modules; only consumed by the
  builder + strip pair within each file.
- \`_format_config\`, \`_format_context\`, \`_build_prefs_block\` (logic
  changed): private to their modules; unchanged signature.
- \`_inject_config\`, \`_inject_context\`, \`_inject_preferences\` (logic
  changed): wired only into LlmAgent's \`before_model_callback\`;
  signature unchanged.
2026-04-27 12:52:39 -07:00
Alem Tuzlak 532eb85f63 fix(showcase/google-adk): subagents fail-loud + emit running state + defensive content access
CR Round 1 bucket (a) findings A2-A5:

A2 (errors recorded as completed): \`_record_delegation\` always set
\`status: "completed"\` even when \`_invoke_sub_agent\` returned a
\`(sub-agent error: …)\` string. The frontend's "failed" badge style was
defined but never reached. Replaced with a typed \`_SubAgentError\` plus
a \`_delegate\` flow that appends a "running" entry, invokes, then
flips to "completed"/"failed" with the actual error message.

A3 (never emits running): the Delegation type union has
\`"running"|"completed"|"failed"\` but only "completed" was ever written.
Now appended at delegation start; demo's "live delegation log" claim is
truthful.

A4 (AttributeError on safety-blocked responses):
\`getattr(candidates[0].content, "parts", None)\` directly accessed
\`.content\` — None content (safety-blocked, empty parts) raises
AttributeError on the inner getattr. Now guards content via getattr
first.

A5 (exception list too narrow): \`except (genai_errors.APIError,
ValueError)\` let httpx.ConnectError, asyncio.TimeoutError, RuntimeError
propagate up and crash the supervisor's tool turn. Catching the broad
\`Exception\` is appropriate here because the user-visible surface is a
structured \`{status: "failed", error}\` dict — server-side traceback is
preserved via \`raise … from exc\`.

Tool return shape changed from \`{"result": str}\` to
\`{"status": "completed"|"failed", result?, error?}\`. Supervisor
instruction updated to describe the new shape so the LLM can handle
sub-agent failures explicitly instead of fabricating a reply.

Call-site enumeration:
- \`_SubAgentError\`, \`_append_delegation\`, \`_update_delegation\`,
  \`_delegate\`: new private helpers, no external callers
- \`_record_delegation\` (removed): was private, no callers outside this
  module
- \`research_agent\`/\`writing_agent\`/\`critique_agent\` (return shape):
  only consumed by the LLM via tool-calling. Frontend reads
  \`state["delegations"]\` directly; its Delegation type already has
  the full status union.
- \`subagents_root_agent\` re-export: unchanged; registry import still
  resolves.
2026-04-27 12:52:39 -07:00
Alem Tuzlak efc17c677d fix(showcase/google-adk): add docs-links entries for all 27 new features
Without per-feature override entries, the dashboard's DocsRow falls
through to the global feature probe in shared/feature-registry.json.
For features whose canonical docs path doesn't exist on
docs.copilotkit.ai (e.g. an ADK-scoped page for shared-state-streaming
where only the langgraph-* equivalent is published) the probe returned
notfound and the docs/shell columns rendered as red ✗.

Mirror the pre-existing 8 entries' pattern: each new feature gets either
\`og_docs_url\` pointing at the real /adk/... page where one exists, or
\`og_docs_url: null\` for features without a canonical ADK page (which
the cell renders as an honest gray "opt-out" dot rather than red ✗).
\`shell_docs_path\` stays null for every feature — there's no
google-adk-scoped docs tree under shell-docs (PR #4085).
2026-04-27 12:52:39 -07:00
Alem Tuzlak 4b46cb4953 test(showcase/scripts): update catalog metadata expectations for google-adk parity
\`generate-catalog.test.ts\` hard-codes the expected wired/stub/unshipped
counts. Adding ~27 demos to google-adk shifted wired 526 → 552, stub
8 → 9, unshipped 203 → 176. Verified via
\`pnpm exec tsx generate-registry.ts\` against the fresh manifest.
2026-04-27 12:52:34 -07:00
Alem Tuzlak a04ed5f757 fix(showcase/google-adk): split tool_rendering_agents into per-variant files
\`validate-fixture-tool-surface.ts\` resolves a demo's backend tool
surface by file name (\`<agentId>.py\` or \`<agentId>_agent.py\`); the
prior plural \`tool_rendering_agents.py\` matched no agentId, so the four
tool-rendering variants had empty tool surfaces and the validator flagged
"weather" fixture drift. Split into per-variant files
(tool_rendering_agent.py, tool_rendering_default_catchall_agent.py,
tool_rendering_custom_catchall_agent.py,
tool_rendering_reasoning_chain_agent.py) that share a new
tool_rendering_common.py for the get_weather / search_flights /
query_data implementations and the system prompt. \`tools=[...]\` is now
a literal at module scope per file so the validator's regex picks it up.

Verified locally: \`pnpm exec tsx validate-fixture-tool-surface.ts\` →
65 fixtures × 534 demos, no drift.
2026-04-27 12:52:15 -07:00
Alem Tuzlak 696c23bb2e fix(showcase/google-adk): expose tool_rendering tools list for fixture validator
\`validate-fixture-tool-surface.ts\` parses backend tool surfaces with
\`/tools\s*=\s*\[/\` — that regex matches \`tools=[...]\` keyword-arg
syntax, not \`"tools": [...]\` dict-key syntax. The previous \`_build\`
helper passed tools through a kwargs dict, leaving the four
tool-rendering variants with empty tool surfaces and triggering aimock
fixture drift on the "weather in Tokyo" suggestion. Inline the four
constructors so \`tools=[get_weather, search_flights, query_data]\` is
visible to the regex.
2026-04-27 12:52:15 -07:00
Alem Tuzlak 7a67cbfc57 chore(showcase/starters): fix crewai-crews tool import for Linux generator
The Windows-generated starter wrote \`from .tools import\` for files inside
agent/tools/, but the Linux generator emits \`from . import\` because
\`filePath.includes("/tools/")\` only matches forward-slash paths
(generate-starters.ts:494). Match the Linux output so the drift check
passes.
2026-04-27 12:52:15 -07:00
Alem Tuzlak 83ba75ab31 chore(showcase/starters): regenerate crewai-crews to match package
Pre-existing drift on main: showcase/packages/crewai-crews/src/agent_server.py
was migrated from BaseHTTPMiddleware to a raw ASGI splice (commits 72c79bf99,
6b1ccfa86, ecbc76872, f16ea4d96) without regenerating the starter, so the
drift check was failing on every PR including this one. Re-emit via
\`pnpm exec tsx showcase/scripts/generate-starters.ts --slug crewai-crews\`.
2026-04-27 12:52:15 -07:00
Alem Tuzlak f7059d3ce7 chore(showcase/starters): regenerate google-adk starter to match package
`generate-starters.ts` regenerates each starter from its source package; the
prior commits added 18 new agent modules + refactored agent_server.py in the
google-adk package, so the starter needed re-emission. Generated via
`pnpm exec tsx showcase/scripts/generate-starters.ts --slug google-adk`.
Fixes drift-check failure on this branch.
2026-04-27 12:52:15 -07:00
Alem Tuzlak 65a6d9bd6f feat(showcase/google-adk): port langgraph-python demos to fill dashboard column
Backend: refactor src/agent_server.py from a single shared LlmAgent at /
to one ADKAgent per demo at /<agent_name>, driven by a new
src/agents/registry.py source-of-truth (with AgentSpec dataclass for
predict_state / emit_messages_snapshot kwargs). Adds 18 per-demo agent
modules covering reasoning, tool-rendering, HITL, shared-state,
multi-agent, A2UI dynamic + fixed-schema, BYOC, open-gen-ui, and others.

Frontend: src/app/api/copilotkit/route.ts now maps each agent name to its
matching backend path. Adds 6 dedicated runtime routes for demos that
need bespoke runtime config: copilotkit-auth (V2 createCopilotRuntimeHandler
with onRequest 401 gate), copilotkit-declarative-gen-ui and
copilotkit-a2ui-fixed-schema (a2ui.injectA2UITool: false), plus
copilotkit-byoc-{hashbrown,json-render} and copilotkit-ogui (shared by
open-gen-ui + advanced).

Manifest: declares 35 features (was 8). Dashboard wired count for
google-adk goes from 8/39 to 35/39, parity_tier minimal -> partial.
Reference (langgraph-python) is at 38/39.

Skipped (intentional): gen-ui-interrupt and interrupt-headless rely on
LangGraph's interrupt() primitive with no direct ADK equivalent;
mcp-apps left for follow-up.
2026-04-27 12:52:07 -07:00
Jordan Ritter 409c3118e1 fix: D5 all-green — load fixtures into aimock + add hitl-steps probe (#4325)
## Summary

- Bundle all 9 D5 (e2e-deep) fixture files into
`showcase/aimock/d5-all.json` so aimock loads them at boot via GitHub
raw URL. **Root cause of 93/158 D5 red cells**: the D5 fixtures in
`showcase/ops/fixtures/d5/` were never loaded into aimock — probes hit
real LLMs producing non-deterministic responses that fail strict
assertions.
- Add new `hitl-steps` D5 feature type + probe script for the
`/demos/hitl` route, which renders a step-selection UI
(`StepsFeedback`), not a time-picker. The previous mapping (`hitl →
hitl-text-input`) drove the wrong interaction against the wrong page.
- Update `RAILWAY.md` with the new fixture URL and updated
`startCommand` (d5-all.json loads before feature-parity.json for match
precedence).

## Post-merge deploy step

After merge, the Railway `startCommand` for `showcase-aimock` must be
updated to include the new `--fixtures` URL:

```sh
node /app/dist/cli.js \
  --proxy-only \
  --provider-openai https://api.openai.com \
  --provider-anthropic https://api.anthropic.com \
  --provider-gemini https://generativelanguage.googleapis.com \
  --fixtures https://raw.githubusercontent.com/CopilotKit/CopilotKit/main/showcase/aimock/d5-all.json \
  --fixtures https://raw.githubusercontent.com/CopilotKit/CopilotKit/main/showcase/aimock/smoke.json \
  --fixtures https://raw.githubusercontent.com/CopilotKit/CopilotKit/main/showcase/aimock/feature-parity.json \
  --validate-on-load \
  --host 0.0.0.0 \
  --port 4010
```

Then restart the aimock service to pick up the new fixtures.

## Test plan

- [x] 100/100 D5 tests pass (11 test files)
- [x] New hitl-steps tests: 7/7 pass
- [x] Existing hitl-text-input tests: no regression (10/10)
- [x] d5-all.json validated: 23 fixtures, correct structure
- [ ] After deploy: trigger D5 probe cycle and verify red count drops
from 93 to near-zero
2026-04-27 12:47:21 -07:00
Ben Taylor ce15e6d510 docs(threads): split /threads into CLI quickstart + manual paths (#4330)
<!--
Thank you for sending the PR! We appreciate you spending the time to
work on these changes.

Help us understand your motivation by explaining why you decided to make
this change.


**Please PLEASE reach out to us first before starting any significant
work on new or existing features.**

By the time you've gotten here, you're looking at creating a pull
request so hopefully we're not too late.

We love community contributions! That said, we want to make sure we're
all on the same page before you start.
Investing a lot of time and effort just to find out it doesn't align
with the upstream project feels awful, and we don't want that to happen.
It also helps to make sure the work you're planning isn't already in
progress.

As described in our contributing guide, please file an issue first:
https://github.com/ag-ui-protocol/ag-ui/issues
Or, reach out to us on Discord: https://discord.com/invite/6dffbvGU3D


You can learn more about contributing to copilotkit here:
https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md

Happy contributing!

-->

## What does this PR do?

(Describe the changes introduced in this PR)
Docs-only, adds a CLI quick start in the main threads page along side
the manual existing app augmentation path.

## Related PRs and Issues

- (Direct link to related PR or issue, if relevant)

## Checklist

- [ ] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [ ] If the PR changes or adds functionality, I have updated the
relevant documentation
2026-04-27 14:32:54 -05:00
Benjamin Taylor 08d94575c2 docs(threads): split /threads into CLI quickstart + manual paths
Restructure /threads using TailoredContent so users pick between
bootstrapping a new project with the v-next CLI or wiring threads
into an existing CopilotKit app. The CLI path walks through
`npx -y @copilotkit/cli-vnext@latest create`, enabling Intelligence
when prompted, cd-ing into the project, installing deps, adding the
OpenAI key, and `npm run dev` (which boots the local Intelligence
Platform, BFF, and web app at localhost:3000). The manual path
preserves the original 4-step flow (runtime config, useThreads,
thread switching, pagination).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:25:48 -05:00
Jordan Ritter 8a98fca2d5 docs(showcase): update D5 fixture README counts and stale docstrings 2026-04-27 11:55:41 -07:00
Jordan Ritter d7b46bd223 fix(showcase): move built-in-agent column to last in dashboard matrix (#4328)
## Summary

- Pin `built-in-agent` to sort position 900 in the dashboard sort map so
the REF column (langgraph-python at 10) stays first.

## Why

`built-in-agent/manifest.yaml` has `sort_order: 0`, which made it render
as the first column. It should be last — it's a minimal single-feature
integration, not the reference.

## Test plan

- [ ] CI green
- [ ] Dashboard at `dashboard.showcase.copilotkit.ai` shows
langgraph-python as first column, built-in-agent as last
2026-04-27 11:52:43 -07:00
Jordan Ritter 866ee6641e fix(showcase): move built-in-agent column to last in dashboard matrix
Its manifest had sort_order: 0 which put it first. Pin it to 900
in the dashboard sort map so the REF column (langgraph-python)
stays first.
2026-04-27 11:48:03 -07:00
Jordan Ritter 3a5d29f0c4 fix(showcase): correct doc counts, fix unfalsifiable registry test, update comments 2026-04-27 11:42:57 -07:00
Jordan Ritter f17d322116 fix(showcase): align Feature type shell_docs_url → shell_docs_path (#4327)
## Summary

- Rename `shell_docs_url` → `shell_docs_path` in the `Feature` interface
(`shell-dashboard/src/lib/registry.ts:13`) to match the JSON data field
name after #4323.

## Why

PR #4323 renamed all JSON data from `shell_docs_url` to
`shell_docs_path` but missed the TypeScript interface. Currently dormant
(no code reads Feature-level shell path), but the next person extending
this code would hit `undefined` from a field that looks defined in the
type.

## Test plan

- [ ] CI green — one-word type rename, no runtime behavior change
2026-04-27 11:41:41 -07:00
Jordan Ritter ca62be1035 fix(showcase): align Feature type field with data — shell_docs_url → shell_docs_path
The Feature interface declared `shell_docs_url` but all JSON
data files use `shell_docs_path` after the docs-green PR.
2026-04-27 11:36:20 -07:00
Jordan Ritter 63f36e4a24 fix(showcase): stringify d5 fixture arguments for aimock validation 2026-04-27 11:24:52 -07:00
Jordan Ritter c8fed358d1 fix(showcase): flatten hitl-steps tool format and drop stale search_flights from d5 fixtures 2026-04-27 11:19:02 -07:00
Tyler Slaton 78b7899140 chore(showcase/dashboard): make docs-og and docs-shell green across the matrix (#4323)
## Summary

Fixes the dashboard at https://dashboard.showcase.copilotkit.ai so every
`docs-og` / `docs-shell` cell that *has* a working docs target shows
green ✓ instead of red ✗.

The previous state: `docs-status.json` flagged virtually every feature
as `notfound` because `showcase/shared/feature-registry.json` pointed at
`https://docs.copilotkit.ai/features/<id>` URLs that all soft-404
(Next.js catch-all + `noindex` meta), and `shell_docs_url` paths like
`/docs/features/<id>` that don't exist in
`shell-docs/src/content/docs/`. Per-package `docs-links.json` overrides
covered ~8 features per integration but had `null` entries for many
cells, which `feature-grid.tsx`/`cell-pieces.tsx` render as red.

## What changed

- **`showcase/shared/feature-registry.json`** — replace dead URLs with
indexable docs.copilotkit.ai pages, rename legacy `shell_docs_url` →
canonical `shell_docs_path`, leave fields unset only for features with
no real docs page yet (auth/agent-config/voice/multimodal/byoc-* and
`kind: testing` features whose docs row is hidden).
- **14 existing `showcase/packages/<framework>/docs-links.json`** — fill
in every `null` with the closest framework-specific page (probed live
with `curl` for 200 + indexable, no `x-matched-path: /[[...slug]]`
catch-all) or a framework-agnostic indexable parent. Where neither a
scoped page nor a working agnostic alternative exists, leave null with a
`missing[]` rationale (honest red ✗).
- **New `showcase/packages/langroid/docs-links.json`** — placeholder
file declaring `features: {}` plus a rationale; every langroid demo with
documentation is covered by the feature-level registry, so per-cell
overrides aren't needed.

No code changes — only JSON sources of truth. The generated bundles
(`shell-dashboard/src/data/{registry,docs-status,catalog}.json` etc.)
are gitignored and rebuilt by `pnpm -C showcase/scripts
{generate-registry,probe-docs}` on dev/CI.

## Verification

- `pnpm -C showcase/scripts probe-docs` → `ok=61 / notfound=0 /
missing=19` across 40 features × 2 links (was effectively all-`notfound`
before).
- `pnpm -C showcase/scripts generate-registry` → all 18 manifests
validate, registry + catalog regenerate cleanly for shell-dashboard,
shell-docs, and shell-dojo.
- Dashboard cell simulation (mirrors the resolver in
`feature-grid.tsx:62-78` + `cell-pieces.tsx:51-62`):
  - **docs-og: 344 green / 72 red**
  - **docs-shell: 343 green / 73 red**
  - **Total: 687 green / 145 red docs cells**
- Remaining reds are exclusively
`auth/voice/multimodal/agent-config/byoc-hashbrown/byoc-json-render` on
integrations whose framework docs don't have those pages — i.e. honest
"not yet documented" signaling.

## Test plan

- [ ] Wait for the dashboard's next build → confirm
`dashboard.showcase.copilotkit.ai` shows green ✓ on `docs-og` and
`docs-shell` for the listed cells.
- [ ] Spot-check a few clicks: e.g. ag2/agentic-chat docs-og (→
`/ag2/prebuilt-components`), strands/tool-rendering docs-shell (→
`/strands/unselected/generative-ui/tool-rendering`).
- [ ] Confirm no manifest validation regression in CI (`pnpm -C
showcase/scripts validate-manifests`).
2026-04-27 11:16:22 -07:00
github-actions[bot] a5edd23d4f style: auto-fix formatting 2026-04-27 18:10:21 +00:00
Jordan Ritter fc0a66cd38 fix(showcase): bundle D5 fixtures for aimock and update startCommand
D5 probes hit real LLMs instead of fixtures because the 8 D5 fixture
files in showcase/ops/fixtures/d5/ were never loaded into aimock.
Railway fetches fixtures from GitHub raw URLs at boot — bundle all
D5 fixtures into d5-all.json and document the updated startCommand
with the new URL appearing before feature-parity.json for match
precedence.
2026-04-27 11:07:13 -07:00
Jordan Ritter d06d0bfdc7 feat(showcase-ops): add hitl-steps D5 probe for /demos/hitl step-selection UI 2026-04-27 11:05:49 -07:00
Sam Julien a44f2f9326 fix(shell-docs): IA polish — sidebar title, nav orphans, legacy redirect (#4324)
## Summary

Six small, independently-verifiable shell-docs cleanup commits. All
scoped to polish — no structural reorganization.

- **Sidebar title now shows the integration name** on framework-scoped
routes. Previously every `/<framework>/*` URL hardcoded `\"CopilotKit
Docs\"` at the top of the sidebar; now `/langgraph-python/*` reads
\"LangGraph (Python)\", `/built-in-agent/*` reads \"Built-in Agent\",
`/ms-agent-dotnet/*` reads \"MS Agent Framework (.NET)\", etc. Unscoped
routes (`/`, `/quickstart`) keep the \"CopilotKit Docs\" default.
- **Event Inspector + Hook Explorer added to the Troubleshooting
sidebar.** Both pages exist on disk but weren't in
`troubleshooting/meta.json`, making them unreachable from the sidebar —
only direct-URL navigation surfaced them. Inserted between Debug Mode
and Observability Connectors so the four debugging tools cluster
together.
- **Framework selector now reflects the stored choice on unscoped
pages.** The dropdown's display label was derived from the URL-derived
`framework` only. On unscoped pages where `framework` is null, it
reverted to the \"Pick an agentic backend\" placeholder even when
localStorage held the user's prior selection — so the choice appeared to
be forgotten on every return to the root. Falls back to
`storedFramework`, matching the precedence the Clear-Selection button
below already uses.
- **Wire the orphan `multi-agent/subagents` page into the App Control
nav.** `content/docs/multi-agent/subagents.mdx` is a real page with
`snippet_cell: subagents` and a lucide icon, but had no entry in any
`meta.json` — only direct-URL navigation reached it. Slotted into App
Control next to `frontend-tools` and `shared-state`.
- **Collapse legacy `/frontend-actions` into `/frontend-tools`.**
`content/docs/frontend-actions.mdx` was a 33-line stub from when the
feature was called \"Frontend Actions\" (the API is now exclusively
`useFrontendTool`). Deleted the orphan + added a 301 redirect in
`next.config.ts` so external links still land cleanly. The HTML anchor
IDs `id=\"frontend-actions-example\"` referenced from 12 framework
`frontend-tools.mdx` files are unaffected (anchors, not URLs).
- **Drop dormant per-framework threads + self-hosting stubs.** 24
byte-identical stub files across 12 framework trees: 12 ×
`integrations/<fw>/threads.mdx` (7L each, body `<Threads />`, all md5
`0371508d…`) and 12 × `integrations/<fw>/premium/self-hosting.mdx` (8L
each, body `<SelfHosting />`, all md5 `06d17f98…`). The
`buildFrameworkOverridesNav` filter already dropped them from the merged
sidebar (root wins), and the framework-scoped router falls back to root
MDX when no per-framework override exists — so deletion is invisible to
users. Net 187 lines gone. Path-exclusion patterns added to
`sync-docs-from-main.ts` so future upstream syncs don't resurrect them.

## Test plan

- [ ] `/langgraph-python/quickstart`,
`/langgraph-typescript/quickstart`, `/langgraph-fastapi/quickstart` show
\"LangGraph (Python)\", \"LangGraph (TypeScript)\", \"LangGraph
(FastAPI)\" respectively at the top of the sidebar.
- [ ] `/built-in-agent/quickstart` shows \"Built-in Agent\".
- [ ] `/mastra/quickstart` shows \"Mastra\".
- [ ] `/ms-agent-dotnet/auth` and `/ms-agent-python/auth` show \"MS
Agent Framework (.NET)\" and \"MS Agent Framework (Python)\".
- [ ] `/quickstart` (unscoped) keeps \"CopilotKit Docs\" — default
unchanged.
- [ ] Pick a framework, navigate back to `/` — the sidebar dropdown
shows the stored choice with violet active styling, not the \"Pick an
agentic backend\" placeholder.
- [ ] Use Clear Selection — dropdown reverts to placeholder; `framework`
is null and `storedFramework` is null.
- [ ] After a dev server restart (meta.json cache is module-scoped): the
Troubleshooting section in any docs page sidebar lists Common Issues →
Error Debugging → Debug Mode → **Event Inspector** → **Hook Explorer** →
Observability Connectors → migrate-* in that order.
- [ ] After a dev server restart: `/multi-agent/subagents` appears in
the App Control sidebar section (after Shared State) and renders with
the \"Sub-Agents\" title.
- [ ] After a dev server restart (next.config.ts redirects load on
startup): `curl -I http://localhost:3003/frontend-actions` returns `301`
with `Location: /frontend-tools`.
- [ ] `/frontend-tools` renders unchanged.
- [ ] All of these continue to render with multi-hundred-KB bodies after
stub deletion (routing fallback to root MDX): `/built-in-agent/threads`,
`/langgraph-python/threads`, `/mastra/threads`,
`/built-in-agent/premium/self-hosting`,
`/langgraph-python/premium/self-hosting`. Sidebar appearance unchanged —
these stubs were already filtered from the override nav.
2026-04-27 11:02:37 -07:00
Sam Julien 4589ff0ea7 docs-sync(needs-review): sync from main (291839119) [NEEDS REVIEW] (#4276)
⚠️ **Docs sync — MANUAL REVIEW REQUIRED**

This PR was auto-opened because the docs-sync script detected
showcase-local modifications overlapping with upstream changes.

The script attempted a best-effort 3-way merge:

- Where `git merge-file` produced a clean merge, the merged content was
written.
- Where `git merge-file` produced conflict markers, **upstream content
was written as-is** and showcase-local modifications were overridden.
**Manual review required.**

### Review items

```
Files where 3-way merge FAILED — upstream content written as-is, local modifications overridden. Manual review REQUIRED before merging this PR:
  - docs/content/docs/integrations/agent-spec/quickstart.mdx
  - docs/content/docs/integrations/langgraph/deep-agents.mdx
  - docs/content/docs/integrations/microsoft-agent-framework/quickstart.mdx

Files auto-merged via 3-way merge (clean, no conflict markers — still worth a glance):
  - docs/content/docs/integrations/built-in-agent/server-tools.mdx
```

### Source

- Upstream ref:
[`291839119`](https://github.com/CopilotKit/CopilotKit/commit/291839119)
- Workflow run:
https://github.com/CopilotKit/CopilotKit/actions/runs/24904970073

**Review before merging.** Auto-merge is intentionally disabled
for `needs-review` PRs — confirm the upstream-wins sections
preserve any intentional showcase-local divergence you want to
keep, then merge manually.
2026-04-27 11:02:20 -07:00
Alem Tuzlak 455d833f0e chore(showcase/dashboard): revert crewai-crews subagents to null + correct langroid rationale
Two follow-up fixes from the second CR pass:

1. crewai-crews/docs-links.json `subagents.og_docs_url` was set to
   `https://docs.copilotkit.ai/crewai-crews/multi-agent-flows` in the
   prior commit. That URL 308-redirects through
   `/crewai-flows/multi-agent-flows` to `/crewai-flows` — the same
   wrong-product overview the original `missing` rationale already
   warned about. Reverting to null with the rationale restored;
   honest red is better than a green badge that lands users on a
   different product's docs.

2. langroid/docs-links.json `missing[0].reason` claimed "every demo
   in langroid's manifest has a working feature-level og_docs_url +
   shell_docs_path in feature-registry.json." That's false: `auth`
   and `agent-config` are langroid demos with no registry entry, so
   those cells render red. Corrected the rationale to acknowledge
   the partial coverage and call out the honest-red intent for those
   two cells.

No probe-state change (`ok=61 / notfound=0 / missing=19` unchanged
because crewai-crews subagents was never an integration that demos
that feature in any case — the override was dead-weight; the fix is
about not lying to a future reader who promotes it).
2026-04-27 19:27:51 +02:00
Sam Julien 2bd355745a chore(shell-docs): drop dormant per-framework threads + self-hosting stubs
24 files in two byte-identical families across 12 integration trees:

- 12 `integrations/<fw>/threads.mdx` — 7 lines each, all md5 0371508d…,
  body is just `<Threads />`.
- 12 `integrations/<fw>/premium/self-hosting.mdx` — 8 lines each, all
  md5 06d17f98…, body is just `<SelfHosting />`.

Both render shared snippets the root-level pages already render. The
`buildFrameworkOverridesNav` filter dropped them from the merged
sidebar (root wins), and the framework-scoped router falls back to
root MDX when no per-framework override exists, so deletion is
invisible to users — `/built-in-agent/threads`,
`/langgraph-python/premium/self-hosting`, etc. continue to render
identically. Verified: each URL still returns 200 with full body
(340–465 KB) by curling the dev server before commit.

Add path-exclusion patterns to sync-docs-from-main.ts so future
upstream syncs don't resurrect them. Same shape as the BIA branch's
`(other)/` exclusion. Sample-tested the regexes against expected-
exclude and expected-keep paths — all classify correctly.

Audit covered every `integrations/<fw>/*.mdx` with body ≤ 2 non-blank
lines; no false-negative stubs of other shapes.
2026-04-27 10:03:46 -07:00
Alem Tuzlak 6995d6f30c chore(showcase/dashboard): replace /multi-agent soft-404 with framework-root or null
Code-review pass surfaced that `https://docs.copilotkit.ai/multi-agent`
is a Next.js SPA fallback (200 + `x-matched-path: /[[...slug]]` +
`<meta robots noindex>`) — the probe correctly flags it `notfound`,
but the per-package override path bypasses the probe and was
rendering green badges that 404 on click.

Replaces the URL across the 9 docs-links.json files where I introduced
it, plus the feature-registry fallback:

- Frameworks WITH an indexable framework root → use that:
  ag2 → /ag2, agno → /agno, google-adk → /adk,
  ms-agent-dotnet → /microsoft-agent-framework,
  strands → /aws-strands.
- Frameworks without a real scoped docs page → null (honest red,
  not lying-green): claude-sdk-python, claude-sdk-typescript,
  spring-ai, langroid.
- Feature-registry `subagents.og_docs_url` → null. The `1 notfound`
  in the prior probe summary is now `0 notfound / 19 missing` —
  same total, but the registry no longer carries a known-bad URL.

Also rewrote `showcase/packages/langroid/docs-links.json` to align
with langroid's actual manifest demos: of the 8 entries the original
file declared, only 3 (`agentic-chat`, `gen-ui-agent`,
`shared-state-streaming`) matched langroid's manifest; the other 5
(`hitl-in-chat`, `tool-rendering`, `gen-ui-tool-based`,
`shared-state-read-write`, `subagents`) were dead weight (the demos
don't exist on langroid). The file is now `features: {}` with a
rationale — every langroid demo has a working feature-level entry in
the registry, so per-cell overrides aren't needed.

Updated stale "missing" rationale strings in claude-sdk-python,
claude-sdk-typescript, spring-ai, strands to match the new state.

Verification
- `pnpm -C showcase/scripts probe-docs` → `ok=61 / notfound=0 /
  missing=19` across 40 features × 2 links.
- Dashboard cell simulation: still 687 docs cells green / 145 red.
  No regression — the `/multi-agent` fix touched 8 dead-weight
  overrides + 1 registry-fallback path that was already not
  rendering.
2026-04-27 18:46:55 +02:00
Sam Julien 0ff9ebc51e fix(shell-docs): collapse legacy /frontend-actions into /frontend-tools
content/docs/frontend-actions.mdx was a 33-line stub from when the
feature was called "Frontend Actions." The product API is now
exclusively useFrontendTool, the canonical page is /frontend-tools
(1967 bytes, snippet_cell-driven, in the App Control sidebar
section), and the orphan stub had no entry in any meta.json — it
only rendered if you typed /frontend-actions directly.

Per the IA analysis: "redirect or delete; pick one." Picked both:
delete the orphan file + add a 301 redirect /frontend-actions →
/frontend-tools so any external link (search results, blog posts,
customer docs) lands cleanly on the canonical page.

Other 'frontend-actions' references in the repo are stable HTML
anchor IDs (`id="frontend-actions-example"` in 12 integration
`frontend-tools.mdx` files) and external links to the legacy
docs.copilotkit.ai site — neither breaks.
2026-04-27 09:33:58 -07:00
Sam Julien 0c70c33abf fix(shell-docs): wire orphan multi-agent/subagents page into App Control nav
content/docs/multi-agent/subagents.mdx is a real, well-written page
(snippet_cell: subagents, lucide/Users icon) covering the supervisor →
specialized-sub-agents pattern. It rendered at /multi-agent/subagents
but had no entry in any meta.json, so it was unreachable from the
sidebar — a true orphan.

Slot it into the existing App Control section (next to frontend-tools
and shared-state, where it fits conceptually as another agent-behavior
control). The structural IA restructure (sam-shell-docs-ia, PR 2) can
promote it to a dedicated '---Multi-Agent---' section later if the
JTBD reorganization warrants it; this commit just stops it from being
hidden.

The 'multi-agent-flows' references in three integration metas
(crewai-flows, llamaindex, pydantic-ai) point at framework-specific
files (e.g. integrations/crewai-flows/multi-agent-flows.mdx), not at
this top-level page — different topic, no overlap.
2026-04-27 09:32:43 -07:00
Sam Julien 31693815fd fix(shell-docs): keep stored framework visible in selector on unscoped pages
The sidebar framework dropdown derived its display label and
"current" highlight from the URL-derived `framework` only. On
unscoped pages (/, /quickstart, /threads, etc.) where `framework` is
null, that resolved to `undefined` and the dropdown reverted to its
"Pick an agentic backend" placeholder — even when localStorage held
the user's prior selection. Visually this looked like the user's
choice had been forgotten on every return to a root-scoped URL.

Fall back to `storedFramework` when `framework` is null. Same
precedence as the Clear-Selection button further down the file
(`framework || storedFramework`). Framework-scoped routes are
unaffected because `framework` is set there.
2026-04-27 09:28:13 -07:00
Sam Julien 91a3b3bd41 fix(shell-docs): list event-inspector + hook-explorer in troubleshooting nav
Both files exist on disk (event-inspector.mdx, hook-explorer.mdx) but
weren't in troubleshooting/meta.json's pages array, so they were
unreachable from the sidebar — only direct-URL navigation surfaced
them. buildNavTree iterates meta.pages exclusively when present
(filesystem auto-discovery only fires when meta.json is missing or
its pages field is missing), so the slugs were effectively orphans.

Inserted between debug-mode and observability-connectors so the four
in-IDE debugging tools (error-debugging → debug-mode → event-inspector
→ hook-explorer) cluster naturally before observability and the
migration-guide tail.

Note: dev server picks up the new entries on restart — readMeta in
lib/docs-render.tsx caches at module scope by design (comment notes
this is intentional).
2026-04-27 09:20:00 -07:00
Sam Julien 13d9af1b40 fix(shell-docs): show integration name in sidebar on framework-scoped routes
The sidebar title on /<framework>/* routes was hardcoded to
"CopilotKit Docs" — a regression noted in the IA analysis where
upstream's `integrations/langgraph/meta.json` correctly rebrands the
sidebar via `title: "LangChain"` + `root: true`.

Pass the integration's display name from the registry (already in
scope at this call site for mergeFrameworkNav and other uses) instead
of the hardcoded string. Verified across slugs: /langgraph-python/*
shows "LangGraph (Python)", /built-in-agent/* shows "Built-in
Agent", /ms-agent-dotnet/* shows "MS Agent Framework (.NET)",
unscoped routes (e.g. /quickstart) keep "CopilotKit Docs" via the
DocsPageView default prop.
2026-04-27 09:17:57 -07:00