mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Clarify domain and app-server adapter names
This commit is contained in:
parent
ec64a9666a
commit
62005852ea
58 changed files with 403 additions and 429 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<PanelThread[]> {
|
||||
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<PanelModelOption[]> {
|
||||
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<PanelHookData> {
|
||||
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<void> {
|
||||
await client.trustHook(appServerHookOperationFromPanelHookItem(hook));
|
||||
}
|
||||
|
||||
export async function setPanelHookEnabled(client: AppServerClient, hook: PanelHookItem, enabled: boolean): Promise<void> {
|
||||
await client.setHookEnabled(appServerHookOperationFromPanelHookItem(hook), enabled);
|
||||
}
|
||||
|
||||
export async function restoreArchivedPanelThread(client: AppServerClient, threadId: string): Promise<PanelThread> {
|
||||
const response = await client.unarchiveThread(threadId);
|
||||
return panelThreadFromAppServerThread(response.thread);
|
||||
}
|
||||
64
src/app-server/resource-operations.ts
Normal file
64
src/app-server/resource-operations.ts
Normal file
|
|
@ -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<Thread[]> {
|
||||
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<ModelMetadata[]> {
|
||||
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<HookData> {
|
||||
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<void> {
|
||||
await client.trustHook(appServerHookOperationFromHookItem(hook));
|
||||
}
|
||||
|
||||
export async function setHookItemEnabled(client: AppServerClient, hook: HookItem, enabled: boolean): Promise<void> {
|
||||
await client.setHookEnabled(appServerHookOperationFromHookItem(hook), enabled);
|
||||
}
|
||||
|
||||
export async function restoreArchivedThread(client: AppServerClient, threadId: string): Promise<Thread> {
|
||||
const response = await client.unarchiveThread(threadId);
|
||||
return threadFromAppServerThread(response.thread);
|
||||
}
|
||||
|
|
@ -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<T> = { kind: "unloaded" } | { kind: "loaded"; data: T };
|
||||
|
||||
export interface SharedAppServerState {
|
||||
threads: SharedCache<readonly PanelThread[]>;
|
||||
threads: SharedCache<readonly Thread[]>;
|
||||
appServerMetadata: SharedCache<SharedAppServerMetadata>;
|
||||
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 }));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<readonly PanelThread[]> };
|
||||
type ThreadListRefreshLifecycleState = { kind: "idle" } | { kind: "refreshing"; promise: Promise<readonly Thread[]> };
|
||||
|
||||
export class SharedAppServerCache {
|
||||
private state: SharedAppServerState = createSharedAppServerState();
|
||||
private threadListRefreshLifecycle: ThreadListRefreshLifecycleState = { kind: "idle" };
|
||||
|
||||
refreshThreadList(
|
||||
fetchThreads: () => Promise<readonly PanelThread[]>,
|
||||
onSnapshot?: (threads: readonly PanelThread[]) => void,
|
||||
): Promise<readonly PanelThread[]> {
|
||||
fetchThreads: () => Promise<readonly Thread[]>,
|
||||
onSnapshot?: (threads: readonly Thread[]) => void,
|
||||
): Promise<readonly Thread[]> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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[],
|
||||
|
|
|
|||
|
|
@ -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<SharedAppServerMetadata | null>;
|
||||
publishAppServerMetadataSnapshot: () => void;
|
||||
refreshModels: () => Promise<void>;
|
||||
loadModels: () => Promise<{ data: PanelModelOption[]; probe: AppServerDiagnostics["probes"]["model/list"] }>;
|
||||
loadModels: () => Promise<{ data: ModelMetadata[]; probe: AppServerDiagnostics["probes"]["model/list"] }>;
|
||||
refreshSkills: (forceReload?: boolean) => Promise<void>;
|
||||
refreshPublishedSkills: (forceReload?: boolean) => Promise<void>;
|
||||
loadSkills: (forceReload?: boolean) => Promise<{ data: PanelSkillOption[]; probe: AppServerDiagnostics["probes"]["skills/list"] }>;
|
||||
loadSkills: (forceReload?: boolean) => Promise<{ data: SkillMetadata[]; probe: AppServerDiagnostics["probes"]["skills/list"] }>;
|
||||
refreshRateLimits: () => Promise<void>;
|
||||
refreshPublishedRateLimits: () => Promise<void>;
|
||||
loadRateLimit: () => Promise<{ data: RateLimitSnapshot | null; probe: AppServerDiagnostics["probes"]["account/rateLimits/read"] }>;
|
||||
|
|
@ -118,11 +118,11 @@ async function refreshModels(host: ChatAppServerMetadataActionsHost): Promise<vo
|
|||
|
||||
async function loadModels(
|
||||
host: ChatAppServerMetadataActionsHost,
|
||||
): Promise<{ data: PanelModelOption[]; probe: AppServerDiagnostics["probes"]["model/list"] }> {
|
||||
): 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) };
|
||||
|
|
|
|||
|
|
@ -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<readonly PanelThread[]>;
|
||||
applyThreadList: (threads: readonly Thread[]) => void;
|
||||
loadThreadList: () => Promise<readonly Thread[]>;
|
||||
startThread: (preview?: string, options?: { syncGoal?: boolean }) => Promise<StartedThreadSummary | null>;
|
||||
}
|
||||
|
||||
|
|
@ -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<readonly PanelThread[]> {
|
||||
async function loadThreadList(host: ChatAppServerThreadActionsHost): Promise<readonly Thread[]> {
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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<readonly PanelThread[]>): Promise<readonly PanelThread[]>;
|
||||
cachedThreadList(): readonly PanelThread[] | null;
|
||||
applyThreadListSnapshot(threads: readonly Thread[]): void;
|
||||
refreshThreadList(fetchThreads: () => Promise<readonly Thread[]>): Promise<readonly Thread[]>;
|
||||
cachedThreadList(): readonly Thread[] | null;
|
||||
publishAppServerMetadata(metadata: SharedAppServerMetadata): void;
|
||||
cachedAppServerMetadata(): SharedAppServerMetadata | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }) };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<string>();
|
||||
|
|
@ -81,8 +81,8 @@ function parseWikiLink(raw: string): ParsedWikiLink | null {
|
|||
return parsed ? { raw, ...parsed } : null;
|
||||
}
|
||||
|
||||
function firstEnabledSkillByName(skills: readonly PanelSkillOption[]): Map<string, PanelSkillOption> {
|
||||
const byName = new Map<string, PanelSkillOption>();
|
||||
function firstEnabledSkillByName(skills: readonly SkillMetadata[]): Map<string, SkillMetadata> {
|
||||
const byName = new Map<string, SkillMetadata>();
|
||||
for (const skill of skills) {
|
||||
if (!skill.enabled) continue;
|
||||
const key = skill.name.toLowerCase();
|
||||
|
|
|
|||
|
|
@ -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<boolean>;
|
||||
startNewThread: () => Promise<void>;
|
||||
selectThread: (threadId: string) => Promise<void>;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string>;
|
||||
requestedReasoningEffort: PendingRuntimeSetting<ReasoningEffort>;
|
||||
requestedApprovalsReviewer: PendingRuntimeSetting<ApprovalsReviewer>;
|
||||
selectedCollaborationMode: PanelCollaborationMode;
|
||||
selectedCollaborationMode: CollaborationMode;
|
||||
requestedServiceTier: PendingRuntimeSetting<RequestedServiceTier>;
|
||||
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<T>(setting: PendingRuntimeSetting<T>)
|
|||
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 ?? [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<void>;
|
||||
toggleFastMode: () => Promise<void>;
|
||||
toggleCollaborationMode: () => Promise<void>;
|
||||
setCollaborationMode: (collaborationMode: PanelCollaborationMode) => Promise<boolean>;
|
||||
setCollaborationMode: (collaborationMode: CollaborationMode) => Promise<boolean>;
|
||||
toggleAutoReview: () => Promise<void>;
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ async function toggleCollaborationMode(host: RuntimeSettingsActionsHost): Promis
|
|||
await setCollaborationMode(host, next);
|
||||
}
|
||||
|
||||
async function setCollaborationMode(host: RuntimeSettingsActionsHost, collaborationMode: PanelCollaborationMode): Promise<boolean> {
|
||||
async function setCollaborationMode(host: RuntimeSettingsActionsHost, collaborationMode: CollaborationMode): Promise<boolean> {
|
||||
dispatch(host, { type: "runtime/requested-collaboration-mode-set", collaborationMode });
|
||||
dispatch(host, { type: "ui/panel-set", panel: null });
|
||||
const result = await applyPendingThreadSettingsResult(host);
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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<string>;
|
||||
requestedReasoningEffort: PendingRuntimeSetting<ReasoningEffort>;
|
||||
requestedApprovalsReviewer: PendingRuntimeSetting<ApprovalsReviewer>;
|
||||
selectedCollaborationMode: PanelCollaborationMode;
|
||||
selectedCollaborationMode: CollaborationMode;
|
||||
requestedServiceTier: PendingRuntimeSetting<RequestedServiceTier>;
|
||||
}
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<ThreadReferenceInput | null> {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -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<void>;
|
||||
startThreadForGoal: (objective: string) => Promise<string | null>;
|
||||
resumeThread: (threadId: string) => Promise<void>;
|
||||
referThread: (thread: PanelThread, message: string) => Promise<ThreadReferenceInput | null>;
|
||||
referThread: (thread: Thread, message: string) => Promise<ThreadReferenceInput | null>;
|
||||
forkThread: (threadId: string) => Promise<void>;
|
||||
rollbackThread: (threadId: string) => Promise<void>;
|
||||
compactThread: (threadId: string) => Promise<void>;
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<readonly PanelThread[]>): Promise<readonly PanelThread[]>;
|
||||
cachedThreadList(): readonly Thread[] | null;
|
||||
refreshThreadList(fetchThreads: () => Promise<readonly Thread[]>): Promise<readonly Thread[]>;
|
||||
openThreadInCurrentView(threadId: string): Promise<void>;
|
||||
openThreadInAvailableView(threadId: string): Promise<void>;
|
||||
}
|
||||
|
||||
interface ThreadSuggestion {
|
||||
thread: PanelThread;
|
||||
thread: Thread;
|
||||
title: string;
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ export async function openThreadPicker(host: ThreadPickerHost): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
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<readonly PanelThread[]> {
|
||||
async function loadThreadPickerThreads(host: ThreadPickerHost): Promise<readonly Thread[]> {
|
||||
const cached = host.cachedThreadList();
|
||||
if (cached) return cached;
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ async function loadThreadPickerThreads(host: ThreadPickerHost): Promise<readonly
|
|||
host.vaultPath,
|
||||
async (client) =>
|
||||
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<readonly
|
|||
class ThreadPickerModal extends SuggestModal<ThreadSuggestion> {
|
||||
constructor(
|
||||
private readonly host: ThreadPickerHost,
|
||||
private readonly threads: readonly PanelThread[],
|
||||
private readonly threads: readonly Thread[],
|
||||
) {
|
||||
super(host.app);
|
||||
this.limit = MAX_THREAD_PICKER_SUGGESTIONS;
|
||||
|
|
|
|||
|
|
@ -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<ThreadsLiveStatus, number> = {
|
|||
};
|
||||
|
||||
export function threadRows(
|
||||
threads: readonly PanelThread[],
|
||||
threads: readonly Thread[],
|
||||
snapshots: OpenCodexPanelSnapshot[],
|
||||
renameStates: ReadonlyMap<string, ThreadsRenameState>,
|
||||
archiveConfirmThreadId: string | null = null,
|
||||
|
|
|
|||
|
|
@ -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<readonly PanelThread[]>): Promise<readonly PanelThread[]>;
|
||||
cachedThreadList(): readonly PanelThread[] | null;
|
||||
refreshThreadList(fetchThreads: () => Promise<readonly Thread[]>): Promise<readonly Thread[]>;
|
||||
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<string, ThreadsRenameState>();
|
||||
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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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<PanelModelOption[]>;
|
||||
models: SettledSettingsData<ModelMetadata[]>;
|
||||
hooks: SettledSettingsData<LoadedHooks>;
|
||||
archivedThreads: SettledSettingsData<PanelThread[]>;
|
||||
archivedThreads: SettledSettingsData<Thread[]>;
|
||||
}
|
||||
|
||||
type SettledSettingsData<T> =
|
||||
|
|
@ -27,9 +27,9 @@ type SettledSettingsData<T> =
|
|||
|
||||
export async function loadSettingsData(client: AppServerClient, cwd: string): Promise<SettingsDataLoad> {
|
||||
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<LoadedHooks> {
|
||||
const hooks = await listPanelHookData(client, cwd);
|
||||
const hooks = await listHookData(client, cwd);
|
||||
return {
|
||||
...hooks,
|
||||
status: hooksStatus(hooks.hooks.length),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<void> {
|
||||
private async trustHook(hook: HookItem): Promise<void> {
|
||||
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<void> {
|
||||
private async setHookEnabled(hook: HookItem, enabled: boolean): Promise<void> {
|
||||
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<void>;
|
||||
refreshOpenViews(): void;
|
||||
refreshSharedThreadListFromOpenSurface(): void;
|
||||
cachedModels(): PanelModelOption[];
|
||||
publishModels(models: PanelModelOption[]): void;
|
||||
cachedModels(): ModelMetadata[];
|
||||
publishModels(models: ModelMetadata[]): void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 () => {
|
||||
|
|
|
|||
|
|
@ -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 & { archived: boolean }> = {}): Thread
|
|||
} as Thread & { archived: boolean };
|
||||
}
|
||||
|
||||
function model(name: string, efforts: ReasoningEffort[], overrides: Partial<PanelModelOption> = {}): PanelModelOption {
|
||||
function model(name: string, efforts: ReasoningEffort[], overrides: Partial<ModelMetadata> = {}): ModelMetadata {
|
||||
return {
|
||||
id: name,
|
||||
model: name,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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" });
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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<HTMLElement>(".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<HTMLElement>(".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<HTMLElement>(".codex-panel__composer-meta-effort")?.dispatchEvent(new MouseEvent("mousedown", { bubbles: true }));
|
||||
await waitForAsyncWork(() => {
|
||||
|
|
|
|||
|
|
@ -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")),
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<string, unknown>, profile: string | null): N
|
|||
};
|
||||
}
|
||||
|
||||
function modelFixture(model: string): PanelModelOption {
|
||||
function modelFixture(model: string): ModelMetadata {
|
||||
return {
|
||||
id: model,
|
||||
model,
|
||||
|
|
|
|||
|
|
@ -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<unknown>) => 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<void>;
|
||||
sendShortcut?: "enter" | "mod-enter";
|
||||
cachedModels?: PanelModelOption[];
|
||||
publishModels?: (models: PanelModelOption[]) => void;
|
||||
cachedModels?: ModelMetadata[];
|
||||
publishModels?: (models: ModelMetadata[]) => void;
|
||||
refreshOpenViews?: () => void;
|
||||
} = {},
|
||||
): CodexPanelSettingTab {
|
||||
|
|
|
|||
Loading…
Reference in a new issue