Four rounds of structural rework on the conversation surface, converging on one registration model for the whole client: - Review fixes: open() leaves the inject factory (SessionsService owns the semantic); ConversationService mounts via ctx.plugin(); the bespoke view registry retires into the 'conversation.view' list slot. - Ring alignment: createChatView factory retired (components get everything through checkable shares at the register call site); the hand-rolled t/i18n threading is deleted wholesale — a future framework-level i18n will supply t as a standard prop keyed by slot name, so no interim manual channel. - Toolview dissolution: ToolViewRegistry / ToolViewResolver / ToolViewOutlet / ctx.toolviews retire. Tool rows are entries of the 'conversation.chat.toolview' keyed slot (scope: session) declared by the chat entry; ToolRowOwnerProps is the unified owner payload; GenericToolCard becomes the call-site fallback; registrants are plain plugins (inject ['slots','conversation'] as the load-order seam); session-dimension dispatch moves into components (useSessions reads parentId); trajectory/waterfall gain same-shape slots the day they render tool rows (RendersCheck rejects empty declarations). Slot names mirror the composition path (<domain>.<entry>.<hole>). - Staging follows current: cell()/binding() are pure resolution (render-safe); the constructor subscribes to the list store and followCurrent opens the event window when the current session changes — staging IS the open signal, business verbs are the timing, React render/commit is decoupled from window lifecycle. A masked current (projection gap) keeps the stage untouched so deferred teardown semantics survive reconnects. Agent Note: .agents/notes/implemented/architecture/ 2026-07-23-toolview-dissolution.md (bilingual pair) records the decision, the four rejected alternatives, and the accepted semantic changes; the web client architecture note and packages/client/AGENTS.md carry the current-state narrative. Verified: typecheck 0, duplication 0 clones (478 files), full coverage run 6190 passed with zero threshold errors, knip 0, doc-sync 24/24, client aggregate tsc 0, render-count checks (one commit per chunk, zero row re-renders under streaming) green.
40 lines
1.8 KiB
TypeScript
40 lines
1.8 KiB
TypeScript
/**
|
|
* Shared conversation contract primitives: the view tab projection (slot
|
|
* entries in 'conversation.view' surface as tabs), the chat store state
|
|
* shared through the declared store, and the selection primitives every
|
|
* domain consumes. Shared face between the skeleton domain (tab strip +
|
|
* view outlet) and the chat domain; domain implementation files import this,
|
|
* never each other. The view ring itself IS the 'conversation.view' slot
|
|
* (contract in slots.ts) — the package-local view registry is retired, and
|
|
* so is the hand-threaded translate channel (framework-level per-slot i18n
|
|
* injection is the planned replacement).
|
|
*/
|
|
|
|
/** Tool call identity as carried on the wire (branded upstream in connection). */
|
|
export type CallId = string
|
|
|
|
/** Selection target for the details linkage channel (toolcall is the step special case). */
|
|
export interface SelectionTarget { turnSeq: number; stepSeq?: number; callId?: CallId; toolName?: string }
|
|
|
|
/**
|
|
* One conversation view tab, projected from a 'conversation.view' slot
|
|
* entry's registration options (label falls back to the entry id).
|
|
*/
|
|
export interface ViewTab { id: string; label: string }
|
|
|
|
/**
|
|
* Chat store state (slot terminal design §4): the per-session store shared by
|
|
* the conversation, chat-view, and details registrations. `createChatStore`
|
|
* implements this shape. `view` may carry a stale persisted id after a view
|
|
* plugin unloads — the slot ledger is the runtime validator (unknown ids fall
|
|
* back to the first registered view).
|
|
*/
|
|
export interface ChatStoreState {
|
|
/** Details-linkage channel (conversation writes, details reads). */
|
|
selection: SelectionTarget | null
|
|
/** Composer draft (persisted; survives session switches and reloads). */
|
|
draft: string
|
|
/** Active conversation view id ('conversation.view' entry id); null falls back to the first view. */
|
|
view: string | null
|
|
}
|