393 Commits

Author SHA1 Message Date
Markus Ecker 8656aae530 feat(core): add listUnavailable/credentialsUnavailable actions and available state
Adds listUnavailable and credentialsUnavailable to memoryRestEvents, adds
available: boolean to MemoryState (defaulting to true), resets available to
true on contextChanged and listRequested, and handles listUnavailable by
clearing memories and setting available: false with a session guard.
2026-06-29 15:11:54 +02:00
Markus Ecker bb117b1ef7 Merge remote-tracking branch 'origin/main' into mme/memory-core
# Conflicts:
#	packages/core/src/index.ts
2026-06-29 13:37:52 +02:00
Markus Ecker 99b221d9e5 fix(core): memory socket never joined its channel (no realtime deltas)
The memory store's socket effect created the `user_meta:memories:<code>`
channel and observed its events, but never subscribed the join-outcome
stream — and `ɵphoenixChannel$` only calls `channel.join()` when that stream
is subscribed. So the socket connected but no `phx_join` was ever sent: the
gateway saw the connection, the channel was never joined, and saved memories
never pushed to the client (REST snapshot worked; live deltas silently never
arrived). The thread store joins because its merged `joinOutcome$` subscribes
the stream.

Merge `ɵjoinPhoenixChannel$(channel$)` into the socket effect's output so the
join actually fires; swallow a failed/timed-out join so a transient rejection
doesn't tear down the metadata stream (Phoenix re-attempts on reconnect). Add
a `joinCount` spy to MockChannel and assert the realtime test actually joins —
this regression passed before because the mock delivered events without a join.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 23:38:33 +02:00
Austin Merrick ca920066ac build(core): raise build heap ceiling to 8GB via cross-env
The @copilotkit/core build (tsdown with dts generation) has a working set
of about 3.45GB. Node's default old-space ceiling is roughly 4GB and CI pins
NODE_OPTIONS to 4096, leaving almost no headroom. Under nx run-many the build
competes for CPU with sibling builds, GC falls behind, and the process tips
over the heap limit. nx flags it as a flaky task and pre-commit/CI builds fail
intermittently with a V8 heap OOM.

Bake the ceiling into the core build script with cross-env so every invocation
path gets consistent headroom: local lefthook hooks, nx run-many, CI, and
direct pnpm build, on every platform including Windows. 8192 matches the value
already used by the e2e workflow and gives roughly 2x headroom over the working
set.

Scoped to core only; it is the single package that OOMs.
2026-06-25 14:01:39 -07:00
Markus Ecker 4211bd58d8 chore: format memory SDK files with oxfmt 2026-06-25 19:49:34 +02:00
Markus Ecker ca8e2fa064 refactor(core): drop thread-store user_meta sharing; memory owns its socket 2026-06-25 18:02:43 +02:00
Markus Ecker 250028469d feat(core): memory store opens its own user_meta:memories socket 2026-06-25 17:58:57 +02:00
Markus Ecker 3e04352d94 feat(core): memory store fetches its own subscribe credentials 2026-06-25 17:54:04 +02:00
Markus Ecker ce24806c1c feat(core): add wsUrl + credentials events to the memory store context 2026-06-25 17:47:48 +02:00
Benjamin Taylor fc1fa82c33 feat(core): thread store with optimistic mutations and realtime, plus threads feature
Add the thread store (optimistic add/rename/archive/delete with delete
rollback-on-reject, session-guarded results, startNewThread/refetchThreads,
getServerState/getServerSnapshot, per-store memoized selectors, and non-fatal
realtime diagnostics for channel-join and metadata-credential failures) and
register the "threads" feature so the SDK can gate thread management.
2026-06-25 10:42:46 -05:00
Markus Ecker 64078772a7 feat(core): export ɵNewMemory and ɵMemoryChanges mutation input types
ɵMemoryStore exposes addMemory(input: NewMemory) and
updateMemory(id, changes: MemoryChanges), but those input types were
internal — a thin framework binding (useMemories / injectMemories) had
no way to name them when wrapping the store. Export them alongside the
existing ɵMemory / ɵMemoryKind / ɵMemoryScope.
2026-06-25 15:40:57 +02:00
Markus Ecker b7db535f58 fix(core): reject refresh() on failed or interrupted re-pull; defer scope default to platform
refresh() now returns a promise that rejects when the re-pull fails
(listFailed) or the store is stopped mid-flight, instead of resolving
silently as if it succeeded — symmetric with the mutation methods. The
error still lands in the error selector for declarative consumers.

