mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-11 02:46:29 +00:00
The agent snapshot's `options` are the state and `controls` only draw them. Running and closed agents draw from the snapshot; drafts and profile forms ask `provider.controls.list.request` with their `providerOptions`, so aliases such as a legacy Fast profile's `service_tier: "fast"` are resolved once, by the daemon, and the draft keeps Fast highlighted. A draft adds only the user's edits and each provider's last-used control values; applying a profile seeds its non-control options (e.g. `sandbox_mode`) into the draft, and a profile form saves them back instead of pruning to the controls it can draw. A daemon without `server_info.features.providerOptionControls` still sends `features` and `featureValues`. `LegacyProviderOptions` in the client package is the one place that translates snapshots, draft listings, create and apply requests, and daemon-config profiles, so the app never branches on it. Persisted preferences and tab layouts rename `featureValues` through tagged COMPAT preprocessors. The features/controls bridge moves from the server into the protocol package so the client can reuse it.
57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import type { ProviderSnapshotEntry } from "@getpaseo/protocol/agent-types";
|
|
import type { AgentProfile } from "@getpaseo/protocol/messages";
|
|
import { formatAgentModeLabel, formatThinkingOptionLabel } from "@/agent-controls/labels";
|
|
|
|
export interface AgentProfileTag {
|
|
id: string;
|
|
label: string;
|
|
}
|
|
|
|
function findEntry(
|
|
entries: readonly ProviderSnapshotEntry[],
|
|
provider: string,
|
|
): ProviderSnapshotEntry | null {
|
|
return entries.find((entry) => entry.provider === provider) ?? null;
|
|
}
|
|
|
|
/**
|
|
* The one-line résumé of a profile in the settings list. Every label falls back
|
|
* to the stored id: a row must stay readable on a host whose provider catalog
|
|
* is offline, or that no longer ships the model the profile names.
|
|
*/
|
|
export function buildAgentProfileTags(input: {
|
|
profile: AgentProfile;
|
|
entries: readonly ProviderSnapshotEntry[] | undefined;
|
|
formatFeatureCount: (count: number) => string;
|
|
}): AgentProfileTag[] {
|
|
const entries = input.entries ?? [];
|
|
const entry = findEntry(entries, input.profile.provider);
|
|
const tags: AgentProfileTag[] = [
|
|
{ id: "provider", label: entry?.label ?? input.profile.provider },
|
|
];
|
|
|
|
const modelId = input.profile.model?.trim();
|
|
if (modelId) {
|
|
const model = entry?.models?.find((candidate) => candidate.id === modelId);
|
|
tags.push({ id: "model", label: model?.label ?? modelId });
|
|
}
|
|
|
|
const modeId = input.profile.modeId?.trim();
|
|
if (modeId) {
|
|
const mode = entry?.modes?.find((candidate) => candidate.id === modeId);
|
|
tags.push({ id: "mode", label: mode ? formatAgentModeLabel(mode) : modeId });
|
|
}
|
|
|
|
const thinkingOptionId = input.profile.thinkingOptionId?.trim();
|
|
if (thinkingOptionId) {
|
|
tags.push({ id: "thinking", label: formatThinkingOptionLabel({ id: thinkingOptionId }) });
|
|
}
|
|
|
|
const featureCount = Object.keys(input.profile.options ?? {}).length;
|
|
if (featureCount > 0) {
|
|
tags.push({ id: "features", label: input.formatFeatureCount(featureCount) });
|
|
}
|
|
|
|
return tags;
|
|
}
|