You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@tanstack/ai already defines a shared identity type for subsystems that persist or recall per-conversation data:
// packages/ai/src/scope.ts (#980)interfaceScope{threadId: string// required — same as ChatMiddlewareContext.threadIduserId?: stringtenantId?: stringnamespace?: string// reserved}
#980 explicitly says persistence and memory should share one vocabulary and that subsystems must not invent a second name (sessionId, conversationId, …) for the conversation key.
#541 (memory middleware) landed after#980 but did not adopt it. Memory still ships:
Redis (and any) key encoding: treat threadId as the conversation segment; keep escaping so : in ids cannot collide.
Docs / skills
docs/memory/* and packages/ai-memory/skills/*: replace sessionId examples with threadId / Scope.
Cross-link persistence + memory to the same identity section (server-derived userId/tenantId, never trust client alone).
Compat (if needed for any pre-release consumers)
Short deprecation window: accept { sessionId } at the edge and map to { threadId: sessionId } with a console warning, then remove.
Or hard cut if memory is still 0.x / unreleased enough that a break is fine — call that out in the PR.
Tests
Contract suite + provider tests: assert isolation by threadId (+ userId / tenantId where relevant).
E2E / panel memory routes: use threadId consistently with chat.
Non-goals
Changing the recall / save adapter verbs.
Forcing persistence store methods to take a full Scope object in the same PR (can stay bare threadId + host-side auth; still document Scope as the identity model).
Acceptance criteria
No public sessionId on memory’s isolation type (or only via deprecated alias).
Memory adapters and middleware use Scope / threadId from @tanstack/ai.
Docs and skills no longer teach MemoryScope.sessionId as the primary key.
Unit + contract tests green; memory e2e/panel paths updated if they hard-code sessionId.
Summary
@tanstack/aialready defines a shared identity type for subsystems that persist or recall per-conversation data:#980explicitly says persistence and memory should share one vocabulary and that subsystems must not invent a second name (sessionId,conversationId, …) for the conversation key.#541(memory middleware) landed after#980but did not adopt it. Memory still ships:Docs bridge at the app boundary (
sessionId: session.threadId) instead of usingScopedirectly.Why this matters
threadId(chat / persistence) vssessionId(memory) increases wiring friction and docs drift.ScopehastenantId/namespace;MemoryScopedoes not.Scope.threadId+ server-deriveduserId/tenantId.Proposed work
Adopt
Scopeas the memory isolation typeexport type MemoryScope = Scope(or dropMemoryScopeand useScopeeverywhere), imported from@tanstack/ai.threadId, notsessionId.Migrate call sites
scopeoption: static or(ctx) => Scope.in-memory,redis,mem0,honcho,hindsight, …): key/store paths usescope.threadId.threadIdas the conversation segment; keep escaping so:in ids cannot collide.Docs / skills
docs/memory/*andpackages/ai-memory/skills/*: replacesessionIdexamples withthreadId/Scope.userId/tenantId, never trust client alone).Compat (if needed for any pre-release consumers)
{ sessionId }at the edge and map to{ threadId: sessionId }with a console warning, then remove.0.x/ unreleased enough that a break is fine — call that out in the PR.Tests
threadId(+userId/tenantIdwhere relevant).threadIdconsistently with chat.Non-goals
recall/saveadapter verbs.Scopeobject in the same PR (can stay barethreadId+ host-side auth; still documentScopeas the identity model).Acceptance criteria
sessionIdon memory’s isolation type (or only via deprecated alias).Scope/threadIdfrom@tanstack/ai.MemoryScope.sessionIdas the primary key.sessionId.References
feat(ai): add shared Scope identity type (precursor for persistence + memory)MemoryScope)threadId; multi-user via host auth /reconstructChat({ authorize }))