The base class @ag-ui/langgraph creates an Observable that calls
runAgentStream() but ignores the returned Promise. Any async rejection
becomes an unhandled promise rejection that crashes the process.
Override run() to properly route async errors through the Observable
error channel so downstream catchError handlers can process them.
The thread naming creates an additional run, using a thread name that
was something like
"thread-naming:${originalthreadiduuid}:${newrandomuuid}" which
shockingly is not a valid uuid. This just drops the first 2 parts and
keeps the random uuid so langgraph can stop being mad.
Keep both defaultThrottleMs (our branch) and inspectorDefaultAnchor +
design-skill context registration (main) in CopilotKitProvider.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Core setter rejects invalid values (NaN, Infinity, negative) instead of
storing them, preventing garbage from reaching downstream consumers.
- Provider initializes defaultThrottleMs synchronously during instance
creation so child hooks see the correct value on their first render.
- Remove phantom notificationThrottle JSDoc reference (API does not exist).
- Remove dead "default" branch in error source detection.
- Fix misleading @default comments re: 0-vs-undefined semantics and
cascade direction.
- Replace React-specific "re-renders" language in framework-agnostic core.
- Add test for dynamic provider defaultThrottleMs changes.
- Add tests for core setter validation behavior.
- Add defaultThrottleMs to renderWithCopilotKit test helper.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace @a2ui/lit with @a2ui/web_core 0.9, introduce createCatalog() API for
custom component catalogs, add basic (18 components) and minimal (5 components)
built-in catalogs, CSS variable theming for dark mode, eliminate XSS vector
(dangerouslySetInnerHTML removed from Text component).
Addresses Tyler's review comment on #3657 — defaultThrottleMs is configuration
that belongs on the copilotkit instance, not as a sibling field in the React
context value.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract renderAndWarmCache() and installBoundingRectSpy() helpers to
eliminate duplicated setup across 4 tests. Add justifying comments on
all necessary type casts (MockResizeObserver, CSSStyleDeclaration,
TextMetrics, canvas getContext overloads).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Self-inflicted resizes (compact↔expanded) were clearing the cache before
the ignoreResizeRef guard, forcing a full re-measurement on the very next
keystroke. Move the guard ahead of invalidation so layout toggles keep the
cache warm — container dimensions don't change during these transitions.
Also reject compactWidth <= 0 from being cached, preventing a zero-width
entry from silently disabling text-width expansion until the next resize.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Merge two ResizeObserver instances into one; inspect entry.target to
decide cache invalidation. Eliminates the ignoreResizeRef race where
two observers could consume the guard independently.
- Move textarea font read out of the cache into evaluateLayout so CSS/
theme changes are picked up without a container resize.
- Return { compactWidth } | null from updateContainerCache; callers use
the value directly instead of the two-step "call then check ref" pattern.
- Hoist cache invalidation above the ignoreResizeRef guard to remove
duplicated containerCacheRef.current = null.
- Add zero-width guard in updateContainerCache to avoid caching
compactWidth: 0 when the container is hidden.
- Replace vi.fn() as any ResizeObserver mock with a class-based
MockResizeObserver that tracks observed targets, enabling per-target
resize triggers in tests.
- Fix empty-font and null-canvas tests to assert data-layout="compact"
(verifying the fallback path) instead of just non-null.
- Add tests: warm-cache keystroke perf (getBoundingClientRect not called),
textarea-only vs container resize invalidation, ignoreResizeRef + cache
invalidation during layout toggle.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix all doc imports to use @copilotkit/runtime/v2 (symbols only
exported from v2 entry point)
- Replace v1 copilotRuntimeNextJSAppRouterEndpoint with v2 pattern
(CopilotRuntime + createCopilotEndpoint + InMemoryAgentRunner)
- Add warning callout on TanStack reasoning example (reasoning events
not surfaced by TanStack converter)
- Fix randomUUID imports in converters: use @copilotkit/shared instead
of Node.js crypto to match codebase convention
- Fix collectEvents timer leak in test-helpers.ts (add clearTimeout)
- Fix JSDoc/comments: convertInputToTanStackAI accurately describes
role allowlist, TanStackInputResult.messages comment updated
- Close TOCTOU window: set abortController synchronously before Observable
creation in classic run(), matching factory run() pattern (M3)
- Add concurrent run guard to classic run() (C1)
- Add threadId/runId to RUN_ERROR events in classic mode (I2)
- Check both 'output' and 'result' property names in classic tool-result (C2/M2)
- Add try/catch around JSON.stringify in classic tool-result (I4/M2)
- Add undefined guards before emitting state snapshot/delta events (I3)
- Guard assignToolsToAgents against factory-mode agent configs (M1)
- Improve error handling in classic error case with proper fallback (C3)
- Improve TanStack converter TODO comment with known gap details (M5)
- Document @ts-expect-error on clone() middlewares access (S1)
- Add JSDoc to AgentFactoryContext.abortController (M4)
- Fix duplicate import and clean up react-router example
- Update docs AgentFactoryContext reference
- Add converter imports (convertAISDKStream, convertTanStackStream) to agent/index.ts
- Update canOverride() to return false for factory configs
- Add factory-path early return in run() that delegates to runFactory()
- Add private runFactory() method that handles aisdk/tanstack/custom factory configs
with full lifecycle management (RUN_STARTED, RUN_FINISHED, RUN_ERROR, abort support)
- Fix copilot-runtime.ts: change BuiltInAgentConfiguration["tools"] indexed access
types to BuiltInAgentClassicConfig["tools"] since tools only exist on classic configs
Source fixes:
- Fix TOCTOU race in concurrent run guard — set abortController
synchronously before Observable creation, closing the window where
two run() calls could both pass the guard
- Add JSON.stringify try/catch in TanStack TOOL_CALL_RESULT handler
(matching existing aisdk.ts protection against circular refs)
- Use role allowlist (user/assistant/tool) instead of denylist in
convertInputToTanStackAI to exclude activity/reasoning roles
- Change error+abort handler from break to return in aisdk converter
to stop processing after error during abort
- Fix version-pinned comments (remove "AI SDK 5.0" reference)
Test fixes:
- Add timedOut flag to collectEventsIncludingErrors to distinguish
hung observables from normal completion
- Add clearTimeout on success/error to prevent timer leaks
- Remove timing-dependent setTimeout in concurrent run guard test
Docs fixes:
- Split imports: copilotRuntimeNextJSAppRouterEndpoint from
@copilotkit/runtime, Agent/converters from @copilotkit/runtime/v2
- Fix forwardedProps example: use CopilotKit properties prop
- Fix useCopilotChat → useCoAgent for state management reference
- Fix model syntax colon → slash (openai/gpt-4o)
Critical fixes:
- Guard concurrent run() calls — throw if agent is already running
- Check both "output" and "result" properties on AI SDK tool-result events
for compatibility with older AI SDK versions
- Handle undefined/missing error in AI SDK error events with proper
Error wrapping instead of throwing undefined
Important fixes:
- Add TOOL_CALL_RESULT handling to TanStack converter (was silently dropped)
- Include threadId and runId in RUN_ERROR events for run correlation
- Guard state tool events (STATE_SNAPSHOT/STATE_DELTA) against undefined
snapshot/delta fields before emitting
- Wrap JSON.stringify in tool-result with try/catch to handle circular refs
- Fix collectEventsIncludingErrors to distinguish error vs normal completion
Test coverage:
- Add tests for convertInputToTanStackAI (message filtering, tool call
mapping, context injection, state serialization)
- Add tests for state management tool results in AI SDK converter
- Add tests for async factory (Promise-returning) paths
- Add tests for tool-result property compatibility (output vs result)
- Add tests for error event handling edge cases
- Add tests for concurrent run guard and RUN_ERROR correlation fields
- Replace flaky setTimeout-based abort test with signal-based sync
Other:
- Add exhaustiveness check (default: never) in config type switch
- Document clone() @ts-expect-error coupling with AbstractAgent.middlewares
- Fix docs: remove incorrect "v6" version reference, fix wrong hook name
Add Agent class extending AbstractAgent that accepts aisdk, tanstack,
or custom configurations via a discriminated union. Routes to the
appropriate converter, handles RUN_STARTED/FINISHED/ERROR lifecycle,
and supports clone/abortRun. Re-export Agent and converters from the
agent barrel.
Add convertTanStackStream async generator that converts TanStack AI
stream chunks (TEXT_MESSAGE_CONTENT, TOOL_CALL_START/ARGS/END) into
AG-UI events. Create converters/index.ts barrel that re-exports both
AI SDK and TanStack converters.
Extract the AI SDK fullStream event-mapping loop into a standalone
async generator (convertAISDKStream) that yields AG-UI BaseEvent
objects. This is a pure converter with no lifecycle events — the
caller handles RUN_STARTED/FINISHED/ERROR.
Extract shared helpers (DEFAULT_LAYOUT_OPTIONS, getLayoutGrid,
renderTypeAndExpectLayout) to eliminate duplication, add explanatory
comments for unavoidable `as any` casts, and add missing test for
canvas.getContext returning null.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Split ResizeObserver into container vs textarea observers so textarea
height changes (typing, manual resize) don't invalidate the dimension
cache unnecessarily — only grid/button resizes invalidate it
- Invalidate cache on self-triggered resizes (compact↔expanded toggle)
even when skipping re-evaluation, preventing stale dimensions
- Validate fontSize and fontFamily before constructing font fallback
string, avoiding malformed CSS font values in Safari
- Add dev-mode console.warn when font resolution or canvas context
fails, making silent measurement path failures diagnosable
- Update test ResizeObserver mock to support multiple observers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Test canvas text measurement triggers expansion for long single-line text
- Test compact layout preserved when text fits within cached width
- Test cache invalidation on resize produces correct re-measurement
- Test empty font string is not cached (guard prevents invalid canvas state)
- Mock ResizeObserver to exercise cache invalidation path in jsdom
- Extend mockLayoutMetrics with getComputedStyle mocks for grid and textarea
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>