Commit Graph

196 Commits

Author SHA1 Message Date
github-actions[bot] 8067ecde90 style: auto-fix formatting 2026-04-22 09:42:34 -05:00
Benjamin Taylor 551be40fe1 fix(threads): surface isLoading=true while waiting for first context dispatch
CR feedback: with the /info gating in useThreads, the underlying
thread store sits at isLoading=false (its initial state) until we
dispatch the first context — which we now defer until
runtimeConnectionStatus === Connected. Consumers reading
`isLoading` during that window would otherwise see the empty-state
branch and render a momentary "no threads" flash instead of a
skeleton.

Track `hasDispatchedContext` in React state; synthesize
isLoading=true while runtimeUrl is set but no context has been
dispatched yet. Once we dispatch, fall through to the store's own
loading flag (which flips true in the contextChanged reducer, then
false after the fetch settles).

Tests:
- use-threads: extend the Connected-gate test to assert
  isLoading=true before Connected, false after the fetch lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 09:42:34 -05:00
Benjamin Taylor d598a197dd chore(threads): code-review fixups
- Rename sortThreadsByUpdatedAt → sortThreadsByRecency to match the
  lastRunAt-preferring sort introduced in the previous commit.
- useThreads: correct the context-dispatch comment to describe what the
  code actually does (null only when runtimeUrl is absent; transient
  status states leave the previous context in place).
- CopilotChatInput: rewrite the `bottomAnchored` prop doc so the
  layout/positioning distinction is self-evident.
- Add changeset calling out the behavior change to suggestions (now
  hidden while `isRunning`) and summarizing the ENT-314 fixes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 09:42:34 -05:00
Benjamin Taylor bbe23e604e fix(threads): skip /connect for absent threads, stabilize switch UX (ENT-314)
- Skip copilotkit.connectAgent when CopilotChat lacks a caller-supplied
  threadId — a locally-minted UUID has no backend record, so /connect
  would always 404 on the intelligence platform.
- Suppress the welcome screen while a connect is in flight and
  unconditionally when the caller has supplied a threadId
  (hasExplicitThreadId). Prevents the "How can I help you today?"
  flash on thread switch.
- Gate suggestions on !isConnecting && !isRunning to avoid painting
  them against a mid-replay message tree.
- Defer the isConnecting release by one animation frame so trailing
  bootstrap renders commit before the flag flips.
- Reserve room for the "Powered by CopilotKit" license badge via a
  new --copilotkit-license-banner-offset CSS var published by the
  banner on mount; chat input consumes it only when bottom-anchored.
- Sort and display threads by lastRunAt (fallback to updatedAt →
  createdAt) so metadata-only actions like archive/rename don't
  reshuffle the list.
- useThreads waits for runtimeConnectionStatus === Connected before
  dispatching the store context, eliminating the speculative /threads
  fetch that fired before /info returned wsUrl.

Threads example polish: restore button + tooltips on
archive/restore/delete, segmented Active/All filter, graceful error
state, skeleton rows on initial load, stable scrollbar gutter,
pre-paint dark-mode class, logo position stable across app/chat
modes, drop dynamic-import drawer wrapper that caused null first
paint, archived-row dimming via child colors instead of opacity.

Tests:
- CopilotChat.absentThreadConnect: connect is skipped without a
  threadId, fires when supplied via prop or config.
- CopilotChatView.connectingGate: isConnecting suppresses welcome;
  hasExplicitThreadId suppresses welcome on empty chat.