toMutationBody no longer defaults scope to "user"; it forwards scope only
when the caller supplies it, so the platform owns the single default.
2026-06-25 14:20:34 +02:00
Markus Ecker 85aa007eb6 feat(core): make memory store refresh() promise-returning
refresh() now resolves once the re-pulled snapshot settles (listSucceeded/
listFailed) for the current session, or immediately when no context is set —
so a useMemories-style binding can expose refresh(): Promise<void>. Mirrors
trackMutation's completion handling.
2026-06-25 13:08:05 +02:00
ranst91 bb69f55c98 chore: release monorepo v1.61.2 2026-06-25 07:54:33 +00:00
Tyler Slaton 947fe2142a fix(core): preserve agent-level headers instead of overwriting them (#5635) (#5637)
Fixes #5635.

## What

Headers set directly on an `HttpAgent` registered via
`agents__unsafe_dev_only` were silently replaced by the provider
headers. Per-agent auth headers (like an `Authorization` for a
self-hosted backend) got dropped, causing 401s.

## Why

`AgentRegistry.applyHeadersToAgent` did `agent.headers = {
...core.headers }`, a full overwrite. The run handler and the react-core
`useAgent` hook did the same. So an agent built with its own headers
lost them on registration, on every `setHeaders`, and before each
request.

## Fix

Merge instead of replace. The registry captures each agent's own headers
once (in a WeakMap, before the first apply) and rebuilds `{
...ownHeaders, ...coreHeaders }`. Core wins on key conflicts, which
keeps the existing "provider headers are authoritative" and logout/clear
behavior. All header application now routes through one method,
`CopilotKitCore.applyHeadersToAgent`, so runs never clobber per-agent
headers.

Vue and Angular benefit too: they dispatch runs through `core.runAgent`
/ `connectAgent`, so the merge is re-applied before every request.

## Tests

- core: 3 new cases in `core-headers.test.ts` (preserve, merge,
retain-across-setHeaders); existing overwrite and clear tests still
pass.
- react-core: new `use-agent-provider-headers.e2e.test.tsx` with a real
provider and an HttpAgent that has its own headers.

Verified locally: format, lint, full core + react-core suites, and both
builds.
2026-06-24 07:45:37 -07:00
Benjamin Taylor f90231f4fd feat(core,react-core): add unarchiveThread to thread store and useThreads
Restores an archived thread via the existing generic PATCH /threads/:id
update path with { archived: false } — the same mechanism example apps
already use for restore — so no new runtime route is required. Mirrors
archiveThread across the core thread store and the v2 useThreads hook.
2026-06-24 08:44:40 -05:00
Markus Ecker b0f2a6fbf3 feat(core): memory store registry on CopilotKitCore
Adds MemoryStoreRegistry (mirroring ThreadStoreRegistry) plus
register/unregister/get/getMemoryStores on CopilotKitCore and
onMemoryStoreRegistered/onMemoryStoreUnregistered subscriber hooks, so a
binding can register a per-agent memory store for sharing/lookup and react to
its lifecycle. Memory stores auto-unregister on agent removal, symmetric with
thread stores. Full core suite green (477 tests).
2026-06-24 13:10:11 +02:00
Markus Ecker be13e02d0c fix(core): memory REST path is runtime-relative /memories (not /api/memories)
runtimeUrl is the CopilotKit runtime mount (e.g. /api/copilotkit); the thread
store uses the relative suffix /threads, which the runtime maps to app-api's
/api/threads. Memory mirrors that with /memories -> /api/memories. /api/memories
would have wrongly produced /api/copilotkit/api/memories.
2026-06-24 13:04:40 +02:00
Markus Ecker 6d96bcdfff feat(core): export the memory store from the package barrel
Surfaces the ɵMemory* types, ɵcreateMemoryStore, selectors, and event groups
from @copilotkit/core, mirroring how ./threads is re-exported.
2026-06-24 12:50:32 +02:00
Markus Ecker dbcf64ee04 feat(core): memory store mutations (server-authoritative add/update/remove)
addMemory POSTs, updateMemory PATCHes (supersede — the id changes), removeMemory
DELETEs against /api/memories. The REST response is applied to local state on
resolve (server-authoritative) and the realtime event reconciles idempotently;
mutation promises resolve to the stored memory (add/update) or void (remove).
Adds isMutating state + mutationFinished tracking via a trackMutation helper
mirroring the thread store.
2026-06-24 12:48:54 +02:00
Markus Ecker 6aef784151 feat(core): memory store REST snapshot + context + selectors
setContext bumps a session and triggers GET /api/memories; the snapshot keeps
only user-scoped memories (v1 surfaces user scope only, matching the realtime
stream). Adds listRequested/listFailed + isLoading/error state, refresh(), and
ɵselectMemories/IsLoading/Error selectors, mirroring the thread store's
bootstrap+fetch effects. Note: REST path is /api/memories — reconcile with how
runtimeUrl is configured if it differs from the thread store's /threads base.
2026-06-24 12:43:34 +02:00
Markus Ecker 3426d8c702 feat(core): wire memory realtime — createMemoryStore consumes memory_metadata
Adds the memory_metadata event type + mapper (created/updated -> upsert,
invalidated -> remove, projecting to the public Memory shape) and a
createMemoryStore that reduces those deltas into observable state. The store
rides an injected user_meta event source (the thread store's
ɵobserveUserMetaEvent in production) — one socket, no lifecycle code on the
memory side. select() re-emits on every change, so React/Angular bindings
re-render when a memory arrives. REST snapshot + mutations land next.
2026-06-24 12:34:56 +02:00
Markus Ecker 4492cb1fdc feat(core): expose ɵobserveUserMetaEvent on the thread store
Lets sibling per-user stores (e.g. the upcoming memory store) ride the
single user_meta socket/channel the thread store already owns, instead of
opening a second socket. The socket effect publishes the live channel session
into a BehaviorSubject; observeUserMetaEvent memoizes a shared, per-event
stream over it (one channel.on(event) fanned out to all subscribers, cleared
on teardown). Phoenix stays fully encapsulated — callers get plain payloads.
Scoped to the user_meta channel only. Additive; socket/reconnect/teardown
flow unchanged.
2026-06-24 12:29:31 +02:00
Markus Ecker 8482743484 feat(core): add memory store reducer (snapshot + realtime upsert/invalidate)
First slice of the framework-agnostic MemoryStore, mirroring the thread
store's micro-redux patterns: session-guarded MemoryState, listSucceeded
snapshot population, and memoryUpserted/memoryInvalidated domain reducers
(prepend-new / replace-in-place / remove). Public kind vocabulary
(topical/episodic/operational). Reducer covered by unit tests.
2026-06-24 12:16:23 +02:00
Tyler Slaton a13c3ee663 chore: merge main into PR 5480 2026-06-23 20:50:16 -07:00
Tyler Slaton 75611b272c chore: merge main into PR 5480 2026-06-23 15:32:09 -07:00
Austin Merrick 4ba201b5c4 fix: repair check-types across all packages and gate it in CI
Repairs TypeScript check-types across the monorepo and adds a CI gate so
regressions are caught going forward:

- core: bundler module resolution and strict-mode fixes
- sdk-js: bundler module resolution; keep codegen, formatter, packaging working
- react-core: fixes across components, hooks, and tests
- react-native: restore catch binding referenced by TypeError cause
- runtime: repair check-types and bound AI SDK schema inference
- web-inspector: nodenext import extensions, export Anchor
- remaining packages and node example: assorted check-types repairs
- deps: add missing type-only devDependencies
- license context driven from /info licenseStatus
- ci: run check-types in the static quality workflow

Squashed from 12 commits for a single, easily-revertable change.
2026-06-23 15:26:47 -07:00
Austin Merrick 30bd6d8f0e test(core): pin remove/re-add baseline; doc + assertion polish
CR round 2 follow-ups (no behavior change):
- Add a core-headers regression test proving the agentOwnHeaders baseline
  stays pristine across remove + re-add (the WeakMap is intentionally not
  cleared on removal; clearing would re-capture polluted headers).
- Correct the stale `headers` config doc ("appended" -> merged on top of each
  HttpAgent's own headers, core wins).
- Tighten the e2e no-provider-headers assertion to toEqual.
2026-06-23 15:22:11 -07:00
tylerslaton 410d34001d chore: release monorepo v1.61.1 2026-06-23 21:00:28 +00:00
Austin Merrick 6bfb12267f docs(core): document header merge/clear contract; pin clear-baseline test
CR round 1 follow-ups (no behavior change):
- Document on setHeaders + applyHeadersToAgent that the merge baseline is the
  agent's construction-time headers, so setHeaders can override but cannot
  remove a per-agent header (the agent's own value re-surfaces on clear), and
  that dynamic updates go through setHeaders, not direct agent.headers mutation.
- Tighten the agentOwnHeaders field comment (captured on first apply, never
  re-captured) and the applyHeadersToAgent method doc.
- Add a core-headers test pinning the clear-reveals-baseline contract.
- Soften the two useAgent test-mock comments: they are an additive stand-in,
  not a faithful model of core's frozen baseline.
2026-06-23 11:43:21 -07:00
Mike Ryan db09796809 fix: gate thread endpoints by runtime capability 2026-06-23 11:32:30 -07:00
Alem Tuzlak 43fdba74aa feat: AG-UI standard interrupt support in useInterrupt + BuiltInAgent
Adds the AG-UI standard interrupt flow (RUN_FINISHED outcome:interrupt + resume array) alongside the legacy on_interrupt path.

- core: forward the standard resume array through runAgent.
- react-core / vue / react-native: useInterrupt handles standard interrupts with resolve()/cancel(), surfaces the primary + full interrupt set, and persists each resolved tool-backed interrupt as a tool-result message so multi-turn conversations stay well-formed (no dangling tool call -> no tool-call loop).
- runtime BuiltInAgent: native interrupts for the aisdk + tanstack factory paths via each SDK's needsApproval primitive (tool-approval-request / CUSTOM approval-requested -> outcome:interrupt); classic interrupt-tool emission + ctx.interrupt() factory primitive; idempotent resume injection mapped to each SDK's native tool-result; getCapabilities advertises humanInTheLoop.interrupts.
- docs: document standard interrupt support.

Verified across core/react-core/runtime unit suites and a real-model multi-turn run on both aisdk and tanstack.
2026-06-23 20:14:17 +02:00
Austin Merrick 59f96620bb fix(core): preserve agent-level headers instead of overwriting them (#5635)
HttpAgent headers configured directly on an agent registered via
agents__unsafe_dev_only were silently replaced by core headers, dropping
per-agent auth headers and causing 401s against self-hosted backends.

Core headers are now merged ON TOP of each agent's construction-time
headers (captured once in a WeakMap before the first apply), with the
core-level value winning on a key conflict. Header application is
centralized in CopilotKitCore.applyHeadersToAgent so the run handler and
the react-core useAgent hook share one merge path and never clobber
per-agent headers.
2026-06-23 10:33:32 -07:00
Jordan Ritter b9311f94b9 fix(core): preserve runtime agent instance across re-connection
`updateRuntimeConnection` unconditionally rebuilt the `remoteAgents` map
with a fresh `ProxiedCopilotRuntimeAgent` for every id on each connect,
discarding the already-registered live instance along with its
accumulated `messages`, `threadId`, and subscriptions. A re-connection
(an `/info` re-settle, or a header/config/transport change) therefore
swapped the live instance for an empty one. Downstream the `use-agent`
memo keys on the instance identity returned by `getAgent(id)`, so the
swap unmounted an already-rendered conversation — the source of the
showcase auth `dom-missing` flap.

Reuse the existing instance for ids still advertised by the runtime
(re-applying only registry-owned headers/credentials in place); mint a
new proxy only for genuinely-new ids; drop ids no longer present. The
disconnect/no-runtime and error paths still clear `remoteAgents`.
2026-06-22 23:16:35 -07:00
Austin Merrick 4c71ea1138 fix(core): allow clearing headers via setHeaders with null/undefined
setHeaders typed headers as Record<string, string>, so there was no
type-safe way to clear a header (e.g. Authorization on logout) — passing
an empty string left the header present with a blank value.

Widen the signature to Record<string, string | null | undefined> and drop
any entry whose value is null/undefined. setHeaders remains a full overwrite,
so clearing one header while keeping the rest is the spread pattern:
setHeaders({ ...copilotkit.headers, Authorization: null }). A shared
normalizeHeaders helper enforces the same string-only invariant at both
write paths (constructor and setHeaders).

Update the react-core AuthTokenSync skill example to show the logout/clear
path and warn that a header must not be managed via both the headers prop and
imperative setHeaders (the provider re-applies prop-derived headers as a full
overwrite when its inputs change). Also update the setHeaders reference
signature docs. Tests cover null/undefined stripping, empty-string
preservation, overwrite-not-merge semantics, single-header clear via spread,
subscriber notification, and propagation to local and remote
(ProxiedCopilotRuntimeAgent) agents.

Fixes #5535
2026-06-19 14:13:02 -07:00
Mike Ryan b094156537 chore: release monorepo v1.61.0 2026-06-18 15:00:19 -07:00
davidmckayv 692e52244c chore: release monorepo v1.60.2 2026-06-17 16:59:44 +00:00
SeoyeonKim 522402886f fix(core): preserve proxied runtime credentials 2026-06-13 11:00:52 +09:00
ranst91 02c3a8aef0 chore: release monorepo v1.60.1 2026-06-12 13:03:45 +00:00
Ran Shem Tov 7805a9a57b fix: update cpk to use latest agui core packages 2026-06-12 11:16:19 +02:00
MikeRyanDev a6e8000c94 chore: release monorepo v1.60.0 2026-06-11 16:27:00 +00:00
Mark Fogle 47c993ccbb fix(core): scope context entries per agent and preserve the a2ui agent list (#5369) 2026-06-11 05:06:15 +00:00
Ran Shem Tov e5d3963db6 fix(core): bump @ag-ui core packages to 0.0.56 and adapt runHttpRequest
Bump @ag-ui/core, @ag-ui/client, @ag-ui/encoder from 0.0.53 to 0.0.56
across all packages.

@ag-ui/client 0.0.56 changed runHttpRequest from (url, requestInit) to a
fetch-thunk signature (() => Promise<Response>). Update the single-route
and connect transport paths in ProxiedCopilotRuntimeAgent to wrap the
request in () => this.fetch(url, init), restoring the broken envelope
transports.

Add @ag-ui/core, client, encoder, proto to minimum-release-age-exclude
in .npmrc so the freshly published 0.0.56 (under the 24h release-age
gate) installs in CI.
2026-06-09 17:47:43 +02:00
contextablemark 9bfeb74bc9 chore: release monorepo v1.59.5 2026-06-05 05:21:08 +00:00
ranst91 47fcb30d0f chore: release monorepo v1.59.4 2026-06-04 17:26:49 +00:00
lukasmoschitz 5de391fa27 fix(core): make setRuntimeTransport idempotent on the requested transport mode (#5179)
## Summary

`setRuntimeTransport` was not idempotent on the **requested** transport
mode. Auto-detect resolves the requested `"auto"` to a concrete
transport (`"rest"`/`"single"`) and writes that back to
`_runtimeTransport`; the guard then compared against that **resolved**
value. So re-applying the same requested mode — which the provider
effect does on **every render** — compared unequal and **re-ran the
entire `/info` handshake**, rebuilding the runtime agents mid-session.

When that re-sync lands during a turn, `useAgent` hands the UI a
freshly-rebuilt (empty) agent for a render, **blanking the whole
transcript** (and any per-message UI bound to it — e.g. the intelligence
indicator) until it replays.

## Fix

Track the **requested** mode separately (`_requestedTransport`) and
guard on it. Re-applying an unchanged requested transport — including
`"auto"` after auto-detect has resolved it — is now a no-op, so no
redundant `/info` re-sync fires.

## Tests

`packages/core/src/__tests__/agent-registry-resync.test.ts`: re-applying
`"auto"` after auto-detect resolves it does **not** refetch `/info`.

## Scope / risk

Touches only `packages/core` (`core/agent-registry.ts` + the test). **No
public API change.** Genuine transport *changes* still re-sync exactly
as before; only redundant re-applications of the same requested mode are
skipped.

> **Verified live:** this idempotency guard *alone* eliminates the
mid-turn re-sync in the e-commerce intelligence demo — instrumentation
shows no `/info` handshake fires during a turn, and the
transcript/indicator no longer flickers. (An earlier draft also made the
re-sync itself non-destructive as defense-in-depth; that was dropped
because, with this guard, no mid-turn re-sync occurs for it to protect
against.)
2026-06-04 11:56:47 +02:00
Jordan Ritter 32551f2bdb fix(react-core): type the active-run completion contract and serialize the suggestion send path
Replace the brittle `"activeRunCompletionPromise" in agent` probe + double
`as unknown as` casts in CopilotChat with a typed `RunCompletionAware`
contract plus an `isRunCompletionAware` type guard, both exported from core.
IntelligenceAgent now declares the property and implements the interface, so
the in-flight-run await is reachable without a cast and non-Intelligence
agents still degrade safely. Cast sites in the attachments/e2e tests and the
MockStepwiseAgent helper are updated to the typed accessor.

Factor the await-then-send logic into a shared `waitForActiveRunToSettle`
helper and call it from BOTH onSubmitInput and handleSelectSuggestion. This
closes the suggestion-path in-flight gap: selecting a suggestion mid-run no
longer pre-empts/aborts the active run (e.g. an interrupt RESUME) — the same
regression PR #5195 fixed for the typed-Enter path. Adds a red-green
regression test that parks the suggestion send on the in-flight promise.
2026-06-03 19:47:38 -07:00
jpr5 be20a389cf chore: release monorepo v1.59.3 2026-06-03 14:53:22 -07:00
Lukas Moschitz 8a79dca3b4 fix(core): make setRuntimeTransport idempotent on the requested transport mode (RD-4)
Auto-detect resolves the requested transport ("auto") to a concrete value
("rest"/"single") and writes it back to _runtimeTransport. setRuntimeTransport
then compared against that resolved value, so re-applying the same requested
mode — which the provider effect does on every render — compared unequal and
re-ran the entire /info handshake, rebuilding the runtime agents mid-session
and blanking the transcript (and any per-message UI bound to it).

Track the requested mode separately (_requestedTransport) and guard on it, so
re-applying an unchanged requested transport is a no-op.

Adds coverage: re-applying "auto" after auto-detect resolves it does not
refetch /info.
2026-06-03 16:28:35 +02:00
ryker 45409d4650 fix(core): add circuit breaker to prevent infinite follow-up loops
processAgentResult recursed into runAgent whenever needsFollowUp was true,
with no depth limit. Any scenario that keeps needsFollowUp = true (LLM
repeatedly calling the same tool, backend RunError retries, reprocessed tool
messages) would loop forever, silently exhausting API quota and DOS'ing the
backend.

Add an absolute MAX_FOLLOW_UP_DEPTH cap (100) based on the existing _runDepth
counter. When the cap is reached, stop recursing, emit a logger.warn for
debuggability, and return normally. The cap is high enough not to affect
legitimate multi-step workflows.

Fixes #4819
2026-06-02 15:53:37 +08:00