Merge remote-tracking branch 'origin/farm/342ec142/fix-model-scope-banner'

This commit is contained in:
can1357
2026-06-12 13:46:41 +02:00
3 changed files with 29 additions and 6 deletions
+4
View File
@@ -15,6 +15,10 @@
- Fixed read-only collab sessions so prompting, interrupts, and other write actions are blocked with a read-only warning instead of being applied
### Fixed
- Fixed the interactive Model scope startup banner so models without an explicit thinking level do not show `:undefined`, and entries that were scoped without a `:level` are no longer rendered with the global default thinking level (which `applyRootSessionOptions` pre-fills on the cycling array for Ctrl+P) ([#2385](https://github.com/can1357/oh-my-pi/issues/2385)).
## [15.11.8] - 2026-06-12
### Added
+6 -5
View File
@@ -245,7 +245,7 @@ export interface InteractiveModeNotify {
}
export function buildModelScopeNotification(
scopedModelsForDisplay: readonly Pick<ScopedModel, "model" | "thinkingLevel">[],
scopedModelsForDisplay: readonly Pick<ScopedModel, "model" | "thinkingLevel" | "explicitThinkingLevel">[],
startupQuiet: boolean,
): InteractiveModeNotify | null {
if (startupQuiet || scopedModelsForDisplay.length === 0) {
@@ -253,13 +253,15 @@ export function buildModelScopeNotification(
}
const modelList = scopedModelsForDisplay
.map(scopedModel => {
const thinkingStr = scopedModel.thinkingLevel ? `:${scopedModel.thinkingLevel}` : "";
const thinkingStr =
scopedModel.explicitThinkingLevel && scopedModel.thinkingLevel
? `:${scopedModel.thinkingLevel}`
: "";
return `${scopedModel.model.id}${thinkingStr}`;
})
.join(", ");
return { kind: "info", message: `Model scope: ${modelList} (Ctrl+P to cycle)` };
}
export async function submitInteractiveInput(
mode: Pick<
InteractiveMode,
@@ -1283,9 +1285,8 @@ export async function runRootCommand(
const versionCheckPromise = checkForNewVersion(VERSION).catch(() => undefined);
const changelogMarkdown = await logger.time("main:getChangelogForDisplay", getChangelogForDisplay, parsedArgs);
const scopedModelsForDisplay = sessionOptions.scopedModels ?? scopedModels;
const modelScopeNotification = buildModelScopeNotification(
scopedModelsForDisplay,
scopedModels,
settingsInstance.get("startup.quiet"),
);
if (modelScopeNotification) {
@@ -1,8 +1,8 @@
import { describe, expect, it } from "bun:test";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import type { ScopedModel } from "@oh-my-pi/pi-coding-agent/config/model-resolver";
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
import { buildModelScopeNotification } from "@oh-my-pi/pi-coding-agent/main";
function scopedModel(id: string): ScopedModel {
return {
model: buildModel({
@@ -32,4 +32,22 @@ describe("buildModelScopeNotification", () => {
message: "Model scope: claude-sonnet-4-5 (Ctrl+P to cycle)",
});
});
it("includes thinking suffix only when explicitly scoped", () => {
const withExplicit = { ...scopedModel("claude-sonnet-4-5"), thinkingLevel: "high" as ThinkingLevel, explicitThinkingLevel: true };
expect(buildModelScopeNotification([withExplicit], false)).toEqual({
kind: "info",
message: "Model scope: claude-sonnet-4-5:high (Ctrl+P to cycle)",
});
});
it("hides the suffix when the level was filled from the global default", () => {
// `applyRootSessionOptions` fills `sessionOptions.scopedModels[*].thinkingLevel`
// with the global default for Ctrl+P cycling — the banner must not surface that
// default as if the user had scoped `:high`.
const withDefault = { ...scopedModel("claude-sonnet-4-5"), thinkingLevel: "high" as ThinkingLevel, explicitThinkingLevel: false };
expect(buildModelScopeNotification([withDefault], false)).toEqual({
kind: "info",
message: "Model scope: claude-sonnet-4-5 (Ctrl+P to cycle)",
});
});
});