- threads (core): lastRunAt sort fallback ordering.
- use-threads: Connecting-state gate defers /threads until Connected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 09:42:34 -05:00
Alem Tuzlak b28d15339c feat(react-core): add pin-to-send scroll mode to CopilotChat v2 (#4142)
## What does this PR do?

Adds a new `"pin-to-send"` value to `CopilotChatView`'s `autoScroll`
prop, matching ChatGPT's scroll behavior: when the user sends a message,
that message scrolls to the top of the viewport and stays there while
the assistant's response streams in below. The user reads at their own
pace — the viewport does not chase the bottom.

### New public API

```ts
autoScroll?: "pin-to-bottom" | "pin-to-send" | "none" | boolean
```

- `"pin-to-bottom"` — current behavior. Chases the bottom as content
streams (still the default).
- `"pin-to-send"` — **new.** Scrolls the latest user message to ~16px
from the top, maintains a dynamic bottom spacer so the message can
actually reach the top, and does not chase the bottom.
- `"none"` — no auto-scroll.
- Boolean back-compat: `true` → `"pin-to-bottom"`, `false` → `"none"`.
Existing consumers unchanged.

`AutoScrollMode` type is exported from the package barrel.

### Example usage

```tsx
<CopilotChat autoScroll="pin-to-send" />
```

### How it works

1. `CopilotChat` computes the latest user message ID from `messages` and
publishes `{ id, sendNonce }` via a new `LastUserMessageContext`. The
nonce increments on each new send so message edits also retrigger.
2. A new `usePinToSend` hook reads the context and, on each new send:
measures viewport + user message heights, sets a spacer `<div>`'s
height, then does a single smooth `scrollTo` to the user message's
offset.
3. A shrink-only `ResizeObserver` on content collapses the spacer as the
assistant's response fills space below, so there's no wasted empty
space.
4. `ScrollView` branches on the normalized mode: existing
`<StickToBottom>` path for `"pin-to-bottom"`, existing plain-div path
for `"none"`, new `PinToSendScrollContainer` for `"pin-to-send"`.

### Edge cases handled

- Thread restore with existing messages doesn't trigger a spurious
scroll.
- `scrollTo` target computed via `getBoundingClientRect` arithmetic —
robust across any CSS positioning.
- Virtualization: the spacer lives outside the virtualized list.
- Back-compat: `autoScroll={true|false}` produces byte-for-byte
identical DOM to pre-change.

### Tests

- 7 unit tests for `normalizeAutoScroll`.
- 4 TDD behavior tests for `usePinToSend` (spacer sizing, scroll target,
shrink-only ResizeObserver, cleanup).
- 5 integration tests for `CopilotChatView` covering all three modes +
boolean back-compat.
- Full `@copilotkit/react-core` suite: **85 files / 1120 tests pass,
zero regressions.**
- publint + attw green across all 13 packages.
- Existing `CopilotChatView.slots.e2e.test.tsx` (43 tests) unchanged.

## Related PRs and Issues

- (none — new feature)

## Checklist

- [x] I have read the Contribution Guide
- [ ] Docs site update to follow in a separate PR

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-22 10:54:35 +02:00
Tyler Slaton a66f068e57 feat(react-core): add pin-to-send scroll mode to CopilotChat v2
Widens CopilotChatView's autoScroll prop to accept "pin-to-bottom" |
"pin-to-send" | "none" | boolean. "pin-to-send" scrolls the latest
user message to ~16px from the top on send and maintains a dynamic
bottom spacer so the viewport doesn't chase the streaming response.

Boolean back-compat: true -> "pin-to-bottom", false -> "none".
2026-04-21 17:41:55 -07:00
Mike Ryan 25f6f15418 refactor(runtime): Support durable compaction of threads 2026-04-21 16:25:11 -07:00
Maxim 073c0edefd fix: resolve merge conflict with main (pnpm-lock.yaml) 2026-04-17 16:36:21 +02:00
Maxim bd2ccbd0fa refactor(core): extract logAndEmitError helper to deduplicate error handling
Consolidate the repeated console.error + emitError + .catch pattern
into a single private logAndEmitError method on CopilotKitCore. All 4
call sites (setDefaultThrottleMs, subscribeToAgentWithOptions validation,
safeCall reportError, unsupported-keys warning) now go through the helper.
2026-04-17 16:33:09 +02:00
AlemTuzlak 9d00b01ccd chore: release monorepo v1.56.2 2026-04-16 16:04:38 +00:00
AlemTuzlak a6e8a48189 chore: release monorepo v1.56.1 2026-04-16 15:38:24 +00:00
Alem Tuzlak b8ff382fe3 fix: wrap Button with forwardRef for Radix DropdownMenuTrigger (#3830)
## Summary

- `Button` component wrapped with `React.forwardRef` to fix ref warning
from Radix UI's `DropdownMenuTrigger asChild` pattern

Closes #2947

## Test plan

- [x] All affected packages build successfully

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-16 12:23:35 +02:00
Alem Tuzlak c3e5582d11 fix: add IME composition guard in CopilotChatInput (#3835)
## Summary
- Skips keydown handling during IME composition (e.g. CJK input) by
checking `isComposing`/`keyCode 229`
- Guards textarea measurement from resetting value mid-composition,
which would break the composition session

Closes #3318
2026-04-16 12:22:12 +02:00
Alem Tuzlak 5add12346b fix: call onChange("") after send in controlled input mode (#3836)
## Summary
- Always calls `onChange("")` after send in controlled mode so the
parent component is notified to clear its state
- Previously `onChange` was only called inside the `!isControlled`
branch, leaving controlled parents unaware the input was submitted

Closes #3593
2026-04-16 12:20:51 +02:00
Alem Tuzlak f624ee1fb7 fix: pass AssistantMessage to onThumbsUp/Down callbacks (#3457) (#3796)
## Summary
- onThumbsUp/onThumbsDown/onReadAloud/onRegenerate callbacks on
CopilotChatAssistantMessage were receiving the browser SyntheticEvent
instead of the AssistantMessage object
- Wrapped the onClick handlers to pass the message explicitly:
`onClick={() => onThumbsUp(message)}`
- Same fix applied to onReadAloud and onRegenerate for consistency

## Test plan
- [x] Red-green verified: test confirms callback arg has `id`, `role`,
`content` and NOT `nativeEvent`/`target`
- [x] Full react-core test suite passes (1071 tests)
- [x] Build passes

Closes #3457
2026-04-16 12:07:26 +02:00
Alem Tuzlak c38d0db229 fix: return null instead of throwing in useRenderCustomMessages (#3497) (#3797)
## Summary
- useRenderCustomMessages threw "Agent not found" when the agent was
undefined during the connecting state
- Changed the throw to return null, allowing the component to render
gracefully while the agent is being resolved

## Test plan
- [x] Red-green verified: test calls hook with nonexistent agent,
asserts returns null not throws
- [x] Full react-core test suite passes (1071 tests)
- [x] Build passes

Closes #3497
2026-04-16 12:03:39 +02:00
Alem Tuzlak 3bda9d28bc fix: guard CopilotListeners against empty agents map (#3249) (#3798)
## Summary
- CopilotListeners called useAgent() unconditionally, which throws when
no agents are registered and no runtimeUrl is configured
- Split into CopilotListeners (outer, handles error subscription) and
CopilotListenersAgentSubscription (inner, uses useAgent)
- Inner component only renders when agents exist or a runtime is
configured

## Test plan
- [x] Red-green verified: render CopilotListeners with no agents, assert
no throw
- [x] Full react-core test suite passes (1071 tests)
- [x] Build passes

Closes #3249
2026-04-16 12:02:54 +02:00
Alem Tuzlak 9641933e13 fix: pass toolCallId to useRenderTool render components (#3843)
Closes #3741

Add `toolCallId` prop to all three status branches (InProgress,
Executing, Complete) of the ToolCallRenderer, and update the
`ReactToolCallRenderer` type to include it in the discriminated union.

Split from #3838.
2026-04-16 11:42:45 +02:00
Maxim bb6f02c62a fix(core,react-core): handle onRunErrorEvent in useAgent and document in subscribeToAgentWithOptions
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>
2026-04-16 00:08:25 +02:00
Maxim 96f230c7cc fix: resolve rebase conflicts — active flag, onRunErrorEvent, async tests
- 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>
2026-04-15 23:15:45 +02:00
Maxim 18a9ad6e58 fix: rename subscribeToAgent to subscribeToAgentWithOptions on CopilotKitCore
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:09:16 +02:00
Maxim 7b94afd862 fix: address code review findings for subscribeToAgent
- 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>
2026-04-15 22:09:14 +02:00
Maxim 7fb4ddcd01 fix: improve type safety, error context, and JSDoc accuracy in subscribeToAgent
- 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>
2026-04-15 22:09:12 +02:00
Maxim b234f466e8 fix: address review findings for subscribeToAgent
- 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>
2026-04-15 22:09:11 +02:00
Maxim b6388b6c61 fix: guard all subscriber callbacks with safeCall and propagate return values
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>
2026-04-15 22:09:10 +02:00
Maxim f1fc008314 refactor: move throttle logic from useAgent hook to CopilotKitCore.subscribeToAgent
Moves the leading+trailing throttle algorithm from the React-specific
useAgent hook into a framework-agnostic subscribeToAgent method on
CopilotKitCore. This consolidates throttle cascade resolution
(throttleMs ?? defaultThrottleMs ?? 0), validation, and the throttle
algorithm into a single location.

Key changes:
- Add subscribeToAgent() to CopilotKitCore with shared throttle gate
  for onMessagesChanged and onStateChanged (run lifecycle events are
  never throttled)
- Fix setDefaultThrottleMs to log errors and preserve previous value
  on invalid input instead of silently erasing
- Simplify useAgent by removing ~60 lines of inline throttle logic
- Angular AgentStore now uses subscribeToAgent, getting throttle
  support via provider-level defaultThrottleMs for free
- Remove duplicate validation from CopilotKitProvider useEffect
- Add direct unit tests for CopilotKitCore.setDefaultThrottleMs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:09:08 +02:00
ranst91 cfb5921108 chore: release monorepo v1.56.0 2026-04-15 17:22:27 +00:00
Jordan Ritter f4887a763e test: add userToggledRef behavior tests for reasoning message
Two new test cases covering the core behavioral fix:
- User collapses during streaming → panel stays collapsed after stream ends
- User collapses then re-expands during streaming → panel stays open after stream ends
2026-04-15 13:10:45 +02:00
Jordan Ritter 921b02ab57 test: wrap fireEvent.click in act() for deterministic reasoning toggle test
Without act(), React 18 defers the state update through its scheduler,
which can race with waitFor polling on slow CI runners (Node 20.x/22.x).
Wrapping in act() forces synchronous flush.
2026-04-15 13:10:45 +02:00
Jordan Ritter adbd38b5e5 fix: respect user expand/collapse intent in reasoning message
The auto-collapse useEffect unconditionally called setIsOpen(false) when
streaming ended, overriding any manual expand/collapse the user had
performed.  Add a userToggledRef that tracks explicit clicks so the
effect only auto-collapses when the user hasn't interacted.
2026-04-15 13:10:44 +02:00
Jordan Ritter d45620c1e7 fix: propagate copyToClipboard success result to CopyButton UI state
The CopyButton in react-core was showing the "copied" checkmark based on
an independent clipboard availability check rather than the actual copy
result. This meant a failed copy (e.g. permission denied) would still
show the success indicator. Now the onClick handler returns the boolean
from copyToClipboard, and handleClick uses that to drive the UI state.
Also removes unsafe type casts of onClick to Promise<void>.
2026-04-15 13:10:43 +02:00
Jordan Ritter 2f4152c8ec fix: extract shared copyToClipboard utility to eliminate clipboard duplication
Address review feedback: extract the repeated clipboard availability check +
writeText + error handling pattern into a shared copyToClipboard() utility in
@copilotkit/shared. All 9 call sites across angular, react-core, and react-ui
now use the shared utility instead of duplicating the same code block.
2026-04-15 13:10:42 +02:00
Jordan Ritter 04739dd6ba fix: guard clipboard calls and only show copied state on success (#2114)
Add null checks for navigator.clipboard across all copy-to-clipboard
calls to prevent TypeError in non-localhost environments where the
Clipboard API is unavailable. The copied indicator now only appears
after a confirmed successful write, preventing false positive UX
feedback when the clipboard API is missing or the write fails.
2026-04-15 13:10:41 +02:00
Jordan Ritter d4c75ce15e fix: replace tautological test with real unit tests for error visibility
Extract getErrorSuppression as a pure testable function from the
routeError closure. Replace the mock-only test that only proved mock
wiring with 12 real assertions covering all visibility x isDev
combinations against the actual logic.
2026-04-15 13:10:41 +02:00
Jordan Ritter 2c3c6a973d fix: surface TOAST/BANNER errors even when showDevConsole=false (#2431)
The routeError function returned early for ALL errors when
showDevConsole was false, suppressing user-visible errors
(TOAST and BANNER visibility) in production.

Now only DEV_ONLY and SILENT errors are suppressed in production.
TOAST and BANNER errors are always surfaced to the chat UI.
2026-04-15 13:10:40 +02:00
Jordan Ritter aff9350f17 fix: pass toolCallId to useRenderTool render components (#3741) 2026-04-14 16:24:45 -07:00
Jordan Ritter d534ccc7a0 fix: call onChange("") after send in controlled input mode (#3593) 2026-04-14 16:24:28 -07:00
Jordan Ritter 39b4ea6ecc docs: clarify client-side debug prop behavior
Updated JSDoc and troubleshooting docs to accurately describe that
the client-side debug prop forwards config to the AG-UI transport
layer, not CopilotKit's own logging. Removed fabricated console.debug
output examples that don't exist.
2026-04-14 14:58:44 -07:00
Jordan Ritter 295a1e609e fix: sync debug prop changes at runtime in CopilotKitProvider
debug was only read at construction time. Added setDebug() to
CopilotKitCore and added it to the provider's prop-sync useEffect
so runtime changes to the debug prop take effect.
2026-04-14 14:58:33 -07:00
Jordan Ritter b63708490d fix: apply oxfmt formatting 2026-04-14 11:53:31 -07:00
Alem Tuzlak 7b9abc142c feat(react-core): add debug prop to CopilotKit provider, thread to AG-UI agent 2026-04-14 18:34:45 +02:00
Alem Tuzlak f55cd5f7e2 Merge remote-tracking branch 'origin/main' into worktree-nested-tinkering-quail
# Conflicts:
#	packages/runtime/src/v2/runtime/handlers/get-runtime-info.ts
2026-04-13 15:03:54 +02:00
Alem Tuzlak 4b279cee64 fix: address code review findings on capabilities
- Restore getCapabilities() return type to Promise<AgentCapabilities>
  with ?? {} fallback, honoring AbstractAgent base class contract
- Simplify type annotation in get-runtime-info.ts to explicit
  AgentCapabilities | undefined instead of complex Awaited<ReturnType<...>>
- Add console.warn logging to per-agent capabilities error catch block
- Fix useCapabilities JSDoc to accurately describe behavior during
  runtime handshake
- Add test for empty capabilities object {} (truthy, included in response)
- Update error isolation test to verify warning is logged
2026-04-13 14:49:50 +02:00
Ran Shemtov dcfd7da220 Merge branch 'main' into fix/issue-3499 2026-04-13 14:43:42 +02:00
github-actions[bot] a6fb46b555 style: auto-fix formatting 2026-04-13 09:23:53 +00:00
Alem Tuzlak ee926b8628 fix: address capabilities review feedback
- Add per-agent error isolation in /info handler so a single
  getCapabilities() failure doesn't 500 the whole endpoint
- Normalize getCapabilities() to return undefined (not {}) when no
  capabilities are set, matching the sync getter
- Replace instanceof ProxiedCopilotRuntimeAgent with duck-type check
  in useCapabilities hook for extensibility
- Add JSDoc warning about shallow-merge behavior on capabilities config
- Add useCapabilities hook tests (5 cases covering both branches)
- Add per-agent error isolation test for get-runtime-info
2026-04-13 11:22:22 +02:00
Alem Tuzlak 327d134ecd Merge remote-tracking branch 'origin/main' into worktree-nested-tinkering-quail
# Conflicts:
#	packages/angular/package.json
#	packages/core/package.json
#	packages/demo-agents/package.json
#	packages/react-core/package.json
#	packages/runtime/package.json
#	packages/shared/package.json
#	packages/sqlite-runner/package.json
#	packages/web-inspector/package.json
#	pnpm-lock.yaml
2026-04-13 11:12:25 +02:00
Jordan Ritter d1c3708050 fix: batch useAgent forceUpdate calls via microtask to prevent scroll jumping (#3499)
When useAgent subscribes to multiple update types (OnMessagesChanged,
OnStateChanged, OnRunStatusChanged), each event fires forceUpdate()
independently. During streaming this causes dozens of re-renders per
second, leading to brief content height fluctuations that trigger
scroll jumping in use-stick-to-bottom.

Coalesce OnStateChanged and OnRunStatusChanged notifications using
queueMicrotask so multiple synchronous events within the same tick
produce a single React re-render. OnMessagesChanged retains its
existing behavior (direct or throttled).
2026-04-12 16:19:55 -07:00
github-actions[bot] 45d4e36280 style: auto-fix formatting 2026-04-12 22:27:35 +00:00
Jordan Ritter f94367ffd7 fix: support dynamic headers function prop for auth token refresh (#2779) 2026-04-12 15:25:17 -07:00