Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions packages/client-runtime/src/state/threadExecution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -436,20 +436,36 @@ describe("formatModelSelectionEffort", () => {
},
];

it("shows the model's default effort when the user never picked one", () => {
expect(formatModelSelectionEffort(selection(), catalog({}))).toBe("High");
});

it("names a stored effort the way the catalog does", () => {
expect(
formatModelSelectionEffort(selection([{ id: "effort", value: "xhigh" }]), catalog({})),
).toBe("Extra High");
});

it("uses the descriptor's current value over the default", () => {
expect(formatModelSelectionEffort(selection(), catalog({ currentValue: "medium" }))).toBe(
"Medium",
);
it("names a reported effort when no stored one overrides it", () => {
const reported = selection([{ id: "effort", value: "xhigh" }]);
expect(formatModelSelectionEffort(selection(), catalog({}), reported)).toBe("Extra High");
expect(
formatModelSelectionEffort(
selection([{ id: "effort", value: "medium" }]),
catalog({}),
reported,
),
).toBe("Medium");
});

it("shows nothing when neither the selection nor the provider states an effort", () => {
// A subagent's selection is written from what the provider reported; the
// catalog's default and current value are guesses about it (#15214).
expect(formatModelSelectionEffort(selection(), catalog({}))).toBeNull();
expect(formatModelSelectionEffort(selection(), catalog({ currentValue: "medium" }))).toBeNull();
// A report for another model is not this thread's either.
expect(
formatModelSelectionEffort(selection(), catalog({}), {
...selection([{ id: "effort", value: "xhigh" }]),
model: "claude-opus-5-5",
}),
).toBeNull();
});

it("shows nothing for a model the catalog does not describe", () => {
Expand Down
26 changes: 20 additions & 6 deletions packages/client-runtime/src/state/threadExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ import {
backgroundWorkHoldsCompletion,
derivePendingBackgroundWork,
} from "@t3tools/shared/orchestrationV2PendingBackgroundWork";
import { getProviderOptionCurrentLabel, getProviderOptionDescriptors } from "@t3tools/shared/model";
import {
getProviderOptionCurrentLabel,
getProviderOptionCurrentValue,
getProviderOptionDescriptors,
isProviderOptionValueStated,
} from "@t3tools/shared/model";
import { formatDuration } from "@t3tools/shared/orchestrationTiming";
import * as DateTime from "effect/DateTime";

Expand Down Expand Up @@ -161,11 +166,12 @@ export function deriveReportedModelSelection(
const REASONING_EFFORT_OPTION_IDS = ["reasoningEffort", "effort", "reasoning", "variant"] as const;

/**
* The reasoning effort a thread's model runs at, resolved and named the way
* the composer's effort picker does: the stored choice when valid, else the
* descriptor's current value, else the model's default. Null when the
* provider catalog has no effort option for this model (a subagent on a
* model the catalog does not describe), rather than guessing.
* The reasoning effort a provider-native subagent's thread states, named the
* way the composer's effort picker does. Only a value the selection carries,
* or the provider reported for it, counts: the adapter writes that selection
* from what the provider told it, so a missing option means the effort is
* unknown, not that the model's catalog default applies. Null when nothing is
* stated or the catalog does not describe the model, rather than guessing.
*/
export function formatModelSelectionEffort(
selection: ModelSelection,
Expand All @@ -178,6 +184,14 @@ export function formatModelSelectionEffort(
for (const id of REASONING_EFFORT_OPTION_IDS) {
const descriptor = descriptors.find((candidate) => candidate.id === id);
if (descriptor?.type !== "select") continue;
// An unstated value is the catalog's pick, not this subagent's. No value
// at all is the resolver's own "unknown", which may still be named.
if (
!isProviderOptionValueStated(id, selection, reportedSelection) &&
getProviderOptionCurrentValue(descriptor, selection, reportedSelection) !== undefined
) {
continue;
}
const label = getProviderOptionCurrentLabel(descriptor, selection, reportedSelection);
if (label) return label;
}
Expand Down
16 changes: 16 additions & 0 deletions packages/shared/src/model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
formatCodexModelName,
formatModelSlugName,
getProviderOptionCurrentLabel,
isProviderOptionValueStated,
getModelSelectionBooleanOptionValue,
getModelSelectionStringOptionValue,
getProviderOptionDescriptors,
Expand Down Expand Up @@ -362,4 +363,19 @@ describe("provider-reported option display", () => {
])("ignores reports after changing the model, instance, or option: %j", (selected) => {
expect(getProviderOptionCurrentLabel(descriptor, selected, reported)).toBe("Unknown");
});

it("tells a stated option from a catalog guess", () => {
expect(isProviderOptionValueStated("variant", selection)).toBe(false);
expect(isProviderOptionValueStated("variant", selection, reported)).toBe(true);
expect(
isProviderOptionValueStated("variant", {
...selection,
options: [{ id: "variant", value: "none" }],
}),
).toBe(true);
expect(isProviderOptionValueStated("variant", { ...selection, model: "other" }, reported)).toBe(
false,
);
expect(isProviderOptionValueStated("effort", selection, reported)).toBe(false);
});
});
15 changes: 15 additions & 0 deletions packages/shared/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,21 @@ function getReportedOptionValue(
return getRawSelectionValueById(reportedSelection.options, id);
}

/**
* Whether the selection carries this option, or the provider reported one for
* the same model and instance. A catalog default or current value is neither.
*/
export function isProviderOptionValueStated(
id: string,
selection?: ModelSelection | null,
reportedSelection?: ModelSelection | null,
): boolean {
return (
selection?.options?.some((option) => option.id === id) === true ||
getReportedOptionValue(id, selection, reportedSelection) !== undefined
);
}

export function getProviderOptionCurrentValue(
descriptor: ProviderOptionDescriptor | null | undefined,
selection?: ModelSelection | null,
Expand Down
Loading