mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-01 22:23:07 +00:00
fix(server): a saved legacy Codex Fast preference wins over a configured service_tier default
The defaults merge put a configured service_tier next to the agent's own legacy fast_mode, and Codex reads service_tier first, so the agent opened Normal. The agent's own alias now replaces the default of the key it stands for.
This commit is contained in:
@@ -99,6 +99,31 @@ export function mergeProviderOptions(
|
||||
return merged;
|
||||
}
|
||||
|
||||
// COMPAT(codexFastPreference): added in v0.10.0, remove after 2027-03-29 once saved Fast preferences have migrated.
|
||||
const LEGACY_OPTION_ALIASES: Record<string, Record<string, string>> = {
|
||||
codex: { fast_mode: "service_tier" },
|
||||
};
|
||||
|
||||
/**
|
||||
* The options a provider opens with: `defaults` from config.json under the agent's `own`
|
||||
* options. An agent's own legacy alias (a saved `fast_mode`) replaces the default of the key it
|
||||
* stands for, so a configured `service_tier` does not override the agent's own Fast preference.
|
||||
*/
|
||||
export function mergeDefaultsUnderOwn(input: {
|
||||
provider: string;
|
||||
defaults: ProviderOptions | undefined;
|
||||
own: ProviderOptions | undefined;
|
||||
}): ProviderOptions | undefined {
|
||||
const { defaults, own } = input;
|
||||
const aliases = LEGACY_OPTION_ALIASES[input.provider];
|
||||
if (!aliases || !defaults || !own) return mergeProviderOptions(defaults, own);
|
||||
const kept = { ...defaults };
|
||||
for (const [alias, canonical] of Object.entries(aliases)) {
|
||||
if (own[alias] !== undefined && own[canonical] === undefined) delete kept[canonical];
|
||||
}
|
||||
return mergeProviderOptions(kept, own);
|
||||
}
|
||||
|
||||
function isPlainObject(value: unknown): value is ProviderOptions {
|
||||
if (value === null || typeof value !== "object") return false;
|
||||
const prototype = Object.getPrototypeOf(value);
|
||||
|
||||
@@ -791,6 +791,24 @@ test("ACP provider configuration retains opaque options", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("a saved legacy Codex Fast preference wins over a configured service_tier default", () => {
|
||||
const registry = buildProviderRegistry(logger, {
|
||||
providerOverrides: { codex: { options: { service_tier: "default", plan_mode: false } } },
|
||||
});
|
||||
const client = registry.codex.createClient(logger);
|
||||
|
||||
// Pre-v0.10 agents saved `fast_mode`; the agent's own preference beats the configured default.
|
||||
expect(client.effectiveOptions?.({ fast_mode: true })).toEqual({
|
||||
fast_mode: true,
|
||||
plan_mode: false,
|
||||
});
|
||||
expect(client.effectiveOptions?.({ service_tier: "fast" })).toEqual({
|
||||
service_tier: "fast",
|
||||
plan_mode: false,
|
||||
});
|
||||
expect(client.effectiveOptions?.({})).toEqual({ service_tier: "default", plan_mode: false });
|
||||
});
|
||||
|
||||
test("cursor provider extending acp uses CursorACPAgentClient", () => {
|
||||
const registry = buildProviderRegistry(logger, {
|
||||
providerOverrides: {
|
||||
|
||||
@@ -48,7 +48,7 @@ import { PiRpcAgentClient } from "./providers/pi/agent.js";
|
||||
import { TraeACPAgentClient } from "./providers/trae-acp-agent.js";
|
||||
import { MockLoadTestAgentClient } from "./providers/mock-load-test-agent.js";
|
||||
import { MockSlowProviderClient } from "./providers/mock-slow-provider.js";
|
||||
import { ToolPolicyUnsupportedError, mergeProviderOptions } from "./provider-options.js";
|
||||
import { ToolPolicyUnsupportedError, mergeDefaultsUnderOwn } from "./provider-options.js";
|
||||
import {
|
||||
AGENT_PROVIDER_DEFINITIONS,
|
||||
BUILTIN_PROVIDER_IDS,
|
||||
@@ -498,6 +498,8 @@ function wrapClientProvider(
|
||||
const archiveNativeSession = inner.archiveNativeSession?.bind(inner);
|
||||
const unarchiveNativeSession = inner.unarchiveNativeSession?.bind(inner);
|
||||
const configuredModelIds = [...profileModels, ...additionalModels].map((model) => model.id);
|
||||
const withDefaults = (own: ProviderOptions | undefined) =>
|
||||
mergeDefaultsUnderOwn({ provider: inner.provider, defaults: providerOptions, own });
|
||||
|
||||
return {
|
||||
provider,
|
||||
@@ -512,7 +514,7 @@ function wrapClientProvider(
|
||||
{
|
||||
...config,
|
||||
provider: inner.provider,
|
||||
providerOptions: mergeProviderOptions(providerOptions, config.providerOptions),
|
||||
providerOptions: withDefaults(config.providerOptions),
|
||||
},
|
||||
launchContext,
|
||||
{ ...options, configuredModelIds },
|
||||
@@ -529,7 +531,7 @@ function wrapClientProvider(
|
||||
{
|
||||
...overrides,
|
||||
provider: inner.provider,
|
||||
providerOptions: mergeProviderOptions(providerOptions, overrides?.providerOptions),
|
||||
providerOptions: withDefaults(overrides?.providerOptions),
|
||||
},
|
||||
launchContext,
|
||||
{ ...options, configuredModelIds },
|
||||
@@ -551,7 +553,7 @@ function wrapClientProvider(
|
||||
config: {
|
||||
...config,
|
||||
provider: inner.provider,
|
||||
providerOptions: mergeProviderOptions(providerOptions, config.providerOptions),
|
||||
providerOptions: withDefaults(config.providerOptions),
|
||||
},
|
||||
env,
|
||||
signal,
|
||||
@@ -560,13 +562,13 @@ function wrapClientProvider(
|
||||
resolveCreateConfig: inner.resolveCreateConfig?.bind(inner),
|
||||
resolveConfiguredModel: inner.resolveConfiguredModel?.bind(inner),
|
||||
isCreateConfigUnattended: inner.isCreateConfigUnattended?.bind(inner),
|
||||
effectiveOptions: (own) => mergeProviderOptions(providerOptions, own) ?? {},
|
||||
effectiveOptions: (own) => withDefaults(own) ?? {},
|
||||
listControls: listControls
|
||||
? async (config) =>
|
||||
await listControls({
|
||||
...config,
|
||||
provider: inner.provider,
|
||||
providerOptions: mergeProviderOptions(providerOptions, config.providerOptions),
|
||||
providerOptions: withDefaults(config.providerOptions),
|
||||
})
|
||||
: undefined,
|
||||
listImportableSessions: listImportableSessions
|
||||
@@ -579,10 +581,7 @@ function wrapClientProvider(
|
||||
config: {
|
||||
...context.config,
|
||||
provider: inner.provider,
|
||||
providerOptions: mergeProviderOptions(
|
||||
providerOptions,
|
||||
context.config.providerOptions,
|
||||
),
|
||||
providerOptions: withDefaults(context.config.providerOptions),
|
||||
},
|
||||
storedConfig: {
|
||||
...context.storedConfig,
|
||||
|
||||
Reference in New Issue
Block a user