Narrow chat runtime projections

This commit is contained in:
murashit 2026-06-22 20:48:19 +09:00
parent b6629a75db
commit 7d36b552a0
38 changed files with 30 additions and 329 deletions

View file

@ -1,6 +1,6 @@
import { normalizeReasoningEffort } from "../../domain/catalog/metadata";
import { approvalPolicyOrNull, approvalsReviewerOrNull, parseServiceTier } from "../../domain/runtime/policy";
import type { ReasoningSummary, SandboxMode, RuntimeConfigSnapshot, Verbosity, WebSearchMode } from "../../domain/runtime/config";
import { approvalsReviewerOrNull, parseServiceTier } from "../../domain/runtime/policy";
import type { ReasoningSummary, RuntimeConfigSnapshot, Verbosity } from "../../domain/runtime/config";
interface ConfigLayerRecord {
name: { type: string; profile?: unknown; [key: string]: unknown };
@ -17,28 +17,18 @@ export interface ConfigReadResult {
export function runtimeConfigSnapshotFromAppServerConfig(response: ConfigReadResult): RuntimeConfigSnapshot {
const config = asRecord(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: approvalsReviewerOrNull(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"])),
};
}
@ -46,10 +36,6 @@ 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 selectedConfigProfile(layers: ConfigReadResult["layers"]): string | null {
let selected: string | null = null;
if (!layers) return null;
@ -72,14 +58,6 @@ function numberOrNull(value: unknown): number | null {
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;
}
@ -87,17 +65,3 @@ function reasoningSummaryOrNull(value: unknown): ReasoningSummary | 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)]));
}

View file

@ -7,7 +7,7 @@ import {
transcriptEntriesFromTurnRecords,
} from "./protocol/turn";
import { normalizeReasoningEffort } from "../domain/catalog/metadata";
import type { ActivePermissionProfile, ApprovalPolicy, ApprovalsReviewer, ServiceTier } from "../domain/runtime/policy";
import type { ApprovalsReviewer, ServiceTier } from "../domain/runtime/policy";
import { parseServiceTier } from "../domain/runtime/policy";
import type { ArchiveThreadInput } from "../domain/threads/archive-markdown";
import type { ThreadActivationSnapshot } from "../domain/threads/activation";
@ -31,9 +31,7 @@ interface ThreadActivationResponse {
cwd: string;
model: string | null;
serviceTier: ServiceTier | null;
approvalPolicy: ApprovalPolicy | null;
approvalsReviewer: ApprovalsReviewer | null;
activePermissionProfile: ActivePermissionProfile | null;
reasoningEffort: string | null;
}
@ -140,9 +138,7 @@ export function threadActivationSnapshotFromAppServerResponse(response: ThreadAc
model: response.model,
reasoningEffort: normalizeReasoningEffort(response.reasoningEffort),
serviceTier: parseServiceTier(response.serviceTier),
approvalPolicy: response.approvalPolicy,
approvalsReviewer: response.approvalsReviewer,
activePermissionProfile: response.activePermissionProfile,
};
}

View file

@ -1,30 +1,20 @@
import type { ReasoningEffort } from "../catalog/metadata";
import { cloneApprovalPolicy, type ApprovalPolicy, type ApprovalsReviewer, type ServiceTier } from "./policy";
import type { ApprovalsReviewer, ServiceTier } from "./policy";
export type ReasoningSummary = "auto" | "concise" | "detailed" | "none";
export type Verbosity = "low" | "medium" | "high";
export type WebSearchMode = "disabled" | "cached" | "live";
export type SandboxMode = "read-only" | "workspace-write" | "danger-full-access";
export interface RuntimeConfigSnapshot {
readonly profile: string | null;
readonly model: string | null;
readonly modelProvider: string | null;
readonly reasoningEffort: ReasoningEffort | null;
readonly rawReasoningEffort: string | null;
readonly reasoningSummary: ReasoningSummary | null;
readonly verbosity: Verbosity | null;
readonly serviceTier: ServiceTier | null;
readonly approvalsReviewer: ApprovalsReviewer | null;
readonly approvalPolicy: ApprovalPolicy | null;
readonly webSearch: WebSearchMode | null;
readonly modelContextWindow: number | null;
readonly autoCompactTokenLimit: number | null;
readonly sandboxMode: SandboxMode | null;
readonly workspaceNetworkAccess: boolean | null;
readonly writableRoots: readonly string[] | null;
readonly rawToolWebSearch: unknown;
readonly rawApps: unknown;
}
export function emptyRuntimeConfigSnapshot(): RuntimeConfigSnapshot {
@ -33,35 +23,15 @@ export function emptyRuntimeConfigSnapshot(): RuntimeConfigSnapshot {
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 cloneRuntimeConfigSnapshot(config: RuntimeConfigSnapshot): RuntimeConfigSnapshot {
return {
...config,
approvalPolicy: cloneApprovalPolicy(config.approvalPolicy),
writableRoots: config.writableRoots ? [...config.writableRoots] : null,
rawToolWebSearch: cloneJsonLike(config.rawToolWebSearch),
rawApps: cloneJsonLike(config.rawApps),
};
}
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)]));
return { ...config };
}

