3119 Commits

Author SHA1 Message Date
Max Korp c5d712f4cf test(runtime): add unit tests for LangGraphAgent.run() async error handling
Verify that async rejections from runAgentStream are routed through the
Observable error channel instead of becoming unhandled promise rejections.
2026-04-08 16:17:55 -07:00
Max Korp cffc4cafe0 fix: catch async errors in LangGraphAgent.run() Observable
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.
2026-04-08 16:17:55 -07:00
Tyler Slaton 02b2638433 fix: generate runtime-client-gql types before tests 2026-04-08 15:32:49 -07:00
Ben Taylor 9181bf9ae0 fix: use plain UUID for thread-naming runs (#3664)
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.
2026-04-08 16:22:23 -05:00
Maxim 9ee8e92766 chore: resolve merge conflicts with origin/main
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>
2026-04-08 22:58:45 +02:00
Max Korp 2142ecea99 fix: use plain UUID for thread-naming runs 2026-04-08 13:52:06 -07:00
Maxim 7a99322e77 fix: harden throttleMs cascade — setter validation, timing fix, JSDoc accuracy, tests
- 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>
2026-04-08 22:05:22 +02:00
Markus Ecker a5c1137465 chore: update ag-ui deps and web-inspector styles 2026-04-08 12:51:07 -07:00
Markus Ecker 71c77d4072 feat(cli): add a2ui and opengenui scaffold options 2026-04-08 12:50:37 -07:00
Markus Ecker e6988014f8 feat(runtime): OpenGenerativeUI middleware + A2UI config cleanup
Add OpenGenerativeUIMiddleware (clarinet streaming JSON parser, held event
buffering, activity snapshot/delta conversion), remove a2ui boolean shorthand,
includeBasicCatalog defaults to false, before_agent SystemMessage ID reuse fix.
2026-04-08 12:50:18 -07:00
Markus Ecker 05ddcfc12a feat(react-core): Open Generative UI — sandboxed HTML/CSS/JS rendering via iframe
AI-generated UI streamed into chat via websandbox iframe (allow-scripts only,
no allow-same-origin), progressive HTML preview with throttled updates,
one-shot auto-resize, sandboxFunctions for host-to-iframe calls, designSkill
styling guidelines, A2UI catalog context injection.
2026-04-08 12:49:38 -07:00
Markus Ecker 93d0a76ddc feat(a2ui-renderer): A2UI v0.9 — BYOC catalogs, dark mode, component-neutral guidelines
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).
2026-04-08 12:48:47 -07:00
Maxim cb7bfae188 refactor: move defaultThrottleMs from React context onto CopilotKitCore instance
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>
2026-04-08 21:44:47 +02:00
Maxim a8e05401e7 fix: improve throttleMs validation, JSDoc accuracy, and test coverage
- Add source attribution to error messages (hook-level vs provider-level)
- Add eager validation of defaultThrottleMs in CopilotKitProvider
- Add tests for invalid provider defaultThrottleMs (NaN, Infinity, -1)
- Remove redundant resolved !== 0 guard in validation
- Fix JSDoc: "streaming" → "message change notifications", "passed
  directly" → "forwarded", align @default terminology
