mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 17:30:31 +00:00
177 lines
6.4 KiB
TypeScript
177 lines
6.4 KiB
TypeScript
import {
|
|
approvalPolicyOrNull,
|
|
appServerApprovalsReviewerOrNull,
|
|
cloneApprovalPolicy,
|
|
parseServiceTier,
|
|
type ApprovalPolicy,
|
|
type ApprovalsReviewer,
|
|
type ServiceTier,
|
|
} from "./runtime-policy";
|
|
import { normalizeReasoningEffort, type ReasoningEffort } from "../../domain/catalog/metadata";
|
|
|
|
type ReasoningSummary = "auto" | "concise" | "detailed" | "none";
|
|
type Verbosity = "low" | "medium" | "high";
|
|
type WebSearchMode = "disabled" | "cached" | "live";
|
|
type SandboxMode = "read-only" | "workspace-write" | "danger-full-access";
|
|
|
|
export type { ActivePermissionProfile } from "./runtime-policy";
|
|
|
|
interface ConfigLayerRecord {
|
|
name: { type: string; profile?: unknown; [key: string]: unknown };
|
|
config: unknown;
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
export interface ConfigReadResult {
|
|
config: unknown;
|
|
origins?: unknown;
|
|
layers: readonly ConfigLayerRecord[] | null;
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
export interface RuntimeConfigSnapshot {
|
|
profile: string | null;
|
|
model: string | null;
|
|
modelProvider: string | null;
|
|
reasoningEffort: ReasoningEffort | null;
|
|
rawReasoningEffort: string | null;
|
|
reasoningSummary: ReasoningSummary | null;
|
|
verbosity: Verbosity | null;
|
|
serviceTier: ServiceTier | null;
|
|
approvalsReviewer: ApprovalsReviewer | null;
|
|
approvalPolicy: ApprovalPolicy | null;
|
|
webSearch: WebSearchMode | null;
|
|
modelContextWindow: number | null;
|
|
autoCompactTokenLimit: number | null;
|
|
sandboxMode: SandboxMode | null;
|
|
workspaceNetworkAccess: boolean | null;
|
|
writableRoots: readonly string[] | null;
|
|
rawToolWebSearch: unknown;
|
|
rawApps: unknown;
|
|
}
|
|
|
|
export function emptyRuntimeConfigSnapshot(): RuntimeConfigSnapshot {
|
|
return {
|
|
profile: null,
|
|
model: null,
|
|
modelProvider: null,
|
|
reasoningEffort: null,
|
|
rawReasoningEffort: null,
|
|
reasoningSummary: null,
|
|
verbosity: null,
|
|
serviceTier: null,
|
|
approvalsReviewer: null,
|
|
approvalPolicy: null,
|
|
webSearch: null,
|
|
modelContextWindow: null,
|
|
autoCompactTokenLimit: null,
|
|
sandboxMode: null,
|
|
workspaceNetworkAccess: null,
|
|
writableRoots: null,
|
|
rawToolWebSearch: null,
|
|
rawApps: null,
|
|
};
|
|
}
|
|
|
|
export function runtimeConfigSnapshotFromAppServerConfig(response: ConfigReadResult): RuntimeConfigSnapshot {
|
|
const config = asConfigRecord(response.config);
|
|
const tools = asRecordOrNull(config["tools"]);
|
|
const workspaceWrite = asRecordOrNull(config["sandbox_workspace_write"]);
|
|
const effort = config["model_reasoning_effort"];
|
|
return {
|
|
profile: selectedConfigProfile(response.layers),
|
|
model: nonEmptyStringOrNull(config["model"]),
|
|
modelProvider: nonEmptyStringOrNull(config["model_provider"]),
|
|
reasoningEffort: normalizeReasoningEffort(effort),
|
|
rawReasoningEffort: nonEmptyStringOrNull(effort),
|
|
reasoningSummary: reasoningSummaryOrNull(config["model_reasoning_summary"]),
|
|
verbosity: verbosityOrNull(config["model_verbosity"]),
|
|
serviceTier: parseServiceTier(config["service_tier"]),
|
|
approvalsReviewer: appServerApprovalsReviewerOrNull(config["approvals_reviewer"]),
|
|
approvalPolicy: approvalPolicyOrNull(config["approval_policy"]),
|
|
webSearch: webSearchModeOrNull(config["web_search"]),
|
|
modelContextWindow: numberOrNull(config["model_context_window"]),
|
|
autoCompactTokenLimit: numberOrNull(config["model_auto_compact_token_limit"]),
|
|
sandboxMode: sandboxModeOrNull(config["sandbox_mode"]),
|
|
workspaceNetworkAccess: booleanOrNull(workspaceWrite?.["network_access"]),
|
|
writableRoots: stringArrayOrNull(workspaceWrite?.["writable_roots"]),
|
|
rawToolWebSearch: cloneJsonLike(asRecordOrNull(tools?.["web_search"])),
|
|
rawApps: cloneJsonLike(asRecordOrNull(config["apps"])),
|
|
};
|
|
}
|
|
|
|
export function cloneRuntimeConfigSnapshot(config: RuntimeConfigSnapshot): RuntimeConfigSnapshot {
|
|
return {
|
|
...config,
|
|
approvalPolicy: cloneApprovalPolicy(config.approvalPolicy),
|
|
writableRoots: config.writableRoots ? [...config.writableRoots] : null,
|
|
rawToolWebSearch: cloneJsonLike(config.rawToolWebSearch),
|
|
rawApps: cloneJsonLike(config.rawApps),
|
|
};
|
|
}
|
|
|
|
type ConfigProjectionRecord = Record<string, unknown>;
|
|
|
|
function asRecord(value: unknown): Record<string, unknown> {
|
|
return value && typeof value === "object" ? (value as Record<string, unknown>) : {};
|
|
}
|
|
|
|
function asRecordOrNull(value: unknown): Record<string, unknown> | null {
|
|
return value && typeof value === "object" ? (value as Record<string, unknown>) : null;
|
|
}
|
|
|
|
function asConfigRecord(value: unknown): ConfigProjectionRecord {
|
|
return asRecord(value) as ConfigProjectionRecord;
|
|
}
|
|
|
|
function selectedConfigProfile(layers: ConfigReadResult["layers"]): string | null {
|
|
let selected: string | null = null;
|
|
if (!layers) return null;
|
|
for (const layer of layers) {
|
|
const name = layer.name;
|
|
if (name.type === "user" && typeof name.profile === "string" && name.profile.length > 0) {
|
|
selected = name.profile;
|
|
}
|
|
}
|
|
return selected;
|
|
}
|
|
|
|
function nonEmptyStringOrNull(value: unknown): string | null {
|
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
}
|
|
|
|
function numberOrNull(value: unknown): number | null {
|
|
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
if (typeof value === "bigint") return Number(value);
|
|
return null;
|
|
}
|
|
|
|
function booleanOrNull(value: unknown): boolean | null {
|
|
return typeof value === "boolean" ? value : null;
|
|
}
|
|
|
|
function stringArrayOrNull(value: unknown): string[] | null {
|
|
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : null;
|
|
}
|
|
|
|
function reasoningSummaryOrNull(value: unknown): ReasoningSummary | null {
|
|
return value === "auto" || value === "concise" || value === "detailed" || value === "none" ? value : null;
|
|
}
|
|
|
|
function verbosityOrNull(value: unknown): Verbosity | null {
|
|
return value === "low" || value === "medium" || value === "high" ? value : null;
|
|
}
|
|
|
|
function webSearchModeOrNull(value: unknown): WebSearchMode | null {
|
|
return value === "disabled" || value === "cached" || value === "live" ? value : null;
|
|
}
|
|
|
|
function sandboxModeOrNull(value: unknown): SandboxMode | null {
|
|
return value === "read-only" || value === "workspace-write" || value === "danger-full-access" ? value : null;
|
|
}
|
|
|
|
function cloneJsonLike(value: unknown): unknown {
|
|
if (Array.isArray(value)) return value.map(cloneJsonLike);
|
|
if (!value || typeof value !== "object") return value;
|
|
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, cloneJsonLike(item)]));
|
|
}
|