Files
paseo/packages/app/src/composer/agent-controls/utils.ts
T
paseo-bot[bot]andNurshot 2f0cb2f54b Show the Codex speed bolt in yellow while Fast or Ultrafast is selected (#6152)
* fix(app): fill the speed icon for accelerated tiers

* fix(app): highlight the Codex speed bolt when Fast or Ultrafast is selected

Codex speed moved from the Fast toggle to a Speed selector, and the
composer only colored toggle features, so the bolt stayed muted for
every speed. A select feature is now active when its selected option is
not the default, and the Codex speed takes the same yellow highlight as
the Fast toggle, on the desktop toolbar and in the compact sheet.

Closes #5939

Co-authored-by: Nurshot <85260051+Nurshot@users.noreply.github.com>

* test(app): assert the Codex speed bolt is yellow on desktop and compact

---------

Co-authored-by: Nurshot <85260051+Nurshot@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-05 21:10:24 +01:00

212 lines
6.4 KiB
TypeScript

import type { AgentFeature, AgentModelDefinition } from "@getpaseo/protocol/agent-types";
import { i18n } from "@/i18n/i18next";
import { formatThinkingOptionLabel } from "@/agent-controls/labels";
import {
FAST_MODE_FEATURE_ID,
PLAN_MODE_FEATURE_ID,
SPEED_FEATURE_ID,
} from "@/agent-controls/policy";
export type ExplainedAgentControl = "mode" | "model" | "thinking";
export type FeatureHighlightColor = "blue" | "default" | "green" | "yellow";
export type AgentControlHintKey =
| "agentControls.hints.thinking"
| "agentControls.hints.model"
| "agentControls.hints.mode";
export function getAgentControlHintKey(selector: ExplainedAgentControl): AgentControlHintKey {
switch (selector) {
case "thinking":
return "agentControls.hints.thinking";
case "model":
return "agentControls.hints.model";
case "mode":
return "agentControls.hints.mode";
default:
throw new Error("unreachable");
}
}
export function normalizeModelId(modelId: string | null | undefined): string | null {
const normalized = typeof modelId === "string" ? modelId.trim() : "";
if (!normalized) {
return null;
}
return normalized;
}
export function getFeatureTooltip(feature: Pick<AgentFeature, "label" | "tooltip">): string {
return feature.tooltip ?? feature.label;
}
export function isFeatureActive(feature: AgentFeature): boolean {
if (feature.type === "toggle") return feature.value;
const selectedOption = feature.options.find((option) => option.id === feature.value);
return selectedOption !== undefined && !selectedOption.isDefault;
}
export function getFeatureHighlightColor(featureId: string): FeatureHighlightColor {
switch (featureId) {
case FAST_MODE_FEATURE_ID:
case SPEED_FEATURE_ID:
return "yellow";
case "auto_accept":
return "green";
case PLAN_MODE_FEATURE_ID:
return "blue";
default:
return "default";
}
}
function findModelById(
models: AgentModelDefinition[] | null,
modelId: string | null,
): AgentModelDefinition | null {
if (!models || !modelId) {
return null;
}
return (
models.find((model) => model.id === modelId) ??
models.find((model) => model.aliases?.includes(modelId)) ??
null
);
}
function getFallbackModel(models: AgentModelDefinition[] | null): AgentModelDefinition | null {
return models?.find((model) => model.isDefault) ?? models?.[0] ?? null;
}
function resolvePreferredModelId(
runtimeSelectedModel: AgentModelDefinition | null,
normalizedConfiguredModelId: string | null,
normalizedRuntimeModelId: string | null,
): string | null {
return runtimeSelectedModel?.id ?? normalizedConfiguredModelId ?? normalizedRuntimeModelId;
}
function pickSelectedModel(
models: AgentModelDefinition[] | null,
preferredModelId: string | null,
fallbackModel: AgentModelDefinition | null,
): AgentModelDefinition | null {
if (!preferredModelId) {
return fallbackModel;
}
return findModelById(models, preferredModelId);
}
function resolveThinkingId(
runtimeThinkingOptionId: string | null | undefined,
explicitThinkingOptionId: string | null | undefined,
selectedModel: AgentModelDefinition | null,
): string | null {
const runtimeThinkingOption = selectedModel?.thinkingOptions?.find(
(option) => option.id === runtimeThinkingOptionId,
);
if (runtimeThinkingOption) {
return runtimeThinkingOption.id;
}
if (explicitThinkingOptionId && explicitThinkingOptionId !== "default") {
return explicitThinkingOptionId;
}
return selectedModel?.defaultThinkingOptionId ?? null;
}
type ThinkingOption = NonNullable<AgentModelDefinition["thinkingOptions"]>[number];
function resolveEffectiveThinking(
thinkingOptions: ThinkingOption[] | null,
resolvedThinkingId: string | null,
): ThinkingOption | null {
const selectedThinking =
thinkingOptions?.find((option) => option.id === resolvedThinkingId) ?? null;
return selectedThinking ?? thinkingOptions?.[0] ?? null;
}
function resolveModelDisplay(
selectedModel: AgentModelDefinition | null,
preferredModelId: string | null,
fallbackModel: AgentModelDefinition | null,
unknownModelLabel: string,
): { activeModelId: string | null; displayModel: string } {
return {
activeModelId: selectedModel?.id ?? preferredModelId ?? null,
displayModel:
selectedModel?.label ?? preferredModelId ?? fallbackModel?.label ?? unknownModelLabel,
};
}
function resolveThinkingDisplay(
effectiveThinking: ThinkingOption | null,
selectedThinkingId: string | null,
unknownThinkingLabel: string,
): string {
if (effectiveThinking) {
return formatThinkingOptionLabel(effectiveThinking);
}
if (selectedThinkingId) {
return formatThinkingOptionLabel({ id: selectedThinkingId });
}
return unknownThinkingLabel;
}
export function resolveAgentModelSelection(input: {
models: AgentModelDefinition[] | null;
runtimeModelId: string | null | undefined;
configuredModelId: string | null | undefined;
runtimeThinkingOptionId: string | null | undefined;
explicitThinkingOptionId: string | null | undefined;
}) {
const {
models,
runtimeModelId,
configuredModelId,
runtimeThinkingOptionId,
explicitThinkingOptionId,
} = input;
const normalizedRuntimeModelId = normalizeModelId(runtimeModelId);
const normalizedConfiguredModelId = normalizeModelId(configuredModelId);
const runtimeSelectedModel = findModelById(models, normalizedRuntimeModelId);
const preferredModelId = resolvePreferredModelId(
runtimeSelectedModel,
normalizedConfiguredModelId,
normalizedRuntimeModelId,
);
const fallbackModel = getFallbackModel(models);
const selectedModel = pickSelectedModel(models, preferredModelId, fallbackModel);
const { activeModelId, displayModel } = resolveModelDisplay(
selectedModel,
preferredModelId,
fallbackModel,
i18n.t("agentControls.model.unknown"),
);
const thinkingOptions = selectedModel?.thinkingOptions ?? null;
const resolvedThinkingId = resolveThinkingId(
runtimeThinkingOptionId,
explicitThinkingOptionId,
selectedModel,
);
const effectiveThinking = resolveEffectiveThinking(thinkingOptions, resolvedThinkingId);
const selectedThinkingId = effectiveThinking?.id ?? resolvedThinkingId;
const displayThinking = resolveThinkingDisplay(
effectiveThinking,
selectedThinkingId,
i18n.t("agentControls.thinking.unknown"),
);
return {
selectedModel,
activeModelId,
displayModel,
thinkingOptions,
selectedThinkingId,
displayThinking,
};
}