The shared visitedRefs Set was mutated in place, so when two sibling
properties referenced the same $def (e.g. billing and shipping both
referencing Address), the second resolution was incorrectly flagged as
circular. Clone the set before recursing so each branch has its own
ancestry path. Added regression test that fails without this fix.
OpenAI SDK v5 removed beta.chat (promoted to chat.completions) and
changed multi-path-param methods to use named params (e.g.
runs.retrieve(runId, { thread_id }) instead of positional args).
- Add isOpenAIV5() detection and getChatCompletionsForStreaming() helper
- Migrate OpenAIAdapter to use helper for streaming completions
- Migrate OpenAIAssistantAdapter runs.retrieve() and
submitToolOutputsStream() to branch on SDK version
- Add openai ^4.85.1 || ^5.0.0 to peerDependencies
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.
Recursive JSON schemas that reference themselves via $ref would cause
infinite recursion and stack overflow. This adds a visited set that
tracks which $ref paths have been seen during resolution. When a cycle
is detected, it breaks with z.any() and logs a console.warn so users
get feedback. Also adds console.warn for the generic z.any() fallback
on unsupported schema types.
Adds tests for circular refs, non-circular $ref resolution, anyOf with
$ref variants, integer type, null type, and unsupported type warning.
The original Math.random() key caused React to remount the CodeBlock on
every render. The PR's content-based key (language + content prefix) still
changed every streaming token, causing the same flickering. Removing the
key entirely lets React use positional identity, which is stable across
re-renders while content streams in.
Closes#2669
The V1 CopilotRuntime constructor did `{...endpointAgents, ...agents}`
which silently spread a factory function to `{}`, losing all agents.
Anyone using the V1 API with a factory function got zero agents and no
error. This wraps factory functions so endpoint agents are merged at
resolution time instead of construction time.
The p tag was changed to div to fix hydration errors, but CSS selectors
still targeted p.copilotKitMarkdownElement. Updated to use the
.copilotKitParagraph class selector so paragraph styling (line-height,
font-size, margin) applies correctly to the new div element.
- 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
- 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
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).
Add AgentsFactory type that accepts a function receiving request context,
enabling multi-tenant and request-scoped agent configuration. The agents
option now accepts a static record, a Promise, or a factory function.
When mode is null (unknown tool skipped), content_block_delta events
with input_json_delta would still call sendActionExecutionArgs using
the previous valid tool call ID, corrupting its arguments.
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.
The Markdown component accepted components but not urlTransform,
preventing users from customizing URL sanitization. Added urlTransform
as an optional prop with passthrough to MemoizedReactMarkdown.
Parse Retry-After as seconds or HTTP-date and use it as the retry delay
instead of exponential backoff. Throw if the server requests a wait
longer than maxRetryAfterSeconds (60s default) to avoid hanging.
When getLanguageModel() returns null and provider/model are undefined
(as with LangChainAdapter), the code constructed "undefined/undefined"
as a model string, causing a cryptic "Unknown provider" error.
Now checks each source of model info explicitly and throws a clear
error message directing users to provide an explicit agents config
when using adapters that don't expose model metadata.
applyCredentialsToAgents/applyCredentialsToAgent were defined but never
called from initialize(), setAgents__unsafe_dev_only(), or
addAgent__unsafe_dev_only(). Only remote agents received credentials
via constructor. Local agents now receive credentials alongside headers.
Skip keydown handling during IME composition (e.g. CJK input) by
checking isComposing/keyCode 229, and guard textarea measurement
from resetting value mid-composition.
The loading spinner only appeared when the last message had role "user".
During tool execution the last message can have role "tool", hiding the
indicator. Now also show it when the trailing message is a tool result.
langchain-mcp-adapters sends tool call result content as an array of
{type:"text", text:string} objects. Extract and join text parts so
downstream consumers always receive a plain string.
Radix UI's asChild pattern requires the child component to forward
refs. The Button component was a plain function, causing a React
warning when nested inside DropdownMenuTrigger. Converted to
React.forwardRef so the ref is properly passed through to the
underlying DOM element.
GoogleGenerativeAI returns "0" as lc_kwargs.id for every message,
which is truthy and bypassed the randomId() fallback. All streamed
messages then shared the same ID, breaking message deduplication.
Now we always use randomId() for new message streams.
checkForUpdates() fired unconditionally on mount, making a network
request even when the dev console was disabled. Now the useEffect
short-circuits when showDevConsole is false.
JSON schemas from tools like Zod can produce union types like
["string", "null"]. The switch statement only handles single type
strings, causing these to fall through silently. Now we detect
Array.isArray(schema.type), filter out "null", and recurse with
the resolved scalar type.
The onAfterRequest middleware callback was being called with an empty
object `{}` instead of the available hook parameters (threadId, runId,
messages, path). Extract and forward these from the hookParams that the
v2 runtime provides.
Providers like @ai-sdk/openai-compatible emit sequential IDs (txt-0,
reasoning-0, msg-0) that collide across requests. The existing check
only caught the literal "0". Expand the check to match the
^(txt|reasoning|msg)-0$ pattern and always use randomUUID() for these.
When @hono/node-server polyfills the Request class, instanceof fails
because the polyfilled object has a different prototype chain.
Replace `reqOrRequest instanceof Request` with a duck-type check
that verifies url, method, and headers properties exist, which
works with both native and polyfilled Request objects.