Closes#1936
`extractParametersFromSchema` now preserves enum values as structured
data on string parameters, recursively extracts nested object
attributes, and converts object arrays to `object[]` type with
attributes. This ensures complex MCP tool schemas survive the
`Parameter[]` -> Zod conversion without losing nested structure.
Split from #3838.
## Summary
- Replace pkg-pr-new preview URLs with published `@copilotkit/*@1.56.0`
versions in the langgraph-python starter
## Context
The preview URLs were used for testing the A2UI schema fix (PR #3929).
Now that 1.56.0 is released, switch back to normal npm versions.
## Test plan
- [x] Verified all packages are published at 1.56.0 on npm
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
Addresses all findings from 7-agent MSAL code review of the starter
crash fix PRs (#3933, #3941, #3943).
**Agent server (claude-sdk-typescript):**
- Remove 6 unnecessary `as any` casts — use TypeScript discriminated
union narrowing on `msg.role`
- Add `ANTHROPIC_API_KEY` validation on startup (exit if missing)
- Add `console.warn` logging to empty catch blocks (tool args + schema
parse failures)
- Sanitize error messages sent to client — no raw `err.message` in SSE
stream
- Fix misleading comment about system/developer role handling
- Set explicit 2MB JSON body limit on Express
- Remove unused `assistantMsgId` variable
**Generation script:**
- Remove dead `_agentDir` parameter from `rewritePythonImports`
- Add warning when `PIN_OVERRIDES` dep not found in framework
dependencies
**Tests (3 new):**
- Context-aware import rewriting for files inside `tools/` directory
- `from agents.X import` relative import rewriting
- `PIN_OVERRIDES` integration test for mastra version pinning
## Test plan
- [x] 254 generate-starters tests pass (3 new)
- [x] Drift check passes
- [x] Pre-commit hooks pass
- Guard TOOL_CALL_ARGS emission with if(toolCallId) check, matching
the existing guard on TOOL_CALL_END
- Wrap catch-block emit() in nested try/catch to handle client
disconnect during error reporting
The Round 2 fixes made tools.py rename and langgraph import
rewriting recursive, changing output for langgraph-python and
langgraph-fastapi tools/ subdirectory files. Committed starters
were stale.
Generation script:
- Make tools.py rename and langgraph import rewrite recursive via
forEachPyFile helper (was only processing top-level .py files)
- Fix from-src.agents regex to use [\w.]+ for dotted sub-paths,
matching the from-agents regex
- Simplify isInsideToolsDir branch to computed prefix variable
- Safe import-os removal: keep if os is used elsewhere in file
- Fix extractUvicornModule JSDoc example to match actual output
Agent server (claude-sdk-typescript):
- Remove dead ternary branches after API key guard
- Remove unreachable ?? "" fallback
Agent server (claude-sdk-typescript):
- Remove 6 unnecessary as-any casts, use TS discriminated union narrowing
- Add ANTHROPIC_API_KEY validation on startup (exit if missing)
- Add logging to empty catch blocks (tool args + schema parse)
- Sanitize error messages sent to client (no raw err.message in SSE)
- Fix misleading comment about system/developer role handling
- Set explicit 2MB JSON body limit
- Remove unused assistantMsgId variable
Generation script:
- Remove dead _agentDir parameter from rewritePythonImports
- Add warning when PIN_OVERRIDES dep not found in dependencies
Tests:
- Add context-aware import rewriting test (files inside tools/)
- Add from-agents.X relative import rewriting test
- Add PIN_OVERRIDES integration test for mastra version pinning
## Summary
- Remove the Open GenUI rendering strategy from all 17 showcase starters
- Clean up all supporting files: feature registries, constraints, e2e
tests, Python middleware, docs
- Regenerate all starters from updated template
### What was removed
The "open-genui" render mode allowed agents to generate arbitrary HTML
rendered in a sandboxed iframe. This is being extricated from starters
into a separate project. The core SDK `OpenGenerativeUIRenderer`
component is **not** affected — only the showcase starter UI option.
### Files changed
- **Template**: Deleted `open-genui/` renderer, updated types.ts,
page.tsx, suggestions hook
- **Registry**: Removed `open-gen-ui` and `byoc-opengenui` features from
all registries (shell, shell-dojolike, shared)
- **Constraints**: Removed "open" constraint block and open-gen-ui
references
- **E2E tests**: Removed Open GenUI test cases from starter-e2e,
screenshots, renderer-selector specs
- **Python middleware**: Removed OPEN_GENUI_INSTRUCTION and open-genui
handling from render_mode.py
- **Starters**: Regenerated all 17 via generate-starters.ts
- **Docs**: Updated QA-COVERAGE.md pill count from 5 to 4
### Local verification
- Docker build of langgraph-python starter: success
- Rendered page shows exactly 4 render modes (Tool-Based, A2UI,
json-render, HashBrown)
- Zero "open-genui" references in rendered HTML
- 521 validation tests pass
## Test plan
- [x] Docker build succeeds locally
- [x] Rendered starter shows 4 modes, no Open GenUI
- [x] Zero grep matches for open-genui across showcase/
- [x] 521 vitest validation tests pass
- [ ] CI green
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
Fixes the last 2 crashing starters (claude-sdk-typescript + mastra)
after PR #3933 resolved 5/7.
1. **ESM resolution failure** (claude-sdk-typescript) — nested
`agent/package.json` in Docker runner stage creates a separate package
boundary that confuses tsx module resolution. Fix: `rm -f
agent/package.json` in Dockerfile template after COPY.
2. **Recursive chown** (all templates) — `chown app:app /app` only
changed the directory, not contents. Mastra needs to create
`/app/src/mastra/public` at runtime. Fix: `chown -R app:app /app` in all
Dockerfile templates.
3. **Mastra version drift** (mastra) — floating `beta` dist-tags resolve
to incompatible versions between `mastra` CLI and `@mastra/core`. Fix:
generation script pins mastra ecosystem deps to stable versions via
`PIN_OVERRIDES` map.
All fixes verified locally with Docker builds before pushing.
## Test plan
- [x] Docker build + run claude-sdk-typescript locally — agent starts on
port 8123
- [x] Docker build + run mastra locally — `mastra 1.6.0 ready in 675 ms`
- [x] 502 generate-starters tests pass
- [x] Drift check passes
- [ ] Deploy to Railway and verify all 17 starters return 200
## Summary
- The docs-sync warning notification was sending "see workflow run for
details" with no actionable information
- Now reads `review-items.txt` and includes the file list directly in
the Slack message
- Recipients can see which files need attention without digging through
CI logs
## Test plan
- [ ] Trigger docs-sync with a file that has showcase-local
modifications (exit code 3 path)
- [ ] Verify Slack notification includes the file list in a code block
- [ ] Verify auto-push-only path (exit code 0) still does NOT send the
warning notification
The source package's src/agent/ was just committed — regenerating
the starter now correctly copies agent/index.ts and agent/package.json
into the starter directory, fixing the drift check.
The src/agent/ directory was never committed to the repo, causing
the drift-check to fail in CI. The starter was generated from a
local-only copy of this directory.
The warning notification for files needing manual review was sending
'see workflow run for details' with no actionable information.
- Read review-items.txt and include file list in the Slack message
- Use jq for proper JSON escaping (handles newlines, quotes, special chars)
- Guard against missing review-items.txt with fallback and ::warning::
- Review-needed notification fires independently of push/merge outcome
Core test (core-subscribe-to-agent.test.ts):
- Replace `as any` on RunErrorEvent with proper EventType.RUN_ERROR type
- Consolidate 4 identical lifecycle tests into one `it.each` block
- Extract silenceConsoleError() helper used across 10 error-path tests
- Document the remaining intentional `as any` in guardAll JS-consumer test
Angular test (agent.spec.ts):
- Make MockAgent extend AbstractAgent, removing all 4 `as unknown as AbstractAgent` double casts
- Replace all `any` types with proper AG-UI types (Message, State, AgentSubscriber, etc.)
- Emit helpers now pass correct AgentSubscriberParams instead of empty objects
- Use userMsg() factory for properly typed test data
- Simplify ProxiedCopilotRuntimeAgent assertion with single narrowing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- Add deployed starter L1-L3 smoke tests to `integration-smoke.spec.ts`
(health, agent endpoint, chat round-trip) hitting live Railway
`demo_url`s from `registry.json`
- Upgrade existing L4 `@tools` test with DOM element assertion
(`Promise.all` + `.some()`) to catch bugs like the `query_data` agent
loop that produced text but never rendered charts
- Add `deployed` boolean field to all 17 starter objects in
`registry.json` (14 healthy, 3 currently down)
- New `starter_deployed_smoke.yml` CI workflow: 6h cron + post-deploy
trigger + manual dispatch, with Slack/GitHub issue alerting on failure
### Context
7+ starters were crashing on Railway for hours with no automated
detection. The existing test suite only covered integration backends —
starters had zero deployed-URL testing. The
`agent-looping-on-query_data` bug shipped undetected because L4 only
checked text keywords, not rendered components.
### Key design decisions
- URLs read dynamically from `registry.json` (not hardcoded) — new
starters auto-tested
- `deployed` field gates which starters run (opt-in via `=== true`),
with `SMOKE_ALL` override
- Single-test-per-starter pattern avoids `fullyParallel` config
overriding serial mode
- Rendered-tools check is a warning (not hard failure) pending
data-testid standardization
- `STARTER_SLUG` env var supports single-starter manual dispatch
filtering
### Spec
https://www.notion.so/copilotkit/3433aa3818528112b2b6f65a4fab92d4
## Test plan
- [ ] Verify `@starter-health` tests pass against the 14 deployed
starters
- [ ] Verify `@starter-agent` tests pass against deployed starters
- [ ] Verify `@starter-chat` tests produce assistant responses on
deployed starters
- [ ] Verify 3 non-deployed starters (mastra, crewai-crews,
claude-sdk-typescript) are skipped by default
- [ ] Verify `SMOKE_ALL=true` includes non-deployed starters
- [ ] Verify `STARTER_SLUG=langgraph-python` filters to a single starter
- [ ] Verify rendered-tools warning fires for integrations without chart
components
- [ ] Verify CI workflow triggers correctly on manual dispatch
- [ ] Verify Slack + GitHub issue creation on failure path
🤖 Generated with [Claude Code](https://claude.com/claude-code)
1. Remove nested agent/package.json in TypeScript Dockerfile template to
prevent ESM module resolution failure (claude-sdk-typescript)
2. Use chown -R for /app in all Dockerfile templates so runtime-created
dirs (e.g. /app/src/mastra/public) are writable by non-root user
3. Pin mastra ecosystem deps to stable versions (1.6.0/1.25.0) in
generation script — floating beta tags caused version drift between
mastra CLI and @mastra/core
New workflow running starter health/agent/chat tests against Railway:
- Triggers: 6h cron, after showcase deploy, manual dispatch
- Alerts on schedule + workflow_run failures (Slack + GitHub issue)
- Issue dedup by title match, continue-on-error on Slack
- Proper working-directory for npm ci and Playwright install
Support retries with configurable delay in checkHealth() for Railway
cold-start scenarios. Captures last error from retry loop instead of
making a redundant final request.
Add a `deployed` boolean to all 17 starter sub-objects. 14 marked
true (healthy on Railway), 3 marked false (mastra, crewai-crews,
claude-sdk-typescript — currently down). Used by smoke tests to
gate which starters are tested.
React's useAgent was missing onRunErrorEvent under OnRunStatusChanged,
causing isRunning to stay true after protocol-level RUN_ERROR events
(infinite spinner). Angular already handled this via PR #3749.
Also updates SubscribeToAgentSubscriber JSDoc to accurately document
onRunErrorEvent as the sixth allowed callback with rationale for its
inclusion despite having stopPropagation in its return type, and adds
a core-level test for onRunErrorEvent firing immediately during
throttle windows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Restore `let active` guard in useAgent subscription effect (removed
during refactor, causing ReferenceError in batchedForceUpdate)
- Add onRunErrorEvent to SubscribeToAgentSubscriber allowed keys
(added on main for Angular AgentStore)
- Fix throttle tests to use async act() for onStateChanged assertions
(batchedForceUpdate uses queueMicrotask, needs await to flush)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the hand-rolled leading+trailing throttle (scheduleOrFlush,
setTimeout, throttleActive state machine) with TanStack Pacer's
Throttler class. Clean up comments to describe the method generically
rather than only in terms of throttling.
No public API changes — throttleMs / defaultThrottleMs stay as-is.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address review feedback: replace Object.entries loop in guardAll
with explicit per-key wrapping so TypeScript can verify all
callback signatures without any casts. Also replace Promise
duck-typing in safeCall with instanceof Promise, and use
Record<string, unknown> instead of any in the unsupported keys check.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the unsupported-key scan from guardAll into a pre-scan that runs
before the throttled/unthrottled branch, so JS consumers passing
unsupported callbacks (e.g. onEvent via `as any`) get a console.warn
regardless of whether throttling is active. Previously, guardAll only
ran on lifecycleOnly in the throttled path, silently dropping
unsupported keys without any diagnostic.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Error state handling in Angular CopilotkitAgentFactory (parity with React)
- Add emitError to guardAll for dropped callbacks (structured monitoring)
- Add emitError to setDefaultThrottleMs for monitoring parity
- Replace empty .catch(() => {}) with logging pattern on emitError
- Add generic typing to safeCall for call-site parameter safety
- Clarify flushPending comment re: sync-only unsubscribe guard
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add `satisfies readonly (keyof AgentSubscriber)[]` to SUBSCRIBE_TO_AGENT_KEYS
so upstream AG-UI renames are caught at compile time
- Fix SubscribeToAgentSubscriber JSDoc: separate AG-UI event handlers (mutation
semantics) from per-item callbacks (void return, excluded for surface area),
note that included lifecycle callbacks also return AgentStateMutation
- Emit invalid throttleMs through emitError so monitoring systems see
misconfiguration, not just console.error
- Add flushPending comment explaining the re-checked `active` flag between
onMessagesChanged and onStateChanged dispatch
- Derive SubscribeToAgentFn from CopilotKitCore['subscribeToAgent'] instead
of manually duplicating the signature (eliminates desync risk)
- Derive StubCore from Pick<CopilotKitCore, ...> in Angular tests
- Add test: async rejection during throttled trailing-edge flush
- Add test: clearing defaultThrottleMs(undefined) makes new subs unthrottled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add .catch() to emitError() in reportError to prevent unhandled
promise rejections if the error reporting infrastructure itself fails
- Add console.warn in guardAll when unsupported callback keys are
dropped, so JS consumers discover they need agent.subscribe() directly
- Hoist ALLOWED_KEYS Set to module scope to avoid per-call allocation
- Fix SubscribeToAgentSubscriber JSDoc: explicitly list the 5 supported
callbacks and mention onNewMessage/onNewToolCall as excluded
- DRY subscribeToAgent() method JSDoc by referencing the type instead
of duplicating the AG-UI exclusion rationale
- Fix safeCall comment: async error path returns Promise<undefined>,
not undefined
- Add JSDoc to setDefaultThrottleMs setter; simplify getter JSDoc
- Fix use-agent.tsx: consistent camelCase callback names, fix @default
tag format, replace unresolvable {@link} with plain text reference
- Add test: emitError/onError integration for SUBSCRIBER_CALLBACK_FAILED
- Add test: unsubscribe + throw combination in onMessagesChanged
- Add test: unsupported callback keys dropped with console.warn
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AgentStore now receives a SubscribeToAgentFn function instead of a
CopilotKitCore instance. The factory binds core.subscribeToAgent once
and passes the bound function, keeping AgentStore decoupled from the
core class while preserving all throttle and error-protection behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add SUBSCRIBER_CALLBACK_FAILED error code and call emitError() in
safeCall so subscriber failures are visible to monitoring systems
and onError handlers, not just console.error
- Document that safeCall intentionally discards return values on the
error path (including lifecycle AgentStateMutation)
- Extract SUBSCRIBE_TO_AGENT_KEYS tuple as single source of truth for
both the SubscribeToAgentSubscriber type and the runtime ALLOWED_KEYS
set, eliminating the one-directional sync risk from the satisfies pattern
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Type `handlers` in use-agent.tsx as `SubscribeToAgentSubscriber` instead
of full `AgentSubscriber` to prevent silent runtime stripping of unsupported
callbacks
- Reframe AG-UI exclusion JSDoc: designed for observation, not event mutation
(stopPropagation semantics can't be safely mediated)
- Add `satisfies` constraint to ALLOWED_KEYS so it stays synchronized with
the SubscribeToAgentSubscriber Pick type at compile time
- Use `.then` instead of `.catch` for standard thenable detection in safeCall
- Include agent ID in all safeCall error messages for multi-agent debugging
- Only wrap lifecycle callbacks in guardAll for throttled path (messages/state
wrappers were immediately overwritten — wasted work)
- Fix "pending flags" → "pending params" in inline comment
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace `as any` cast in notifyLifecycle with type-safe branching,
type the re-entrant test callback params via SubscribeToAgentSubscriber,
and replace `Record<string, any>` on Angular stub's core with a
typed StubCore interface.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add ALLOWED_KEYS filter in guardAll to prevent runtime leakage of
extra properties from JS consumers or `as any` casts
- Check `active` flag between flushPending dispatches so unsubscribing
inside onMessagesChanged prevents onStateChanged from firing
- Use real CopilotKitCore instance in Angular test stub instead of
passthrough that bypasses throttle and safeCall logic
- Reword SubscribeToAgentSubscriber and subscribeToAgent JSDoc to
accurately explain why AG-UI event handlers are excluded (mutation
return values silently discarded) rather than implying a clean
return-type split
- Add leading+trailing pattern summary to useAgent throttleMs JSDoc
- Fix setDefaultThrottleMs JSDoc: "logged as errors and ignored"
instead of ambiguous "rejected by the setter"
- Add tests: re-entrant notifications during flush, multiple
simultaneous subscriptions with independent throttle windows,
unsubscribe isolation, unsubscribe-during-flush prevents sibling
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce SubscribeToAgentSubscriber, a Pick of AgentSubscriber limited
to the five notification/lifecycle callbacks (onMessagesChanged,
onStateChanged, onRunInitialized, onRunFinalized, onRunFailed). Event
handlers that return AgentStateMutation (e.g. onEvent,
onToolCallStartEvent) should use agent.subscribe() directly so their
mutation and stopPropagation semantics are preserved — safeCall's
error-swallowing would silently discard those return values.
This is a compile-time constraint only; no runtime behavior changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address code review findings for subscribeToAgent:
- Wrap ALL subscriber callbacks (not just onMessagesChanged/onStateChanged)
with safeCall error protection so a throwing lifecycle or event callback
cannot corrupt the agent's notification loop
- safeCall now returns the result on the success path, preserving
AgentStateMutation return values from subscriber callbacks
- Extract SubscribeToAgentOptions named interface for extensibility
- Remove redundant pendingMessages/pendingState boolean flags — use
latestMessagesParams/latestStateParams !== null instead
- Add guardAll helper used by both throttled and unthrottled paths
- Fix JSDoc: reference public defaultThrottleMs (not private field),
document shared throttle window, use callback names instead of enum
- Add 5 new core-level tests: trailing-edge re-arm, onRunFailed
passthrough, async rejection handling, unthrottled exception safety,
unthrottled lifecycle exception safety
- Extract RUN_INPUT constant and notifyLifecycle helper, reducing test
helper duplication
- Remove ephemeral review-reference from test section header
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>