View file

@ -1,25 +1,6 @@
export type ApprovalsReviewer = "user" | "auto_review" | "guardian_subagent";
export type ApprovalPolicy =
| "untrusted"
| "on-failure"
| "on-request"
| {
readonly granular: {
readonly sandbox_approval: boolean;
readonly rules: boolean;
readonly skill_approval: boolean;
readonly request_permissions: boolean;
readonly mcp_elicitations: boolean;
};
}
| "never";
export type ServiceTier = string;
export interface ActivePermissionProfile {
readonly id: string;
readonly extends: string | null;
}
export function approvalsReviewerOrNull(value: unknown): ApprovalsReviewer | null {
return value === "user" || value === "auto_review" || value === "guardian_subagent" ? value : null;
}
@ -28,40 +9,3 @@ export function parseServiceTier(value: unknown): ServiceTier | null {
if (typeof value === "string" && value.length > 0) return value;
return null;
}
export function approvalPolicyOrNull(value: unknown): ApprovalPolicy | null {
if (value === "untrusted" || value === "on-failure" || value === "on-request" || value === "never") return value;
const granular = asRecordOrNull(asRecordOrNull(value)?.["granular"]);
if (!granular) return null;
const sandboxApproval = granular["sandbox_approval"];
const rules = granular["rules"];
const skillApproval = granular["skill_approval"];
const requestPermissions = granular["request_permissions"];
const mcpElicitations = granular["mcp_elicitations"];
if (
typeof sandboxApproval !== "boolean" ||
typeof rules !== "boolean" ||
typeof skillApproval !== "boolean" ||
typeof requestPermissions !== "boolean" ||
typeof mcpElicitations !== "boolean"
) {
return null;
}
return {
granular: {
sandbox_approval: sandboxApproval,
rules,
skill_approval: skillApproval,
request_permissions: requestPermissions,
mcp_elicitations: mcpElicitations,
},
};
}
export function cloneApprovalPolicy(value: ApprovalPolicy | null): ApprovalPolicy | null {
return value && typeof value === "object" ? { granular: { ...value.granular } } : value;
}
function asRecordOrNull(value: unknown): Record<string, unknown> | null {
return value && typeof value === "object" ? (value as Record<string, unknown>) : null;
}

View file

