summaryrefslogtreecommitdiffhomepage
path: root/src/features/chat/store.svelte.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-08-20 19:36:12 +0900
committerAdam Malczewski <[email protected]>2026-08-20 19:36:12 +0900
commitfb7eb3105e1fbbdefdad9348f9132815b5bbe52d (patch)
treedeb95e97a917424ea67470b168b91349a41d1c08 /src/features/chat/store.svelte.ts
parent63588c3c69b32d180dc78a2cc187cc8aa22ad7e0 (diff)
downloaddispatch-web-fb7eb3105e1fbbdefdad9348f9132815b5bbe52d.tar.gz
dispatch-web-fb7eb3105e1fbbdefdad9348f9132815b5bbe52d.zip
feat(named-agents): sidebar view, synthetic provider, auto-save, snapshot semantics
Implement the frontend of the Named Agents feature (plan §5-§9): - New features/named-agents module: pure logic (types re-exported from @dispatch/wire + transport-contract, validation, provider/model options, snapshot helpers, network normalizers, auto-save status model) + an injected auto-save controller (name debounce, immediate provider/model save, monotonic stale-response guard) + the collapsible sidebar card view. - Store: /named-agents CRUD + boot seed; selectModel(model, snapshot?) persists the raw model WITH the namedAgent snapshot; draft promotion carries it; refreshModel restores ModelResponse.namedAgent. - Chat store setNamedAgent (sends namedAgent on chat.send); Tab.snapshot + setSnapshot (retained across rename/remove, persisted with tabs). - Model selector: synthetic Named Agents provider ALWAYS first; selecting one resolves to the raw model + records a snapshot; a retained snapshot of a renamed/removed agent still displays as unavailable (plan §7). - Composition root wires the view (viewKinds + loaded-modules manifest) + feeds the selector. Tests: logic + controller + selector + app-store CRUD (1246 pass), typecheck 0, biome clean (only pre-existing config infos pending a future migrate), build OK.
Diffstat (limited to 'src/features/chat/store.svelte.ts')
-rw-r--r--src/features/chat/store.svelte.ts16
1 files changed, 16 insertions, 0 deletions
diff --git a/src/features/chat/store.svelte.ts b/src/features/chat/store.svelte.ts
index 24a1d06..c83c5fd 100644
--- a/src/features/chat/store.svelte.ts
+++ b/src/features/chat/store.svelte.ts
@@ -34,6 +34,7 @@ import {
selectOrderedTurnMetrics,
} from "../../core/metrics";
import type { ConversationCache } from "../conversation-cache";
+import type { NamedAgentSelectionSnapshot } from "../named-agents";
import type { ChatTransport, HistorySync, MetricsSync } from "./ports";
export interface ChatStoreDependencies {
@@ -145,6 +146,15 @@ export interface ChatStore {
cancelQueuedMessage(messageId: string): void;
setModel(model: string): void;
/**
+ * Set (or clear, with null) the Named Agent selection snapshot this chat sends
+ * with `chat.send` (plan §7). The backend persists it on the conversation at
+ * creation so it freezes the friendly id/name + resolved model — later edits to
+ * the Named Agent do not change this conversation's selection. The raw model
+ * (already set via `setModel`) is sent alongside; the snapshot is display/identity
+ * metadata that preserves HOW it was selected.
+ */
+ setNamedAgent(snapshot: NamedAgentSelectionSnapshot | null): void;
+ /**
* Update the chat limit LIVE: re-normalizes, then adjusts the loaded window.
* Lowering it unloads older committed chunks (deferred via the gate while the
* reader is scrolled up, catching up on the next mutation). Raising it
@@ -180,6 +190,7 @@ export function createChatStore(deps: ChatStoreDependencies): ChatStore {
let _pendingSync = $state(false);
let _error = $state<string | null>(null);
let _model = $state<string | undefined>(deps.model);
+ let _namedAgent = $state<NamedAgentSelectionSnapshot | null>(null);
let disposed = false;
let chatLimit = normalizeChatLimit(deps.chatLimit);
@@ -342,6 +353,7 @@ export function createChatStore(deps: ChatStoreDependencies): ChatStore {
conversationId: deps.conversationId,
message: text,
...(_model !== undefined ? { model: _model } : {}),
+ ...(_namedAgent !== null ? { namedAgent: _namedAgent } : {}),
...(deps.workspaceId !== undefined ? { workspaceId: deps.workspaceId } : {}),
...(images !== undefined && images.length > 0 ? { images: [...images] } : {}),
};
@@ -379,6 +391,10 @@ export function createChatStore(deps: ChatStoreDependencies): ChatStore {
_model = model;
},
+ setNamedAgent(snapshot: NamedAgentSelectionSnapshot | null): void {
+ _namedAgent = snapshot;
+ },
+
async setChatLimit(limit: number): Promise<void> {
const prev = chatLimit;
chatLimit = normalizeChatLimit(limit);