- Extract shared mock helpers to reduce test duplication

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:31:28 +02:00
Maxim c8db6476a8 test: verify CopilotSidebar/CopilotPopup inherit throttleMs type
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:14:51 +02:00
Maxim a7c57cef9c feat: add throttleMs prop to CopilotChat, forwarded to internal useAgent
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:11:46 +02:00
Maxim e30d27b46b test: guard throttleMs:0 override of provider defaultThrottleMs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:07:57 +02:00
Maxim af98091bda feat: add defaultThrottleMs to CopilotKitProvider, read as fallback in useAgent
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:49:57 +02:00
Maxim 8a1f111602 Merge branch 'main' into perf/chat-input-cache-container-measurements 2026-04-08 19:38:34 +02:00
Maxim ad4271c266 test(react-core): extract shared helpers and document casts in cache tests
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>
2026-04-08 19:22:33 +02:00
Maxim 35e35bb5bc fix(react-core): preserve cache across layout toggles and reject zero-width entries
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>
2026-04-08 18:54:25 +02:00
Maxim 84d531c1e3 fix: address review feedback — single observer, fresh font read, test coverage
- 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>
2026-04-08 18:39:22 +02:00
Alem Tuzlak 990acb46ab fix(runtime): address CR round 1 findings
- 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
2026-04-08 18:03:44 +02:00
Martha Kelly Schumann 04d73d1dca Merge branch 'main' into claude/langgraph-tests-cleanup-1jVZ3 2026-04-08 08:52:43 -07:00
Alem Tuzlak a8715b9631 style(runtime): fix formatting in agent test files 2026-04-08 17:40:47 +02:00
Alem Tuzlak 9b15a7c378 fix(runtime): address PR review feedback
- 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
2026-04-08 17:32:50 +02:00
Tyler Slaton da8e58f1a1 Merge branch 'main' into fix/CPK-7154-agent-text-wiped-multiple-tool-calls 2026-04-08 08:25:46 -07:00
Alem Tuzlak 920640cb5a test(runtime): update Agent tests to use BuiltInAgent factory mode 2026-04-08 17:15:00 +02:00
Alem Tuzlak 802d20e95d refactor(runtime): remove Agent class, absorb into BuiltInAgent 2026-04-08 17:14:59 +02:00
Alem Tuzlak 3fcf2fbaf9 feat(runtime): add factory-path branch to BuiltInAgent.run()
- 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
2026-04-08 17:14:58 +02:00
Alem Tuzlak d320a5217c feat(runtime): add factory config types to BuiltInAgentConfiguration union 2026-04-08 17:14:56 +02:00
Alem Tuzlak 7e69300537 fix(runtime): address CR loop round 1 findings
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)
2026-04-08 17:14:55 +02:00
Alem Tuzlak 4e33d42fb6 refactor(tests): test-hygiene fixes for Agent test files
- Replace Record<string, unknown> return types on TanStack mock chunk
  builders with inferred types via as const
- Remove dynamic imports in converter-aisdk error tests — use
  top-level collectEventsIncludingErrors import instead
- Remove redundant as RunAgentInput casts in converter-tanstack-input
  tests (createDefaultInput already returns the correct type)
- Add comments explaining necessary casts in createAgent overloads
  (TypeScript limitation with discriminated union narrowing)
2026-04-08 17:14:54 +02:00
Alem Tuzlak b344d08e17 fix(runtime): address code review feedback on Agent class
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
2026-04-08 17:14:52 +02:00
Alem Tuzlak 051f55a7de style: apply prettier formatting to new Agent files 2026-04-08 17:14:49 +02:00
Alem Tuzlak 31919c4cf4 refactor(test): replace type casts with eventField in converter tests 2026-04-08 17:14:48 +02:00
Alem Tuzlak ebfd2c33fc refactor(test): remove all type casts from Agent test files 2026-04-08 17:14:47 +02:00
Alem Tuzlak 5f0a718932 feat(agent): add convertInputToTanStackAI utility for message/prompt conversion 2026-04-08 17:14:45 +02:00
Alem Tuzlak aae03a7ce0 test(agent): add custom converter (passthrough) tests 2026-04-08 17:13:58 +02:00
Alem Tuzlak 8b264f8735 test(agent): add core Agent class tests with parameterized lifecycle/abort/clone 2026-04-08 17:13:57 +02:00
Alem Tuzlak 4b544cc99b test(agent): add AI SDK converter tests 2026-04-08 17:13:55 +02:00
Alem Tuzlak dfcf032b6b test(agent): add TanStack AI converter tests 2026-04-08 17:13:54 +02:00
Alem Tuzlak c07aa13b9e test(agent): add shared test utilities for Agent class 2026-04-08 17:13:52 +02:00
Alem Tuzlak af9de02ee9 fix(agent): support async factory functions in Agent config types 2026-04-08 17:13:51 +02:00
Alem Tuzlak b9b5164033 feat(runtime): add universal Agent class with multi-backend support
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.
2026-04-08 17:13:49 +02:00
Alem Tuzlak 3997203e47 feat(runtime): add TanStack AI stream converter and barrel export
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.
2026-04-08 17:13:48 +02:00
Alem Tuzlak ddc58b1e1a feat(runtime): extract AI SDK stream converter from BuiltInAgent
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.
2026-04-08 17:13:46 +02:00
Maxim f35df00b16 test(react-core): improve test hygiene in container dimension cache tests
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>
2026-04-07 23:49:24 +02:00
Maxim 8da887c14c fix(react-core): harden container dimension cache in CopilotChatInput
- 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>
2026-04-07 23:36:47 +02:00
Maxim 27bde85b6f test(react-core): add tests for container dimension cache in CopilotChatInput
- 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>
2026-04-07 23:10:10 +02:00