mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Clarify runtime module responsibilities
This commit is contained in:
parent
09545939cc
commit
8c775dcd99
47 changed files with 211 additions and 209 deletions
|
|
@ -22,7 +22,7 @@ The source tree is organized by responsibility rather than by the original singl
|
|||
- `src/features/chat/` owns the main Codex chat surface: Obsidian `ItemView` classes, panel orchestration, request/app-server controllers, composer behavior, display models, chat-only UI renderers, approvals, user input, thread actions, and panel-specific state.
|
||||
- `src/features/threads-view/` owns the dedicated Obsidian thread list view, including app-server thread list rendering and live open-panel snapshot aggregation.
|
||||
- `src/features/selection-rewrite/` owns the Markdown editor selection rewrite command, popover, prompt/output handling, and ephemeral rewrite thread runner.
|
||||
- `src/runtime/` owns Codex runtime configuration projection, model metadata, collaboration mode, and compact labels used by views.
|
||||
- `src/runtime/` owns Codex runtime config projection, model metadata, effective runtime setting resolution, override-command parsing/labels, and status summaries shared by views.
|
||||
- `src/workspace/` owns Obsidian workspace coordination across Codex surfaces, including panel discovery/opening, open-panel snapshots, and thread surface broadcasts.
|
||||
- `src/shared/` contains feature-neutral helpers, including reusable DOM pieces and unified diff display helpers shared by chat and selection rewrite.
|
||||
- `src/settings/` contains Obsidian settings models, settings-tab rendering, and app-server-backed dynamic settings data.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AppServerDiagnostics } from "../app-server/compatibility";
|
||||
import type { AppServerDiagnostics } from "./compatibility";
|
||||
import type { ConfigReadResponse } from "../generated/app-server/v2/ConfigReadResponse";
|
||||
import type { Model } from "../generated/app-server/v2/Model";
|
||||
import type { RateLimitSnapshot } from "../generated/app-server/v2/RateLimitSnapshot";
|
||||
|
|
@ -9,7 +9,7 @@ import {
|
|||
createSharedAppServerState,
|
||||
type SharedAppServerMetadata,
|
||||
type SharedAppServerState,
|
||||
} from "./shared-app-server-state";
|
||||
} from "./shared-cache-state";
|
||||
|
||||
type ThreadListRefreshLifecycleState = { kind: "idle" } | { kind: "refreshing"; promise: Promise<readonly Thread[]> };
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ import type { ThreadStartResponse } from "../generated/app-server/v2/ThreadStart
|
|||
import type { Turn } from "../generated/app-server/v2/Turn";
|
||||
import type { TurnStartResponse } from "../generated/app-server/v2/TurnStartResponse";
|
||||
import { namingPrompt, titleFromNamingTurn, type ThreadNamingContext } from "../domain/threads/naming";
|
||||
import { runtimeOverride, validatedRuntimeOverride } from "../runtime/model";
|
||||
import { runtimeOverride, validatedRuntimeOverride } from "../runtime/models";
|
||||
import {
|
||||
createStructuredTurnRunLifecycle,
|
||||
structuredTurnRunMatches,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
type CapabilityProbeMethod,
|
||||
} from "../../../app-server/compatibility";
|
||||
import type { McpServerStatus } from "../../../generated/app-server/v2/McpServerStatus";
|
||||
import type { SharedAppServerMetadata } from "../../../runtime/shared-app-server-state";
|
||||
import type { SharedAppServerMetadata } from "../../../app-server/shared-cache-state";
|
||||
import { mcpStatusLines as buildMcpStatusLines } from "../mcp-status";
|
||||
import { cloneAppServerDiagnostics, type ChatAppServerBaseHost } from "./shared";
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { type AppServerDiagnostics, capabilityProbeError, capabilityProbeOk } fr
|
|||
import type { Model } from "../../../generated/app-server/v2/Model";
|
||||
import type { RateLimitSnapshot } from "../../../generated/app-server/v2/RateLimitSnapshot";
|
||||
import type { SkillMetadata } from "../../../generated/app-server/v2/SkillMetadata";
|
||||
import type { SharedAppServerMetadata } from "../../../runtime/shared-app-server-state";
|
||||
import type { SharedAppServerMetadata } from "../../../app-server/shared-cache-state";
|
||||
import { cloneAppServerDiagnostics, type ChatAppServerBaseHost } from "./shared";
|
||||
|
||||
export interface ChatAppServerMetadataActionsHost extends ChatAppServerBaseHost {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { AppServerClient } from "../../../app-server/client";
|
||||
import { upsertThread } from "../../../domain/threads/model";
|
||||
import type { Thread } from "../../../generated/app-server/v2/Thread";
|
||||
import { requestedOrConfiguredServiceTier, type RuntimeSnapshot } from "../../../runtime/state";
|
||||
import { requestedOrConfiguredServiceTier, type RuntimeSnapshot } from "../../../runtime/effective-settings";
|
||||
import { resumedThreadAction } from "../thread-resume";
|
||||
import type { ChatAppServerBaseHost } from "./shared";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Thread } from "../../generated/app-server/v2/Thread";
|
||||
import type { SharedAppServerMetadata } from "../../runtime/shared-app-server-state";
|
||||
import type { SharedAppServerMetadata } from "../../app-server/shared-cache-state";
|
||||
import type { CodexPanelSettings } from "../../settings/model";
|
||||
import type { ChatTurnDiffViewState } from "./ui/turn-diff";
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
setPendingRuntimeSetting,
|
||||
unchangedRuntimeSetting,
|
||||
type PendingRuntimeSetting,
|
||||
} from "../../runtime/state";
|
||||
} from "../../runtime/effective-settings";
|
||||
import type { PendingApproval } from "./requests/approvals/model";
|
||||
import type { ComposerSuggestion } from "./composer/suggestions";
|
||||
import { upsertDisplayItem } from "./display/stream-updates";
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
REASONING_EFFORTS,
|
||||
sortedAvailableModels,
|
||||
supportedEffortsForModel,
|
||||
} from "../../../runtime/model";
|
||||
} from "../../../runtime/models";
|
||||
import { SLASH_COMMANDS, slashCommandSubcommands, type SlashCommandName } from "./slash-commands";
|
||||
import { getThreadTitle } from "../../../domain/threads/model";
|
||||
import { shortThreadId } from "../../../utils";
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { App, Component, EventRef, WorkspaceLeaf } from "obsidian";
|
|||
|
||||
import type { AppServerClient } from "../../../app-server/client";
|
||||
import type { ArchiveExportAdapter } from "../../../domain/threads/export";
|
||||
import type { RuntimeSnapshot } from "../../../runtime/state";
|
||||
import type { RuntimeSnapshot } from "../../../runtime/effective-settings";
|
||||
import type { ChatState, ChatStateStore } from "../chat-state";
|
||||
import type { CodexChatHost } from "../chat-host";
|
||||
import type { ChatMessageScrollIntentController } from "../panel/message-scroll-intent-controller";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { readRuntimeConfig } from "../../../../runtime/config";
|
||||
import { autoReviewActive, currentModel, currentReasoningEffort, fastModeActive } from "../../../../runtime/state";
|
||||
import { compactReasoningEffortLabel } from "../../../../runtime/settings";
|
||||
import { contextSummary } from "../../../../runtime/view";
|
||||
import { autoReviewActive, currentModel, currentReasoningEffort, fastModeActive } from "../../../../runtime/effective-settings";
|
||||
import { compactReasoningEffortLabel } from "../../../../runtime/override-commands";
|
||||
import { contextSummary } from "../../../../runtime/status-summary";
|
||||
import type { ChatState } from "../../chat-state";
|
||||
import type { ComposerContextMeterCellViewModel, ComposerContextMeterViewModel, ComposerMetaViewModel } from "./types";
|
||||
import type { runtimeSnapshotForChatState } from "./runtime";
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import {
|
|||
pendingRuntimeSettingLabel,
|
||||
serviceTierLabel,
|
||||
supportedReasoningEfforts,
|
||||
} from "../../../../runtime/state";
|
||||
import { sortedAvailableModels } from "../../../../runtime/model";
|
||||
import { contextSummary, rateLimitSummary } from "../../../../runtime/view";
|
||||
} from "../../../../runtime/effective-settings";
|
||||
import { sortedAvailableModels } from "../../../../runtime/models";
|
||||
import { contextSummary, rateLimitSummary } from "../../../../runtime/status-summary";
|
||||
import type { ChatState } from "../../chat-state";
|
||||
import { statusValue, usageLimitStatusLines } from "../../status-lines";
|
||||
import type { RuntimeChoice, RuntimeComposerChoicesInput, RuntimeSnapshotInput } from "./types";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Thread } from "../../../../generated/app-server/v2/Thread";
|
||||
import { getThreadTitle } from "../../../../domain/threads/model";
|
||||
import { effectiveConfigSections, rateLimitSummary } from "../../../../runtime/view";
|
||||
import { effectiveConfigSections, rateLimitSummary } from "../../../../runtime/status-summary";
|
||||
import type { ToolbarThreadRow, ToolbarViewModel } from "../../toolbar-model";
|
||||
import { connectionDiagnosticsModel } from "./diagnostics";
|
||||
import type { ToolbarViewModelInput } from "./types";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ReasoningEffort } from "../../../../generated/app-server/ReasoningEffort";
|
||||
import type { RuntimeSnapshot } from "../../../../runtime/state";
|
||||
import type { RuntimeSnapshot } from "../../../../runtime/effective-settings";
|
||||
import type { ChatState } from "../../chat-state";
|
||||
import type { ToolbarThreadRow } from "../../toolbar-model";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ReasoningEffort } from "../../../../generated/app-server/ReasoningEffort";
|
||||
import type { RuntimeSnapshot } from "../../../../runtime/state";
|
||||
import type { RuntimeSnapshot } from "../../../../runtime/effective-settings";
|
||||
import type { SendShortcut } from "../../../../shared/ui/keyboard";
|
||||
import type { ChatState } from "../../chat-state";
|
||||
import type { ToolbarThreadRow } from "../../toolbar-model";
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import type { Model } from "../../../generated/app-server/v2/Model";
|
||||
import type { Thread } from "../../../generated/app-server/v2/Thread";
|
||||
import type { OpenCodexPanelSnapshot } from "../../../runtime/open-panel-snapshot";
|
||||
import type { OpenCodexPanelSnapshot } from "../../../workspace/open-panel-snapshot";
|
||||
import { readRuntimeConfig } from "../../../runtime/config";
|
||||
import { currentModel } from "../../../runtime/state";
|
||||
import { currentModel } from "../../../runtime/effective-settings";
|
||||
import { activeTurnId, chatTurnBusy, type ChatState } from "../chat-state";
|
||||
import type { DisplayItem } from "../display/types";
|
||||
import type { RestoredThreadState } from "./lifecycle";
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import type { ModeKind } from "../../../generated/app-server/ModeKind";
|
|||
import type { ReasoningEffort } from "../../../generated/app-server/ReasoningEffort";
|
||||
import type { ApprovalsReviewer } from "../../../generated/app-server/v2/ApprovalsReviewer";
|
||||
import type { ThreadSettingsUpdateParams } from "../../../generated/app-server/v2/ThreadSettingsUpdateParams";
|
||||
import { collaborationModeToggleMessage, nextCollaborationMode } from "../../../runtime/collaboration-mode";
|
||||
import { collaborationModeToggleMessage, nextCollaborationMode } from "../../../runtime/override-commands";
|
||||
import { readRuntimeConfig } from "../../../runtime/config";
|
||||
import {
|
||||
autoReviewActive,
|
||||
|
|
@ -13,8 +13,8 @@ import {
|
|||
pendingRuntimeSettingPayload,
|
||||
requestedTurnRuntimeSettings,
|
||||
type RuntimeSnapshot,
|
||||
} from "../../../runtime/state";
|
||||
import { modelOverrideMessage, reasoningEffortOverrideMessage } from "../../../runtime/settings";
|
||||
} from "../../../runtime/effective-settings";
|
||||
import { modelOverrideMessage, reasoningEffortOverrideMessage } from "../../../runtime/override-commands";
|
||||
import type { ChatAction, ChatState, ChatStateStore } from "../chat-state";
|
||||
|
||||
type ThreadSettingsUpdate = Omit<ThreadSettingsUpdateParams, "threadId">;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import {
|
|||
parseModelOverride,
|
||||
parseReasoningEffortOverride,
|
||||
reasoningEffortOverrideMessage,
|
||||
} from "../../runtime/settings";
|
||||
} from "../../runtime/override-commands";
|
||||
|
||||
export interface SlashCommandExecutionContext {
|
||||
activeThreadId: string | null;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { RateLimitSummary } from "../../runtime/view";
|
||||
import type { RateLimitSummary } from "../../runtime/status-summary";
|
||||
|
||||
export function statusValue(value: unknown, fallback: string): string {
|
||||
if (typeof value === "string") return value;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { EffectiveConfigSection, RateLimitSummary } from "../../runtime/view";
|
||||
import type { EffectiveConfigSection, RateLimitSummary } from "../../runtime/status-summary";
|
||||
|
||||
type ToolbarPanelKind = "history" | "chat-actions" | "status";
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import type { ChatThreadGoalActions } from "../threads/thread-goal-actions";
|
|||
import type { ThreadHistoryController } from "../threads/thread-history-controller";
|
||||
import type { ThreadRenameController } from "../threads/thread-rename-controller";
|
||||
import type { ChatInboundController } from "../inbound/controller";
|
||||
import { currentModel } from "../../../runtime/state";
|
||||
import { currentModel } from "../../../runtime/effective-settings";
|
||||
import { ChatMessageRenderer } from "../ui/message-stream";
|
||||
import type { ChatPanelContext } from "../panel/context";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { ButtonHTMLAttributes, ComponentChild as UiNode, TargetedKeyboardEvent } from "preact";
|
||||
import { useLayoutEffect, useRef } from "preact/hooks";
|
||||
|
||||
import type { EffectiveConfigSection, RateLimitSummary } from "../../../runtime/view";
|
||||
import type { EffectiveConfigSection, RateLimitSummary } from "../../../runtime/status-summary";
|
||||
import { IconButton } from "../../../shared/ui/components";
|
||||
import { renderUiRoot } from "../../../shared/ui/ui-root";
|
||||
import type { ToolbarDiagnosticSection, ToolbarThreadRow, ToolbarViewModel } from "../toolbar-model";
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import type { DisplayDetailSection, DisplayItem } from "./display/types";
|
|||
import type { ReasoningEffort } from "../../generated/app-server/ReasoningEffort";
|
||||
import type { Model } from "../../generated/app-server/v2/Model";
|
||||
import type { Thread } from "../../generated/app-server/v2/Thread";
|
||||
import { collaborationModeLabel as formatCollaborationModeLabel } from "../../runtime/collaboration-mode";
|
||||
import type { RuntimeSnapshot } from "../../runtime/state";
|
||||
import { collaborationModeLabel as formatCollaborationModeLabel } from "../../runtime/override-commands";
|
||||
import type { RuntimeSnapshot } from "../../runtime/effective-settings";
|
||||
import { chatTurnBusy, createChatStateStore, type ChatState, type ChatAction } from "./chat-state";
|
||||
import type { OpenCodexPanelSnapshot } from "../../runtime/open-panel-snapshot";
|
||||
import type { SharedAppServerMetadata } from "../../runtime/shared-app-server-state";
|
||||
import type { OpenCodexPanelSnapshot } from "../../workspace/open-panel-snapshot";
|
||||
import type { SharedAppServerMetadata } from "../../app-server/shared-cache-state";
|
||||
import type { CodexChatHost } from "./chat-host";
|
||||
import { createSystemItem } from "./display/system";
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import type { ThreadItem } from "../../generated/app-server/v2/ThreadItem";
|
|||
import type { ThreadStartResponse } from "../../generated/app-server/v2/ThreadStartResponse";
|
||||
import type { Turn } from "../../generated/app-server/v2/Turn";
|
||||
import type { TurnStartResponse } from "../../generated/app-server/v2/TurnStartResponse";
|
||||
import { runtimeOverride, validatedRuntimeOverride } from "../../runtime/model";
|
||||
import { runtimeOverride, validatedRuntimeOverride } from "../../runtime/models";
|
||||
import type { SelectionRewriteRuntimeSettings } from "./model";
|
||||
import { SELECTION_REWRITE_DEVELOPER_INSTRUCTIONS, SELECTION_REWRITE_SERVICE_NAME } from "./prompt";
|
||||
import { SelectionRewriteOutputError, selectionRewriteOutputParseResultFromTurn, type SelectionRewriteOutput } from "./output";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { OpenCodexPanelSnapshot } from "../../runtime/open-panel-snapshot";
|
||||
import type { OpenCodexPanelSnapshot } from "../../workspace/open-panel-snapshot";
|
||||
import type { Thread } from "../../generated/app-server/v2/Thread";
|
||||
import { getThreadTitle } from "../../domain/threads/model";
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { VIEW_TYPE_CODEX_THREADS } from "../../constants";
|
|||
import type { Thread } from "../../generated/app-server/v2/Thread";
|
||||
import type { CodexPanelSettings } from "../../settings/model";
|
||||
import { exportArchivedThreadMarkdown } from "../../domain/threads/export";
|
||||
import type { OpenCodexPanelSnapshot } from "../../runtime/open-panel-snapshot";
|
||||
import type { OpenCodexPanelSnapshot } from "../../workspace/open-panel-snapshot";
|
||||
import { findThreadNamingContext, THREAD_NAMING_CONTEXT_UNAVAILABLE_MESSAGE } from "../../domain/threads/naming";
|
||||
import { generateThreadTitleWithCodex } from "../../app-server/thread-naming";
|
||||
import { renderThreadsView, unmountThreadsView } from "./renderer";
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import type { CodexChatHost } from "./features/chat/chat-host";
|
|||
import { CodexChatTurnDiffView } from "./features/chat/chat-turn-diff-view";
|
||||
import { openThreadPicker, type ThreadPickerHost } from "./features/thread-picker/modal";
|
||||
import { CodexThreadsView, type CodexThreadsHost } from "./features/threads-view/view";
|
||||
import { SharedAppServerCache } from "./runtime/shared-app-server-cache";
|
||||
import { SharedAppServerCache } from "./app-server/shared-cache";
|
||||
import { DEFAULT_SETTINGS, getVaultPath, normalizeSettings, settingsMatchNormalizedData, type CodexPanelSettings } from "./settings/model";
|
||||
import { CodexPanelSettingTab, type CodexPanelSettingTabHost } from "./settings/tab";
|
||||
import { persistedChatTurnDiffViewState, type ChatTurnDiffViewState } from "./features/chat/ui/turn-diff";
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
import type { CollaborationMode } from "../generated/app-server/CollaborationMode";
|
||||
import type { ModeKind } from "../generated/app-server/ModeKind";
|
||||
import type { ReasoningEffort } from "../generated/app-server/ReasoningEffort";
|
||||
|
||||
export function nextCollaborationMode(mode: ModeKind): ModeKind {
|
||||
return mode === "plan" ? "default" : "plan";
|
||||
}
|
||||
|
||||
export function collaborationModeLabel(mode: ModeKind): string {
|
||||
return mode === "plan" ? "Plan" : "Default";
|
||||
}
|
||||
|
||||
export function collaborationModeToggleMessage(mode: ModeKind): string {
|
||||
return mode === "plan" ? "Plan mode on for subsequent turns." : "Plan mode off for subsequent turns.";
|
||||
}
|
||||
|
||||
export function planCollaborationMode(model: string, reasoningEffort: ReasoningEffort | null): CollaborationMode {
|
||||
return {
|
||||
mode: "plan",
|
||||
settings: {
|
||||
model,
|
||||
reasoning_effort: reasoningEffort,
|
||||
developer_instructions: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function defaultCollaborationMode(model: string, reasoningEffort: ReasoningEffort | null): CollaborationMode {
|
||||
return {
|
||||
mode: "default",
|
||||
settings: {
|
||||
model,
|
||||
reasoning_effort: reasoningEffort,
|
||||
developer_instructions: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import type { SandboxMode } from "../generated/app-server/v2/SandboxMode";
|
|||
import type { SandboxWorkspaceWrite } from "../generated/app-server/v2/SandboxWorkspaceWrite";
|
||||
import type { ToolsV2 } from "../generated/app-server/v2/ToolsV2";
|
||||
import { parseServiceTier, type ServiceTier } from "../app-server/service-tier";
|
||||
import { isReasoningEffort } from "./model";
|
||||
import { isReasoningEffort } from "./models";
|
||||
|
||||
export interface RuntimeConfigProjection {
|
||||
profile: string | null;
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ import {
|
|||
type ServiceTier,
|
||||
type ServiceTierRequest,
|
||||
} from "../app-server/service-tier";
|
||||
import { defaultCollaborationMode, planCollaborationMode } from "./collaboration-mode";
|
||||
import { findModelByIdOrName, supportedEffortsForModel } from "./model";
|
||||
import { findModelByIdOrName, supportedEffortsForModel } from "./models";
|
||||
import { readRuntimeConfig, type RuntimeConfigProjection } from "./config";
|
||||
|
||||
export type PendingRuntimeSetting<T> = { kind: "unchanged" } | { kind: "set"; value: T } | { kind: "resetToConfig" };
|
||||
|
|
@ -116,11 +115,7 @@ export function autoReviewActive(
|
|||
export function requestedTurnRuntimeSettings(snapshot: RuntimeSnapshot): TurnRuntimeSettings {
|
||||
const model = currentModel(snapshot);
|
||||
const effort = currentReasoningEffort(snapshot);
|
||||
const collaborationMode = model
|
||||
? snapshot.selectedCollaborationMode === "plan"
|
||||
? planCollaborationMode(model, effort)
|
||||
: defaultCollaborationMode(model, effort)
|
||||
: null;
|
||||
const collaborationMode = model ? turnCollaborationMode(snapshot.selectedCollaborationMode, model, effort) : null;
|
||||
return {
|
||||
collaborationMode,
|
||||
warning: model ? null : "No effective model is available. Sending without a mode override.",
|
||||
|
|
@ -191,6 +186,17 @@ function isAutoReviewReviewer(value: ApprovalsReviewer | null): boolean {
|
|||
return value === "auto_review" || value === "guardian_subagent";
|
||||
}
|
||||
|
||||
function turnCollaborationMode(mode: ModeKind, model: string, reasoningEffort: ReasoningEffort | null): CollaborationMode {
|
||||
return {
|
||||
mode,
|
||||
settings: {
|
||||
model,
|
||||
reasoning_effort: reasoningEffort,
|
||||
developer_instructions: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function currentModelServiceTiers(
|
||||
snapshot: RuntimeSnapshot,
|
||||
config: RuntimeConfigProjection = readRuntimeConfig(snapshot.effectiveConfig),
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import type { ReasoningEffort } from "../generated/app-server/ReasoningEffort";
|
||||
import { isReasoningEffort } from "./model";
|
||||
import type { ModeKind } from "../generated/app-server/ModeKind";
|
||||
import { isReasoningEffort } from "./models";
|
||||
|
||||
const DEFAULT_ALIASES = new Set(["default", "reset", "clear", "off"]);
|
||||
|
||||
|
|
@ -38,3 +39,15 @@ export function compactReasoningEffortLabel(effort: ReasoningEffort | null): str
|
|||
if (effort === "minimal") return "min";
|
||||
return effort;
|
||||
}
|
||||
|
||||
export function nextCollaborationMode(mode: ModeKind): ModeKind {
|
||||
return mode === "plan" ? "default" : "plan";
|
||||
}
|
||||
|
||||
export function collaborationModeLabel(mode: ModeKind): string {
|
||||
return mode === "plan" ? "Plan" : "Default";
|
||||
}
|
||||
|
||||
export function collaborationModeToggleMessage(mode: ModeKind): string {
|
||||
return mode === "plan" ? "Plan mode on for subsequent turns." : "Plan mode off for subsequent turns.";
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ import type { RateLimitWindow } from "../generated/app-server/v2/RateLimitWindow
|
|||
import type { SpendControlLimitSnapshot } from "../generated/app-server/v2/SpendControlLimitSnapshot";
|
||||
import type { ThreadTokenUsage } from "../generated/app-server/v2/ThreadTokenUsage";
|
||||
import { jsonPreview } from "../utils";
|
||||
import { sortedAvailableModels } from "./model";
|
||||
import { sortedAvailableModels } from "./models";
|
||||
import { readRuntimeConfig, type RuntimeConfigProjection } from "./config";
|
||||
import {
|
||||
currentApprovalsReviewer,
|
||||
|
|
@ -14,7 +14,7 @@ import {
|
|||
pendingRuntimeSettingLabel,
|
||||
serviceTierLabel,
|
||||
type RuntimeSnapshot,
|
||||
} from "./state";
|
||||
} from "./effective-settings";
|
||||
|
||||
export interface ContextSummary {
|
||||
label: string;
|
||||
|
|
@ -2,7 +2,7 @@ import { FileSystemAdapter, type App } from "obsidian";
|
|||
|
||||
import { DEFAULT_CODEX_PATH } from "../constants";
|
||||
import type { ReasoningEffort } from "../generated/app-server/ReasoningEffort";
|
||||
import { normalizeReasoningEffort } from "../runtime/model";
|
||||
import { normalizeReasoningEffort } from "../runtime/models";
|
||||
import type { SendShortcut } from "../shared/ui/keyboard";
|
||||
|
||||
export interface CodexPanelSettings {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import type { ReasoningEffort } from "../generated/app-server/ReasoningEffort";
|
|||
import type { HookMetadata } from "../generated/app-server/v2/HookMetadata";
|
||||
import type { Model } from "../generated/app-server/v2/Model";
|
||||
import type { Thread } from "../generated/app-server/v2/Thread";
|
||||
import { findModelByIdOrName, REASONING_EFFORTS, sortedAvailableModels, supportedEffortsForModel } from "../runtime/model";
|
||||
import { findModelByIdOrName, REASONING_EFFORTS, sortedAvailableModels, supportedEffortsForModel } from "../runtime/models";
|
||||
import { archivedThreadDisplayTitle } from "../domain/threads/model";
|
||||
import { errorMessage } from "../utils";
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { App, WorkspaceLeaf } from "obsidian";
|
|||
|
||||
import { VIEW_TYPE_CODEX_PANEL } from "../constants";
|
||||
import { CodexChatView } from "../features/chat/view";
|
||||
import type { OpenCodexPanelSnapshot } from "../runtime/open-panel-snapshot";
|
||||
import type { OpenCodexPanelSnapshot } from "./open-panel-snapshot";
|
||||
|
||||
const BOOT_RESTORED_PANEL_LOAD_DELAY_MS = 1_000;
|
||||
const BOOT_RESTORED_PANEL_LOAD_STAGGER_MS = 250;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { VIEW_TYPE_CODEX_THREADS } from "../constants";
|
|||
import { CodexThreadsView } from "../features/threads-view/view";
|
||||
import type { Model } from "../generated/app-server/v2/Model";
|
||||
import type { Thread } from "../generated/app-server/v2/Thread";
|
||||
import type { SharedAppServerMetadata } from "../runtime/shared-app-server-state";
|
||||
import type { SharedAppServerMetadata } from "../app-server/shared-cache-state";
|
||||
import type { WorkspacePanelCoordinator } from "./panel-coordinator";
|
||||
|
||||
export interface ThreadSurfaceCoordinatorOptions {
|
||||
|
|
|
|||
93
tests/app-server/shared-cache-state.test.ts
Normal file
93
tests/app-server/shared-cache-state.test.ts
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { createAppServerDiagnostics } from "../../src/app-server/compatibility";
|
||||
import {
|
||||
applySharedAppServerMetadata,
|
||||
applySharedModels,
|
||||
applySharedThreadList,
|
||||
cachedSharedAppServerMetadata,
|
||||
cachedSharedThreadList,
|
||||
createSharedAppServerState,
|
||||
} from "../../src/app-server/shared-cache-state";
|
||||
import type { Model } from "../../src/generated/app-server/v2/Model";
|
||||
import type { Thread } from "../../src/generated/app-server/v2/Thread";
|
||||
|
||||
describe("shared app-server cache state", () => {
|
||||
it("keeps snapshots detached from caller-owned arrays", () => {
|
||||
const sourceThreads = [threadFixture("thread-1")];
|
||||
const threadState = applySharedThreadList(createSharedAppServerState(), sourceThreads);
|
||||
sourceThreads.push(threadFixture("thread-2"));
|
||||
|
||||
const cachedThreads = cachedSharedThreadList(threadState);
|
||||
expect(cachedThreads?.map((thread) => thread.id)).toEqual(["thread-1"]);
|
||||
|
||||
const mutableCachedThreads = cachedThreads as Thread[];
|
||||
mutableCachedThreads.push(threadFixture("thread-3"));
|
||||
expect(cachedSharedThreadList(threadState)?.map((thread) => thread.id)).toEqual(["thread-1"]);
|
||||
|
||||
const sourceModels = [modelFixture("gpt-5.5")];
|
||||
const modelState = applySharedModels(createSharedAppServerState(), sourceModels);
|
||||
sourceModels.push(modelFixture("gpt-5.6"));
|
||||
expect(modelState.availableModels.map((model) => model.model)).toEqual(["gpt-5.5"]);
|
||||
|
||||
const metadataState = applySharedAppServerMetadata(createSharedAppServerState(), {
|
||||
effectiveConfig: null,
|
||||
availableModels: sourceModels,
|
||||
availableSkills: [{ name: "skill", description: "", path: "/tmp/skill", scope: "repo", enabled: true }],
|
||||
rateLimit: null,
|
||||
appServerDiagnostics: {
|
||||
...createAppServerDiagnostics(),
|
||||
mcpServers: [{ name: "server", startupStatus: "ready", authStatus: null, toolCount: 1, message: null }],
|
||||
},
|
||||
});
|
||||
sourceModels.push(modelFixture("gpt-5.7"));
|
||||
const cachedMetadata = cachedSharedAppServerMetadata(metadataState);
|
||||
expect(cachedMetadata?.availableModels.map((model) => model.model)).toEqual(["gpt-5.5", "gpt-5.6"]);
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
turns: [],
|
||||
};
|
||||
}
|
||||
|
||||
function modelFixture(model: string): Model {
|
||||
return {
|
||||
id: model,
|
||||
model,
|
||||
upgrade: null,
|
||||
upgradeInfo: null,
|
||||
availabilityNux: null,
|
||||
displayName: model,
|
||||
description: "",
|
||||
hidden: false,
|
||||
supportedReasoningEfforts: [],
|
||||
defaultReasoningEffort: "medium",
|
||||
inputModalities: [],
|
||||
supportsPersonality: false,
|
||||
additionalSpeedTiers: [],
|
||||
serviceTiers: [],
|
||||
defaultServiceTier: null,
|
||||
isDefault: false,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { statusValue, usageLimitStatusLines } from "../../../src/features/chat/status-lines";
|
||||
import type { RateLimitSummary } from "../../../src/runtime/view";
|
||||
import type { RateLimitSummary } from "../../../src/runtime/status-summary";
|
||||
|
||||
describe("status line helpers", () => {
|
||||
it("formats primitive and structured diagnostic values", () => {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
type ThreadsRowModel,
|
||||
} from "../../../src/features/threads-view/state";
|
||||
import type { Thread } from "../../../src/generated/app-server/v2/Thread";
|
||||
import type { OpenCodexPanelSnapshot } from "../../../src/runtime/open-panel-snapshot";
|
||||
import type { OpenCodexPanelSnapshot } from "../../../src/workspace/open-panel-snapshot";
|
||||
import { changeInputValue, installObsidianDomShims } from "../../support/dom";
|
||||
|
||||
installObsidianDomShims();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { DEFAULT_SETTINGS } from "../src/settings/model";
|
|||
import type CodexPanelPlugin from "../src/main";
|
||||
import type { CodexChatView } from "../src/features/chat/view";
|
||||
import type { Thread } from "../src/generated/app-server/v2/Thread";
|
||||
import type { SharedAppServerCache } from "../src/runtime/shared-app-server-cache";
|
||||
import type { SharedAppServerCache } from "../src/app-server/shared-cache";
|
||||
import type { WorkspacePanelCoordinator } from "../src/workspace/panel-coordinator";
|
||||
import type { ThreadSurfaceCoordinator } from "../src/workspace/thread-surface-coordinator";
|
||||
import { installObsidianDomShims } from "./support/dom";
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
collaborationModeLabel,
|
||||
collaborationModeToggleMessage,
|
||||
defaultCollaborationMode,
|
||||
nextCollaborationMode,
|
||||
planCollaborationMode,
|
||||
} from "../../src/runtime/collaboration-mode";
|
||||
|
||||
describe("collaboration mode", () => {
|
||||
it("toggles between Default and Plan mode", () => {
|
||||
expect(nextCollaborationMode("default")).toBe("plan");
|
||||
expect(nextCollaborationMode("plan")).toBe("default");
|
||||
expect(collaborationModeLabel("default")).toBe("Default");
|
||||
expect(collaborationModeLabel("plan")).toBe("Plan");
|
||||
});
|
||||
|
||||
it("formats slash command status messages", () => {
|
||||
expect(collaborationModeToggleMessage("plan")).toBe("Plan mode on for subsequent turns.");
|
||||
expect(collaborationModeToggleMessage("default")).toBe("Plan mode off for subsequent turns.");
|
||||
});
|
||||
|
||||
it("builds the Plan collaboration mode payload", () => {
|
||||
expect(planCollaborationMode("gpt-5.5", "high")).toEqual({
|
||||
mode: "plan",
|
||||
settings: {
|
||||
model: "gpt-5.5",
|
||||
reasoning_effort: "high",
|
||||
developer_instructions: null,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("builds the Default collaboration mode payload", () => {
|
||||
expect(defaultCollaborationMode("gpt-5.5", "high")).toEqual({
|
||||
mode: "default",
|
||||
settings: {
|
||||
model: "gpt-5.5",
|
||||
reasoning_effort: "high",
|
||||
developer_instructions: null,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
17
tests/runtime/override-commands.test.ts
Normal file
17
tests/runtime/override-commands.test.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { collaborationModeLabel, collaborationModeToggleMessage, nextCollaborationMode } from "../../src/runtime/override-commands";
|
||||
|
||||
describe("runtime override commands", () => {
|
||||
it("toggles between Default and Plan mode", () => {
|
||||
expect(nextCollaborationMode("default")).toBe("plan");
|
||||
expect(nextCollaborationMode("plan")).toBe("default");
|
||||
expect(collaborationModeLabel("default")).toBe("Default");
|
||||
expect(collaborationModeLabel("plan")).toBe("Plan");
|
||||
});
|
||||
|
||||
it("formats slash command status messages", () => {
|
||||
expect(collaborationModeToggleMessage("plan")).toBe("Plan mode on for subsequent turns.");
|
||||
expect(collaborationModeToggleMessage("default")).toBe("Plan mode off for subsequent turns.");
|
||||
});
|
||||
});
|
||||
|
|
@ -2,8 +2,6 @@ import { describe, expect, it } from "vitest";
|
|||
|
||||
import type { ConfigReadResponse } from "../../src/generated/app-server/v2/ConfigReadResponse";
|
||||
import type { Model } from "../../src/generated/app-server/v2/Model";
|
||||
import type { Thread } from "../../src/generated/app-server/v2/Thread";
|
||||
import { createAppServerDiagnostics } from "../../src/app-server/compatibility";
|
||||
import {
|
||||
compactModelLabel,
|
||||
compactReasoningEffortLabel,
|
||||
|
|
@ -11,7 +9,7 @@ import {
|
|||
parseModelOverride,
|
||||
parseReasoningEffortOverride,
|
||||
reasoningEffortOverrideMessage,
|
||||
} from "../../src/runtime/settings";
|
||||
} from "../../src/runtime/override-commands";
|
||||
import {
|
||||
autoReviewActive,
|
||||
currentApprovalsReviewer,
|
||||
|
|
@ -28,17 +26,9 @@ import {
|
|||
setPendingRuntimeSetting,
|
||||
serviceTierLabel,
|
||||
type RuntimeSnapshot,
|
||||
} from "../../src/runtime/state";
|
||||
} from "../../src/runtime/effective-settings";
|
||||
import { readRuntimeConfig } from "../../src/runtime/config";
|
||||
import { contextSummary, effectiveConfigSections, rateLimitSummary } from "../../src/runtime/view";
|
||||
import {
|
||||
applySharedAppServerMetadata,
|
||||
applySharedModels,
|
||||
applySharedThreadList,
|
||||
cachedSharedAppServerMetadata,
|
||||
cachedSharedThreadList,
|
||||
createSharedAppServerState,
|
||||
} from "../../src/runtime/shared-app-server-state";
|
||||
import { contextSummary, effectiveConfigSections, rateLimitSummary } from "../../src/runtime/status-summary";
|
||||
|
||||
describe("runtime settings", () => {
|
||||
it("parses model overrides", () => {
|
||||
|
|
@ -47,38 +37,6 @@ describe("runtime settings", () => {
|
|||
expect(parseModelOverride("")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps shared app-server cache snapshots detached from caller-owned arrays", () => {
|
||||
const sourceThreads = [threadFixture("thread-1")];
|
||||
const threadState = applySharedThreadList(createSharedAppServerState(), sourceThreads);
|
||||
sourceThreads.push(threadFixture("thread-2"));
|
||||
|
||||
const cachedThreads = cachedSharedThreadList(threadState);
|
||||
expect(cachedThreads?.map((thread) => thread.id)).toEqual(["thread-1"]);
|
||||
|
||||
const mutableCachedThreads = cachedThreads as Thread[];
|
||||
mutableCachedThreads.push(threadFixture("thread-3"));
|
||||
expect(cachedSharedThreadList(threadState)?.map((thread) => thread.id)).toEqual(["thread-1"]);
|
||||
|
||||
const sourceModels = [modelFixture("gpt-5.5")];
|
||||
const modelState = applySharedModels(createSharedAppServerState(), sourceModels);
|
||||
sourceModels.push(modelFixture("gpt-5.6"));
|
||||
expect(modelState.availableModels.map((model) => model.model)).toEqual(["gpt-5.5"]);
|
||||
|
||||
const metadataState = applySharedAppServerMetadata(createSharedAppServerState(), {
|
||||
effectiveConfig: null,
|
||||
availableModels: sourceModels,
|
||||
availableSkills: [{ name: "skill", description: "", path: "/tmp/skill", scope: "repo", enabled: true }],
|
||||
rateLimit: null,
|
||||
appServerDiagnostics: {
|
||||
...createAppServerDiagnostics(),
|
||||
mcpServers: [{ name: "server", startupStatus: "ready", authStatus: null, toolCount: 1, message: null }],
|
||||
},
|
||||
});
|
||||
sourceModels.push(modelFixture("gpt-5.7"));
|
||||
const cachedMetadata = cachedSharedAppServerMetadata(metadataState);
|
||||
expect(cachedMetadata?.availableModels.map((model) => model.model)).toEqual(["gpt-5.5", "gpt-5.6"]);
|
||||
});
|
||||
|
||||
it("parses reasoning effort overrides", () => {
|
||||
expect(parseReasoningEffortOverride("high")).toBe("high");
|
||||
expect(parseReasoningEffortOverride("default")).toBeNull();
|
||||
|
|
@ -131,6 +89,28 @@ describe("runtime settings", () => {
|
|||
expect(pendingRuntimeSettingPayload(snapshot.requestedReasoningEffort)).toBe("low");
|
||||
});
|
||||
|
||||
it("builds the Plan collaboration mode payload from selected runtime settings", () => {
|
||||
expect(
|
||||
requestedTurnRuntimeSettings(
|
||||
runtimeSnapshot({
|
||||
selectedCollaborationMode: "plan",
|
||||
requestedModel: setPendingRuntimeSetting("gpt-5.5"),
|
||||
requestedReasoningEffort: setPendingRuntimeSetting("high"),
|
||||
}),
|
||||
),
|
||||
).toEqual({
|
||||
collaborationMode: {
|
||||
mode: "plan",
|
||||
settings: {
|
||||
model: "gpt-5.5",
|
||||
reasoning_effort: "high",
|
||||
developer_instructions: null,
|
||||
},
|
||||
},
|
||||
warning: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves approval reviewer from requested, active, then effective config", () => {
|
||||
expect(
|
||||
currentApprovalsReviewer(
|
||||
|
|
@ -701,31 +681,6 @@ function configLayer(config: Record<string, unknown>, profile: string | null): N
|
|||
};
|
||||
}
|
||||
|
||||
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,
|
||||
turns: [],
|
||||
};
|
||||
}
|
||||
|
||||
function modelFixture(model: string): Model {
|
||||
return {
|
||||
id: model,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ 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 { findModelByIdOrName, sortedAvailableModels, supportedEffortsForModel } from "../../src/runtime/model";
|
||||
import { findModelByIdOrName, sortedAvailableModels, supportedEffortsForModel } from "../../src/runtime/models";
|
||||
import { CodexPanelSettingTab } from "../../src/settings/tab";
|
||||
import { archivedThreadDisplayTitle } from "../../src/domain/threads/model";
|
||||
import { notices } from "../mocks/obsidian";
|
||||
|
|
|
|||
Loading…
Reference in a new issue