authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-09 09:13:52-07:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-09 09:47:21-07:00
log9fdb45be1efb0e0b542a0dd78d868de6f71d7d4a
treee8e861c56557446f870d00987394b96ce5eb43ff
parentb946f00f1a31f16a51f9bd1f579baf40c8eaed83

Remove service tier setting from Codex flow and contracts

- Drop `serviceTier` from orchestration/provider contracts and server dispatch paths - Remove service-tier app setting/UI and related resolver logic - Keep fast badge behavior tied to explicit fast-mode boolean

9 files changed, 26 insertions(+), 130 deletions(-)

apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+7-10
...@@ -5,7 +5,6 @@ import {...@@ -5,7 +5,6 @@ import {
5 type OrchestrationEvent,5 type OrchestrationEvent,
6 type ProviderModelOptions,6 type ProviderModelOptions,
7 type ProviderKind,7 type ProviderKind,
8 type ProviderServiceTier,
9 type ProviderStartOptions,8 type ProviderStartOptions,
10 type OrchestrationSession,9 type OrchestrationSession,
11 ThreadId,10 ThreadId,
...@@ -205,7 +204,6 @@ const make = Effect.gen(function* () {...@@ -205,7 +204,6 @@ const make = Effect.gen(function* () {
205 readonly provider?: ProviderKind;204 readonly provider?: ProviderKind;
206 readonly model?: string;205 readonly model?: string;
207 readonly modelOptions?: ProviderModelOptions;206 readonly modelOptions?: ProviderModelOptions;
208 readonly serviceTier?: ProviderServiceTier | null;
209 readonly providerOptions?: ProviderStartOptions;207 readonly providerOptions?: ProviderStartOptions;
210 },208 },
211 ) {209 ) {
...@@ -241,7 +239,6 @@ const make = Effect.gen(function* () {...@@ -241,7 +239,6 @@ const make = Effect.gen(function* () {
241 : {}),239 : {}),
242 ...(effectiveCwd ? { cwd: effectiveCwd } : {}),240 ...(effectiveCwd ? { cwd: effectiveCwd } : {}),
243 ...(desiredModel ? { model: desiredModel } : {}),241 ...(desiredModel ? { model: desiredModel } : {}),
244 ...(options?.serviceTier !== undefined ? { serviceTier: options.serviceTier } : {}),
245 ...(options?.modelOptions !== undefined ? { modelOptions: options.modelOptions } : {}),242 ...(options?.modelOptions !== undefined ? { modelOptions: options.modelOptions } : {}),
246 ...(options?.providerOptions !== undefined ? { providerOptions: options.providerOptions } : {}),243 ...(options?.providerOptions !== undefined ? { providerOptions: options.providerOptions } : {}),
247 ...(input?.resumeCursor !== undefined ? { resumeCursor: input.resumeCursor } : {}),244 ...(input?.resumeCursor !== undefined ? { resumeCursor: input.resumeCursor } : {}),
...@@ -328,7 +325,6 @@ const make = Effect.gen(function* () {...@@ -328,7 +325,6 @@ const make = Effect.gen(function* () {
328 readonly attachments?: ReadonlyArray<ChatAttachment>;325 readonly attachments?: ReadonlyArray<ChatAttachment>;
329 readonly provider?: ProviderKind;326 readonly provider?: ProviderKind;
330 readonly model?: string;327 readonly model?: string;
331 readonly serviceTier?: ProviderServiceTier | null;
332 readonly modelOptions?: ProviderModelOptions;328 readonly modelOptions?: ProviderModelOptions;
333 readonly providerOptions?: ProviderStartOptions;329 readonly providerOptions?: ProviderStartOptions;
334 readonly interactionMode?: "default" | "plan";330 readonly interactionMode?: "default" | "plan";
...@@ -344,7 +340,6 @@ const make = Effect.gen(function* () {...@@ -344,7 +340,6 @@ const make = Effect.gen(function* () {
344 yield* ensureSessionForThread(input.threadId, input.createdAt, {340 yield* ensureSessionForThread(input.threadId, input.createdAt, {
345 ...(input.provider !== undefined ? { provider: input.provider } : {}),341 ...(input.provider !== undefined ? { provider: input.provider } : {}),
346 ...(input.model !== undefined ? { model: input.model } : {}),342 ...(input.model !== undefined ? { model: input.model } : {}),
347 ...(input.serviceTier !== undefined ? { serviceTier: input.serviceTier } : {}),
348 ...(input.modelOptions !== undefined ? { modelOptions: input.modelOptions } : {}),343 ...(input.modelOptions !== undefined ? { modelOptions: input.modelOptions } : {}),
349 ...(input.providerOptions !== undefined ? { providerOptions: input.providerOptions } : {}),344 ...(input.providerOptions !== undefined ? { providerOptions: input.providerOptions } : {}),
350 });345 });
...@@ -365,7 +360,6 @@ const make = Effect.gen(function* () {...@@ -365,7 +360,6 @@ const make = Effect.gen(function* () {
365 ...(normalizedInput ? { input: normalizedInput } : {}),360 ...(normalizedInput ? { input: normalizedInput } : {}),
366 ...(normalizedAttachments.length > 0 ? { attachments: normalizedAttachments } : {}),361 ...(normalizedAttachments.length > 0 ? { attachments: normalizedAttachments } : {}),
367 ...(modelForTurn !== undefined ? { model: modelForTurn } : {}),362 ...(modelForTurn !== undefined ? { model: modelForTurn } : {}),
368 ...(input.serviceTier !== undefined ? { serviceTier: input.serviceTier } : {}),
369 ...(input.modelOptions !== undefined ? { modelOptions: input.modelOptions } : {}),363 ...(input.modelOptions !== undefined ? { modelOptions: input.modelOptions } : {}),
370 ...(input.interactionMode !== undefined ? { interactionMode: input.interactionMode } : {}),364 ...(input.interactionMode !== undefined ? { interactionMode: input.interactionMode } : {}),
371 });365 });
...@@ -480,7 +474,6 @@ const make = Effect.gen(function* () {...@@ -480,7 +474,6 @@ const make = Effect.gen(function* () {
480 ...(message.attachments !== undefined ? { attachments: message.attachments } : {}),474 ...(message.attachments !== undefined ? { attachments: message.attachments } : {}),
481 ...(event.payload.provider !== undefined ? { provider: event.payload.provider } : {}),475 ...(event.payload.provider !== undefined ? { provider: event.payload.provider } : {}),
482 ...(event.payload.model !== undefined ? { model: event.payload.model } : {}),476 ...(event.payload.model !== undefined ? { model: event.payload.model } : {}),
483 ...(event.payload.serviceTier !== undefined ? { serviceTier: event.payload.serviceTier } : {}),
484 ...(event.payload.modelOptions !== undefined ? { modelOptions: event.payload.modelOptions } : {}),477 ...(event.payload.modelOptions !== undefined ? { modelOptions: event.payload.modelOptions } : {}),
485 ...(event.payload.providerOptions !== undefined ? { providerOptions: event.payload.providerOptions } : {}),478 ...(event.payload.providerOptions !== undefined ? { providerOptions: event.payload.providerOptions } : {}),
486 interactionMode: event.payload.interactionMode,479 interactionMode: event.payload.interactionMode,
...@@ -639,9 +632,13 @@ const make = Effect.gen(function* () {...@@ -639,9 +632,13 @@ const make = Effect.gen(function* () {
639 return;632 return;
640 }633 }
641 const cachedProviderOptions = threadProviderOptions.get(event.payload.threadId);634 const cachedProviderOptions = threadProviderOptions.get(event.payload.threadId);
642 yield* ensureSessionForThread(event.payload.threadId, event.occurredAt, {635 yield* ensureSessionForThread(
643 ...(cachedProviderOptions !== undefined ? { providerOptions: cachedProviderOptions } : {}),636 event.payload.threadId,
644 });637 event.occurredAt,
638 cachedProviderOptions !== undefined
639 ? { providerOptions: cachedProviderOptions }
640 : undefined,
641 );
645 return;642 return;
646 }643 }
647 case "thread.turn-start-requested":644 case "thread.turn-start-requested":
apps/server/src/orchestration/decider.ts-1
...@@ -301,7 +301,6 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"...@@ -301,7 +301,6 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"
301 messageId: command.message.messageId,301 messageId: command.message.messageId,
302 ...(command.provider !== undefined ? { provider: command.provider } : {}),302 ...(command.provider !== undefined ? { provider: command.provider } : {}),
303 ...(command.model !== undefined ? { model: command.model } : {}),303 ...(command.model !== undefined ? { model: command.model } : {}),
304 ...(command.serviceTier !== undefined ? { serviceTier: command.serviceTier } : {}),
305 ...(command.modelOptions !== undefined ? { modelOptions: command.modelOptions } : {}),304 ...(command.modelOptions !== undefined ? { modelOptions: command.modelOptions } : {}),
306 ...(command.providerOptions !== undefined ? { providerOptions: command.providerOptions } : {}),305 ...(command.providerOptions !== undefined ? { providerOptions: command.providerOptions } : {}),
307 assistantDeliveryMode: command.assistantDeliveryMode ?? DEFAULT_ASSISTANT_DELIVERY_MODE,306 assistantDeliveryMode: command.assistantDeliveryMode ?? DEFAULT_ASSISTANT_DELIVERY_MODE,
apps/server/src/provider/Layers/CodexAdapter.ts-1
...@@ -1354,7 +1354,6 @@ const makeCodexAdapter = (options?: CodexAdapterLiveOptions) =>...@@ -1354,7 +1354,6 @@ const makeCodexAdapter = (options?: CodexAdapterLiveOptions) =>
1354 threadId: input.threadId,1354 threadId: input.threadId,
1355 ...(input.input !== undefined ? { input: input.input } : {}),1355 ...(input.input !== undefined ? { input: input.input } : {}),
1356 ...(input.model !== undefined ? { model: input.model } : {}),1356 ...(input.model !== undefined ? { model: input.model } : {}),
1357 ...(input.serviceTier !== undefined ? { serviceTier: input.serviceTier } : {}),
1358 ...(input.modelOptions?.codex?.reasoningEffort !== undefined1357 ...(input.modelOptions?.codex?.reasoningEffort !== undefined
1359 ? { effort: input.modelOptions.codex.reasoningEffort }1358 ? { effort: input.modelOptions.codex.reasoningEffort }
1360 : {}),1359 : {}),
apps/web/src/appSettings.test.ts+4-16
...@@ -4,7 +4,6 @@ import {...@@ -4,7 +4,6 @@ import {
4 getAppModelOptions,4 getAppModelOptions,
5 getSlashModelOptions,5 getSlashModelOptions,
6 normalizeCustomModelSlugs,6 normalizeCustomModelSlugs,
7 resolveAppServiceTier,
8 shouldShowFastTierIcon,7 shouldShowFastTierIcon,
9 resolveAppModelSelection,8 resolveAppModelSelection,
10} from "./appSettings";9} from "./appSettings";
...@@ -85,21 +84,10 @@ describe("getSlashModelOptions", () => {...@@ -85,21 +84,10 @@ describe("getSlashModelOptions", () => {
85 });84 });
86});85});
8786
88describe("resolveAppServiceTier", () => {
89 it("maps automatic to no override", () => {
90 expect(resolveAppServiceTier("auto")).toBeNull();
91 });
92
93 it("preserves explicit service tier overrides", () => {
94 expect(resolveAppServiceTier("fast")).toBe("fast");
95 expect(resolveAppServiceTier("flex")).toBe("flex");
96 });
97});
98
99describe("shouldShowFastTierIcon", () => {87describe("shouldShowFastTierIcon", () => {
100 it("shows the fast-tier icon only for gpt-5.4 on fast tier", () => {88 it("shows the fast-tier icon only for gpt-5.4 when fast mode is enabled", () => {
101 expect(shouldShowFastTierIcon("gpt-5.4", "fast")).toBe(true);89 expect(shouldShowFastTierIcon("gpt-5.4", true)).toBe(true);
102 expect(shouldShowFastTierIcon("gpt-5.4", "auto")).toBe(false);90 expect(shouldShowFastTierIcon("gpt-5.4", false)).toBe(false);
103 expect(shouldShowFastTierIcon("gpt-5.3-codex", "fast")).toBe(false);91 expect(shouldShowFastTierIcon("gpt-5.3-codex", true)).toBe(false);
104 });92 });
105});93});
apps/web/src/appSettings.ts+3-27
...@@ -1,30 +1,11 @@...@@ -1,30 +1,11 @@
1import { useCallback, useSyncExternalStore } from "react";1import { useCallback, useSyncExternalStore } from "react";
2import { Option, Schema } from "effect";2import { Option, Schema } from "effect";
3import { type ProviderKind, type ProviderServiceTier } from "@t3tools/contracts";3import { type ProviderKind } from "@t3tools/contracts";
4import { getDefaultModel, getModelOptions, normalizeModelSlug } from "@t3tools/shared/model";4import { getDefaultModel, getModelOptions, normalizeModelSlug } from "@t3tools/shared/model";
55
6const APP_SETTINGS_STORAGE_KEY = "t3code:app-settings:v1";6const APP_SETTINGS_STORAGE_KEY = "t3code:app-settings:v1";
7const MAX_CUSTOM_MODEL_COUNT = 32;7const MAX_CUSTOM_MODEL_COUNT = 32;
8export const MAX_CUSTOM_MODEL_LENGTH = 256;8export const MAX_CUSTOM_MODEL_LENGTH = 256;
9export const APP_SERVICE_TIER_OPTIONS = [
10 {
11 value: "auto",
12 label: "Automatic",
13 description: "Use Codex defaults without forcing a service tier.",
14 },
15 {
16 value: "fast",
17 label: "Fast",
18 description: "Request the fast service tier when the model supports it.",
19 },
20 {
21 value: "flex",
22 label: "Flex",
23 description: "Request the flex service tier when the model supports it.",
24 },
25] as const;
26export type AppServiceTier = (typeof APP_SERVICE_TIER_OPTIONS)[number]["value"];
27const AppServiceTierSchema = Schema.Literals(["auto", "fast", "flex"]);
28const MODELS_WITH_FAST_SUPPORT = new Set(["gpt-5.4"]);9const MODELS_WITH_FAST_SUPPORT = new Set(["gpt-5.4"]);
29const BUILT_IN_MODEL_SLUGS_BY_PROVIDER: Record<ProviderKind, ReadonlySet<string>> = {10const BUILT_IN_MODEL_SLUGS_BY_PROVIDER: Record<ProviderKind, ReadonlySet<string>> = {
30 codex: new Set(getModelOptions("codex").map((option) => option.slug)),11 codex: new Set(getModelOptions("codex").map((option) => option.slug)),
...@@ -41,7 +22,6 @@ const AppSettingsSchema = Schema.Struct({...@@ -41,7 +22,6 @@ const AppSettingsSchema = Schema.Struct({
41 enableAssistantStreaming: Schema.Boolean.pipe(22 enableAssistantStreaming: Schema.Boolean.pipe(
42 Schema.withConstructorDefault(() => Option.some(false)),23 Schema.withConstructorDefault(() => Option.some(false)),
43 ),24 ),
44 codexServiceTier: AppServiceTierSchema.pipe(Schema.withConstructorDefault(() => Option.some("auto"))),
45 customCodexModels: Schema.Array(Schema.String).pipe(25 customCodexModels: Schema.Array(Schema.String).pipe(
46 Schema.withConstructorDefault(() => Option.some([])),26 Schema.withConstructorDefault(() => Option.some([])),
47 ),27 ),
...@@ -53,17 +33,13 @@ export interface AppModelOption {...@@ -53,17 +33,13 @@ export interface AppModelOption {
53 isCustom: boolean;33 isCustom: boolean;
54}34}
5535
56export function resolveAppServiceTier(serviceTier: AppServiceTier): ProviderServiceTier | null {
57 return serviceTier === "auto" ? null : serviceTier;
58}
59
60export function shouldShowFastTierIcon(36export function shouldShowFastTierIcon(
61 model: string | null | undefined,37 model: string | null | undefined,
62 serviceTier: AppServiceTier,38 fastModeEnabled: boolean,
63): boolean {39): boolean {
64 const normalizedModel = normalizeModelSlug(model);40 const normalizedModel = normalizeModelSlug(model);
65 return (41 return (
66 resolveAppServiceTier(serviceTier) === "fast" &&42 fastModeEnabled &&
67 normalizedModel !== null &&43 normalizedModel !== null &&
68 MODELS_WITH_FAST_SUPPORT.has(normalizedModel)44 MODELS_WITH_FAST_SUPPORT.has(normalizedModel)
69 );45 );
apps/web/src/components/ChatView.tsx+7-12
...@@ -205,9 +205,7 @@ import { readNativeApi } from "~/nativeApi";...@@ -205,9 +205,7 @@ import { readNativeApi } from "~/nativeApi";
205import {205import {
206 getAppModelOptions,206 getAppModelOptions,
207 resolveAppModelSelection,207 resolveAppModelSelection,
208 resolveAppServiceTier,
209 shouldShowFastTierIcon,208 shouldShowFastTierIcon,
210 type AppServiceTier,
211 useAppSettings,209 useAppSettings,
212} from "../appSettings";210} from "../appSettings";
213import {211import {
...@@ -785,8 +783,6 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -785,8 +783,6 @@ export default function ChatView({ threadId }: ChatViewProps) {
785 activeThread.messages.length > 0 ||783 activeThread.messages.length > 0 ||
786 activeThread.session !== null),784 activeThread.session !== null),
787 );785 );
788 const selectedServiceTierSetting = settings.codexServiceTier;
789 const selectedServiceTier = resolveAppServiceTier(selectedServiceTierSetting);
790 const lockedProvider: ProviderKind | null = hasThreadStarted786 const lockedProvider: ProviderKind | null = hasThreadStarted
791 ? (sessionProvider ?? selectedProviderByThreadId ?? null)787 ? (sessionProvider ?? selectedProviderByThreadId ?? null)
792 : null;788 : null;
...@@ -1255,9 +1251,9 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -1255,9 +1251,9 @@ export default function ChatView({ threadId }: ChatViewProps) {
1255 label: name,1251 label: name,
1256 description: `${providerLabel} · ${slug}`,1252 description: `${providerLabel} · ${slug}`,
1257 showFastBadge:1253 showFastBadge:
1258 provider === "codex" && shouldShowFastTierIcon(slug, selectedServiceTierSetting),1254 provider === "codex" && shouldShowFastTierIcon(slug, selectedCodexFastModeEnabled),
1259 }));1255 }));
1260 }, [composerTrigger, searchableModelOptions, selectedServiceTierSetting, workspaceEntries]);1256 }, [composerTrigger, searchableModelOptions, selectedCodexFastModeEnabled, workspaceEntries]);
1261 const composerMenuOpen = Boolean(composerTrigger);1257 const composerMenuOpen = Boolean(composerTrigger);
1262 const activeComposerMenuItem = useMemo(1258 const activeComposerMenuItem = useMemo(
1263 () =>1259 () =>
...@@ -2665,7 +2661,6 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -2665,7 +2661,6 @@ export default function ChatView({ threadId }: ChatViewProps) {
2665 attachments: turnAttachments,2661 attachments: turnAttachments,
2666 },2662 },
2667 model: selectedModel || undefined,2663 model: selectedModel || undefined,
2668 serviceTier: selectedServiceTier,
2669 ...(selectedModelOptionsForDispatch2664 ...(selectedModelOptionsForDispatch
2670 ? { modelOptions: selectedModelOptionsForDispatch }2665 ? { modelOptions: selectedModelOptionsForDispatch }
2671 : {}),2666 : {}),
...@@ -3700,7 +3695,7 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -3700,7 +3695,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
3700 model={selectedModelForPickerWithCustomFallback}3695 model={selectedModelForPickerWithCustomFallback}
3701 lockedProvider={lockedProvider}3696 lockedProvider={lockedProvider}
3702 modelOptionsByProvider={modelOptionsByProvider}3697 modelOptionsByProvider={modelOptionsByProvider}
3703 serviceTierSetting={selectedServiceTierSetting}3698 fastModeEnabled={selectedCodexFastModeEnabled}
3704 onProviderModelChange={onProviderModelSelect}3699 onProviderModelChange={onProviderModelSelect}
3705 />3700 />
37063701
...@@ -5548,7 +5543,7 @@ const ProviderModelPicker = memo(function ProviderModelPicker(props: {...@@ -5548,7 +5543,7 @@ const ProviderModelPicker = memo(function ProviderModelPicker(props: {
5548 model: ModelSlug;5543 model: ModelSlug;
5549 lockedProvider: ProviderKind | null;5544 lockedProvider: ProviderKind | null;
5550 modelOptionsByProvider: Record<ProviderKind, ReadonlyArray<{ slug: string; name: string }>>;5545 modelOptionsByProvider: Record<ProviderKind, ReadonlyArray<{ slug: string; name: string }>>;
5551 serviceTierSetting: AppServiceTier;5546 fastModeEnabled: boolean;
5552 disabled?: boolean;5547 disabled?: boolean;
5553 onProviderModelChange: (provider: ProviderKind, model: ModelSlug) => void;5548 onProviderModelChange: (provider: ProviderKind, model: ModelSlug) => void;
5554}) {5549}) {
...@@ -5578,10 +5573,10 @@ const ProviderModelPicker = memo(function ProviderModelPicker(props: {...@@ -5578,10 +5573,10 @@ const ProviderModelPicker = memo(function ProviderModelPicker(props: {
5578 disabled={props.disabled}5573 disabled={props.disabled}
5579 />5574 />
5580 }5575 }
5581 >5576 >
5582 <span className="flex min-w-0 items-center gap-2">5577 <span className="flex min-w-0 items-center gap-2">
5583 <ProviderIcon aria-hidden="true" className="size-4 shrink-0 text-muted-foreground/70" />5578 <ProviderIcon aria-hidden="true" className="size-4 shrink-0 text-muted-foreground/70" />
5584 {props.provider === "codex" && shouldShowFastTierIcon(props.model, props.serviceTierSetting) ? (5579 {props.provider === "codex" && shouldShowFastTierIcon(props.model, props.fastModeEnabled) ? (
5585 <ZapIcon className="size-3.5 shrink-0 text-amber-500" />5580 <ZapIcon className="size-3.5 shrink-0 text-amber-500" />
5586 ) : null}5581 ) : null}
5587 <span className="truncate">{selectedModelLabel}</span>5582 <span className="truncate">{selectedModelLabel}</span>
...@@ -5627,7 +5622,7 @@ const ProviderModelPicker = memo(function ProviderModelPicker(props: {...@@ -5627,7 +5622,7 @@ const ProviderModelPicker = memo(function ProviderModelPicker(props: {
5627 onClick={() => setIsMenuOpen(false)}5622 onClick={() => setIsMenuOpen(false)}
5628 >5623 >
5629 {option.value === "codex" &&5624 {option.value === "codex" &&
5630 shouldShowFastTierIcon(modelOption.slug, props.serviceTierSetting) ? (5625 shouldShowFastTierIcon(modelOption.slug, props.fastModeEnabled) ? (
5631 <ZapIcon className="size-3.5 shrink-0 text-amber-500" />5626 <ZapIcon className="size-3.5 shrink-0 text-amber-500" />
5632 ) : null}5627 ) : null}
5633 {modelOption.name}5628 {modelOption.name}
apps/web/src/routes/_chat.settings.tsx+5-55
...@@ -3,14 +3,8 @@ import { useQuery } from "@tanstack/react-query";...@@ -3,14 +3,8 @@ import { useQuery } from "@tanstack/react-query";
3import { useCallback, useState } from "react";3import { useCallback, useState } from "react";
4import { type ProviderKind } from "@t3tools/contracts";4import { type ProviderKind } from "@t3tools/contracts";
5import { getModelOptions, normalizeModelSlug } from "@t3tools/shared/model";5import { getModelOptions, normalizeModelSlug } from "@t3tools/shared/model";
6import { ZapIcon } from "lucide-react";6
77import { MAX_CUSTOM_MODEL_LENGTH, useAppSettings } from "../appSettings";
8import {
9 APP_SERVICE_TIER_OPTIONS,
10 MAX_CUSTOM_MODEL_LENGTH,
11 shouldShowFastTierIcon,
12 useAppSettings,
13} from "../appSettings";
14import { isElectron } from "../env";8import { isElectron } from "../env";
15import { useTheme } from "../hooks/useTheme";9import { useTheme } from "../hooks/useTheme";
16import { serverConfigQueryOptions } from "../lib/serverReactQuery";10import { serverConfigQueryOptions } from "../lib/serverReactQuery";
...@@ -18,7 +12,6 @@ import { ensureNativeApi } from "../nativeApi";...@@ -18,7 +12,6 @@ import { ensureNativeApi } from "../nativeApi";
18import { preferredTerminalEditor } from "../terminal-links";12import { preferredTerminalEditor } from "../terminal-links";
19import { Button } from "../components/ui/button";13import { Button } from "../components/ui/button";
20import { Input } from "../components/ui/input";14import { Input } from "../components/ui/input";
21import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue } from "../components/ui/select";
22import { Switch } from "../components/ui/switch";15import { Switch } from "../components/ui/switch";
23import { SidebarInset } from "~/components/ui/sidebar";16import { SidebarInset } from "~/components/ui/sidebar";
2417
...@@ -103,7 +96,6 @@ function SettingsRouteView() {...@@ -103,7 +96,6 @@ function SettingsRouteView() {
10396
104 const codexBinaryPath = settings.codexBinaryPath;97 const codexBinaryPath = settings.codexBinaryPath;
105 const codexHomePath = settings.codexHomePath;98 const codexHomePath = settings.codexHomePath;
106 const codexServiceTier = settings.codexServiceTier;
107 const keybindingsConfigPath = serverConfigQuery.data?.keybindingsConfigPath ?? null;99 const keybindingsConfigPath = serverConfigQuery.data?.keybindingsConfigPath ?? null;
108100
109 const openKeybindingsFile = useCallback(() => {101 const openKeybindingsFile = useCallback(() => {
...@@ -310,43 +302,6 @@ function SettingsRouteView() {...@@ -310,43 +302,6 @@ function SettingsRouteView() {
310 </div>302 </div>
311303
312 <div className="space-y-5">304 <div className="space-y-5">
313 <label className="block space-y-1">
314 <span className="text-xs font-medium text-foreground">Default service tier</span>
315 <Select
316 items={APP_SERVICE_TIER_OPTIONS.map((option) => ({
317 label: option.label,
318 value: option.value,
319 }))}
320 value={codexServiceTier}
321 onValueChange={(value) => {
322 if (!value) return;
323 updateSettings({ codexServiceTier: value });
324 }}
325 >
326 <SelectTrigger>
327 <SelectValue />
328 </SelectTrigger>
329 <SelectPopup alignItemWithTrigger={false}>
330 {APP_SERVICE_TIER_OPTIONS.map((option) => (
331 <SelectItem key={option.value} value={option.value}>
332 <div className="flex min-w-0 items-center gap-2">
333 {option.value === "fast" ? (
334 <ZapIcon className="size-3.5 text-amber-500" />
335 ) : (
336 <span className="size-3.5 shrink-0" aria-hidden="true" />
337 )}
338 <span className="truncate">{option.label}</span>
339 </div>
340 </SelectItem>
341 ))}
342 </SelectPopup>
343 </Select>
344 <span className="text-xs text-muted-foreground">
345 {APP_SERVICE_TIER_OPTIONS.find((option) => option.value === codexServiceTier)
346 ?.description ?? "Use Codex defaults without forcing a service tier."}
347 </span>
348 </label>
349
350 {MODEL_PROVIDER_SETTINGS.map((providerSettings) => {305 {MODEL_PROVIDER_SETTINGS.map((providerSettings) => {
351 const provider = providerSettings.provider;306 const provider = providerSettings.provider;
352 const customModels = getCustomModelsForProvider(settings, provider);307 const customModels = getCustomModelsForProvider(settings, provider);
...@@ -445,14 +400,9 @@ function SettingsRouteView() {...@@ -445,14 +400,9 @@ function SettingsRouteView() {
445 key={`${provider}:${slug}`}400 key={`${provider}:${slug}`}
446 className="flex items-center justify-between gap-3 rounded-lg border border-border bg-background px-3 py-2"401 className="flex items-center justify-between gap-3 rounded-lg border border-border bg-background px-3 py-2"
447 >402 >
448 <div className="flex min-w-0 flex-1 items-center gap-2">403 <code className="min-w-0 flex-1 truncate text-xs text-foreground">
449 {provider === "codex" && shouldShowFastTierIcon(slug, codexServiceTier) ? (404 {slug}
450 <ZapIcon className="size-3.5 shrink-0 text-amber-500" />405 </code>
451 ) : null}
452 <code className="min-w-0 flex-1 truncate text-xs text-foreground">
453 {slug}
454 </code>
455 </div>
456 <Button406 <Button
457 size="xs"407 size="xs"
458 variant="ghost"408 variant="ghost"
packages/contracts/src/orchestration.ts-5
...@@ -42,8 +42,6 @@ export const ProviderSandboxMode = Schema.Literals([...@@ -42,8 +42,6 @@ export const ProviderSandboxMode = Schema.Literals([
42 "danger-full-access",42 "danger-full-access",
43]);43]);
44export type ProviderSandboxMode = typeof ProviderSandboxMode.Type;44export type ProviderSandboxMode = typeof ProviderSandboxMode.Type;
45export const ProviderServiceTier = Schema.Literals(["fast", "flex"]);
46export type ProviderServiceTier = typeof ProviderServiceTier.Type;
47export const DEFAULT_PROVIDER_KIND: ProviderKind = "codex";45export const DEFAULT_PROVIDER_KIND: ProviderKind = "codex";
48const CodexProviderStartOptions = Schema.Struct({46const CodexProviderStartOptions = Schema.Struct({
49 binaryPath: Schema.optional(TrimmedNonEmptyString),47 binaryPath: Schema.optional(TrimmedNonEmptyString),
...@@ -371,7 +369,6 @@ export const ThreadTurnStartCommand = Schema.Struct({...@@ -371,7 +369,6 @@ export const ThreadTurnStartCommand = Schema.Struct({
371 }),369 }),
372 provider: Schema.optional(ProviderKind),370 provider: Schema.optional(ProviderKind),
373 model: Schema.optional(TrimmedNonEmptyString),371 model: Schema.optional(TrimmedNonEmptyString),
374 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),
375 modelOptions: Schema.optional(ProviderModelOptions),372 modelOptions: Schema.optional(ProviderModelOptions),
376 providerOptions: Schema.optional(ProviderStartOptions),373 providerOptions: Schema.optional(ProviderStartOptions),
377 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),374 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),
...@@ -394,7 +391,6 @@ const ClientThreadTurnStartCommand = Schema.Struct({...@@ -394,7 +391,6 @@ const ClientThreadTurnStartCommand = Schema.Struct({
394 }),391 }),
395 provider: Schema.optional(ProviderKind),392 provider: Schema.optional(ProviderKind),
396 model: Schema.optional(TrimmedNonEmptyString),393 model: Schema.optional(TrimmedNonEmptyString),
397 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),
398 modelOptions: Schema.optional(ProviderModelOptions),394 modelOptions: Schema.optional(ProviderModelOptions),
399 providerOptions: Schema.optional(ProviderStartOptions),395 providerOptions: Schema.optional(ProviderStartOptions),
400 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),396 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),
...@@ -675,7 +671,6 @@ export const ThreadTurnStartRequestedPayload = Schema.Struct({...@@ -675,7 +671,6 @@ export const ThreadTurnStartRequestedPayload = Schema.Struct({
675 messageId: MessageId,671 messageId: MessageId,
676 provider: Schema.optional(ProviderKind),672 provider: Schema.optional(ProviderKind),
677 model: Schema.optional(TrimmedNonEmptyString),673 model: Schema.optional(TrimmedNonEmptyString),
678 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),
679 modelOptions: Schema.optional(ProviderModelOptions),674 modelOptions: Schema.optional(ProviderModelOptions),
680 providerOptions: Schema.optional(ProviderStartOptions),675 providerOptions: Schema.optional(ProviderStartOptions),
681 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),676 assistantDeliveryMode: Schema.optional(AssistantDeliveryMode),
packages/contracts/src/provider.ts-3
...@@ -19,7 +19,6 @@ import {...@@ -19,7 +19,6 @@ import {
19 ProviderKind,19 ProviderKind,
20 ProviderRequestKind,20 ProviderRequestKind,
21 ProviderSandboxMode,21 ProviderSandboxMode,
22 ProviderServiceTier,
23 ProviderUserInputAnswers,22 ProviderUserInputAnswers,
24 RuntimeMode,23 RuntimeMode,
25} from "./orchestration";24} from "./orchestration";
...@@ -65,7 +64,6 @@ export const ProviderSessionStartInput = Schema.Struct({...@@ -65,7 +64,6 @@ export const ProviderSessionStartInput = Schema.Struct({
65 model: Schema.optional(TrimmedNonEmptyStringSchema),64 model: Schema.optional(TrimmedNonEmptyStringSchema),
66 modelOptions: Schema.optional(ProviderModelOptions),65 modelOptions: Schema.optional(ProviderModelOptions),
67 resumeCursor: Schema.optional(Schema.Unknown),66 resumeCursor: Schema.optional(Schema.Unknown),
68 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),
69 approvalPolicy: Schema.optional(ProviderApprovalPolicy),67 approvalPolicy: Schema.optional(ProviderApprovalPolicy),
70 sandboxMode: Schema.optional(ProviderSandboxMode),68 sandboxMode: Schema.optional(ProviderSandboxMode),
71 providerOptions: Schema.optional(ProviderStartOptions),69 providerOptions: Schema.optional(ProviderStartOptions),
...@@ -82,7 +80,6 @@ export const ProviderSendTurnInput = Schema.Struct({...@@ -82,7 +80,6 @@ export const ProviderSendTurnInput = Schema.Struct({
82 Schema.Array(ChatAttachment).check(Schema.isMaxLength(PROVIDER_SEND_TURN_MAX_ATTACHMENTS)),80 Schema.Array(ChatAttachment).check(Schema.isMaxLength(PROVIDER_SEND_TURN_MAX_ATTACHMENTS)),
83 ),81 ),
84 model: Schema.optional(TrimmedNonEmptyStringSchema),82 model: Schema.optional(TrimmedNonEmptyStringSchema),
85 serviceTier: Schema.optional(Schema.NullOr(ProviderServiceTier)),
86 modelOptions: Schema.optional(ProviderModelOptions),83 modelOptions: Schema.optional(ProviderModelOptions),
87 interactionMode: Schema.optional(ProviderInteractionMode),84 interactionMode: Schema.optional(ProviderInteractionMode),
88});85});