Resolve the single conflict in packages/web-inspector/src/index.ts by keeping
both additions: this branch's CpkMemoryList memory-tab element and main's
ɵCpkThreadDetails back-compat alias (independent top-level declarations).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The inspector subscribed to AG-UI events only through onAgentsChanged, which
skips per-thread clones, leaving the event timeline empty during runs
(regression of #3872). Subscribe to the run instance reported by
onAgentRunStarted so its events are recorded.
Add an onAgentRunStarted subscriber event fired from RunHandler.runAgent and
connectAgent with the instance that actually runs. Per-thread clones (from
useAgent) are not in the agent registry, so onAgentsChanged never fires for
them and subscribers that only track registry agents can't observe their run.
Final naming decision. Renames the public component + element across the
board: React/Angular CopilotDrawer -> CopilotThreadsDrawer, the Lit element
copilotkit-drawer -> copilotkit-threads-drawer (tag, CopilotKitThreadsDrawer
class, COPILOTKIT_THREADS_DRAWER_TAG, defineCopilotKitThreadsDrawer), the
@copilotkit/web-components/drawer subpath -> /threads-drawer (+ src dir),
the CopilotThreadsDrawerRow directive / copilotThreadsDrawerRow input, and
all prose/test references. Generic types (DrawerThread, DrawerFilter),
--cpk-drawer-* tokens, and ::part names are unchanged. Behavior unchanged.
Three snapshot tests (lines 751/771/789) call test() while the file uses
explicit vitest named imports. They pass at runtime via vitest's global
but fail tsc check-types (TS2593). Add test to the import.
Memory, NewMemory, MemoryChanges, MemoryKind, and MemoryScope are the
memory types surfaced by the useMemories / injectMemories hook result
shapes, so export them unprefixed as supported public API instead of
behind the ɵ "internal" marker. Internal memory plumbing (MemoryStore,
the selectMemories* selectors, state/context/event types,
createMemoryStore) keeps the ɵ prefix.
Updates the react-core and angular hook signatures, the web-inspector
Memories tab, and the affected tests to the unprefixed names.
Add three flat test cases verifying the silent-degrade contract:
404/501 list response sets available:false with no error; 500 response
sets error and keeps available:true; 404 subscribe response is silent
with no console.warn emitted.
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.
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>
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.
ɵ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.
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.
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.
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.
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.
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).
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.
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.
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.