diff --git a/packages/cli/src/api-types.ts b/packages/cli/src/api-types.ts
index f100bca1..13b48377 100644
--- a/packages/cli/src/api-types.ts
+++ b/packages/cli/src/api-types.ts
@@ -1,4 +1,5 @@
import type {
+ AgentModelSelection,
AgentModelSelections,
ConfigFile,
ModelPreference,
@@ -107,6 +108,7 @@ export type WorkspaceFileSearchResponse = FileSystemEntry[]
export interface InstanceData {
messageHistory: string[]
+ agentModelSelections: AgentModelSelection
}
export interface BinaryRecord {
diff --git a/packages/cli/src/config/schema.ts b/packages/cli/src/config/schema.ts
index 2ebda652..f9b641d6 100644
--- a/packages/cli/src/config/schema.ts
+++ b/packages/cli/src/config/schema.ts
@@ -13,7 +13,6 @@ const PreferencesSchema = z.object({
lastUsedBinary: z.string().optional(),
environmentVariables: z.record(z.string()).default({}),
modelRecents: z.array(ModelPreferenceSchema).default([]),
- agentModelSelections: AgentModelSelectionsSchema.default({}),
diffViewMode: z.enum(["split", "unified"]).default("split"),
toolOutputExpansion: z.enum(["expanded", "collapsed"]).default("expanded"),
diagnosticsExpansion: z.enum(["expanded", "collapsed"]).default("expanded"),
diff --git a/packages/cli/src/server/http-server.ts b/packages/cli/src/server/http-server.ts
index f4c04530..81e1b487 100644
--- a/packages/cli/src/server/http-server.ts
+++ b/packages/cli/src/server/http-server.ts
@@ -67,7 +67,11 @@ export function createHttpServer(deps: HttpServerDeps) {
registerFilesystemRoutes(app, { fileSystemBrowser: deps.fileSystemBrowser })
registerMetaRoutes(app, { serverMeta: deps.serverMeta })
registerEventRoutes(app, { eventBus: deps.eventBus, registerClient: registerSseClient })
- registerStorageRoutes(app, { instanceStore: deps.instanceStore, eventBus: deps.eventBus })
+ registerStorageRoutes(app, {
+ instanceStore: deps.instanceStore,
+ eventBus: deps.eventBus,
+ workspaceManager: deps.workspaceManager,
+ })
registerInstanceProxyRoutes(app, { workspaceManager: deps.workspaceManager, logger: proxyLogger })
diff --git a/packages/cli/src/server/routes/storage.ts b/packages/cli/src/server/routes/storage.ts
index e4211a34..a2a874ee 100644
--- a/packages/cli/src/server/routes/storage.ts
+++ b/packages/cli/src/server/routes/storage.ts
@@ -2,25 +2,36 @@ import { FastifyInstance } from "fastify"
import { z } from "zod"
import { InstanceStore } from "../../storage/instance-store"
import { EventBus } from "../../events/bus"
+import { ModelPreferenceSchema } from "../../config/schema"
import type { InstanceData } from "../../api-types"
+import { WorkspaceManager } from "../../workspaces/manager"
interface RouteDeps {
instanceStore: InstanceStore
eventBus: EventBus
+ workspaceManager: WorkspaceManager
}
const InstanceDataSchema = z.object({
messageHistory: z.array(z.string()).default([]),
+ agentModelSelections: z.record(z.string(), ModelPreferenceSchema).default({}),
})
const EMPTY_INSTANCE_DATA: InstanceData = {
messageHistory: [],
+ agentModelSelections: {},
}
export function registerStorageRoutes(app: FastifyInstance, deps: RouteDeps) {
+ const resolveStorageKey = (instanceId: string): string => {
+ const workspace = deps.workspaceManager.get(instanceId)
+ return workspace?.path ?? instanceId
+ }
+
app.get<{ Params: { id: string } }>("/api/storage/instances/:id", async (request, reply) => {
try {
- const data = await deps.instanceStore.read(request.params.id)
+ const storageId = resolveStorageKey(request.params.id)
+ const data = await deps.instanceStore.read(storageId)
return data
} catch (error) {
reply.code(500)
@@ -31,7 +42,8 @@ export function registerStorageRoutes(app: FastifyInstance, deps: RouteDeps) {
app.put<{ Params: { id: string } }>("/api/storage/instances/:id", async (request, reply) => {
try {
const body = InstanceDataSchema.parse(request.body ?? {})
- await deps.instanceStore.write(request.params.id, body)
+ const storageId = resolveStorageKey(request.params.id)
+ await deps.instanceStore.write(storageId, body)
deps.eventBus.publish({ type: "instance.dataChanged", instanceId: request.params.id, data: body })
reply.code(204)
} catch (error) {
@@ -42,7 +54,8 @@ export function registerStorageRoutes(app: FastifyInstance, deps: RouteDeps) {
app.delete<{ Params: { id: string } }>("/api/storage/instances/:id", async (request, reply) => {
try {
- await deps.instanceStore.delete(request.params.id)
+ const storageId = resolveStorageKey(request.params.id)
+ await deps.instanceStore.delete(storageId)
deps.eventBus.publish({ type: "instance.dataChanged", instanceId: request.params.id, data: EMPTY_INSTANCE_DATA })
reply.code(204)
} catch (error) {
diff --git a/packages/cli/src/storage/instance-store.ts b/packages/cli/src/storage/instance-store.ts
index a63973d3..48550840 100644
--- a/packages/cli/src/storage/instance-store.ts
+++ b/packages/cli/src/storage/instance-store.ts
@@ -6,6 +6,7 @@ import type { InstanceData } from "../api-types"
const DEFAULT_INSTANCE_DATA: InstanceData = {
messageHistory: [],
+ agentModelSelections: {},
}
export class InstanceStore {
diff --git a/packages/ui/src/lib/storage.ts b/packages/ui/src/lib/storage.ts
index 434c7a6c..b55c1ca3 100644
--- a/packages/ui/src/lib/storage.ts
+++ b/packages/ui/src/lib/storage.ts
@@ -6,6 +6,7 @@ export type ConfigData = AppConfig
const DEFAULT_INSTANCE_DATA: InstanceData = {
messageHistory: [],
+ agentModelSelections: {},
}
function isDeepEqual(a: unknown, b: unknown): boolean {
@@ -150,9 +151,11 @@ export class ServerStorage {
private normalizeInstanceData(data?: InstanceData | null): InstanceData {
const source = data ?? DEFAULT_INSTANCE_DATA
const messageHistory = Array.isArray(source.messageHistory) ? [...source.messageHistory] : []
+ const agentModelSelections = { ...(source.agentModelSelections ?? {}) }
return {
...source,
messageHistory,
+ agentModelSelections,
}
}
diff --git a/packages/ui/src/main.tsx b/packages/ui/src/main.tsx
index 080336f0..cbcf57d6 100644
--- a/packages/ui/src/main.tsx
+++ b/packages/ui/src/main.tsx
@@ -2,6 +2,7 @@ import { render } from "solid-js/web"
import App from "./App"
import { ThemeProvider } from "./lib/theme"
import { ConfigProvider } from "./stores/preferences"
+import { InstanceConfigProvider } from "./stores/instance-config"
import "./index.css"
import "@git-diff-view/solid/styles/diff-view-pure.css"
@@ -14,9 +15,11 @@ if (!root) {
render(
() => (
-
-
-
+
+
+
+
+
),
root,
diff --git a/packages/ui/src/stores/instance-config.tsx b/packages/ui/src/stores/instance-config.tsx
new file mode 100644
index 00000000..598c1e00
--- /dev/null
+++ b/packages/ui/src/stores/instance-config.tsx
@@ -0,0 +1,138 @@
+import { createContext, createMemo, createSignal, onCleanup, type Accessor, type ParentComponent, useContext } from "solid-js"
+import type { InstanceData } from "../../../cli/src/api-types"
+import { storage } from "../lib/storage"
+
+const DEFAULT_INSTANCE_DATA: InstanceData = { messageHistory: [], agentModelSelections: {} }
+
+const [instanceDataMap, setInstanceDataMap] = createSignal