diff --git a/src/app-server/catalog-model.ts b/src/app-server/catalog-model.ts index 01234800..c8637312 100644 --- a/src/app-server/catalog-model.ts +++ b/src/app-server/catalog-model.ts @@ -1,10 +1,10 @@ import type { HookMetadata } from "../generated/app-server/v2/HookMetadata"; import type { Model } from "../generated/app-server/v2/Model"; -import type { SkillMetadata } from "../generated/app-server/v2/SkillMetadata"; +import type { SkillMetadata as AppServerSkillMetadata } from "../generated/app-server/v2/SkillMetadata"; import type { AppServerHookOperation } from "./client"; -import type { PanelHookItem, PanelModelOption, PanelSkillOption } from "../domain/catalog/metadata"; +import type { HookItem, ModelMetadata, SkillMetadata } from "../domain/catalog/metadata"; -function panelModelOptionFromAppServerModel(model: Model): PanelModelOption { +function modelMetadataFromAppServerModel(model: Model): ModelMetadata { return { id: model.id, model: model.model, @@ -21,11 +21,11 @@ function panelModelOptionFromAppServerModel(model: Model): PanelModelOption { }; } -export function panelModelOptionsFromAppServerModels(models: readonly Model[]): PanelModelOption[] { - return models.map((model) => panelModelOptionFromAppServerModel(model)); +export function modelMetadataFromAppServerModels(models: readonly Model[]): ModelMetadata[] { + return models.map((model) => modelMetadataFromAppServerModel(model)); } -function panelSkillOptionFromAppServerSkill(skill: SkillMetadata): PanelSkillOption { +function skillMetadataFromAppServerSkill(skill: AppServerSkillMetadata): SkillMetadata { return { name: skill.name, description: skill.description, @@ -36,11 +36,11 @@ function panelSkillOptionFromAppServerSkill(skill: SkillMetadata): PanelSkillOpt }; } -export function panelSkillOptionsFromAppServerSkills(skills: readonly SkillMetadata[]): PanelSkillOption[] { - return skills.map((skill) => panelSkillOptionFromAppServerSkill(skill)); +export function skillMetadataFromAppServerSkills(skills: readonly AppServerSkillMetadata[]): SkillMetadata[] { + return skills.map((skill) => skillMetadataFromAppServerSkill(skill)); } -function panelHookItemFromAppServerHook(hook: HookMetadata): PanelHookItem { +function hookItemFromAppServerHook(hook: HookMetadata): HookItem { return { key: hook.key, eventName: hook.eventName, @@ -55,11 +55,11 @@ function panelHookItemFromAppServerHook(hook: HookMetadata): PanelHookItem { }; } -export function panelHookItemsFromAppServerHooks(hooks: readonly HookMetadata[]): PanelHookItem[] { - return hooks.map((hook) => panelHookItemFromAppServerHook(hook)); +export function hookItemsFromAppServerHooks(hooks: readonly HookMetadata[]): HookItem[] { + return hooks.map((hook) => hookItemFromAppServerHook(hook)); } -export function appServerHookOperationFromPanelHookItem(hook: PanelHookItem): AppServerHookOperation { +export function appServerHookOperationFromHookItem(hook: HookItem): AppServerHookOperation { return { key: hook.key, currentHash: hook.currentHash, diff --git a/src/app-server/panel-data.ts b/src/app-server/panel-data.ts deleted file mode 100644 index 7f6bf009..00000000 --- a/src/app-server/panel-data.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { AppServerClient } from "./client"; -import { - appServerHookOperationFromPanelHookItem, - panelHookItemsFromAppServerHooks, - panelModelOptionsFromAppServerModels, - panelSkillOptionsFromAppServerSkills, -} from "./catalog-model"; -import { panelThreadFromAppServerThread, panelThreadsFromAppServerThreads } from "./thread-model"; -import type { PanelHookItem, PanelModelOption, PanelSkillOption } from "../domain/catalog/metadata"; -import type { PanelThread } from "../domain/threads/model"; - -export interface PanelHookData { - hooks: PanelHookItem[]; - warnings: string[]; - errors: string[]; -} - -export async function listPanelThreads(client: AppServerClient, cwd: string, options: { archived?: boolean } = {}): Promise { - const archived = options.archived ?? false; - const response = await client.listThreads(cwd, archived); - return panelThreadsFromAppServerThreads(response.data, { archived }); -} - -export async function listPanelModelOptions( - client: AppServerClient, - options: { includeHidden?: boolean } = {}, -): Promise { - const response = await client.listModels(options.includeHidden ?? false); - return panelModelOptionsFromAppServerModels(response.data); -} - -export async function listPanelSkillCatalog( - client: AppServerClient, - cwd: string, - options: { forceReload?: boolean; enabledOnly?: boolean } = {}, -): Promise<{ skills: PanelSkillOption[]; totalCount: number }> { - const response = await client.listSkills(cwd, options.forceReload ?? false); - const skills = response.data.flatMap((entry) => entry.skills); - return { - skills: panelSkillOptionsFromAppServerSkills(options.enabledOnly === false ? skills : skills.filter((skill) => skill.enabled)), - totalCount: skills.length, - }; -} - -export async function listPanelHookData(client: AppServerClient, cwd: string): Promise { - const response = await client.listHooks(cwd); - const entry = response.data.find((item) => item.cwd === cwd); - if (!entry) return { hooks: [], warnings: [], errors: [] }; - return { - hooks: panelHookItemsFromAppServerHooks(entry.hooks), - warnings: entry.warnings, - errors: entry.errors.map((error) => JSON.stringify(error)), - }; -} - -export async function trustPanelHook(client: AppServerClient, hook: PanelHookItem): Promise { - await client.trustHook(appServerHookOperationFromPanelHookItem(hook)); -} - -export async function setPanelHookEnabled(client: AppServerClient, hook: PanelHookItem, enabled: boolean): Promise { - await client.setHookEnabled(appServerHookOperationFromPanelHookItem(hook), enabled); -} - -export async function restoreArchivedPanelThread(client: AppServerClient, threadId: string): Promise { - const response = await client.unarchiveThread(threadId); - return panelThreadFromAppServerThread(response.thread); -} diff --git a/src/app-server/resource-operations.ts b/src/app-server/resource-operations.ts new file mode 100644 index 00000000..ae7074c5 --- /dev/null +++ b/src/app-server/resource-operations.ts @@ -0,0 +1,64 @@ +import type { AppServerClient } from "./client"; +import { + appServerHookOperationFromHookItem, + hookItemsFromAppServerHooks, + modelMetadataFromAppServerModels, + skillMetadataFromAppServerSkills, +} from "./catalog-model"; +import { threadFromAppServerThread, threadsFromAppServerThreads } from "./thread-model"; +import type { HookItem, ModelMetadata, SkillMetadata } from "../domain/catalog/metadata"; +import type { Thread } from "../domain/threads/model"; + +export interface HookData { + hooks: HookItem[]; + warnings: string[]; + errors: string[]; +} + +export async function listThreads(client: AppServerClient, cwd: string, options: { archived?: boolean } = {}): Promise { + const archived = options.archived ?? false; + const response = await client.listThreads(cwd, archived); + return threadsFromAppServerThreads(response.data, { archived }); +} + +export async function listModelMetadata(client: AppServerClient, options: { includeHidden?: boolean } = {}): Promise { + const response = await client.listModels(options.includeHidden ?? false); + return modelMetadataFromAppServerModels(response.data); +} + +export async function listSkillCatalog( + client: AppServerClient, + cwd: string, + options: { forceReload?: boolean; enabledOnly?: boolean } = {}, +): Promise<{ skills: SkillMetadata[]; totalCount: number }> { + const response = await client.listSkills(cwd, options.forceReload ?? false); + const skills = response.data.flatMap((entry) => entry.skills); + return { + skills: skillMetadataFromAppServerSkills(options.enabledOnly === false ? skills : skills.filter((skill) => skill.enabled)), + totalCount: skills.length, + }; +} + +export async function listHookData(client: AppServerClient, cwd: string): Promise { + const response = await client.listHooks(cwd); + const entry = response.data.find((item) => item.cwd === cwd); + if (!entry) return { hooks: [], warnings: [], errors: [] }; + return { + hooks: hookItemsFromAppServerHooks(entry.hooks), + warnings: entry.warnings, + errors: entry.errors.map((error) => JSON.stringify(error)), + }; +} + +export async function trustHookItem(client: AppServerClient, hook: HookItem): Promise { + await client.trustHook(appServerHookOperationFromHookItem(hook)); +} + +export async function setHookItemEnabled(client: AppServerClient, hook: HookItem, enabled: boolean): Promise { + await client.setHookEnabled(appServerHookOperationFromHookItem(hook), enabled); +} + +export async function restoreArchivedThread(client: AppServerClient, threadId: string): Promise { + const response = await client.unarchiveThread(threadId); + return threadFromAppServerThread(response.thread); +} diff --git a/src/app-server/shared-cache-state.ts b/src/app-server/shared-cache-state.ts index 4afe8b6a..32601f52 100644 --- a/src/app-server/shared-cache-state.ts +++ b/src/app-server/shared-cache-state.ts @@ -1,13 +1,13 @@ import type { AppServerDiagnostics } from "./compatibility"; import type { ConfigReadResponse } from "../generated/app-server/v2/ConfigReadResponse"; import type { RateLimitSnapshot } from "../generated/app-server/v2/RateLimitSnapshot"; -import type { PanelThread } from "../domain/threads/model"; -import type { PanelModelOption, PanelSkillOption } from "../domain/catalog/metadata"; +import type { Thread } from "../domain/threads/model"; +import type { ModelMetadata, SkillMetadata } from "../domain/catalog/metadata"; export interface SharedAppServerMetadata { effectiveConfig: ConfigReadResponse | null; - availableModels: readonly PanelModelOption[]; - availableSkills: readonly PanelSkillOption[]; + availableModels: readonly ModelMetadata[]; + availableSkills: readonly SkillMetadata[]; rateLimit: RateLimitSnapshot | null; appServerDiagnostics: AppServerDiagnostics; } @@ -15,9 +15,9 @@ export interface SharedAppServerMetadata { type SharedCache = { kind: "unloaded" } | { kind: "loaded"; data: T }; export interface SharedAppServerState { - threads: SharedCache; + threads: SharedCache; appServerMetadata: SharedCache; - availableModels: readonly PanelModelOption[]; + availableModels: readonly ModelMetadata[]; } export function createSharedAppServerState(): SharedAppServerState { @@ -28,7 +28,7 @@ export function createSharedAppServerState(): SharedAppServerState { }; } -export function applySharedThreadList(state: SharedAppServerState, threads: readonly PanelThread[]): SharedAppServerState { +export function applySharedThreadList(state: SharedAppServerState, threads: readonly Thread[]): SharedAppServerState { return { ...state, threads: { kind: "loaded", data: cloneThreads(threads) }, @@ -40,23 +40,23 @@ export function applySharedAppServerMetadata(state: SharedAppServerState, metada return { ...state, appServerMetadata: { kind: "loaded", data: clonedMetadata }, - availableModels: cloneModelOptions(clonedMetadata.availableModels), + availableModels: cloneModelMetadata(clonedMetadata.availableModels), }; } -export function applySharedModels(state: SharedAppServerState, models: readonly PanelModelOption[]): SharedAppServerState { - const clonedModels = cloneModelOptions(models); +export function applySharedModels(state: SharedAppServerState, models: readonly ModelMetadata[]): SharedAppServerState { + const clonedModels = cloneModelMetadata(models); return { ...state, appServerMetadata: state.appServerMetadata.kind === "loaded" - ? { kind: "loaded", data: { ...state.appServerMetadata.data, availableModels: cloneModelOptions(clonedModels) } } + ? { kind: "loaded", data: { ...state.appServerMetadata.data, availableModels: cloneModelMetadata(clonedModels) } } : state.appServerMetadata, availableModels: clonedModels, }; } -export function cachedSharedThreadList(state: SharedAppServerState): readonly PanelThread[] | null { +export function cachedSharedThreadList(state: SharedAppServerState): readonly Thread[] | null { return state.threads.kind === "loaded" ? cloneThreads(state.threads.data) : null; } @@ -65,15 +65,15 @@ export function cachedSharedAppServerMetadata(state: SharedAppServerState): Shar return null; } -export function cachedSharedModels(state: SharedAppServerState): PanelModelOption[] { - return cloneModelOptions(state.availableModels); +export function cachedSharedModels(state: SharedAppServerState): ModelMetadata[] { + return cloneModelMetadata(state.availableModels); } function cloneSharedAppServerMetadata(metadata: SharedAppServerMetadata): SharedAppServerMetadata { return { ...metadata, - availableModels: cloneModelOptions(metadata.availableModels), - availableSkills: cloneSkillOptions(metadata.availableSkills), + availableModels: cloneModelMetadata(metadata.availableModels), + availableSkills: cloneSkillMetadata(metadata.availableSkills), appServerDiagnostics: { probes: { ...metadata.appServerDiagnostics.probes }, mcpServers: metadata.appServerDiagnostics.mcpServers.map((server) => ({ ...server })), @@ -81,11 +81,11 @@ function cloneSharedAppServerMetadata(metadata: SharedAppServerMetadata): Shared }; } -function cloneThreads(threads: readonly PanelThread[]): PanelThread[] { +function cloneThreads(threads: readonly Thread[]): Thread[] { return threads.map((thread) => ({ ...thread })); } -function cloneModelOptions(models: readonly PanelModelOption[]): PanelModelOption[] { +function cloneModelMetadata(models: readonly ModelMetadata[]): ModelMetadata[] { return models.map((model) => ({ ...model, supportedReasoningEfforts: [...model.supportedReasoningEfforts], @@ -95,6 +95,6 @@ function cloneModelOptions(models: readonly PanelModelOption[]): PanelModelOptio })); } -function cloneSkillOptions(skills: readonly PanelSkillOption[]): PanelSkillOption[] { +function cloneSkillMetadata(skills: readonly SkillMetadata[]): SkillMetadata[] { return skills.map((skill) => ({ ...skill })); } diff --git a/src/app-server/shared-cache.ts b/src/app-server/shared-cache.ts index 72e9159a..8d8dff3d 100644 --- a/src/app-server/shared-cache.ts +++ b/src/app-server/shared-cache.ts @@ -1,5 +1,5 @@ -import type { PanelThread } from "../domain/threads/model"; -import type { PanelModelOption } from "../domain/catalog/metadata"; +import type { Thread } from "../domain/threads/model"; +import type { ModelMetadata } from "../domain/catalog/metadata"; import { applySharedAppServerMetadata, applySharedModels, @@ -12,16 +12,16 @@ import { type SharedAppServerState, } from "./shared-cache-state"; -type ThreadListRefreshLifecycleState = { kind: "idle" } | { kind: "refreshing"; promise: Promise }; +type ThreadListRefreshLifecycleState = { kind: "idle" } | { kind: "refreshing"; promise: Promise }; export class SharedAppServerCache { private state: SharedAppServerState = createSharedAppServerState(); private threadListRefreshLifecycle: ThreadListRefreshLifecycleState = { kind: "idle" }; refreshThreadList( - fetchThreads: () => Promise, - onSnapshot?: (threads: readonly PanelThread[]) => void, - ): Promise { + fetchThreads: () => Promise, + onSnapshot?: (threads: readonly Thread[]) => void, + ): Promise { if (this.threadListRefreshLifecycle.kind === "refreshing") return this.threadListRefreshLifecycle.promise; const promise = fetchThreads() .then((threads) => { @@ -38,11 +38,11 @@ export class SharedAppServerCache { return promise; } - applyThreadListSnapshot(threads: readonly PanelThread[]): void { + applyThreadListSnapshot(threads: readonly Thread[]): void { this.state = applySharedThreadList(this.state, threads); } - cachedThreadList(): readonly PanelThread[] | null { + cachedThreadList(): readonly Thread[] | null { return cachedSharedThreadList(this.state); } @@ -54,11 +54,11 @@ export class SharedAppServerCache { return cachedSharedAppServerMetadata(this.state); } - applyModelsSnapshot(models: readonly PanelModelOption[]): void { + applyModelsSnapshot(models: readonly ModelMetadata[]): void { this.state = applySharedModels(this.state, models); } - cachedModels(): PanelModelOption[] { + cachedModels(): ModelMetadata[] { return cachedSharedModels(this.state); } } diff --git a/src/app-server/thread-model.ts b/src/app-server/thread-model.ts index 2724fa2c..eb85feb3 100644 --- a/src/app-server/thread-model.ts +++ b/src/app-server/thread-model.ts @@ -1,7 +1,7 @@ -import type { Thread } from "../generated/app-server/v2/Thread"; -import type { PanelThread } from "../domain/threads/model"; +import type { Thread as AppServerThread } from "../generated/app-server/v2/Thread"; +import type { Thread } from "../domain/threads/model"; -export function panelThreadFromAppServerThread(thread: Thread, options: { archived?: boolean } = {}): PanelThread { +export function threadFromAppServerThread(thread: AppServerThread, options: { archived?: boolean } = {}): Thread { return { id: thread.id, preview: normalizeString(thread.preview), @@ -12,8 +12,8 @@ export function panelThreadFromAppServerThread(thread: Thread, options: { archiv }; } -export function panelThreadsFromAppServerThreads(threads: readonly Thread[], options: { archived?: boolean } = {}): PanelThread[] { - return threads.map((thread) => panelThreadFromAppServerThread(thread, options)); +export function threadsFromAppServerThreads(threads: readonly AppServerThread[], options: { archived?: boolean } = {}): Thread[] { + return threads.map((thread) => threadFromAppServerThread(thread, options)); } function normalizeNullableString(value: string | null): string | null { diff --git a/src/app-server/thread-title-generation.ts b/src/app-server/thread-title-generation.ts index ebe97edf..f1ca094f 100644 --- a/src/app-server/thread-title-generation.ts +++ b/src/app-server/thread-title-generation.ts @@ -5,10 +5,10 @@ import { type EphemeralStructuredTurnRuntimeClient, type StructuredTurnOutputSchema, } from "./ephemeral-structured-turn"; -import { panelModelOptionsFromAppServerModels } from "./catalog-model"; +import { modelMetadataFromAppServerModels } from "./catalog-model"; import type { Turn } from "../generated/app-server/v2/Turn"; -import type { PanelModelOption, ReasoningEffort } from "../domain/catalog/metadata"; -import { runtimeOverride, validatedRuntimeOverrideForModelOptions } from "../domain/catalog/runtime-overrides"; +import type { ModelMetadata, ReasoningEffort } from "../domain/catalog/metadata"; +import { runtimeOverride, validatedRuntimeOverrideForModelMetadata } from "../domain/catalog/runtime-overrides"; import { namingPrompt, titleFromGeneratedText, type ThreadNamingContext } from "../domain/threads/naming"; import { turnConversationSummary } from "../domain/threads/transcript"; @@ -84,9 +84,9 @@ export function threadNamingRuntimeOverride(settings: ThreadNamingRuntimeSetting export function validatedThreadNamingRuntimeOverride( settings: ThreadNamingRuntimeSettings, - models: readonly PanelModelOption[], + models: readonly ModelMetadata[], ): ThreadNamingRuntimeOverride { - return validatedRuntimeOverrideForModelOptions({ model: settings.threadNamingModel, effort: settings.threadNamingEffort }, models); + return validatedRuntimeOverrideForModelMetadata({ model: settings.threadNamingModel, effort: settings.threadNamingEffort }, models); } async function threadNamingRuntimeOverrideForClient( @@ -97,7 +97,7 @@ async function threadNamingRuntimeOverrideForClient( if (!runtime.model || !runtime.effort) return runtime; try { const response = await client.listModels(false); - return validatedThreadNamingRuntimeOverride(settings, panelModelOptionsFromAppServerModels(response.data)); + return validatedThreadNamingRuntimeOverride(settings, modelMetadataFromAppServerModels(response.data)); } catch { return runtime; } diff --git a/src/domain/catalog/metadata.ts b/src/domain/catalog/metadata.ts index db669487..d70471f5 100644 --- a/src/domain/catalog/metadata.ts +++ b/src/domain/catalog/metadata.ts @@ -1,9 +1,9 @@ -interface PanelModelServiceTier { +interface ModelServiceTier { id: string; name: string; } -export interface PanelModelOption { +export interface ModelMetadata { id: string; model: string; displayName: string; @@ -13,12 +13,12 @@ export interface PanelModelOption { defaultReasoningEffort: string | null; inputModalities: readonly string[]; additionalSpeedTiers: readonly string[]; - serviceTiers: readonly PanelModelServiceTier[]; + serviceTiers: readonly ModelServiceTier[]; defaultServiceTier: string | null; isDefault: boolean; } -export interface PanelSkillOption { +export interface SkillMetadata { name: string; description: string; shortDescription?: string; @@ -27,9 +27,9 @@ export interface PanelSkillOption { enabled: boolean; } -type PanelHookTrustStatus = "managed" | "untrusted" | "trusted" | "modified"; +type HookTrustStatus = "managed" | "untrusted" | "trusted" | "modified"; -export interface PanelHookItem { +export interface HookItem { key: string; eventName: string; matcher: string | null; @@ -39,7 +39,7 @@ export interface PanelHookItem { enabled: boolean; isManaged: boolean; currentHash: string; - trustStatus: PanelHookTrustStatus; + trustStatus: HookTrustStatus; } export const REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh"] as const; @@ -54,25 +54,25 @@ export function normalizeReasoningEffort(value: unknown): ReasoningEffort | null return isReasoningEffort(value) ? value : null; } -export function supportedEffortsForModelOption(model: PanelModelOption | null): ReasoningEffort[] { +export function supportedEffortsForModelMetadata(model: ModelMetadata | null): ReasoningEffort[] { const efforts = model?.supportedReasoningEfforts.filter(isReasoningEffort) ?? []; return efforts.length > 0 ? efforts : [...REASONING_EFFORTS]; } -export function defaultEffortForModelOption(model: PanelModelOption | null): ReasoningEffort | null { +export function defaultEffortForModelMetadata(model: ModelMetadata | null): ReasoningEffort | null { return normalizeReasoningEffort(model?.defaultReasoningEffort); } -export function sortedModelOptions(models: readonly PanelModelOption[]): PanelModelOption[] { +export function sortedModelMetadata(models: readonly ModelMetadata[]): ModelMetadata[] { return [...models] .filter((model) => !model.hidden) .sort((a, b) => Number(b.isDefault) - Number(a.isDefault) || a.model.localeCompare(b.model)); } -export function findModelOptionByIdOrName( - models: readonly PanelModelOption[], +export function findModelMetadataByIdOrName( + models: readonly ModelMetadata[], modelIdOrName: string | null | undefined, -): PanelModelOption | null { +): ModelMetadata | null { if (!modelIdOrName) return null; return models.find((model) => !model.hidden && (model.model === modelIdOrName || model.id === modelIdOrName)) ?? null; } diff --git a/src/domain/catalog/runtime-overrides.ts b/src/domain/catalog/runtime-overrides.ts index a1efdeb8..ca917c75 100644 --- a/src/domain/catalog/runtime-overrides.ts +++ b/src/domain/catalog/runtime-overrides.ts @@ -1,5 +1,5 @@ -import type { PanelModelOption, ReasoningEffort } from "./metadata"; -import { findModelOptionByIdOrName, supportedEffortsForModelOption } from "./metadata"; +import type { ModelMetadata, ReasoningEffort } from "./metadata"; +import { findModelMetadataByIdOrName, supportedEffortsForModelMetadata } from "./metadata"; export interface RuntimeOverrideSettings { model: string | null; @@ -18,16 +18,16 @@ export function runtimeOverride(settings: RuntimeOverrideSettings): RuntimeOverr }; } -export function validatedRuntimeOverrideForModelOptions( +export function validatedRuntimeOverrideForModelMetadata( settings: RuntimeOverrideSettings, - models: readonly PanelModelOption[], + models: readonly ModelMetadata[], ): RuntimeOverride { const runtime = runtimeOverride(settings); if (!runtime.model || !runtime.effort) return runtime; - const model = findModelOptionByIdOrName(models, runtime.model); + const model = findModelMetadataByIdOrName(models, runtime.model); if (!model) return runtime; - const supportedEfforts = new Set(supportedEffortsForModelOption(model)); + const supportedEfforts = new Set(supportedEffortsForModelMetadata(model)); return supportedEfforts.has(runtime.effort) ? runtime : { model: runtime.model }; } diff --git a/src/domain/threads/export.ts b/src/domain/threads/export.ts index 08dcd589..9cca3295 100644 --- a/src/domain/threads/export.ts +++ b/src/domain/threads/export.ts @@ -1,6 +1,6 @@ import type { Turn } from "../../generated/app-server/v2/Turn"; import { shortThreadId } from "../../utils"; -import { getThreadTitle, type PanelThread } from "./model"; +import { getThreadTitle, type Thread } from "./model"; import { referencedThreadDisplayFromPrompt } from "./reference"; import { turnTranscriptEntries, type TurnTranscriptEntry } from "./transcript"; @@ -36,7 +36,7 @@ export interface ArchiveExportSettings { vaultPath?: string; } -export interface ArchiveThreadInput extends PanelThread { +export interface ArchiveThreadInput extends Thread { turns: Turn[]; } diff --git a/src/domain/threads/model.ts b/src/domain/threads/model.ts index dc97ca08..c9e70281 100644 --- a/src/domain/threads/model.ts +++ b/src/domain/threads/model.ts @@ -3,7 +3,7 @@ import { shortThreadId } from "../../utils"; const MAX_THREAD_DISPLAY_TITLE_LENGTH = 96; const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; -export interface PanelThread { +export interface Thread { id: string; preview: string; name: string | null; @@ -12,23 +12,19 @@ export interface PanelThread { updatedAt: number; } -export function getThreadTitle(thread: PanelThread): string { +export function getThreadTitle(thread: Thread): string { return ( [thread.name, thread.preview, thread.id].map((value) => (typeof value === "string" ? normalizeTitle(value) : "")).find(Boolean) ?? thread.id ); } -export function explicitThreadName(thread: PanelThread): string | null { +export function explicitThreadName(thread: Thread): string | null { const name = typeof thread.name === "string" ? normalizeTitle(thread.name) : ""; return name.length > 0 ? name : null; } -export function codexPanelDisplayTitle( - activeThreadId: string | null, - threads: readonly PanelThread[], - fallbackTitle?: string | null, -): string { +export function codexPanelDisplayTitle(activeThreadId: string | null, threads: readonly Thread[], fallbackTitle?: string | null): string { if (!activeThreadId) return "Codex"; const thread = threads.find((item) => item.id === activeThreadId); @@ -36,24 +32,24 @@ export function codexPanelDisplayTitle( return title ? `Codex: ${title}` : "Codex"; } -export function inheritedForkThreadName(threadId: string, threads: readonly PanelThread[]): string | null { +export function inheritedForkThreadName(threadId: string, threads: readonly Thread[]): string | null { const thread = threads.find((item) => item.id === threadId); return thread ? explicitThreadName(thread) : null; } -export function upsertThread(threads: readonly PanelThread[], thread: PanelThread): PanelThread[] { +export function upsertThread(threads: readonly Thread[], thread: Thread): Thread[] { const index = threads.findIndex((item) => item.id === thread.id); if (index === -1) return [thread, ...threads]; return threads.map((item, itemIndex) => (itemIndex === index ? { ...item, ...thread } : item)); } -export function archivedThreadDisplayTitle(thread: PanelThread): string { +export function archivedThreadDisplayTitle(thread: Thread): string { const title = fullThreadTitle(thread); if (!title || title === thread.id || UUID_PATTERN.test(title)) return "Untitled archived thread"; return truncateTitle(title, MAX_THREAD_DISPLAY_TITLE_LENGTH); } -function fullThreadTitle(thread: PanelThread): string { +function fullThreadTitle(thread: Thread): string { return normalizeTitle(getThreadTitle(thread)); } diff --git a/src/domain/threads/reference.ts b/src/domain/threads/reference.ts index 8e20f0d4..f55fffd5 100644 --- a/src/domain/threads/reference.ts +++ b/src/domain/threads/reference.ts @@ -1,7 +1,7 @@ import type { Turn } from "../../generated/app-server/v2/Turn"; import type { UserInput } from "../../generated/app-server/v2/UserInput"; import { shortThreadId } from "../../utils"; -import { getThreadTitle, type PanelThread } from "./model"; +import { getThreadTitle, type Thread } from "./model"; import { chronologicalTurnConversationSummaries } from "./transcript"; export const REFERENCED_THREAD_TURN_LIMIT = 20; @@ -34,7 +34,7 @@ export function referencedThreadTurns(turns: Turn[]): ReferencedThreadTurn[] { return chronologicalTurnConversationSummaries(turns); } -export function referencedThreadPrompt(thread: PanelThread, turns: ReferencedThreadTurn[], userRequest: string): string { +export function referencedThreadPrompt(thread: Thread, turns: ReferencedThreadTurn[], userRequest: string): string { const reference = referencedThreadDisplay(thread, turns.length); const envelope = referencedThreadEnvelope(reference, userRequest); @@ -57,11 +57,11 @@ export function referencedThreadPrompt(thread: PanelThread, turns: ReferencedThr ].join("\n"); } -function referencedThreadStatus(thread: PanelThread, count: number): string { +function referencedThreadStatus(thread: Thread, count: number): string { return `Referencing ${shortThreadId(thread.id)} (${String(count)}/${String(REFERENCED_THREAD_TURN_LIMIT)} turns).`; } -function referencedThreadDisplay(thread: PanelThread, count: number): ReferencedThreadDisplay { +function referencedThreadDisplay(thread: Thread, count: number): ReferencedThreadDisplay { return { threadId: thread.id, title: getThreadTitle(thread), @@ -71,7 +71,7 @@ function referencedThreadDisplay(thread: PanelThread, count: number): Referenced } export function referencedThreadInput( - thread: PanelThread, + thread: Thread, turns: readonly ReferencedThreadTurn[], userRequest: string, messageInput: UserInput[], diff --git a/src/features/chat/app-server/metadata-actions.ts b/src/features/chat/app-server/metadata-actions.ts index 0a985c0e..ae2de406 100644 --- a/src/features/chat/app-server/metadata-actions.ts +++ b/src/features/chat/app-server/metadata-actions.ts @@ -1,8 +1,8 @@ import { type AppServerDiagnostics, capabilityProbeError, capabilityProbeOk } from "../../../app-server/compatibility"; -import { listPanelModelOptions, listPanelSkillCatalog } from "../../../app-server/panel-data"; +import { listModelMetadata, listSkillCatalog } from "../../../app-server/resource-operations"; import type { RateLimitSnapshot } from "../../../generated/app-server/v2/RateLimitSnapshot"; import type { SharedAppServerMetadata } from "../../../app-server/shared-cache-state"; -import type { PanelModelOption, PanelSkillOption } from "../../../domain/catalog/metadata"; +import type { ModelMetadata, SkillMetadata } from "../../../domain/catalog/metadata"; import { cloneAppServerDiagnostics, type ChatAppServerBaseHost } from "./shared"; export interface ChatAppServerMetadataActionsHost extends ChatAppServerBaseHost { @@ -17,10 +17,10 @@ export interface ChatAppServerMetadataActions { refreshPublishedAppServerMetadata: () => Promise; publishAppServerMetadataSnapshot: () => void; refreshModels: () => Promise; - loadModels: () => Promise<{ data: PanelModelOption[]; probe: AppServerDiagnostics["probes"]["model/list"] }>; + loadModels: () => Promise<{ data: ModelMetadata[]; probe: AppServerDiagnostics["probes"]["model/list"] }>; refreshSkills: (forceReload?: boolean) => Promise; refreshPublishedSkills: (forceReload?: boolean) => Promise; - loadSkills: (forceReload?: boolean) => Promise<{ data: PanelSkillOption[]; probe: AppServerDiagnostics["probes"]["skills/list"] }>; + loadSkills: (forceReload?: boolean) => Promise<{ data: SkillMetadata[]; probe: AppServerDiagnostics["probes"]["skills/list"] }>; refreshRateLimits: () => Promise; refreshPublishedRateLimits: () => Promise; loadRateLimit: () => Promise<{ data: RateLimitSnapshot | null; probe: AppServerDiagnostics["probes"]["account/rateLimits/read"] }>; @@ -118,11 +118,11 @@ async function refreshModels(host: ChatAppServerMetadataActionsHost): Promise { +): Promise<{ data: ModelMetadata[]; probe: AppServerDiagnostics["probes"]["model/list"] }> { const client = host.currentClient(); if (!client) return { data: [], probe: capabilityProbeError("model/list", new Error("Codex app-server is not connected.")) }; try { - const data = await listPanelModelOptions(client); + const data = await listModelMetadata(client); return { data, probe: capabilityProbeOk("model/list", `${String(data.length)} models`), @@ -151,11 +151,11 @@ async function refreshPublishedSkills(host: ChatAppServerMetadataActionsHost, fo async function loadSkills( host: ChatAppServerMetadataActionsHost, forceReload = false, -): Promise<{ data: PanelSkillOption[]; probe: AppServerDiagnostics["probes"]["skills/list"] }> { +): Promise<{ data: SkillMetadata[]; probe: AppServerDiagnostics["probes"]["skills/list"] }> { const client = host.currentClient(); if (!client) return { data: [], probe: capabilityProbeError("skills/list", new Error("Codex app-server is not connected.")) }; try { - const catalog = await listPanelSkillCatalog(client, host.vaultPath, { forceReload }); + const catalog = await listSkillCatalog(client, host.vaultPath, { forceReload }); return { data: catalog.skills, probe: capabilityProbeOk("skills/list", `${String(catalog.totalCount)} skills`) }; } catch (error) { return { data: [], probe: capabilityProbeError("skills/list", error) }; diff --git a/src/features/chat/app-server/thread-actions.ts b/src/features/chat/app-server/thread-actions.ts index 25f45c82..a7395fcd 100644 --- a/src/features/chat/app-server/thread-actions.ts +++ b/src/features/chat/app-server/thread-actions.ts @@ -1,5 +1,5 @@ -import { listPanelThreads } from "../../../app-server/panel-data"; -import type { PanelThread } from "../../../domain/threads/model"; +import { listThreads } from "../../../app-server/resource-operations"; +import type { Thread } from "../../../domain/threads/model"; import { requestedOrConfiguredServiceTier, type RuntimeSnapshot } from "../runtime/effective-settings"; import { resumedThreadActionFromAppServerResponse } from "../threads/thread-resume"; import type { ChatAppServerBaseHost } from "./shared"; @@ -10,13 +10,13 @@ interface StartedThreadSummary { export interface ChatAppServerThreadActionsHost extends ChatAppServerBaseHost { runtimeSnapshot: () => RuntimeSnapshot; - publishThreadList: (threads: readonly PanelThread[]) => void; + publishThreadList: (threads: readonly Thread[]) => void; syncThreadGoal: (threadId: string) => void; } export interface ChatAppServerThreadActions { - applyThreadList: (threads: readonly PanelThread[]) => void; - loadThreadList: () => Promise; + applyThreadList: (threads: readonly Thread[]) => void; + loadThreadList: () => Promise; startThread: (preview?: string, options?: { syncGoal?: boolean }) => Promise; } @@ -30,14 +30,14 @@ export function createChatAppServerThreadActions(host: ChatAppServerThreadAction }; } -function applyThreadList(host: ChatAppServerThreadActionsHost, threads: readonly PanelThread[]): void { +function applyThreadList(host: ChatAppServerThreadActionsHost, threads: readonly Thread[]): void { host.stateStore.dispatch({ type: "thread-list/applied", threads, threadsLoaded: true }); } -async function loadThreadList(host: ChatAppServerThreadActionsHost): Promise { +async function loadThreadList(host: ChatAppServerThreadActionsHost): Promise { const client = host.currentClient(); if (!client) throw new Error("Codex app-server is not connected."); - return listPanelThreads(client, host.vaultPath); + return listThreads(client, host.vaultPath); } async function startThread( diff --git a/src/features/chat/chat-host.ts b/src/features/chat/chat-host.ts index aa845e8b..66476443 100644 --- a/src/features/chat/chat-host.ts +++ b/src/features/chat/chat-host.ts @@ -1,4 +1,4 @@ -import type { PanelThread } from "../../domain/threads/model"; +import type { Thread } from "../../domain/threads/model"; import type { SharedAppServerMetadata } from "../../app-server/shared-cache-state"; import type { CodexPanelSettings } from "../../settings/model"; import type { ChatTurnDiffViewState } from "./ui/turn-diff"; @@ -13,9 +13,9 @@ export interface CodexChatHost { notifyThreadRenamed(threadId: string, name: string | null): void; refreshThreadsViewLiveState(): void; refreshSharedThreadListFromOpenSurface(): void; - applyThreadListSnapshot(threads: readonly PanelThread[]): void; - refreshThreadList(fetchThreads: () => Promise): Promise; - cachedThreadList(): readonly PanelThread[] | null; + applyThreadListSnapshot(threads: readonly Thread[]): void; + refreshThreadList(fetchThreads: () => Promise): Promise; + cachedThreadList(): readonly Thread[] | null; publishAppServerMetadata(metadata: SharedAppServerMetadata): void; cachedAppServerMetadata(): SharedAppServerMetadata | null; } diff --git a/src/features/chat/chat-state-actions.ts b/src/features/chat/chat-state-actions.ts index 4f5f3d75..5d8230b1 100644 --- a/src/features/chat/chat-state-actions.ts +++ b/src/features/chat/chat-state-actions.ts @@ -1,16 +1,16 @@ import type { InitializeResponse } from "../../generated/app-server/InitializeResponse"; -import type { PanelThread } from "../../domain/threads/model"; +import type { Thread } from "../../domain/threads/model"; import type { ThreadTokenUsage } from "../../generated/app-server/v2/ThreadTokenUsage"; import type { ReasoningEffort } from "../../domain/catalog/metadata"; import type { ChatRuntimeState } from "./runtime/state"; -import type { PanelCollaborationMode } from "./runtime/collaboration"; +import type { CollaborationMode } from "./runtime/collaboration"; import { parseServiceTier, type ServiceTier } from "../../app-server/thread-settings"; import type { ChatAction, PendingTurnStart } from "./chat-state"; import type { DisplayItem } from "./display/types"; export interface ActiveThreadResumedAction { type: "active-thread/resumed"; - thread: PanelThread; + thread: Thread; cwd: string; model: string | null; reasoningEffort: ReasoningEffort | null; @@ -20,7 +20,7 @@ export interface ActiveThreadResumedAction { activePermissionProfile: ChatRuntimeState["activePermissionProfile"]; displayItems?: readonly DisplayItem[]; status?: string; - listedThreads?: readonly PanelThread[]; + listedThreads?: readonly Thread[]; } export interface ActiveThreadSettingsAppliedAction { @@ -28,7 +28,7 @@ export interface ActiveThreadSettingsAppliedAction { cwd: string; model: string | null; reasoningEffort: ReasoningEffort | null; - collaborationMode: PanelCollaborationMode; + collaborationMode: CollaborationMode; serviceTier: ServiceTier | null; approvalPolicy: ChatRuntimeState["activeApprovalPolicy"]; approvalsReviewer: ChatRuntimeState["activeApprovalsReviewer"]; @@ -39,7 +39,7 @@ export interface ActiveThreadSettingsAppliedActionSettings { cwd: string; model: string | null; effort: ReasoningEffort | null; - collaborationMode: { mode: PanelCollaborationMode }; + collaborationMode: { mode: CollaborationMode }; serviceTier: string | null; approvalPolicy: ChatRuntimeState["activeApprovalPolicy"]; approvalsReviewer: ChatRuntimeState["activeApprovalsReviewer"]; @@ -66,7 +66,7 @@ export function clearActiveThreadAction(): ChatAction { return { type: "active-thread/cleared" }; } -export function applyThreadListAction(threads: readonly PanelThread[], threadsLoaded?: boolean): ChatAction { +export function applyThreadListAction(threads: readonly Thread[], threadsLoaded?: boolean): ChatAction { return { type: "thread-list/applied", threads, ...(threadsLoaded === undefined ? {} : { threadsLoaded }) }; } diff --git a/src/features/chat/chat-state-selectors.ts b/src/features/chat/chat-state-selectors.ts index 119a285a..a2943b52 100644 --- a/src/features/chat/chat-state-selectors.ts +++ b/src/features/chat/chat-state-selectors.ts @@ -1,6 +1,6 @@ import { activeTurnId as selectActiveTurnId, chatTurnBusy, pendingTurnStart } from "./chat-state"; import type { ChatState, PendingTurnStart } from "./chat-state"; -import type { PanelThread } from "../../domain/threads/model"; +import type { Thread } from "../../domain/threads/model"; import type { PendingApproval } from "./requests/approval"; import type { PendingUserInput } from "./requests/user-input"; import type { DisplayItem } from "./display/types"; @@ -17,7 +17,7 @@ export interface SubmissionStateSnapshot { activeThreadId: string | null; activeTurnId: string | null; busy: boolean; - listedThreads: readonly PanelThread[]; + listedThreads: readonly Thread[]; displayItems: readonly DisplayItem[]; pendingTurnStart: PendingTurnStart | null; } @@ -39,7 +39,7 @@ export function canSwitchToThread(state: ChatState, threadId: string): boolean { return !chatTurnBusy(state) || threadId === state.activeThread.id; } -export function listedThreads(state: ChatState): readonly PanelThread[] { +export function listedThreads(state: ChatState): readonly Thread[] { return state.threadList.listedThreads; } diff --git a/src/features/chat/chat-state.ts b/src/features/chat/chat-state.ts index a17b0aef..27582843 100644 --- a/src/features/chat/chat-state.ts +++ b/src/features/chat/chat-state.ts @@ -2,15 +2,15 @@ import type { InitializeResponse } from "../../generated/app-server/InitializeRe import type { ReasoningEffort } from "../../domain/catalog/metadata"; import type { ConfigReadResponse } from "../../generated/app-server/v2/ConfigReadResponse"; import type { RateLimitSnapshot } from "../../generated/app-server/v2/RateLimitSnapshot"; -import type { PanelThread } from "../../domain/threads/model"; -import type { PanelModelOption, PanelSkillOption } from "../../domain/catalog/metadata"; +import type { Thread } from "../../domain/threads/model"; +import type { ModelMetadata, SkillMetadata } from "../../domain/catalog/metadata"; import type { ThreadGoal } from "../../generated/app-server/v2/ThreadGoal"; import type { ThreadSettingsUpdate } from "../../app-server/thread-settings"; import type { ThreadTokenUsage } from "../../generated/app-server/v2/ThreadTokenUsage"; import type { AppServerDiagnostics } from "../../app-server/compatibility"; import { createAppServerDiagnostics } from "../../app-server/compatibility"; import type { ApprovalsReviewer } from "./runtime/approvals"; -import type { PanelCollaborationMode } from "./runtime/collaboration"; +import type { CollaborationMode } from "./runtime/collaboration"; import type { RequestedServiceTier } from "./runtime/service-tier-state"; import { commitPendingThreadSettingsRuntimeState, @@ -55,12 +55,12 @@ interface ChatConnectionState { initializeResponse: InitializeResponse | null; appServerDiagnostics: AppServerDiagnostics; rateLimit: RateLimitSnapshot | null; - availableModels: readonly PanelModelOption[]; - availableSkills: readonly PanelSkillOption[]; + availableModels: readonly ModelMetadata[]; + availableSkills: readonly SkillMetadata[]; } interface ChatThreadListState { - listedThreads: readonly PanelThread[]; + listedThreads: readonly Thread[]; threadsLoaded: boolean; } @@ -108,15 +108,15 @@ type ConnectionAction = | { type: "connection/metadata-applied"; effectiveConfig?: ConfigReadResponse | null; - availableModels?: readonly PanelModelOption[]; - availableSkills?: readonly PanelSkillOption[]; + availableModels?: readonly ModelMetadata[]; + availableSkills?: readonly SkillMetadata[]; rateLimit?: RateLimitSnapshot | null; appServerDiagnostics?: AppServerDiagnostics; }; interface ThreadListAppliedAction { type: "thread-list/applied"; - threads?: readonly PanelThread[]; + threads?: readonly Thread[]; threadsLoaded?: boolean; } @@ -132,7 +132,7 @@ type RuntimeAction = | { type: "runtime/requested-effort-set"; effort: ReasoningEffort | null } | { type: "runtime/requested-service-tier-set"; serviceTier: RequestedServiceTier | null } | { type: "runtime/requested-approvals-reviewer-set"; approvalsReviewer: ApprovalsReviewer | null } - | { type: "runtime/requested-collaboration-mode-set"; collaborationMode: PanelCollaborationMode } + | { type: "runtime/requested-collaboration-mode-set"; collaborationMode: CollaborationMode } | { type: "runtime/pending-thread-settings-committed"; update: ThreadSettingsUpdate }; interface TurnStartedAction { diff --git a/src/features/chat/composer/suggestions.ts b/src/features/chat/composer/suggestions.ts index 9f4cfc31..d062cf7c 100644 --- a/src/features/chat/composer/suggestions.ts +++ b/src/features/chat/composer/suggestions.ts @@ -1,8 +1,8 @@ -import type { PanelThread } from "../../../domain/threads/model"; -import type { PanelModelOption, PanelSkillOption } from "../../../domain/catalog/metadata"; +import type { Thread } from "../../../domain/threads/model"; +import type { ModelMetadata, SkillMetadata } from "../../../domain/catalog/metadata"; import { prepareFuzzySearch, sortSearchResults, type SearchResult } from "obsidian"; -import { findModelOptionByIdOrName, sortedModelOptions } from "../../../domain/catalog/metadata"; -import { isReasoningEffort, REASONING_EFFORTS, supportedEffortsForModelOption } from "../../../domain/catalog/metadata"; +import { findModelMetadataByIdOrName, sortedModelMetadata } from "../../../domain/catalog/metadata"; +import { isReasoningEffort, REASONING_EFFORTS, supportedEffortsForModelMetadata } from "../../../domain/catalog/metadata"; import { SLASH_COMMANDS, slashCommandSubcommands, type SlashCommandName } from "./slash-commands"; import { getThreadTitle } from "../../../domain/threads/model"; import { shortThreadId } from "../../../utils"; @@ -52,9 +52,9 @@ export function parseSlashCommand(text: string): { command: SlashCommandName; ar export function activeComposerSuggestions( beforeCursor: string, notes: NoteCandidate[], - skills: readonly PanelSkillOption[], - threads: readonly PanelThread[] = [], - models: readonly PanelModelOption[] = [], + skills: readonly SkillMetadata[], + threads: readonly Thread[] = [], + models: readonly ModelMetadata[] = [], currentModel: string | null = null, ): ComposerSuggestion[] { return ( @@ -269,7 +269,7 @@ function activeSlashSubcommandSuggestions(beforeCursor: string): ComposerSuggest })); } -function activeThreadCommandSuggestions(beforeCursor: string, threads: readonly PanelThread[]): ComposerSuggestion[] | null { +function activeThreadCommandSuggestions(beforeCursor: string, threads: readonly Thread[]): ComposerSuggestion[] | null { const completion = activeCommandArgumentCompletionQuery(beforeCursor, /^\/(?:resume|refer|archive|rename)\s+([^\s\n]{0,120})$/); if (!completion) return null; @@ -295,7 +295,7 @@ function activeThreadCommandSuggestions(beforeCursor: string, threads: readonly })); } -function activeModelOverrideSuggestions(beforeCursor: string, models: readonly PanelModelOption[]): ComposerSuggestion[] | null { +function activeModelOverrideSuggestions(beforeCursor: string, models: readonly ModelMetadata[]): ComposerSuggestion[] | null { const completion = activeCommandArgumentCompletionQuery(beforeCursor, /^\/model\s+([^\n]{0,120})$/); if (!completion) return null; @@ -310,7 +310,7 @@ function activeModelOverrideSuggestions(beforeCursor: string, models: readonly P start, appendSpaceOnInsert: true, }, - ...sortedModelOptions(models) + ...sortedModelMetadata(models) .map((model, index) => { const id = model.id.toLowerCase(); const name = model.model.toLowerCase(); @@ -336,7 +336,7 @@ function activeModelOverrideSuggestions(beforeCursor: string, models: readonly P function activeReasoningEffortSuggestions( beforeCursor: string, - models: readonly PanelModelOption[], + models: readonly ModelMetadata[], currentModel: string | null, ): ComposerSuggestion[] | null { const completion = activeCommandArgumentCompletionQuery(beforeCursor, /^\/reasoning\s+([^\n]{0,120})$/); @@ -344,8 +344,8 @@ function activeReasoningEffortSuggestions( const { query, start } = completion; if (query === "default" || isReasoningEffort(query)) return null; - const model = findModelOptionByIdOrName(models, currentModel); - const efforts = model ? supportedEffortsForModelOption(model) : REASONING_EFFORTS; + const model = findModelMetadataByIdOrName(models, currentModel); + const efforts = model ? supportedEffortsForModelMetadata(model) : REASONING_EFFORTS; const modelDetail = model ? `Supported by ${model.model}` : "Supported reasoning effort"; const suggestions = [ { @@ -378,7 +378,7 @@ function activeCommandArgumentCompletionQuery(beforeCursor: string, pattern: Reg return { query, start: beforeCursor.length - rawQuery.length }; } -function activeSkillSuggestions(beforeCursor: string, skills: readonly PanelSkillOption[]): ComposerSuggestion[] | null { +function activeSkillSuggestions(beforeCursor: string, skills: readonly SkillMetadata[]): ComposerSuggestion[] | null { const match = /(^|[\s([{])\$([^\s\])}]{0,120})$/.exec(beforeCursor); if (match?.index === undefined) return null; diff --git a/src/features/chat/composer/wikilink-context.ts b/src/features/chat/composer/wikilink-context.ts index 94a3b07f..4c6782dc 100644 --- a/src/features/chat/composer/wikilink-context.ts +++ b/src/features/chat/composer/wikilink-context.ts @@ -1,5 +1,5 @@ import type { UserInput } from "../../../generated/app-server/v2/UserInput"; -import type { PanelSkillOption } from "../../../domain/catalog/metadata"; +import type { SkillMetadata } from "../../../domain/catalog/metadata"; import { parseObsidianWikiLink } from "../../../shared/obsidian/wikilinks"; export interface ParsedWikiLink { @@ -38,7 +38,7 @@ export function userInputWithWikiLinkMentions(text: string, resolveMention: Wiki export function userInputWithWikiLinkMentionsAndSkills( text: string, resolveMention: WikiLinkMentionResolver, - skills: readonly PanelSkillOption[], + skills: readonly SkillMetadata[], ): UserInput[] { const input: UserInput[] = [{ type: "text", text, text_elements: [] }]; const seenPaths = new Set(); @@ -81,8 +81,8 @@ function parseWikiLink(raw: string): ParsedWikiLink | null { return parsed ? { raw, ...parsed } : null; } -function firstEnabledSkillByName(skills: readonly PanelSkillOption[]): Map { - const byName = new Map(); +function firstEnabledSkillByName(skills: readonly SkillMetadata[]): Map { + const byName = new Map(); for (const skill of skills) { if (!skill.enabled) continue; const key = skill.name.toLowerCase(); diff --git a/src/features/chat/panel/context.ts b/src/features/chat/panel/context.ts index 7ef06284..8653e68d 100644 --- a/src/features/chat/panel/context.ts +++ b/src/features/chat/panel/context.ts @@ -24,7 +24,7 @@ export interface ChatPanelContext { lifecycle: ChatPanelLifecycleContext; render: ChatPanelRenderContext; runtime: ChatPanelRuntimeContext; - thread: ChatPanelThreadContext; + thread: ChatThreadContext; liveState: ChatPanelLiveStateContext; scroll: ChatPanelScrollContext; status: ChatPanelStatusContext; @@ -99,7 +99,7 @@ interface ChatPanelRuntimeContext { statusSummaryLines: () => string[]; } -interface ChatPanelThreadContext { +interface ChatThreadContext { ensureRestoredThreadLoaded: () => Promise; startNewThread: () => Promise; selectThread: (threadId: string) => Promise; diff --git a/src/features/chat/panel/model/runtime.ts b/src/features/chat/panel/model/runtime.ts index 99e87136..937583d2 100644 --- a/src/features/chat/panel/model/runtime.ts +++ b/src/features/chat/panel/model/runtime.ts @@ -6,7 +6,7 @@ import { serviceTierLabel, supportedReasoningEfforts, } from "../../runtime/effective-settings"; -import { sortedModelOptions } from "../../../../domain/catalog/metadata"; +import { sortedModelMetadata } from "../../../../domain/catalog/metadata"; import { contextSummary, rateLimitSummary, type RateLimitSummary } from "../../runtime/status-summary"; import type { EffortStatusLinesInput, @@ -46,7 +46,7 @@ export function runtimeComposerChoices(input: RuntimeComposerChoicesInput): { } { const config = readRuntimeConfig(input.state.connection.effectiveConfig); const activeModel = currentModel(input.snapshot, config); - const models = sortedModelOptions(input.state.connection.availableModels); + const models = sortedModelMetadata(input.state.connection.availableModels); const modelChoices: RuntimeChoice[] = models.slice(0, 12).map((model) => ({ label: model.model, selected: activeModel === model.model, diff --git a/src/features/chat/panel/model/toolbar.ts b/src/features/chat/panel/model/toolbar.ts index a31def41..badc3528 100644 --- a/src/features/chat/panel/model/toolbar.ts +++ b/src/features/chat/panel/model/toolbar.ts @@ -1,4 +1,4 @@ -import type { PanelThread } from "../../../../domain/threads/model"; +import type { Thread } from "../../../../domain/threads/model"; import { getThreadTitle } from "../../../../domain/threads/model"; import { effectiveConfigSections, rateLimitSummary } from "../../runtime/status-summary"; import { connectionDiagnosticSections } from "../../diagnostics"; @@ -36,7 +36,7 @@ export function toolbarViewModel(input: ToolbarViewModelInput): ToolbarViewModel } function toolbarThreadRows(input: { - threads: readonly PanelThread[]; + threads: readonly Thread[]; activeThreadId: string | null; turnBusy: boolean; archiveConfirmThreadId: string | null; diff --git a/src/features/chat/panel/snapshot.ts b/src/features/chat/panel/snapshot.ts index 3a3524eb..2b6c1171 100644 --- a/src/features/chat/panel/snapshot.ts +++ b/src/features/chat/panel/snapshot.ts @@ -1,4 +1,4 @@ -import type { PanelThread } from "../../../domain/threads/model"; +import type { Thread } from "../../../domain/threads/model"; import type { OpenCodexPanelSnapshot } from "../../../workspace/open-panel-snapshot"; import { readRuntimeConfig } from "../runtime/config"; import { currentModel } from "../runtime/effective-settings"; @@ -154,7 +154,7 @@ function displayItemsSignature(items: readonly DisplayItem[]): string { return stableSignature(items); } -function threadListSignature(threads: readonly PanelThread[]): string { +function threadListSignature(threads: readonly Thread[]): string { return threads.map((thread) => signatureParts(thread.id, thread.name, thread.preview, thread.updatedAt, thread.archived)).join("\n"); } diff --git a/src/features/chat/runtime/collaboration.ts b/src/features/chat/runtime/collaboration.ts index e4119ca6..f38b13d7 100644 --- a/src/features/chat/runtime/collaboration.ts +++ b/src/features/chat/runtime/collaboration.ts @@ -1,13 +1,13 @@ -export type PanelCollaborationMode = "default" | "plan"; +export type CollaborationMode = "default" | "plan"; -export function nextCollaborationMode(mode: PanelCollaborationMode): PanelCollaborationMode { +export function nextCollaborationMode(mode: CollaborationMode): CollaborationMode { return mode === "plan" ? "default" : "plan"; } -export function collaborationModeLabel(mode: PanelCollaborationMode): string { +export function collaborationModeLabel(mode: CollaborationMode): string { return mode === "plan" ? "Plan" : "Default"; } -export function collaborationModeToggleMessage(mode: PanelCollaborationMode): string { +export function collaborationModeToggleMessage(mode: CollaborationMode): string { return mode === "plan" ? "Plan mode on for subsequent turns." : "Plan mode off for subsequent turns."; } diff --git a/src/features/chat/runtime/effective-settings.ts b/src/features/chat/runtime/effective-settings.ts index 91ce209f..6b4cb5ae 100644 --- a/src/features/chat/runtime/effective-settings.ts +++ b/src/features/chat/runtime/effective-settings.ts @@ -3,7 +3,7 @@ import type { AskForApproval } from "../../../generated/app-server/v2/AskForAppr import type { ConfigReadResponse } from "../../../generated/app-server/v2/ConfigReadResponse"; import type { RateLimitSnapshot } from "../../../generated/app-server/v2/RateLimitSnapshot"; import type { ThreadTokenUsage } from "../../../generated/app-server/v2/ThreadTokenUsage"; -import { findModelOptionByIdOrName, type PanelModelOption } from "../../../domain/catalog/metadata"; +import { findModelMetadataByIdOrName, type ModelMetadata } from "../../../domain/catalog/metadata"; import { configuredServiceTierRequestValue, clearedServiceTierRequestValue, @@ -11,9 +11,9 @@ import { type ServiceTier, type ServiceTierRequest, } from "../../../app-server/thread-settings"; -import { supportedEffortsForModelOption, type ReasoningEffort } from "../../../domain/catalog/metadata"; +import { supportedEffortsForModelMetadata, type ReasoningEffort } from "../../../domain/catalog/metadata"; import { readRuntimeConfig, type RuntimeConfigProjection } from "./config"; -import type { PanelCollaborationMode } from "./collaboration"; +import type { CollaborationMode } from "./collaboration"; import { isAutoReviewReviewer, type ApprovalsReviewer } from "./approvals"; import { isFastServiceTier, type RequestedServiceTier } from "./service-tier-state"; @@ -24,7 +24,7 @@ export interface RuntimeSnapshot { activeThreadId: string | null; activeModel: string | null; activeReasoningEffort: ReasoningEffort | null; - activeCollaborationMode: PanelCollaborationMode; + activeCollaborationMode: CollaborationMode; activeServiceTier: ServiceTier | null; activeApprovalPolicy: AskForApproval | null; activeApprovalsReviewer: ApprovalsReviewer | null; @@ -32,12 +32,12 @@ export interface RuntimeSnapshot { requestedModel: PendingRuntimeSetting; requestedReasoningEffort: PendingRuntimeSetting; requestedApprovalsReviewer: PendingRuntimeSetting; - selectedCollaborationMode: PanelCollaborationMode; + selectedCollaborationMode: CollaborationMode; requestedServiceTier: PendingRuntimeSetting; tokenUsage: ThreadTokenUsage | null; rateLimit: RateLimitSnapshot | null; hasThreadTurns: boolean; - availableModels: readonly PanelModelOption[]; + availableModels: readonly ModelMetadata[]; } export function currentServiceTier( @@ -109,7 +109,7 @@ export function autoReviewActive( export function supportedReasoningEfforts(snapshot: RuntimeSnapshot): ReasoningEffort[] { const model = currentModel(snapshot); - return supportedEffortsForModelOption(findModelOptionByIdOrName(snapshot.availableModels, model)); + return supportedEffortsForModelMetadata(findModelMetadataByIdOrName(snapshot.availableModels, model)); } export function serviceTierLabel( @@ -170,6 +170,6 @@ export function pendingRuntimeSettingLabel(setting: PendingRuntimeSetting) function currentModelServiceTiers( snapshot: RuntimeSnapshot, config: RuntimeConfigProjection = readRuntimeConfig(snapshot.effectiveConfig), -): PanelModelOption["serviceTiers"] { - return findModelOptionByIdOrName(snapshot.availableModels, currentModel(snapshot, config))?.serviceTiers ?? []; +): ModelMetadata["serviceTiers"] { + return findModelMetadataByIdOrName(snapshot.availableModels, currentModel(snapshot, config))?.serviceTiers ?? []; } diff --git a/src/features/chat/runtime/runtime-settings-actions.ts b/src/features/chat/runtime/runtime-settings-actions.ts index 671891a9..49135675 100644 --- a/src/features/chat/runtime/runtime-settings-actions.ts +++ b/src/features/chat/runtime/runtime-settings-actions.ts @@ -1,7 +1,7 @@ import type { AppServerClient } from "../../../app-server/client"; import type { ReasoningEffort } from "../../../domain/catalog/metadata"; import { autoReviewReviewerForState, autoReviewToggleMessage, nextAutoReviewState } from "./approvals"; -import type { PanelCollaborationMode } from "./collaboration"; +import type { CollaborationMode } from "./collaboration"; import { collaborationModeToggleMessage, nextCollaborationMode } from "./collaboration"; import { readRuntimeConfig } from "./config"; import { autoReviewActive, fastModeActive, type RuntimeSnapshot } from "./effective-settings"; @@ -41,7 +41,7 @@ export interface ChatRuntimeSettingsActions { setRequestedReasoningEffortFromUi: (effort: ReasoningEffort | null) => Promise; toggleFastMode: () => Promise; toggleCollaborationMode: () => Promise; - setCollaborationMode: (collaborationMode: PanelCollaborationMode) => Promise; + setCollaborationMode: (collaborationMode: CollaborationMode) => Promise; toggleAutoReview: () => Promise; } @@ -119,7 +119,7 @@ async function toggleCollaborationMode(host: RuntimeSettingsActionsHost): Promis await setCollaborationMode(host, next); } -async function setCollaborationMode(host: RuntimeSettingsActionsHost, collaborationMode: PanelCollaborationMode): Promise { +async function setCollaborationMode(host: RuntimeSettingsActionsHost, collaborationMode: CollaborationMode): Promise { dispatch(host, { type: "runtime/requested-collaboration-mode-set", collaborationMode }); dispatch(host, { type: "ui/panel-set", panel: null }); const result = await applyPendingThreadSettingsResult(host); diff --git a/src/features/chat/runtime/service-tier-state.ts b/src/features/chat/runtime/service-tier-state.ts index 10a0ab65..fe23d312 100644 --- a/src/features/chat/runtime/service-tier-state.ts +++ b/src/features/chat/runtime/service-tier-state.ts @@ -1,8 +1,8 @@ -import type { PanelModelOption } from "../../../domain/catalog/metadata"; +import type { ModelMetadata } from "../../../domain/catalog/metadata"; export type RequestedServiceTier = "fast" | "off"; -export function isFastServiceTier(value: string | null | undefined, serviceTiers: PanelModelOption["serviceTiers"] = []): boolean { +export function isFastServiceTier(value: string | null | undefined, serviceTiers: ModelMetadata["serviceTiers"] = []): boolean { if (!value) return false; if (value === "fast") return true; if (serviceTiers.length === 0) return value === "priority"; diff --git a/src/features/chat/runtime/state.ts b/src/features/chat/runtime/state.ts index d03ce288..a1ffb629 100644 --- a/src/features/chat/runtime/state.ts +++ b/src/features/chat/runtime/state.ts @@ -1,7 +1,7 @@ import type { ActivePermissionProfile } from "../../../generated/app-server/v2/ActivePermissionProfile"; import type { AskForApproval } from "../../../generated/app-server/v2/AskForApproval"; import { parseServiceTier, type ServiceTier, type ThreadSettingsUpdate } from "../../../app-server/thread-settings"; -import type { PanelCollaborationMode } from "./collaboration"; +import type { CollaborationMode } from "./collaboration"; import type { ReasoningEffort } from "../../../domain/catalog/metadata"; import type { ApprovalsReviewer } from "./approvals"; import type { RequestedServiceTier } from "./service-tier-state"; @@ -15,7 +15,7 @@ import { export interface ChatRuntimeState { activeModel: string | null; activeReasoningEffort: ReasoningEffort | null; - activeCollaborationMode: PanelCollaborationMode; + activeCollaborationMode: CollaborationMode; activeServiceTier: ServiceTier | null; activeApprovalPolicy: AskForApproval | null; activeApprovalsReviewer: ApprovalsReviewer | null; @@ -23,7 +23,7 @@ export interface ChatRuntimeState { requestedModel: PendingRuntimeSetting; requestedReasoningEffort: PendingRuntimeSetting; requestedApprovalsReviewer: PendingRuntimeSetting; - selectedCollaborationMode: PanelCollaborationMode; + selectedCollaborationMode: CollaborationMode; requestedServiceTier: PendingRuntimeSetting; } @@ -90,10 +90,7 @@ export function setRequestedApprovalsReviewerRuntimeState( }; } -export function setSelectedCollaborationModeRuntimeState( - state: ChatRuntimeState, - collaborationMode: PanelCollaborationMode, -): ChatRuntimeState { +export function setSelectedCollaborationModeRuntimeState(state: ChatRuntimeState, collaborationMode: CollaborationMode): ChatRuntimeState { return { ...state, selectedCollaborationMode: collaborationMode, diff --git a/src/features/chat/runtime/status-summary.ts b/src/features/chat/runtime/status-summary.ts index 24466b82..0c941150 100644 --- a/src/features/chat/runtime/status-summary.ts +++ b/src/features/chat/runtime/status-summary.ts @@ -2,8 +2,8 @@ import type { RateLimitWindow } from "../../../generated/app-server/v2/RateLimit import type { SpendControlLimitSnapshot } from "../../../generated/app-server/v2/SpendControlLimitSnapshot"; import type { ThreadTokenUsage } from "../../../generated/app-server/v2/ThreadTokenUsage"; import { jsonPreview } from "../../../utils"; -import { sortedModelOptions } from "../../../domain/catalog/metadata"; -import { defaultEffortForModelOption } from "../../../domain/catalog/metadata"; +import { sortedModelMetadata } from "../../../domain/catalog/metadata"; +import { defaultEffortForModelMetadata } from "../../../domain/catalog/metadata"; import { readRuntimeConfig, type RuntimeConfigProjection } from "./config"; import { currentApprovalsReviewer, @@ -184,14 +184,14 @@ function contextUsageTokens(usage: ThreadTokenUsage): number { function configuredModel(snapshot: RuntimeSnapshot, config: RuntimeConfigProjection): string | null { if (config.model) return config.model; - return sortedModelOptions(snapshot.availableModels).find((model) => model.isDefault)?.model ?? null; + return sortedModelMetadata(snapshot.availableModels).find((model) => model.isDefault)?.model ?? null; } function configuredReasoningEffort(snapshot: RuntimeSnapshot, config: RuntimeConfigProjection): string | null { if (config.rawReasoningEffort) return config.rawReasoningEffort; const model = configuredModel(snapshot, config); - return defaultEffortForModelOption( - sortedModelOptions(snapshot.availableModels).find((availableModel) => availableModel.model === model) ?? null, + return defaultEffortForModelMetadata( + sortedModelMetadata(snapshot.availableModels).find((availableModel) => availableModel.model === model) ?? null, ); } diff --git a/src/features/chat/threads/thread-actions.ts b/src/features/chat/threads/thread-actions.ts index 461adeba..c3dff974 100644 --- a/src/features/chat/threads/thread-actions.ts +++ b/src/features/chat/threads/thread-actions.ts @@ -1,7 +1,7 @@ import { Notice } from "obsidian"; import type { AppServerClient } from "../../../app-server/client"; -import { panelThreadFromAppServerThread } from "../../../app-server/thread-model"; +import { threadFromAppServerThread } from "../../../app-server/thread-model"; import { exportArchivedThreadMarkdown } from "../../../domain/threads/export"; import type { ArchiveExportAdapter } from "../../../domain/threads/export"; import { inheritedForkThreadName } from "../../../domain/threads/model"; @@ -88,7 +88,7 @@ async function archiveThreadOnServer( if (saveMarkdown) { const response = await client.readThread(threadId, true); const result = await exportArchivedThreadMarkdown( - { ...panelThreadFromAppServerThread(response.thread, { archived: true }), turns: response.thread.turns }, + { ...threadFromAppServerThread(response.thread, { archived: true }), turns: response.thread.turns }, { ...settings, vaultPath: host.vaultPath }, host.archiveAdapter(), ); @@ -182,7 +182,7 @@ async function rollbackThread(host: ChatThreadActionsHost, threadId: string): Pr try { host.setStatus("Rolling back latest turn..."); const response = await client.rollbackThread(threadId); - const thread = panelThreadFromAppServerThread(response.thread); + const thread = threadFromAppServerThread(response.thread); dispatch( host, resumedThreadActionFromActiveRuntime({ diff --git a/src/features/chat/threads/thread-rename-controller.ts b/src/features/chat/threads/thread-rename-controller.ts index 5de065ed..58a16f7d 100644 --- a/src/features/chat/threads/thread-rename-controller.ts +++ b/src/features/chat/threads/thread-rename-controller.ts @@ -6,7 +6,7 @@ import { THREAD_NAMING_CONTEXT_UNAVAILABLE_MESSAGE, type ThreadNamingContext, } from "../../../domain/threads/naming"; -import type { PanelThread } from "../../../domain/threads/model"; +import type { Thread } from "../../../domain/threads/model"; import type { Turn } from "../../../generated/app-server/v2/Turn"; import type { CodexPanelSettings } from "../../../settings/model"; import type { ChatAction, ChatState, ChatStateStore } from "../chat-state"; @@ -257,7 +257,7 @@ export class ThreadRenameController { return Boolean(this.thread(threadId)?.name?.trim()); } - private thread(threadId: string): PanelThread | undefined { + private thread(threadId: string): Thread | undefined { return this.state.threadList.listedThreads.find((item) => item.id === threadId); } } diff --git a/src/features/chat/threads/thread-resume.ts b/src/features/chat/threads/thread-resume.ts index dba9200d..63a853f8 100644 --- a/src/features/chat/threads/thread-resume.ts +++ b/src/features/chat/threads/thread-resume.ts @@ -1,9 +1,9 @@ import { parseServiceTier } from "../../../app-server/thread-settings"; import { upsertThread } from "../../../domain/threads/model"; -import { panelThreadFromAppServerThread } from "../../../app-server/thread-model"; +import { threadFromAppServerThread } from "../../../app-server/thread-model"; import type { ReasoningEffort } from "../../../domain/catalog/metadata"; import type { AskForApproval } from "../../../generated/app-server/v2/AskForApproval"; -import type { PanelThread } from "../../../domain/threads/model"; +import type { Thread } from "../../../domain/threads/model"; import type { ThreadStartResponse } from "../../../generated/app-server/v2/ThreadStartResponse"; import type { ThreadResumeResponse } from "../../../generated/app-server/v2/ThreadResumeResponse"; import type { ChatRuntimeState } from "../runtime/state"; @@ -11,7 +11,7 @@ import type { DisplayItem } from "../display/types"; import type { ActiveThreadResumedAction } from "../chat-state-actions"; interface ThreadActivationResponse { - thread: PanelThread; + thread: Thread; cwd: string; model: string | null; serviceTier: string | null; @@ -23,18 +23,18 @@ interface ThreadActivationResponse { export interface ResumedThreadActionParams { response: ThreadActivationResponse; - listedThreads?: readonly PanelThread[]; + listedThreads?: readonly Thread[]; displayItems?: readonly DisplayItem[]; } export interface ResumedThreadFromAppServerParams { response: ThreadStartResponse | ThreadResumeResponse; - listedThreads?: readonly PanelThread[]; + listedThreads?: readonly Thread[]; displayItems?: readonly DisplayItem[]; } export interface ResumedThreadFromActiveRuntimeParams { - thread: PanelThread; + thread: Thread; cwd: string; runtime: Pick< ChatRuntimeState, @@ -45,7 +45,7 @@ export interface ResumedThreadFromActiveRuntimeParams { | "activeApprovalsReviewer" | "activePermissionProfile" >; - listedThreads?: readonly PanelThread[]; + listedThreads?: readonly Thread[]; displayItems?: readonly DisplayItem[]; } @@ -93,7 +93,7 @@ export function resumedThreadAction(params: ResumedThreadActionParams): ActiveTh function threadActivationResponseFromAppServerResponse(response: ThreadStartResponse | ThreadResumeResponse): ThreadActivationResponse { return { - thread: panelThreadFromAppServerThread(response.thread), + thread: threadFromAppServerThread(response.thread), cwd: response.cwd, model: response.model, reasoningEffort: response.reasoningEffort, diff --git a/src/features/chat/turns/slash-command-actions.ts b/src/features/chat/turns/slash-command-actions.ts index dc5b5c9d..5c48831f 100644 --- a/src/features/chat/turns/slash-command-actions.ts +++ b/src/features/chat/turns/slash-command-actions.ts @@ -4,7 +4,7 @@ import { referencedThreadTurns, REFERENCED_THREAD_TURN_LIMIT, } from "../../../domain/threads/reference"; -import type { PanelThread } from "../../../domain/threads/model"; +import type { Thread } from "../../../domain/threads/model"; import { executeSlashCommand as runSlashCommand, type SlashCommandExecutionResult, @@ -128,7 +128,7 @@ async function executeSlashCommand( async function referencedThreadInput( host: SlashCommandActionsHost, client: AppServerClient, - thread: PanelThread, + thread: Thread, message: string, ): Promise { try { diff --git a/src/features/chat/turns/slash-command-execution.ts b/src/features/chat/turns/slash-command-execution.ts index a2c3ab4a..4376cba3 100644 --- a/src/features/chat/turns/slash-command-execution.ts +++ b/src/features/chat/turns/slash-command-execution.ts @@ -1,5 +1,5 @@ import type { ReasoningEffort } from "../../../domain/catalog/metadata"; -import type { PanelThread } from "../../../domain/threads/model"; +import type { Thread } from "../../../domain/threads/model"; import type { ThreadGoal } from "../../../generated/app-server/v2/ThreadGoal"; import type { ThreadGoalStatus } from "../../../generated/app-server/v2/ThreadGoalStatus"; import type { UserInput } from "../../../generated/app-server/v2/UserInput"; @@ -24,11 +24,11 @@ import { export interface SlashCommandExecutionContext { activeThreadId: string | null; busy: boolean; - listedThreads: readonly PanelThread[]; + listedThreads: readonly Thread[]; startNewThread: () => Promise; startThreadForGoal: (objective: string) => Promise; resumeThread: (threadId: string) => Promise; - referThread: (thread: PanelThread, message: string) => Promise; + referThread: (thread: Thread, message: string) => Promise; forkThread: (threadId: string) => Promise; rollbackThread: (threadId: string) => Promise; compactThread: (threadId: string) => Promise; @@ -392,7 +392,7 @@ function lineToRow(line: string): DisplayDetailMetaRow { return { key: "message", value: line }; } -type ThreadResolution = { ok: true; thread: PanelThread } | { ok: false; message: string }; +type ThreadResolution = { ok: true; thread: Thread } | { ok: false; message: string }; function parseReferArgs(args: string): { threadQuery: string; message: string } | null { const parsed = parseThreadAndTextArgs(args); @@ -414,7 +414,7 @@ function parseThreadAndNameArgs(args: string): { threadQuery: string; text: stri return text ? { threadQuery: parsed.threadQuery, text } : null; } -function resolveThreadArgument(args: string, threads: readonly PanelThread[]): ThreadResolution { +function resolveThreadArgument(args: string, threads: readonly Thread[]): ThreadResolution { const query = args.trim(); if (!query) { const thread = threads.at(0); diff --git a/src/features/chat/view.ts b/src/features/chat/view.ts index 577461a0..ff70fa87 100644 --- a/src/features/chat/view.ts +++ b/src/features/chat/view.ts @@ -4,8 +4,8 @@ import type { AppServerClient } from "../../app-server/client"; import { VIEW_TYPE_CODEX_PANEL } from "../../constants"; import type { DisplayDetailSection, DisplayItem } from "./display/types"; import type { ReasoningEffort } from "../../domain/catalog/metadata"; -import type { PanelModelOption } from "../../domain/catalog/metadata"; -import type { PanelThread } from "../../domain/threads/model"; +import type { ModelMetadata } from "../../domain/catalog/metadata"; +import type { Thread } from "../../domain/threads/model"; import { collaborationModeLabel as formatCollaborationModeLabel } from "./runtime/collaboration"; import type { RuntimeSnapshot } from "./runtime/effective-settings"; import { chatTurnBusy, createChatStateStore, type ChatState, type ChatAction } from "./chat-state"; @@ -409,7 +409,7 @@ export class CodexChatView extends ItemView { return this.loadSharedThreadList(); } - applyThreadListSnapshot(threads: readonly PanelThread[]): void { + applyThreadListSnapshot(threads: readonly Thread[]): void { this.controllers.appServer.threads.applyThreadList(threads); this.refreshTabHeader(); this.controllers.render.controller.render(); @@ -420,7 +420,7 @@ export class CodexChatView extends ItemView { this.controllers.render.controller.render(); } - applyAvailableModelsSnapshot(models: readonly PanelModelOption[]): void { + applyAvailableModelsSnapshot(models: readonly ModelMetadata[]): void { this.dispatch({ type: "connection/metadata-applied", availableModels: models }); this.controllers.render.controller.render(); } diff --git a/src/features/selection-rewrite/runner.ts b/src/features/selection-rewrite/runner.ts index 68d6fba9..6e8fec30 100644 --- a/src/features/selection-rewrite/runner.ts +++ b/src/features/selection-rewrite/runner.ts @@ -6,9 +6,9 @@ import { type StructuredTurnOutputSchema, } from "../../app-server/ephemeral-structured-turn"; import type { ReasoningEffort } from "../../domain/catalog/metadata"; -import { panelModelOptionsFromAppServerModels } from "../../app-server/catalog-model"; -import type { PanelModelOption } from "../../domain/catalog/metadata"; -import { runtimeOverride, validatedRuntimeOverrideForModelOptions } from "../../domain/catalog/runtime-overrides"; +import { modelMetadataFromAppServerModels } from "../../app-server/catalog-model"; +import type { ModelMetadata } from "../../domain/catalog/metadata"; +import { runtimeOverride, validatedRuntimeOverrideForModelMetadata } from "../../domain/catalog/runtime-overrides"; import type { SelectionRewriteRuntimeSettings } from "./model"; import { SELECTION_REWRITE_DEVELOPER_INSTRUCTIONS, SELECTION_REWRITE_SERVICE_NAME } from "./prompt"; import { SelectionRewriteOutputError, selectionRewriteOutputParseResultFromTurn, type SelectionRewriteOutput } from "./output"; @@ -86,9 +86,9 @@ export function selectionRewriteRuntimeOverride(settings: SelectionRewriteRuntim export function validatedSelectionRewriteRuntimeOverride( settings: SelectionRewriteRuntimeSettings, - models: readonly PanelModelOption[], + models: readonly ModelMetadata[], ): SelectionRewriteRuntimeOverride { - return validatedRuntimeOverrideForModelOptions( + return validatedRuntimeOverrideForModelMetadata( { model: settings.rewriteSelectionModel, effort: settings.rewriteSelectionEffort }, models, ); @@ -102,7 +102,7 @@ async function selectionRewriteRuntimeOverrideForClient( if (!runtime.model || !runtime.effort) return runtime; try { const response = await client.listModels(false); - return validatedSelectionRewriteRuntimeOverride(settings, panelModelOptionsFromAppServerModels(response.data)); + return validatedSelectionRewriteRuntimeOverride(settings, modelMetadataFromAppServerModels(response.data)); } catch { return runtime; } diff --git a/src/features/thread-picker/modal.ts b/src/features/thread-picker/modal.ts index 19abfb29..048abfc0 100644 --- a/src/features/thread-picker/modal.ts +++ b/src/features/thread-picker/modal.ts @@ -1,9 +1,9 @@ import { Notice, Platform, SuggestModal, type App } from "obsidian"; -import { listPanelThreads } from "../../app-server/panel-data"; +import { listThreads } from "../../app-server/resource-operations"; import { withShortLivedAppServerClient } from "../../app-server/short-lived-client"; import { getThreadTitle } from "../../domain/threads/model"; -import type { PanelThread } from "../../domain/threads/model"; +import type { Thread } from "../../domain/threads/model"; import type { CodexPanelSettings } from "../../settings/model"; import { shortThreadId } from "../../utils"; @@ -11,14 +11,14 @@ export interface ThreadPickerHost { readonly app: App; readonly settings: CodexPanelSettings; readonly vaultPath: string; - cachedThreadList(): readonly PanelThread[] | null; - refreshThreadList(fetchThreads: () => Promise): Promise; + cachedThreadList(): readonly Thread[] | null; + refreshThreadList(fetchThreads: () => Promise): Promise; openThreadInCurrentView(threadId: string): Promise; openThreadInAvailableView(threadId: string): Promise; } interface ThreadSuggestion { - thread: PanelThread; + thread: Thread; title: string; } @@ -41,7 +41,7 @@ export async function openThreadPicker(host: ThreadPickerHost): Promise { } } -export function threadPickerSuggestions(threads: readonly PanelThread[], queryText: string): ThreadSuggestion[] { +export function threadPickerSuggestions(threads: readonly Thread[], queryText: string): ThreadSuggestion[] { const query = queryText.trim().toLowerCase(); return [...threads] .sort((a, b) => b.updatedAt - a.updatedAt) @@ -78,7 +78,7 @@ export function threadOpenModeFromEvent(evt: MouseEvent | KeyboardEvent): Thread return "current"; } -async function loadThreadPickerThreads(host: ThreadPickerHost): Promise { +async function loadThreadPickerThreads(host: ThreadPickerHost): Promise { const cached = host.cachedThreadList(); if (cached) return cached; @@ -87,7 +87,7 @@ async function loadThreadPickerThreads(host: ThreadPickerHost): Promise host.refreshThreadList(async () => { - return listPanelThreads(client, host.vaultPath); + return listThreads(client, host.vaultPath); }), { unhandledServerRequestMessage: "Codex thread picker does not handle server requests.", @@ -98,7 +98,7 @@ async function loadThreadPickerThreads(host: ThreadPickerHost): Promise { constructor( private readonly host: ThreadPickerHost, - private readonly threads: readonly PanelThread[], + private readonly threads: readonly Thread[], ) { super(host.app); this.limit = MAX_THREAD_PICKER_SUGGESTIONS; diff --git a/src/features/threads-view/state.ts b/src/features/threads-view/state.ts index c19e1efe..64a4e9b5 100644 --- a/src/features/threads-view/state.ts +++ b/src/features/threads-view/state.ts @@ -1,5 +1,5 @@ import type { OpenCodexPanelSnapshot } from "../../workspace/open-panel-snapshot"; -import type { PanelThread } from "../../domain/threads/model"; +import type { Thread } from "../../domain/threads/model"; import { getThreadTitle } from "../../domain/threads/model"; type ThreadsLiveStatus = "needs-input" | "approval" | "running" | "draft" | "offline" | "open"; @@ -12,7 +12,7 @@ export interface ThreadsLiveState { } export interface ThreadsRowModel { - thread: PanelThread; + thread: Thread; title: string; live: ThreadsLiveState | null; selected: boolean; @@ -33,7 +33,7 @@ const STATUS_PRIORITY: Record = { }; export function threadRows( - threads: readonly PanelThread[], + threads: readonly Thread[], snapshots: OpenCodexPanelSnapshot[], renameStates: ReadonlyMap, archiveConfirmThreadId: string | null = null, diff --git a/src/features/threads-view/view.ts b/src/features/threads-view/view.ts index e175903f..29e99a82 100644 --- a/src/features/threads-view/view.ts +++ b/src/features/threads-view/view.ts @@ -2,10 +2,10 @@ import { ItemView, Notice, type WorkspaceLeaf } from "obsidian"; import type { AppServerClient } from "../../app-server/client"; import { ConnectionManager, StaleConnectionError } from "../../app-server/connection-manager"; -import { listPanelThreads } from "../../app-server/panel-data"; -import { panelThreadFromAppServerThread } from "../../app-server/thread-model"; +import { listThreads } from "../../app-server/resource-operations"; +import { threadFromAppServerThread } from "../../app-server/thread-model"; import { VIEW_TYPE_CODEX_THREADS } from "../../constants"; -import type { PanelThread } from "../../domain/threads/model"; +import type { Thread } from "../../domain/threads/model"; import type { CodexPanelSettings } from "../../settings/model"; import { exportArchivedThreadMarkdown } from "../../domain/threads/export"; import type { OpenCodexPanelSnapshot } from "../../workspace/open-panel-snapshot"; @@ -40,8 +40,8 @@ export interface CodexThreadsHost { getOpenPanelSnapshots(): OpenCodexPanelSnapshot[]; notifyThreadArchived(threadId: string, options?: { closeOpenPanels?: boolean }): void; notifyThreadRenamed(threadId: string, name: string | null): void; - refreshThreadList(fetchThreads: () => Promise): Promise; - cachedThreadList(): readonly PanelThread[] | null; + refreshThreadList(fetchThreads: () => Promise): Promise; + cachedThreadList(): readonly Thread[] | null; } type ThreadsViewStatus = @@ -58,7 +58,7 @@ export class CodexThreadsView extends ItemView { private connectionLifecycle: ThreadsViewConnectionLifecycleState = { kind: "idle" }; private refreshLifecycle: ThreadsViewRefreshLifecycleState = { kind: "idle" }; private status: ThreadsViewStatus = { kind: "idle" }; - private threads: readonly PanelThread[] = []; + private threads: readonly Thread[] = []; private readonly renameStates = new Map(); private archiveConfirmThreadId: string | null = null; @@ -132,7 +132,7 @@ export class CodexThreadsView extends ItemView { if (this.isStaleRefresh(refresh) || !this.client) return; const threads = await this.plugin.refreshThreadList(async () => { if (!this.client) return []; - return listPanelThreads(this.client, this.plugin.vaultPath); + return listThreads(this.client, this.plugin.vaultPath); }); if (this.isStaleRefresh(refresh)) return; this.threads = threads; @@ -253,7 +253,7 @@ export class CodexThreadsView extends ItemView { this.scheduleRender(); } - applyThreadListSnapshot(threads: readonly PanelThread[]): void { + applyThreadListSnapshot(threads: readonly Thread[]): void { this.threads = threads; this.status = threads.length === 0 ? { kind: "empty", message: "No threads" } : { kind: "idle" }; this.render(); @@ -367,7 +367,7 @@ export class CodexThreadsView extends ItemView { if (saveMarkdown) { const response = await this.client.readThread(threadId, true); const result = await exportArchivedThreadMarkdown( - { ...panelThreadFromAppServerThread(response.thread, { archived: true }), turns: response.thread.turns }, + { ...threadFromAppServerThread(response.thread, { archived: true }), turns: response.thread.turns }, { ...this.plugin.settings, vaultPath: this.plugin.vaultPath }, this.app.vault.adapter, ); diff --git a/src/settings/app-server-data.ts b/src/settings/app-server-data.ts index af34f10b..171bb2ce 100644 --- a/src/settings/app-server-data.ts +++ b/src/settings/app-server-data.ts @@ -1,17 +1,17 @@ import type { AppServerClient } from "../app-server/client"; -import { listPanelHookData, listPanelModelOptions, listPanelThreads, type PanelHookData } from "../app-server/panel-data"; -import type { PanelModelOption } from "../domain/catalog/metadata"; -import type { PanelThread } from "../domain/threads/model"; +import { listHookData, listModelMetadata, listThreads, type HookData } from "../app-server/resource-operations"; +import type { ModelMetadata } from "../domain/catalog/metadata"; +import type { Thread } from "../domain/threads/model"; import { errorMessage } from "../utils"; -export interface LoadedHooks extends PanelHookData { +export interface LoadedHooks extends HookData { status: string; } export interface SettingsDataLoad { - models: SettledSettingsData; + models: SettledSettingsData; hooks: SettledSettingsData; - archivedThreads: SettledSettingsData; + archivedThreads: SettledSettingsData; } type SettledSettingsData = @@ -27,9 +27,9 @@ type SettledSettingsData = export async function loadSettingsData(client: AppServerClient, cwd: string): Promise { const [modelsResult, hooksResult, archivedThreadsResult] = await Promise.allSettled([ - listPanelModelOptions(client), - listPanelHookData(client, cwd), - listPanelThreads(client, cwd, { archived: true }), + listModelMetadata(client), + listHookData(client, cwd), + listThreads(client, cwd, { archived: true }), ] as const); return { @@ -57,7 +57,7 @@ export async function loadSettingsData(client: AppServerClient, cwd: string): Pr } export async function loadHookData(client: AppServerClient, cwd: string): Promise { - const hooks = await listPanelHookData(client, cwd); + const hooks = await listHookData(client, cwd); return { ...hooks, status: hooksStatus(hooks.hooks.length), diff --git a/src/settings/dynamic-sections.ts b/src/settings/dynamic-sections.ts index 0c83d89c..dcf0455c 100644 --- a/src/settings/dynamic-sections.ts +++ b/src/settings/dynamic-sections.ts @@ -1,7 +1,7 @@ import { Setting } from "obsidian"; -import type { PanelHookItem } from "../domain/catalog/metadata"; -import type { PanelThread } from "../domain/threads/model"; +import type { HookItem } from "../domain/catalog/metadata"; +import type { Thread } from "../domain/threads/model"; import { archivedThreadDisplayTitle } from "../domain/threads/model"; import { shortThreadId } from "../utils"; @@ -10,7 +10,7 @@ export interface ArchivedThreadSectionState { exportFolderTemplate: string; exportFilenameTemplate: string; exportTags: string; - threads: PanelThread[]; + threads: Thread[]; loaded: boolean; loading: boolean; status: string; @@ -22,14 +22,14 @@ export interface ArchivedThreadSectionState { } export interface HookSectionState { - hooks: PanelHookItem[]; + hooks: HookItem[]; warnings: string[]; errors: string[]; loaded: boolean; loading: boolean; status: string; - onTrust(hook: PanelHookItem): void; - onToggleEnabled(hook: PanelHookItem, enabled: boolean): void; + onTrust(hook: HookItem): void; + onToggleEnabled(hook: HookItem, enabled: boolean): void; } export function renderHookSection(containerEl: HTMLElement, state: HookSectionState): void { @@ -166,7 +166,7 @@ function renderHooks(containerEl: HTMLElement, state: HookSectionState): void { } } -function renderHookRow(list: HTMLElement, hook: PanelHookItem, state: HookSectionState): void { +function renderHookRow(list: HTMLElement, hook: HookItem, state: HookSectionState): void { const canTrust = !hook.isManaged && (hook.trustStatus === "untrusted" || hook.trustStatus === "modified"); const hookName = firstNonEmptyString(hook.statusMessage, hook.command, hook.matcher, hook.eventName); const setting = new Setting(list) diff --git a/src/settings/tab.ts b/src/settings/tab.ts index 5b5c28da..fb044924 100644 --- a/src/settings/tab.ts +++ b/src/settings/tab.ts @@ -1,14 +1,14 @@ import { type App, Notice, type Plugin, PluginSettingTab, Setting, setIcon } from "obsidian"; import type { AppServerClient } from "../app-server/client"; -import { restoreArchivedPanelThread, setPanelHookEnabled, trustPanelHook } from "../app-server/panel-data"; +import { restoreArchivedThread, setHookItemEnabled, trustHookItem } from "../app-server/resource-operations"; import { withShortLivedAppServerClient } from "../app-server/short-lived-client"; import { DEFAULT_CODEX_PATH } from "../constants"; import type { ReasoningEffort } from "../domain/catalog/metadata"; -import type { PanelHookItem, PanelModelOption } from "../domain/catalog/metadata"; -import type { PanelThread } from "../domain/threads/model"; -import { REASONING_EFFORTS, supportedEffortsForModelOption } from "../domain/catalog/metadata"; -import { findModelOptionByIdOrName, sortedModelOptions } from "../domain/catalog/metadata"; +import type { HookItem, ModelMetadata } from "../domain/catalog/metadata"; +import type { Thread } from "../domain/threads/model"; +import { REASONING_EFFORTS, supportedEffortsForModelMetadata } from "../domain/catalog/metadata"; +import { findModelMetadataByIdOrName, sortedModelMetadata } from "../domain/catalog/metadata"; import { archivedThreadDisplayTitle } from "../domain/threads/model"; import { errorMessage } from "../utils"; import { @@ -37,13 +37,13 @@ export class CodexPanelSettingTab extends PluginSettingTab { private settingsDataAutoLoadStarted = false; private settingsDynamicOperationId = 0; private settingsDataRefreshLifecycle: SettingsDataRefreshLifecycleState = { kind: "idle" }; - private archivedThreads: PanelThread[] = []; + private archivedThreads: Thread[] = []; private archivedThreadsLifecycle = createSettingsDynamicSectionLifecycle(); - private hooks: PanelHookItem[] = []; + private hooks: HookItem[] = []; private hookWarnings: string[] = []; private hookErrors: string[] = []; private hooksLifecycle = createSettingsDynamicSectionLifecycle(); - private models: PanelModelOption[] = []; + private models: ModelMetadata[] = []; private modelsLifecycle = createSettingsDynamicSectionLifecycle(); constructor( @@ -127,7 +127,7 @@ export class CodexPanelSettingTab extends PluginSettingTab { .setDesc("Choose the model and reasoning effort used to suggest thread names.") .addDropdown((dropdown) => { const current = this.plugin.settings.threadNamingModel; - const options = this.modelOptions(); + const options = this.modelMetadata(); dropdown.selectEl.ariaLabel = "Automatic thread naming model"; dropdown.addOption(CODEX_DEFAULT_VALUE, "Codex default"); if (current && !options.some((model) => model.model === current || model.id === current)) { @@ -164,7 +164,7 @@ export class CodexPanelSettingTab extends PluginSettingTab { .setDesc("Choose the model and reasoning effort used by rewrite selection.") .addDropdown((dropdown) => { const current = this.plugin.settings.rewriteSelectionModel; - const options = this.modelOptions(); + const options = this.modelMetadata(); dropdown.selectEl.ariaLabel = "Selection rewrite model"; dropdown.addOption(CODEX_DEFAULT_VALUE, "Codex default"); if (current && !options.some((model) => model.model === current || model.id === current)) { @@ -394,7 +394,7 @@ export class CodexPanelSettingTab extends PluginSettingTab { } } - private async trustHook(hook: PanelHookItem): Promise { + private async trustHook(hook: HookItem): Promise { const operationId = this.nextSettingsDynamicOperationId(); this.hooksLifecycle = transitionSettingsDynamicSectionLifecycle(this.hooksLifecycle, { type: "started", @@ -403,7 +403,7 @@ export class CodexPanelSettingTab extends PluginSettingTab { }); this.display(); try { - await this.withSettingsConnection((client) => trustPanelHook(client, hook)); + await this.withSettingsConnection((client) => trustHookItem(client, hook)); this.hooksLifecycle = transitionSettingsDynamicSectionLifecycle(this.hooksLifecycle, { type: "loaded", status: "Trusted hook definition.", @@ -421,7 +421,7 @@ export class CodexPanelSettingTab extends PluginSettingTab { } } - private async setHookEnabled(hook: PanelHookItem, enabled: boolean): Promise { + private async setHookEnabled(hook: HookItem, enabled: boolean): Promise { const operationId = this.nextSettingsDynamicOperationId(); this.hooksLifecycle = transitionSettingsDynamicSectionLifecycle(this.hooksLifecycle, { type: "started", @@ -430,7 +430,7 @@ export class CodexPanelSettingTab extends PluginSettingTab { }); this.display(); try { - await this.withSettingsConnection((client) => setPanelHookEnabled(client, hook, enabled)); + await this.withSettingsConnection((client) => setHookItemEnabled(client, hook, enabled)); this.hooksLifecycle = transitionSettingsDynamicSectionLifecycle(this.hooksLifecycle, { type: "loaded", status: enabled ? "Enabled hook." : "Disabled hook.", @@ -478,7 +478,7 @@ export class CodexPanelSettingTab extends PluginSettingTab { }); this.display(); try { - const restoredThread = await this.withSettingsConnection((client) => restoreArchivedPanelThread(client, threadId)); + const restoredThread = await this.withSettingsConnection((client) => restoreArchivedThread(client, threadId)); this.archivedThreads = this.archivedThreads.filter((thread) => thread.id !== threadId); this.archivedThreadsLifecycle = transitionSettingsDynamicSectionLifecycle(this.archivedThreadsLifecycle, { type: "loaded", @@ -509,13 +509,13 @@ export class CodexPanelSettingTab extends PluginSettingTab { return this.settingsDynamicOperationId; } - private modelOptions(): PanelModelOption[] { - return sortedModelOptions(this.models); + private modelMetadata(): ModelMetadata[] { + return sortedModelMetadata(this.models); } private effortOptions(modelIdOrName: string | null): ReasoningEffort[] { const model = this.selectedModel(modelIdOrName); - return model ? supportedEffortsForModelOption(model) : [...REASONING_EFFORTS]; + return model ? supportedEffortsForModelMetadata(model) : [...REASONING_EFFORTS]; } private namingEffortSupported(effort: ReasoningEffort | null): boolean { @@ -526,8 +526,8 @@ export class CodexPanelSettingTab extends PluginSettingTab { return !effort || this.effortOptions(this.plugin.settings.rewriteSelectionModel).includes(effort); } - private selectedModel(modelIdOrName: string | null): PanelModelOption | null { - return findModelOptionByIdOrName(this.models, modelIdOrName); + private selectedModel(modelIdOrName: string | null): ModelMetadata | null { + return findModelMetadataByIdOrName(this.models, modelIdOrName); } } @@ -537,6 +537,6 @@ export interface CodexPanelSettingTabHost { saveSettings(): Promise; refreshOpenViews(): void; refreshSharedThreadListFromOpenSurface(): void; - cachedModels(): PanelModelOption[]; - publishModels(models: PanelModelOption[]): void; + cachedModels(): ModelMetadata[]; + publishModels(models: ModelMetadata[]): void; } diff --git a/src/workspace/panel-coordinator.ts b/src/workspace/panel-coordinator.ts index c180df5c..c26a0584 100644 --- a/src/workspace/panel-coordinator.ts +++ b/src/workspace/panel-coordinator.ts @@ -146,7 +146,7 @@ export class WorkspacePanelCoordinator { panelLeavesForThread(threadId: string): WorkspaceLeaf[] { return this.panelLeaves().filter((leaf) => { if (leaf.view instanceof CodexChatView) return leaf.view.openPanelSnapshot().threadId === threadId; - return restoredPanelThreadId(leaf) === threadId; + return restoredThreadId(leaf) === threadId; }); } @@ -211,7 +211,7 @@ export class WorkspacePanelCoordinator { private findRestoredThreadPanelTarget(threadId: string): ThreadPanelTarget | null { for (const leaf of this.panelLeaves()) { if (leaf.view instanceof CodexChatView) continue; - if (restoredPanelThreadId(leaf) !== threadId) continue; + if (restoredThreadId(leaf) !== threadId) continue; return { kind: "restored", leaf }; } return null; @@ -369,7 +369,7 @@ function focusedPanelViewId(leaf: WorkspaceLeaf | null): string | null { return leaf?.view instanceof CodexChatView ? leaf.view.openPanelSnapshot().viewId : null; } -function restoredPanelThreadId(leaf: WorkspaceLeaf): string | null { +function restoredThreadId(leaf: WorkspaceLeaf): string | null { const state = leaf.getViewState().state; if (!state || typeof state !== "object") return null; const threadId = (state as { threadId?: unknown }).threadId; diff --git a/src/workspace/thread-surface-coordinator.ts b/src/workspace/thread-surface-coordinator.ts index f2a24e12..a08d89ed 100644 --- a/src/workspace/thread-surface-coordinator.ts +++ b/src/workspace/thread-surface-coordinator.ts @@ -2,8 +2,8 @@ import type { App } from "obsidian"; import { VIEW_TYPE_CODEX_THREADS } from "../constants"; import { CodexThreadsView } from "../features/threads-view/view"; -import type { PanelModelOption } from "../domain/catalog/metadata"; -import type { PanelThread } from "../domain/threads/model"; +import type { ModelMetadata } from "../domain/catalog/metadata"; +import type { Thread } from "../domain/threads/model"; import type { SharedAppServerMetadata } from "../app-server/shared-cache-state"; import type { WorkspacePanelCoordinator } from "./panel-coordinator"; @@ -33,7 +33,7 @@ export class ThreadSurfaceCoordinator { if (threadsView) void threadsView.refresh(); } - applyThreadListSnapshot(threads: readonly PanelThread[]): void { + applyThreadListSnapshot(threads: readonly Thread[]): void { for (const view of this.options.panels.panelViews()) { view.applyThreadListSnapshot(threads); } @@ -48,7 +48,7 @@ export class ThreadSurfaceCoordinator { } } - publishModels(models: readonly PanelModelOption[]): void { + publishModels(models: readonly ModelMetadata[]): void { for (const view of this.options.panels.panelViews()) { view.applyAvailableModelsSnapshot(models); } diff --git a/tests/app-server/catalog-model.test.ts b/tests/app-server/catalog-model.test.ts index 3362b1e1..8a14c5c2 100644 --- a/tests/app-server/catalog-model.test.ts +++ b/tests/app-server/catalog-model.test.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from "vitest"; import { - appServerHookOperationFromPanelHookItem, - panelHookItemsFromAppServerHooks, - panelModelOptionsFromAppServerModels, - panelSkillOptionsFromAppServerSkills, + appServerHookOperationFromHookItem, + hookItemsFromAppServerHooks, + modelMetadataFromAppServerModels, + skillMetadataFromAppServerSkills, } from "../../src/app-server/catalog-model"; import type { HookMetadata } from "../../src/generated/app-server/v2/HookMetadata"; import type { Model } from "../../src/generated/app-server/v2/Model"; @@ -12,7 +12,7 @@ import type { SkillMetadata } from "../../src/generated/app-server/v2/SkillMetad describe("app-server catalog model mappers", () => { it("maps app-server models to panel model options", () => { - expect(panelModelOptionsFromAppServerModels([modelFixture()])).toEqual([ + expect(modelMetadataFromAppServerModels([modelFixture()])).toEqual([ { id: "gpt-5.5-id", model: "gpt-5.5", @@ -33,11 +33,11 @@ describe("app-server catalog model mappers", () => { it("preserves unknown app-server default reasoning efforts as raw catalog metadata", () => { const model = { ...modelFixture(), defaultReasoningEffort: "extreme" as never }; - expect(panelModelOptionsFromAppServerModels([model])[0]?.defaultReasoningEffort).toBe("extreme"); + expect(modelMetadataFromAppServerModels([model])[0]?.defaultReasoningEffort).toBe("extreme"); }); it("maps app-server skills to composer skill options", () => { - expect(panelSkillOptionsFromAppServerSkills([skillFixture()])).toEqual([ + expect(skillMetadataFromAppServerSkills([skillFixture()])).toEqual([ { name: "writer", description: "Write notes", @@ -50,7 +50,7 @@ describe("app-server catalog model mappers", () => { }); it("maps app-server hooks to settings hook items", () => { - expect(panelHookItemsFromAppServerHooks([hookFixture()])).toEqual([ + expect(hookItemsFromAppServerHooks([hookFixture()])).toEqual([ { key: "hook-key", eventName: "postToolUse", @@ -67,10 +67,10 @@ describe("app-server catalog model mappers", () => { }); it("maps panel hook items to minimal app-server hook operations", () => { - const hook = panelHookItemsFromAppServerHooks([hookFixture()])[0]; + const hook = hookItemsFromAppServerHooks([hookFixture()])[0]; if (!hook) throw new Error("Expected mapped hook"); - expect(appServerHookOperationFromPanelHookItem(hook)).toEqual({ + expect(appServerHookOperationFromHookItem(hook)).toEqual({ key: "hook-key", currentHash: "hash", trustStatus: "modified", diff --git a/tests/app-server/panel-data.test.ts b/tests/app-server/resource-operations.test.ts similarity index 72% rename from tests/app-server/panel-data.test.ts rename to tests/app-server/resource-operations.test.ts index 14b7b0a1..fa258238 100644 --- a/tests/app-server/panel-data.test.ts +++ b/tests/app-server/resource-operations.test.ts @@ -1,21 +1,21 @@ import { describe, expect, it, vi } from "vitest"; import type { AppServerClient } from "../../src/app-server/client"; -import { listPanelHookData, listPanelSkillCatalog, listPanelThreads } from "../../src/app-server/panel-data"; +import { listHookData, listSkillCatalog, listThreads } from "../../src/app-server/resource-operations"; -describe("panel app-server data loaders", () => { - it("maps listed threads to panel threads with archive state", async () => { - const listThreads = vi.fn().mockResolvedValue({ +describe("app-server resource operations", () => { + it("maps listed threads to domain threads with archive state", async () => { + const clientListThreads = vi.fn().mockResolvedValue({ data: [{ id: "thread-1", preview: "Preview", name: null, createdAt: 10, updatedAt: 20 }], }); const client = { - listThreads, + listThreads: clientListThreads, } as unknown as AppServerClient; - await expect(listPanelThreads(client, "/vault", { archived: true })).resolves.toEqual([ + await expect(listThreads(client, "/vault", { archived: true })).resolves.toEqual([ { id: "thread-1", preview: "Preview", name: null, archived: true, createdAt: 10, updatedAt: 20 }, ]); - expect(listThreads).toHaveBeenCalledWith("/vault", true); + expect(clientListThreads).toHaveBeenCalledWith("/vault", true); }); it("uses only hook rows for the requested cwd", async () => { @@ -28,7 +28,7 @@ describe("panel app-server data loaders", () => { }), } as unknown as AppServerClient; - await expect(listPanelHookData(client, "/vault")).resolves.toMatchObject({ + await expect(listHookData(client, "/vault")).resolves.toMatchObject({ hooks: [{ key: "vault" }], warnings: ["warn"], errors: ['{"message":"err"}'], @@ -50,7 +50,7 @@ describe("panel app-server data loaders", () => { }), } as unknown as AppServerClient; - await expect(listPanelSkillCatalog(client, "/vault")).resolves.toMatchObject({ + await expect(listSkillCatalog(client, "/vault")).resolves.toMatchObject({ skills: [{ name: "enabled", description: "Enabled skill", path: "/skills/enabled", enabled: true }], totalCount: 2, }); diff --git a/tests/app-server/shared-cache-state.test.ts b/tests/app-server/shared-cache-state.test.ts index f47956a0..0172bf8a 100644 --- a/tests/app-server/shared-cache-state.test.ts +++ b/tests/app-server/shared-cache-state.test.ts @@ -10,9 +10,8 @@ import { cachedSharedThreadList, createSharedAppServerState, } from "../../src/app-server/shared-cache-state"; -import type { PanelModelOption } from "../../src/domain/catalog/metadata"; -import type { PanelThread } from "../../src/domain/threads/model"; -import type { Thread } from "../../src/generated/app-server/v2/Thread"; +import type { ModelMetadata } from "../../src/domain/catalog/metadata"; +import type { Thread } from "../../src/domain/threads/model"; describe("shared app-server cache state", () => { it("keeps snapshots detached from caller-owned arrays", () => { @@ -23,7 +22,7 @@ describe("shared app-server cache state", () => { const cachedThreads = cachedSharedThreadList(threadState); expect(cachedThreads?.map((thread) => thread.id)).toEqual(["thread-1"]); - const mutableCachedThreads = cachedThreads as PanelThread[]; + const mutableCachedThreads = cachedThreads as Thread[]; mutableCachedThreads.push(threadFixture("thread-3")); expect(cachedSharedThreadList(threadState)?.map((thread) => thread.id)).toEqual(["thread-1"]); @@ -51,33 +50,18 @@ describe("shared app-server cache state", () => { }); }); -function threadFixture(id: string): Thread & { archived: boolean } { +function threadFixture(id: string): Thread { return { id, - sessionId: "session", - forkedFromId: null, - parentThreadId: null, preview: "", - ephemeral: false, - modelProvider: "openai", - createdAt: 1, - updatedAt: 1, - status: { type: "idle" }, - path: null, - cwd: "/vault", - cliVersion: "0.0.0", - source: "appServer", - threadSource: null, - agentNickname: null, - agentRole: null, - gitInfo: null, name: null, archived: false, - turns: [], + createdAt: 1, + updatedAt: 1, }; } -function modelFixture(model: string): PanelModelOption { +function modelFixture(model: string): ModelMetadata { return { id: model, model, diff --git a/tests/features/chat/chat-app-server-actions.test.ts b/tests/features/chat/chat-app-server-actions.test.ts index 5e6ab2c1..1f6ce6cc 100644 --- a/tests/features/chat/chat-app-server-actions.test.ts +++ b/tests/features/chat/chat-app-server-actions.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it, vi } from "vitest"; import type { AppServerClient } from "../../../src/app-server/client"; -import { panelThreadFromAppServerThread } from "../../../src/app-server/thread-model"; +import { threadFromAppServerThread } from "../../../src/app-server/thread-model"; import { createChatAppServerDiagnosticsActions } from "../../../src/features/chat/app-server/diagnostics-actions"; import { createChatAppServerMetadataActions } from "../../../src/features/chat/app-server/metadata-actions"; import { createChatAppServerThreadActions } from "../../../src/features/chat/app-server/thread-actions"; @@ -16,11 +16,11 @@ describe("chat app-server controllers", () => { it("publishes newly started threads before the first turn completes", async () => { const state = createChatState(); const existing = threadFixture("existing"); - state.threadList.listedThreads = [panelThreadFromAppServerThread(existing)]; + state.threadList.listedThreads = [threadFromAppServerThread(existing)]; const stateStore = createChatStateStore(state); const started = threadFixture("started"); - const optimistic = panelThreadFromAppServerThread({ ...started, preview: "first prompt" }); - const existingPanelThread = panelThreadFromAppServerThread(existing); + const optimistic = threadFromAppServerThread({ ...started, preview: "first prompt" }); + const existingThread = threadFromAppServerThread(existing); const publishThreadList = vi.fn(); const syncThreadGoal = vi.fn(); const client = { @@ -47,8 +47,8 @@ describe("chat app-server controllers", () => { await controller.startThread("first prompt"); - expect(stateStore.getState().threadList.listedThreads).toEqual([optimistic, existingPanelThread]); - expect(publishThreadList).toHaveBeenCalledWith([optimistic, existingPanelThread]); + expect(stateStore.getState().threadList.listedThreads).toEqual([optimistic, existingThread]); + expect(publishThreadList).toHaveBeenCalledWith([optimistic, existingThread]); expect(syncThreadGoal).toHaveBeenCalledWith("started"); }); @@ -111,7 +111,7 @@ describe("chat app-server controllers", () => { await controller.startThread("local preview"); - expect(publishThreadList).toHaveBeenCalledWith([panelThreadFromAppServerThread(started)]); + expect(publishThreadList).toHaveBeenCalledWith([threadFromAppServerThread(started)]); }); it("reuses cached app-server metadata for deferred diagnostics", async () => { diff --git a/tests/features/chat/composer/composer-suggestions.test.ts b/tests/features/chat/composer/composer-suggestions.test.ts index 52ec3437..11e76884 100644 --- a/tests/features/chat/composer/composer-suggestions.test.ts +++ b/tests/features/chat/composer/composer-suggestions.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import type { ReasoningEffort } from "../../../../src/generated/app-server/ReasoningEffort"; import type { Thread } from "../../../../src/generated/app-server/v2/Thread"; -import type { PanelModelOption } from "../../../../src/domain/catalog/metadata"; +import type { ModelMetadata } from "../../../../src/domain/catalog/metadata"; import { activeComposerSuggestions, applyComposerSuggestionInsertion, @@ -46,7 +46,7 @@ function thread(overrides: Partial = {}): Thread } as Thread & { archived: boolean }; } -function model(name: string, efforts: ReasoningEffort[], overrides: Partial = {}): PanelModelOption { +function model(name: string, efforts: ReasoningEffort[], overrides: Partial = {}): ModelMetadata { return { id: name, model: name, diff --git a/tests/features/chat/runtime/runtime-settings-actions.test.ts b/tests/features/chat/runtime/runtime-settings-actions.test.ts index 9048bd38..7677d61c 100644 --- a/tests/features/chat/runtime/runtime-settings-actions.test.ts +++ b/tests/features/chat/runtime/runtime-settings-actions.test.ts @@ -8,7 +8,7 @@ import { createChatState, createChatStateStore, type ChatState } from "../../../ import { runtimeSnapshotForChatSlices } from "../../../../src/features/chat/panel/model"; import type { ActiveThreadSettingsAppliedAction } from "../../../../src/features/chat/chat-state-actions"; import type { AppServerClient } from "../../../../src/app-server/client"; -import type { PanelModelOption } from "../../../../src/domain/catalog/metadata"; +import type { ModelMetadata } from "../../../../src/domain/catalog/metadata"; describe("createChatRuntimeSettingsActions", () => { it("applies pending runtime overrides through thread settings and commits them", async () => { @@ -139,7 +139,7 @@ function runtimeSnapshotFixture(state: ChatState) { }); } -function modelFixture(model: string, fastTierId: string): PanelModelOption { +function modelFixture(model: string, fastTierId: string): ModelMetadata { return { id: model, model, diff --git a/tests/features/chat/threads/thread-naming.test.ts b/tests/features/chat/threads/thread-naming.test.ts index 29a907fa..7d04b435 100644 --- a/tests/features/chat/threads/thread-naming.test.ts +++ b/tests/features/chat/threads/thread-naming.test.ts @@ -31,7 +31,7 @@ import type { ThreadItem } from "../../../../src/generated/app-server/v2/ThreadI import type { ThreadStartResponse } from "../../../../src/generated/app-server/v2/ThreadStartResponse"; import type { Turn } from "../../../../src/generated/app-server/v2/Turn"; import type { TurnStartResponse } from "../../../../src/generated/app-server/v2/TurnStartResponse"; -import { panelModelOptionsFromAppServerModels } from "../../../../src/app-server/catalog-model"; +import { modelMetadataFromAppServerModels } from "../../../../src/app-server/catalog-model"; describe("thread naming", () => { it("extracts the first user request and final assistant response from a completed turn", () => { @@ -264,7 +264,7 @@ describe("thread naming", () => { expect( validatedThreadNamingRuntimeOverride( { threadNamingModel: "gpt-5.4-mini", threadNamingEffort: "minimal" }, - panelModelOptionsFromAppServerModels([model("gpt-5.4-mini", ["low", "medium", "high", "xhigh"])]), + modelMetadataFromAppServerModels([model("gpt-5.4-mini", ["low", "medium", "high", "xhigh"])]), ), ).toEqual({ model: "gpt-5.4-mini" }); }); @@ -273,7 +273,7 @@ describe("thread naming", () => { expect( validatedThreadNamingRuntimeOverride( { threadNamingModel: "gpt-5.4-mini", threadNamingEffort: "low" }, - panelModelOptionsFromAppServerModels([model("gpt-5.4-mini", ["low", "medium", "high", "xhigh"])]), + modelMetadataFromAppServerModels([model("gpt-5.4-mini", ["low", "medium", "high", "xhigh"])]), ), ).toEqual({ model: "gpt-5.4-mini", effort: "low" }); }); diff --git a/tests/features/chat/ui/renderers/composer.test.ts b/tests/features/chat/ui/renderers/composer.test.ts index eae1e05d..6e652007 100644 --- a/tests/features/chat/ui/renderers/composer.test.ts +++ b/tests/features/chat/ui/renderers/composer.test.ts @@ -161,13 +161,13 @@ describe("composer renderer decisions", () => { await waitForAsyncWork(() => { expect(parent.querySelector(".codex-panel__composer-meta-popover--model")?.textContent).toBe("gpt-5.5gpt-5.4"); }); - const modelOptions = Array.from(parent.querySelectorAll(".codex-panel__composer-meta-option")); - expect(modelOptions.map((option) => option.getAttribute("role"))).toEqual([null, null]); - expect(modelOptions.map((option) => option.getAttribute("tabindex"))).toEqual([null, null]); - expect(modelOptions.map((option) => option.getAttribute("aria-selected"))).toEqual([null, null]); - expect(modelOptions.every((option) => !option.classList.contains("is-selected"))).toBe(true); - expect(modelOptions.every((option) => !option.classList.contains("codex-panel-ui__nav-item"))).toBe(true); - expect(modelOptions.every((option) => !option.classList.contains("codex-panel__toolbar-panel-item"))).toBe(true); + const metaOptions = Array.from(parent.querySelectorAll(".codex-panel__composer-meta-option")); + expect(metaOptions.map((option) => option.getAttribute("role"))).toEqual([null, null]); + expect(metaOptions.map((option) => option.getAttribute("tabindex"))).toEqual([null, null]); + expect(metaOptions.map((option) => option.getAttribute("aria-selected"))).toEqual([null, null]); + expect(metaOptions.every((option) => !option.classList.contains("is-selected"))).toBe(true); + expect(metaOptions.every((option) => !option.classList.contains("codex-panel-ui__nav-item"))).toBe(true); + expect(metaOptions.every((option) => !option.classList.contains("codex-panel__toolbar-panel-item"))).toBe(true); parent.querySelector(".codex-panel__composer-meta-effort")?.dispatchEvent(new MouseEvent("mousedown", { bubbles: true })); await waitForAsyncWork(() => { diff --git a/tests/features/chat/view-connection.test.ts b/tests/features/chat/view-connection.test.ts index 8ced5f74..f5f5166e 100644 --- a/tests/features/chat/view-connection.test.ts +++ b/tests/features/chat/view-connection.test.ts @@ -5,7 +5,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { DEFAULT_SETTINGS } from "../../../src/settings/model"; import type { CodexChatHost } from "../../../src/features/chat/chat-host"; import { createAppServerDiagnostics } from "../../../src/app-server/compatibility"; -import { panelThreadFromAppServerThread } from "../../../src/app-server/thread-model"; +import { threadFromAppServerThread } from "../../../src/app-server/thread-model"; import { createChatState, type ChatState } from "../../../src/features/chat/chat-state"; import { composerSlotSnapshot } from "../../../src/features/chat/panel/snapshot"; import type { ServerNotification } from "../../../src/generated/app-server/ServerNotification"; @@ -159,7 +159,7 @@ describe("CodexChatView connection lifecycle", () => { expect(refreshThreadList).toHaveBeenCalledOnce(); expect((view as unknown as { state: { threadList: { listedThreads: unknown[] } } }).state.threadList.listedThreads).toEqual( - threads.map((thread) => panelThreadFromAppServerThread(thread)), + threads.map((thread) => threadFromAppServerThread(thread)), ); }); @@ -393,7 +393,7 @@ describe("CodexChatView connection lifecycle", () => { expect(client.readAccountRateLimits).toHaveBeenCalledOnce(); expect(client.listThreads).toHaveBeenCalledWith("/vault", false); expect((view as unknown as { state: { threadList: { listedThreads: unknown[] } } }).state.threadList.listedThreads).toEqual([ - panelThreadFromAppServerThread(threadFixture("thread-1")), + threadFromAppServerThread(threadFixture("thread-1")), ]); }); diff --git a/tests/features/chat/view-model.test.ts b/tests/features/chat/view-model.test.ts index 174c4733..d1c36280 100644 --- a/tests/features/chat/view-model.test.ts +++ b/tests/features/chat/view-model.test.ts @@ -16,7 +16,7 @@ import { toolbarViewModel, } from "../../../src/features/chat/panel/model"; import type { ChatState } from "../../../src/features/chat/chat-state"; -import type { PanelModelOption } from "../../../src/domain/catalog/metadata"; +import type { ModelMetadata } from "../../../src/domain/catalog/metadata"; import type { Thread } from "../../../src/generated/app-server/v2/Thread"; import type { ConfigReadResponse } from "../../../src/generated/app-server/v2/ConfigReadResponse"; @@ -295,7 +295,7 @@ function threadFixture(id: string, name: string | null): Thread & { archived: bo }; } -function modelFixture(model: string, fastTierId?: string): PanelModelOption { +function modelFixture(model: string, fastTierId?: string): ModelMetadata { return { id: model, model, diff --git a/tests/features/selection-rewrite/selection-rewrite.test.ts b/tests/features/selection-rewrite/selection-rewrite.test.ts index 5919b725..e6b6da9a 100644 --- a/tests/features/selection-rewrite/selection-rewrite.test.ts +++ b/tests/features/selection-rewrite/selection-rewrite.test.ts @@ -26,7 +26,7 @@ import { type SelectionRewriteClientFactory, } from "../../../src/features/selection-rewrite/runner"; import type { AppServerClientHandlers } from "../../../src/app-server/client"; -import type { PanelModelOption } from "../../../src/domain/catalog/metadata"; +import type { ModelMetadata } from "../../../src/domain/catalog/metadata"; import type { InitializeResponse } from "../../../src/generated/app-server/InitializeResponse"; import type { ModelListResponse } from "../../../src/generated/app-server/v2/ModelListResponse"; import type { ServerNotification } from "../../../src/generated/app-server/ServerNotification"; @@ -501,7 +501,7 @@ describe("selection rewrite runtime overrides", () => { it("omits an explicit selection rewrite effort when the selected model does not support it", () => { expect( validatedSelectionRewriteRuntimeOverride({ rewriteSelectionModel: "gpt-5.4-mini", rewriteSelectionEffort: "minimal" }, [ - panelModel("gpt-5.4-mini", ["low", "medium", "high", "xhigh"]), + modelMetadata("gpt-5.4-mini", ["low", "medium", "high", "xhigh"]), ]), ).toEqual({ model: "gpt-5.4-mini" }); }); @@ -775,7 +775,7 @@ function turnCompletedNotification(threadId: string, completedTurn: Turn): Serve }; } -function panelModel(name: string, efforts: ReasoningEffort[]): PanelModelOption { +function modelMetadata(name: string, efforts: ReasoningEffort[]): ModelMetadata { return { id: name, model: name, diff --git a/tests/runtime/runtime-settings.test.ts b/tests/runtime/runtime-settings.test.ts index 9f5193bd..411d44bd 100644 --- a/tests/runtime/runtime-settings.test.ts +++ b/tests/runtime/runtime-settings.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; import type { ConfigReadResponse } from "../../src/generated/app-server/v2/ConfigReadResponse"; -import type { PanelModelOption } from "../../src/domain/catalog/metadata"; +import type { ModelMetadata } from "../../src/domain/catalog/metadata"; import { compactModelLabel, compactReasoningEffortLabel, @@ -698,7 +698,7 @@ function configLayer(config: Record, profile: string | null): N }; } -function modelFixture(model: string): PanelModelOption { +function modelFixture(model: string): ModelMetadata { return { id: model, model, diff --git a/tests/settings/settings-tab.test.ts b/tests/settings/settings-tab.test.ts index 93f61559..061f8df7 100644 --- a/tests/settings/settings-tab.test.ts +++ b/tests/settings/settings-tab.test.ts @@ -6,8 +6,8 @@ import type { Thread } from "../../src/generated/app-server/v2/Thread"; import type { HookMetadata } from "../../src/generated/app-server/v2/HookMetadata"; import type { Model } from "../../src/generated/app-server/v2/Model"; import type { ReasoningEffort } from "../../src/generated/app-server/ReasoningEffort"; -import type { PanelModelOption } from "../../src/domain/catalog/metadata"; -import { panelModelOptionsFromAppServerModels } from "../../src/app-server/catalog-model"; +import type { ModelMetadata } from "../../src/domain/catalog/metadata"; +import { modelMetadataFromAppServerModels } from "../../src/app-server/catalog-model"; import { CodexPanelSettingTab } from "../../src/settings/tab"; import { archivedThreadDisplayTitle } from "../../src/domain/threads/model"; import { notices } from "../mocks/obsidian"; @@ -193,7 +193,7 @@ describe("settings tab", () => { withShortLivedAppServerClientMock.mockImplementation( (_codexPath: string, _cwd: string, operation: (client: unknown) => Promise) => operation(client), ); - const tab = newSettingsTab({ cachedModels: panelModelOptionsFromAppServerModels([model("gpt-cached")]), publishModels }); + const tab = newSettingsTab({ cachedModels: modelMetadataFromAppServerModels([model("gpt-cached")]), publishModels }); tab.display(); @@ -201,7 +201,7 @@ describe("settings tab", () => { await flushPromises(); - expect(publishModels).toHaveBeenCalledWith(panelModelOptionsFromAppServerModels([model("gpt-5.5")])); + expect(publishModels).toHaveBeenCalledWith(modelMetadataFromAppServerModels([model("gpt-5.5")])); expect(tab.containerEl.textContent).toContain("gpt-5.5"); }); @@ -348,8 +348,8 @@ function newSettingsTab( options: { saveSettings?: () => Promise; sendShortcut?: "enter" | "mod-enter"; - cachedModels?: PanelModelOption[]; - publishModels?: (models: PanelModelOption[]) => void; + cachedModels?: ModelMetadata[]; + publishModels?: (models: ModelMetadata[]) => void; refreshOpenViews?: () => void; } = {}, ): CodexPanelSettingTab {