@ -1,23 +1,8 @@
import type { ReasoningEffort } from "../catalog/metadata";
import type { ApprovalPolicy, ApprovalsReviewer } from "./policy";
import type { ReasoningSummary } from "./config";
import type { ApprovalsReviewer } from "./policy";
export type RuntimeServiceTierRequest = string | null | undefined;
export type ModeKind = "plan" | "default";
type Personality = "none" | "friendly" | "pragmatic";
type NetworkAccess = "restricted" | "enabled";
type SandboxPolicy =
| { type: "dangerFullAccess" }
| { type: "readOnly"; networkAccess: boolean }
| { type: "externalSandbox"; networkAccess: NetworkAccess }
| {
type: "workspaceWrite";
writableRoots: string[];
networkAccess: boolean;
excludeTmpdirEnvVar: boolean;
excludeSlashTmp: boolean;
};
export interface CollaborationMode {
mode: ModeKind;
@ -30,16 +15,11 @@ export interface CollaborationMode {
export interface RuntimeSettingsPatch {
cwd?: string | null;
approvalPolicy?: ApprovalPolicy | null;
approvalsReviewer?: ApprovalsReviewer | null;
sandboxPolicy?: SandboxPolicy | null;
permissions?: string | null;
model?: string | null;
serviceTier?: string | null;
effort?: ReasoningEffort | null;
summary?: ReasoningSummary | null;
collaborationMode?: CollaborationMode | null;
personality?: Personality | null;
}
export function applyRuntimeSettingsPatchValue<K extends keyof RuntimeSettingsPatch>(

View file

@ -1,5 +1,5 @@
import type { ReasoningEffort } from "../catalog/metadata";
import type { ActivePermissionProfile, ApprovalPolicy, ApprovalsReviewer, ServiceTier } from "../runtime/policy";
import type { ApprovalsReviewer, ServiceTier } from "../runtime/policy";
import type { Thread } from "./model";
export interface ThreadActivationSnapshot {
@ -7,8 +7,6 @@ export interface ThreadActivationSnapshot {
cwd: string;
model: string | null;
serviceTier: ServiceTier | null;
approvalPolicy: ApprovalPolicy | null;
approvalsReviewer: ApprovalsReviewer | null;
activePermissionProfile: ActivePermissionProfile | null;
reasoningEffort: ReasoningEffort | null;
}

View file

@ -24,9 +24,7 @@ export function runtimeSnapshotForChatSlices(input: RuntimeSnapshotInput): Runti
activeReasoningEffort: input.runtime.activeReasoningEffort,
activeCollaborationMode: input.runtime.activeCollaborationMode,
activeServiceTier: input.runtime.activeServiceTier,
activeApprovalPolicy: input.runtime.activeApprovalPolicy,
activeApprovalsReviewer: input.runtime.activeApprovalsReviewer,
activePermissionProfile: input.runtime.activePermissionProfile,
requestedModel: input.runtime.requestedModel,
requestedReasoningEffort: input.runtime.requestedReasoningEffort,
requestedApprovalsReviewer: input.runtime.requestedApprovalsReviewer,

View file

@ -18,15 +18,7 @@ interface ResumedThreadActionParams {
interface ResumedThreadFromActiveRuntimeParams {
thread: Thread;
cwd: string;
runtime: Pick<
ChatRuntimeState,
| "activeModel"
| "activeReasoningEffort"
| "activeServiceTier"
| "activeApprovalPolicy"
| "activeApprovalsReviewer"
| "activePermissionProfile"
>;
runtime: Pick<ChatRuntimeState, "activeModel" | "activeReasoningEffort" | "activeServiceTier" | "activeApprovalsReviewer">;
listedThreads?: readonly Thread[];
items?: readonly MessageStreamItem[];
}
@ -38,9 +30,7 @@ export interface ActiveThreadResumedAction {
model: string | null;
reasoningEffort: ReasoningEffort | null;
serviceTier: ServiceTier | null;
approvalPolicy: ChatRuntimeState["activeApprovalPolicy"];
approvalsReviewer: ChatRuntimeState["activeApprovalsReviewer"];
activePermissionProfile: ChatRuntimeState["activePermissionProfile"];
items?: readonly MessageStreamItem[];
status?: string;
listedThreads?: readonly Thread[];
@ -54,9 +44,7 @@ export interface ActiveThreadSettingsAppliedAction {
reasoningEffort: ReasoningEffort | null;
collaborationMode: CollaborationModeSelection;
serviceTier: ServiceTier | null;
approvalPolicy: ChatRuntimeState["activeApprovalPolicy"];
approvalsReviewer: ChatRuntimeState["activeApprovalsReviewer"];
activePermissionProfile: ChatRuntimeState["activePermissionProfile"];
}
export interface ActiveThreadSettingsAppliedActionSettings {
@ -65,9 +53,7 @@ export interface ActiveThreadSettingsAppliedActionSettings {
effort: string | null;
collaborationMode: { mode: CollaborationModeSelection };
serviceTier: string | null;
approvalPolicy: ChatRuntimeState["activeApprovalPolicy"];
approvalsReviewer: ChatRuntimeState["activeApprovalsReviewer"];
activePermissionProfile: ChatRuntimeState["activePermissionProfile"];
}
export interface ConnectionInitializedAction {
@ -125,9 +111,7 @@ export function resumedThreadActionFromActiveRuntime(params: ResumedThreadFromAc
model: params.runtime.activeModel,
reasoningEffort: params.runtime.activeReasoningEffort,
serviceTier: params.runtime.activeServiceTier,
approvalPolicy: params.runtime.activeApprovalPolicy,
approvalsReviewer: params.runtime.activeApprovalsReviewer,
activePermissionProfile: params.runtime.activePermissionProfile,
},
...(params.listedThreads ? { listedThreads: params.listedThreads } : {}),
...(params.items ? { items: params.items } : {}),
@ -143,9 +127,7 @@ export function resumedThreadAction(params: ResumedThreadActionParams): ActiveTh
model: response.model,
reasoningEffort: response.reasoningEffort,
serviceTier: response.serviceTier,
approvalPolicy: response.approvalPolicy,
approvalsReviewer: response.approvalsReviewer,
activePermissionProfile: response.activePermissionProfile,
...(params.items ? { items: params.items } : {}),
...(params.listedThreads ? { listedThreads: upsertThread(params.listedThreads, response.thread) } : {}),
...(params.preserveRequestedRuntimeSettings ? { preserveRequestedRuntimeSettings: true } : {}),
@ -160,8 +142,6 @@ export function activeThreadSettingsAppliedAction(settings: ActiveThreadSettings
reasoningEffort: normalizeReasoningEffort(settings.effort),
collaborationMode: settings.collaborationMode.mode,
serviceTier: parseServiceTier(settings.serviceTier),
approvalPolicy: settings.approvalPolicy,
approvalsReviewer: settings.approvalsReviewer,
activePermissionProfile: settings.activePermissionProfile,
};
}

View file

@ -336,9 +336,7 @@ function reduceActiveThreadResumedTransition(state: ChatState, action: ActiveThr
activeReasoningEffort: action.reasoningEffort,
activeCollaborationMode: initialActiveChatRuntimeState().activeCollaborationMode,
activeServiceTier: action.serviceTier,
activeApprovalPolicy: action.approvalPolicy,
activeApprovalsReviewer: action.approvalsReviewer,
activePermissionProfile: action.activePermissionProfile,
},
turn: initialTurnState(),
messageStream: initialMessageStreamState(action.items ?? []),
@ -361,9 +359,7 @@ function reduceActiveThreadSettingsAppliedTransition(state: ChatState, action: A
activeCollaborationMode: action.collaborationMode,
selectedCollaborationMode: action.collaborationMode,
activeServiceTier: action.serviceTier,
activeApprovalPolicy: action.approvalPolicy,
activeApprovalsReviewer: action.approvalsReviewer,
activePermissionProfile: action.activePermissionProfile,
},
});
}

View file

@ -1,7 +1,7 @@
import type { ModelMetadata, ReasoningEffort } from "../../../../domain/catalog/metadata";
import type { RuntimeConfigSnapshot } from "../../../../domain/runtime/config";
import type { RateLimitSnapshot, ThreadTokenUsage } from "../../../../domain/runtime/metrics";
import type { ActivePermissionProfile, ApprovalPolicy, ApprovalsReviewer, ServiceTier } from "../../../../domain/runtime/policy";
import type { ApprovalsReviewer, ServiceTier } from "../../../../domain/runtime/policy";
import type { ActiveCollaborationMode, CollaborationModeSelection, PendingRuntimeIntent, RequestedFastMode } from "./intent";
export interface RuntimeSnapshot {
@ -11,9 +11,7 @@ export interface RuntimeSnapshot {
activeReasoningEffort: ReasoningEffort | null;
activeCollaborationMode: ActiveCollaborationMode;
activeServiceTier: ServiceTier | null;
activeApprovalPolicy: ApprovalPolicy | null;
activeApprovalsReviewer: ApprovalsReviewer | null;
activePermissionProfile: ActivePermissionProfile | null;
requestedModel: PendingRuntimeIntent<string>;
requestedReasoningEffort: PendingRuntimeIntent<ReasoningEffort>;
requestedApprovalsReviewer: PendingRuntimeIntent<ApprovalsReviewer>;

View file

@ -1,10 +1,4 @@
import {
parseServiceTier,
type ActivePermissionProfile,
type ApprovalPolicy,
type ApprovalsReviewer,
type ServiceTier,
} from "../../../../domain/runtime/policy";
import { parseServiceTier, type ApprovalsReviewer, type ServiceTier } from "../../../../domain/runtime/policy";
import type { RuntimeSettingsPatch } from "../../../../domain/runtime/thread-settings";
import { normalizeReasoningEffort, type ReasoningEffort } from "../../../../domain/catalog/metadata";
import {
@ -22,9 +16,7 @@ export interface ChatRuntimeState {
readonly activeReasoningEffort: ReasoningEffort | null;
readonly activeCollaborationMode: ActiveCollaborationMode;
readonly activeServiceTier: ServiceTier | null;
readonly activeApprovalPolicy: ApprovalPolicy | null;
readonly activeApprovalsReviewer: ApprovalsReviewer | null;
readonly activePermissionProfile: ActivePermissionProfile | null;
readonly requestedModel: PendingRuntimeIntent<string>;
readonly requestedReasoningEffort: PendingRuntimeIntent<ReasoningEffort>;
readonly requestedApprovalsReviewer: PendingRuntimeIntent<ApprovalsReviewer>;
@ -34,22 +26,14 @@ export interface ChatRuntimeState {
export function initialActiveChatRuntimeState(): Pick<
ChatRuntimeState,
| "activeModel"
| "activeReasoningEffort"
| "activeCollaborationMode"
| "activeServiceTier"
| "activeApprovalPolicy"
| "activeApprovalsReviewer"
| "activePermissionProfile"
"activeModel" | "activeReasoningEffort" | "activeCollaborationMode" | "activeServiceTier" | "activeApprovalsReviewer"
> {
return {
activeModel: null,
activeReasoningEffort: null,
activeCollaborationMode: null,
activeServiceTier: null,
activeApprovalPolicy: null,
activeApprovalsReviewer: null,
activePermissionProfile: null,
};
}

View file

@ -315,13 +315,13 @@ function threadStartResponse(threadId: string): ThreadStartResponse {
model: "gpt-5.1",
modelProvider: "openai",
serviceTier: null,
approvalPolicy: "never",
cwd: "/vault",
runtimeWorkspaceRoots: [],
instructionSources: [],
approvalPolicy: "never",
approvalsReviewer: "auto_review",
sandbox: { type: "readOnly", networkAccess: false },
activePermissionProfile: null,
sandbox: { type: "readOnly", networkAccess: false },
reasoningEffort: null,
};
}

View file

@ -15,9 +15,7 @@ describe("app-server thread activation", () => {
cwd: "/vault",
model: "gpt-5.5",
serviceTier: "fast",
approvalPolicy: "on-request",
approvalsReviewer: "user",
activePermissionProfile: null,
reasoningEffort: "high",
});
});
@ -29,13 +27,13 @@ function responseFixture(thread: ThreadRecord): ThreadResumeResponse {
model: "gpt-5.5",
modelProvider: "openai",
serviceTier: "fast",
approvalPolicy: "on-request",
cwd: "/vault",
runtimeWorkspaceRoots: [],
instructionSources: [],
approvalPolicy: "on-request",
approvalsReviewer: "user",
sandbox: { type: "readOnly", networkAccess: false },
activePermissionProfile: null,
sandbox: { type: "readOnly", networkAccess: false },
reasoningEffort: "high",
initialTurnsPage: null,
};

View file

@ -272,13 +272,13 @@ function threadStartResponse(threadId: string): ThreadStartResponse {
model: "gpt-5.1",
modelProvider: "openai",
serviceTier: null,
approvalPolicy: "never",
cwd: "/vault",
runtimeWorkspaceRoots: [],
instructionSources: [],
approvalPolicy: "never",
approvalsReviewer: "auto_review",
sandbox: { type: "readOnly", networkAccess: false },
activePermissionProfile: null,
sandbox: { type: "readOnly", networkAccess: false },
reasoningEffort: null,
};
}

View file

@ -14,9 +14,7 @@ function createHost(overrides: Partial<ChatReconnectActionsHost> = {}) {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
const host: ChatReconnectActionsHost = {
stateStore,

View file

@ -45,9 +45,7 @@ describe("chat server actions", () => {
cwd: "/vault",
model: "gpt-5",
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
reasoningEffort: null,
}),
} as unknown as AppServerClient;
@ -81,9 +79,7 @@ describe("chat server actions", () => {
cwd: "/vault",
model: "gpt-5",
serviceTier: "fast",
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
reasoningEffort: null,
});
const client = {
@ -120,9 +116,7 @@ describe("chat server actions", () => {
cwd: "/vault",
model: "gpt-5",
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
reasoningEffort: null,
}),
} as unknown as AppServerClient;
@ -151,9 +145,7 @@ describe("chat server actions", () => {
cwd: "/vault",
model: "gpt-5",
serviceTier: "flex",
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
reasoningEffort: null,
});
const client = {
@ -184,9 +176,7 @@ describe("chat server actions", () => {
cwd: "/vault",
model: "gpt-5",
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
reasoningEffort: null,
}),
} as unknown as AppServerClient;
@ -232,12 +222,12 @@ describe("chat server actions", () => {
model: "gpt-5",
modelProvider: "openai",
serviceTier: null,
approvalPolicy: "on-request",
runtimeWorkspaceRoots: [],
instructionSources: [],
approvalPolicy: "on-request",
approvalsReviewer: "user",
sandbox: { type: "readOnly", networkAccess: false },
activePermissionProfile: null,
sandbox: { type: "readOnly", networkAccess: false },
reasoningEffort: null,
});

View file

@ -132,9 +132,7 @@ describe("submitComposer", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
stateStore.dispatch({ type: "turn/started", threadId: "thread", turnId: "turn" });

View file

@ -33,9 +33,7 @@ function resumeThread(stateStore: ChatStateStore, items: readonly MessageStreamI
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
items,
});
stateStore.dispatch({ type: "runtime/requested-collaboration-mode-set", collaborationMode: "plan" });

View file

@ -97,9 +97,7 @@ describe("executeSlashCommandWithState", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
await executeSlashCommandWithState(host, "compact", "");
@ -116,9 +114,7 @@ describe("executeSlashCommandWithState", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
await executeSlashCommandWithState(host, "compact", "");

View file

@ -49,9 +49,7 @@ function createHost(overrides: TurnSubmissionHostOverrides = {}) {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
return {};
}),
@ -116,9 +114,7 @@ describe("TurnSubmissionActions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
startTurn.mockImplementation(async () => {
stateStore.dispatch({ type: "active-thread/cleared" });
@ -142,9 +138,7 @@ describe("TurnSubmissionActions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
stateStore.dispatch({ type: "turn/started", threadId: "thread", turnId: "turn" });
const actions = createTurnSubmissionActions(host);
@ -176,9 +170,7 @@ describe("TurnSubmissionActions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
const optimistic = optimisticTurnStart({ id: "local-user", text: "pending", codexInput: textInput("pending") });
stateStore.dispatch({
@ -208,9 +200,7 @@ describe("TurnSubmissionActions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
}
@ -236,9 +226,7 @@ describe("TurnSubmissionActions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
stateStore.dispatch({ type: "turn/started", threadId: "thread", turnId: "turn" });
steerTurn.mockImplementation(async () => {
@ -264,9 +252,7 @@ describe("TurnSubmissionActions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
stateStore.dispatch({ type: "turn/started", threadId: "thread", turnId: "turn" });
steerTurn.mockImplementation(async () => {

View file

@ -161,9 +161,7 @@ describe("createChatPanelSessionGraph actions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: "on-request",
approvalsReviewer: null,
activePermissionProfile: null,
});
stateStore.dispatch({ type: "ui/panel-set", panel: "history" });

View file

@ -48,9 +48,7 @@ describe("MessageStreamPresenter scroll pinning", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
const projection = messageStreamSurfaceProjectionFromState(

View file

@ -81,7 +81,7 @@ describe("chat panel surface projections", () => {
expect(debugDetails["vaultPath"]).toBe("/vault");
expect(debugDetails["configuredCommand"]).toBe("codex");
expect(debugDetails["runtimeConfig"]).toMatchObject({ model: "gpt-debug", approvalPolicy: "on-request" });
expect(debugDetails["runtimeConfig"]).toMatchObject({ model: "gpt-debug" });
expect(debugDetails["runtime"]).toMatchObject({ requestedModel: { kind: "set", value: "gpt-debug" } });
expect(debugDetails["availableModels"]).toMatchObject([{ model: "gpt-debug" }]);
unmountUiRoot(parent);

View file

@ -1584,19 +1584,19 @@ describe("ChatInboundHandler", () => {
threadId: "thread-active",
threadSettings: {
cwd: "/workspace/active",
approvalPolicy: "on-request",
approvalsReviewer: "auto_review",
sandboxPolicy: { type: "readOnly", networkAccess: false },
activePermissionProfile: null,
model: "gpt-5.5",
modelProvider: "openai",
serviceTier: "fast",
approvalPolicy: "on-request",
effort: "high",
summary: null,
collaborationMode: {
mode: "default",
settings: { model: "gpt-5.5", reasoning_effort: "high", developer_instructions: null },
},
activePermissionProfile: null,
personality: null,
},
},
@ -1605,9 +1605,7 @@ describe("ChatInboundHandler", () => {
expect(handler.currentState().activeThread.cwd).toBe("/workspace/active");
expect(handler.currentState().runtime.activeModel).toBe("gpt-5.5");
expect(handler.currentState().runtime.activeServiceTier).toBe("fast");
expect(handler.currentState().runtime.activeApprovalPolicy).toBe("on-request");
expect(handler.currentState().runtime.activeApprovalsReviewer).toBe("auto_review");
expect(handler.currentState().runtime.activePermissionProfile).toBeNull();
expect(chatStateMessageStreamItems(handler.currentState())).toEqual([]);
});
@ -1617,9 +1615,7 @@ describe("ChatInboundHandler", () => {
state = chatStateWith(state, { activeThread: { cwd: "/workspace/active" } });
state = chatStateWith(state, { runtime: { activeModel: "gpt-active" } });
state = chatStateWith(state, { runtime: { activeServiceTier: "flex" } });
state = chatStateWith(state, { runtime: { activeApprovalPolicy: "on-request" } });
state = chatStateWith(state, { runtime: { activeApprovalsReviewer: "user" } });
state = chatStateWith(state, { runtime: { activePermissionProfile: { id: ":workspace", extends: null } } });
const handler = handlerForState(state);
handler.handleNotification({
@ -1628,19 +1624,19 @@ describe("ChatInboundHandler", () => {
threadId: "thread-other",
threadSettings: {
cwd: "/workspace/other",
approvalPolicy: "never",
approvalsReviewer: "auto_review",
sandboxPolicy: { type: "readOnly", networkAccess: false },
activePermissionProfile: { id: ":read-only", extends: null },
model: "gpt-other",
modelProvider: "openai",
serviceTier: "fast",
approvalPolicy: "never",
effort: "high",
summary: null,
collaborationMode: {
mode: "plan",
settings: { model: "gpt-other", reasoning_effort: "high", developer_instructions: null },
},
activePermissionProfile: { id: ":read-only", extends: null },
personality: null,
},
},
@ -1649,9 +1645,7 @@ describe("ChatInboundHandler", () => {
expect(handler.currentState().activeThread.cwd).toBe("/workspace/active");
expect(handler.currentState().runtime.activeModel).toBe("gpt-active");
expect(handler.currentState().runtime.activeServiceTier).toBe("flex");
expect(handler.currentState().runtime.activeApprovalPolicy).toBe("on-request");
expect(handler.currentState().runtime.activeApprovalsReviewer).toBe("user");
expect(handler.currentState().runtime.activePermissionProfile).toEqual({ id: ":workspace", extends: null });
});
it("syncs null service tier from settings notifications", () => {
@ -1666,19 +1660,19 @@ describe("ChatInboundHandler", () => {
threadId: "thread-active",
threadSettings: {
cwd: "/workspace/active",
approvalPolicy: "on-request",
approvalsReviewer: "user",
sandboxPolicy: { type: "readOnly", networkAccess: false },
activePermissionProfile: null,
model: "gpt-5.5",
modelProvider: "openai",
serviceTier: null,
approvalPolicy: "on-request",
effort: "high",
summary: null,
collaborationMode: {
mode: "default",
settings: { model: "gpt-5.5", reasoning_effort: "high", developer_instructions: null },
},
activePermissionProfile: null,
personality: null,
},
},

View file

@ -442,16 +442,16 @@ function threadSettingsUpdatedNotification(): Extract<ServerNotification, { meth
threadId: "thread-active",
threadSettings: {
cwd: "/vault",
approvalPolicy: "on-request",
approvalsReviewer: "user",
sandboxPolicy: { type: "readOnly", networkAccess: false },
activePermissionProfile: null,
model: "gpt-5.5",
modelProvider: "openai",
serviceTier: null,
approvalPolicy: "on-request",
effort: "medium",
summary: null,
collaborationMode: { mode: "default", settings: { model: "gpt-5.5", reasoning_effort: "medium", developer_instructions: null } },
activePermissionProfile: null,
personality: null,
},
},

View file

@ -388,9 +388,7 @@ function threadSettings(
reasoningEffort: "high",
collaborationMode: "default",
serviceTier,
approvalPolicy: "on-request",
approvalsReviewer,
activePermissionProfile: null,
};
}

View file

@ -17,9 +17,7 @@ describe("chat thread resume helpers", () => {
activeModel: "gpt-5.5",
activeReasoningEffort: "high",
activeServiceTier: "fast",
activeApprovalPolicy: "on-request",
activeApprovalsReviewer: "user",
activePermissionProfile: null,
},
listedThreads: [existing],
items: [loading],
@ -32,9 +30,7 @@ describe("chat thread resume helpers", () => {
model: "gpt-5.5",
reasoningEffort: "high",
serviceTier: "fast",
approvalPolicy: "on-request",
approvalsReviewer: "user",
activePermissionProfile: null,
items: [loading],
});
expect(action.listedThreads?.map((thread) => thread.id)).toEqual(["thread", "existing"]);
@ -63,9 +59,7 @@ function responseFixture(thread: Thread): ThreadActivationSnapshot {
model: "gpt-5.5",
serviceTier: "fast",
cwd: "/vault",
approvalPolicy: "on-request",
approvalsReviewer: "user",
activePermissionProfile: null,
reasoningEffort: "high",
};
}

View file

@ -24,7 +24,6 @@ describe("chatReducer", () => {
state = chatStateWith(state, { runtime: { activeModel: "gpt-5.1" } });
state = chatStateWith(state, { runtime: { activeReasoningEffort: "high" } });
state = chatStateWith(state, { runtime: { activeServiceTier: "fast" } });
state = chatStateWith(state, { runtime: { activeApprovalPolicy: "on-request" } });
state = chatStateWith(state, { runtime: { activeApprovalsReviewer: "auto_review" } });
state = chatStateWith(state, { runtime: { activeCollaborationMode: "plan" } });
state = chatStateWith(state, { runtime: { selectedCollaborationMode: "plan" } });
@ -58,7 +57,6 @@ describe("chatReducer", () => {
expect(next.runtime.activeModel).toBeNull();
expect(next.runtime.activeReasoningEffort).toBeNull();
expect(next.runtime.activeServiceTier).toBeNull();
expect(next.runtime.activeApprovalPolicy).toBeNull();
expect(next.runtime.activeApprovalsReviewer).toBeNull();
expect(next.runtime.activeCollaborationMode).toBeNull();
expect(next.runtime.requestedModel).toEqual({ kind: "unchanged" });
@ -116,9 +114,7 @@ describe("chatReducer", () => {
model: "gpt-5.1",
reasoningEffort: "high",
serviceTier: "fast",
approvalPolicy: "on-request",
approvalsReviewer: "user",
activePermissionProfile: null,
items: resumedItems,
});
@ -158,9 +154,7 @@ describe("chatReducer", () => {
model: "gpt-5",
reasoningEffort: "medium",
serviceTier: "fast",
approvalPolicy: "on-request",
approvalsReviewer: "user",
activePermissionProfile: null,
preserveRequestedRuntimeSettings: true,
});
@ -188,9 +182,7 @@ describe("chatReducer", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
expect(chatStateMessageStreamItems(next)).toEqual([]);
@ -709,9 +701,7 @@ describe("chatReducer", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
panelA.dispatch({ type: "composer/draft-set", draft: "panel A draft" });
panelA.dispatch({ type: "request/user-input-queued", input: userInput(1) });
@ -724,9 +714,7 @@ describe("chatReducer", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
panelB.dispatch({ type: "composer/draft-set", draft: "panel B draft" });
panelB.dispatch({ type: "request/user-input-queued", input: userInput(2) });

View file

@ -50,9 +50,7 @@ describe("createActiveThreadIdentitySync", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
controller.applyThreadArchiveToActiveIdentity("thread");
@ -74,9 +72,7 @@ describe("createActiveThreadIdentitySync", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
controller.applyThreadArchiveToActiveIdentity("other");
@ -111,9 +107,7 @@ describe("createActiveThreadIdentitySync", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
controller.applyThreadRenameToActiveIdentity("thread", "New");

View file

@ -208,9 +208,7 @@ describe("createGoalActions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
return { threadId: "thread-new" };
});

View file

@ -20,9 +20,7 @@ function activation(threadId: string, overrides: Partial<ChatThreadResumeSnapsho
cwd: "/vault",
model: "gpt-test",
serviceTier: null,
approvalPolicy: "on-request",
approvalsReviewer: "user",
activePermissionProfile: null,
reasoningEffort: null,
},
rolloutPath: null,
@ -114,9 +112,7 @@ describe("ResumeActions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
stateStore.dispatch({ type: "turn/started", threadId: "active", turnId: "turn" });
@ -158,9 +154,7 @@ describe("ResumeActions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
await recovery.resolveAndFlush(tokenUsageFixture(42));

View file

@ -12,9 +12,7 @@ function resumeThreadState(stateStore: ChatStateStore, threadId: string): void {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
}

View file

@ -61,9 +61,7 @@ describe("thread management actions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
const controller = threadManagementActions(host);
@ -78,9 +76,7 @@ describe("thread management actions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
compact.resolve(undefined);
await pendingCompact;
@ -250,9 +246,7 @@ describe("thread management actions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
host.stateStore.dispatch({
type: "thread-list/applied",
@ -272,9 +266,7 @@ describe("thread management actions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
fork.resolve({ thread: { ...archivedThread(), id: "forked", sessionId: "forked", name: null } });
await pendingFork;
@ -348,9 +340,7 @@ describe("thread management actions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
host.stateStore.dispatch({
type: "message-stream/items-replaced",
@ -383,9 +373,7 @@ describe("thread management actions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
host.stateStore.dispatch({
type: "message-stream/items-replaced",
@ -406,9 +394,7 @@ describe("thread management actions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
rollback.resolve({ thread: rollbackThread() });
await pendingRollback;
@ -437,9 +423,7 @@ describe("thread management actions", () => {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: null,
approvalsReviewer: null,
activePermissionProfile: null,
});
host.stateStore.dispatch({
type: "message-stream/items-replaced",

View file

@ -1091,9 +1091,7 @@ function startedThread(threadId: string) {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: "on-request",
approvalsReviewer: null,
activePermissionProfile: null,
};
}
@ -1110,9 +1108,7 @@ function resumedThread(threadId: string) {
model: null,
reasoningEffort: null,
serviceTier: null,
approvalPolicy: "on-request",
approvalsReviewer: null,
activePermissionProfile: null,
};
}

View file

@ -839,13 +839,13 @@ function threadStartResponse(threadId: string): ThreadStartResponse {
model: "gpt-5.1",
modelProvider: "openai",
serviceTier: null,
approvalPolicy: "never",
cwd: "/vault",
runtimeWorkspaceRoots: [],
instructionSources: [],
approvalPolicy: "never",
approvalsReviewer: "auto_review",
sandbox: { type: "readOnly", networkAccess: false },
activePermissionProfile: null,
sandbox: { type: "readOnly", networkAccess: false },
reasoningEffort: null,
};
}

View file

@ -558,9 +558,7 @@ function runtimeSnapshot(overrides: Partial<RuntimeSnapshot> = {}): RuntimeSnaps
activeReasoningEffort: null,
activeCollaborationMode: null,
activeServiceTier: null,
activeApprovalPolicy: null,
activeApprovalsReviewer: null,
activePermissionProfile: null,
requestedModel: { kind: "unchanged" },
requestedReasoningEffort: { kind: "unchanged" },
requestedApprovalsReviewer: { kind: "unchanged" },

View file

@ -35,9 +35,7 @@ function fastMode(serviceTier: string | null, serviceTiers: ModelMetadata["servi
activeReasoningEffort: null,
activeCollaborationMode: "default",
activeServiceTier: serviceTier,
activeApprovalPolicy: null,
activeApprovalsReviewer: null,
activePermissionProfile: null,
requestedModel: { kind: "unchanged" },
requestedReasoningEffort: { kind: "unchanged" },
requestedApprovalsReviewer: { kind: "unchanged" },

View file

@ -30,7 +30,6 @@ describe("settings", () => {
archiveExportTags: "codex, archive",
model: "gpt-5.5",
sandboxMode: "workspace-write",
approvalPolicy: "on-request",
hooks: [{ event: "postToolUse" }],
extraPanelState: { threadId: "thread-1" },
};