fix(gsd): apply fast service tier outside auto-mode (#2126)

This commit is contained in:
mastertyko 2026-03-23 16:49:09 +01:00 committed by GitHub
parent a9667209ef
commit b0fc552a2e
3 changed files with 60 additions and 10 deletions

View file

@ -20,21 +20,27 @@ import { saveActivityLog } from "../activity-log.js";
// printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
let isFirstSession = true;
async function syncServiceTierStatus(ctx: ExtensionContext): Promise<void> {
const { getEffectiveServiceTier, formatServiceTierFooterStatus } = await import("../service-tier.js");
ctx.ui.setStatus("gsd-fast", formatServiceTierFooterStatus(getEffectiveServiceTier(), ctx.model?.id));
}
export function registerHooks(pi: ExtensionAPI): void {
pi.on("session_start", async (_event, ctx) => {
resetWriteGateState();
resetToolCallLoopGuard();
await syncServiceTierStatus(ctx);
if (isFirstSession) {
isFirstSession = false;
} else {
try {
const gsdBinPath = process.env.GSD_BIN_PATH;
if (gsdBinPath) {
const { dirname } = await import('node:path');
const { dirname } = await import("node:path");
const { printWelcomeScreen } = await import(
join(dirname(gsdBinPath), 'welcome-screen.js')
join(dirname(gsdBinPath), "welcome-screen.js")
) as { printWelcomeScreen: (opts: { version: string; modelName?: string; provider?: string }) => void };
printWelcomeScreen({ version: process.env.GSD_VERSION || '0.0.0' });
printWelcomeScreen({ version: process.env.GSD_VERSION || "0.0.0" });
}
} catch { /* non-fatal */ }
}
@ -192,8 +198,11 @@ export function registerHooks(pi: ExtensionAPI): void {
markToolEnd(event.toolCallId);
});
pi.on("model_select", async (_event, ctx) => {
await syncServiceTierStatus(ctx);
});
pi.on("before_provider_request", async (event) => {
if (!isAutoActive()) return;
const modelId = event.model?.id;
if (!modelId) return;
const { getEffectiveServiceTier, supportsServiceTier } = await import("../service-tier.js");
@ -205,4 +214,3 @@ export function registerHooks(pi: ExtensionAPI): void {
return payload;
});
}

View file

@ -23,6 +23,8 @@ import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./comm
export type ServiceTierSetting = "priority" | "flex" | undefined;
const SERVICE_TIER_SCOPE_NOTE = "Only affects gpt-5.4 models, regardless of provider.";
// ─── Gating ──────────────────────────────────────────────────────────────────
/**
@ -51,7 +53,7 @@ export function formatServiceTierStatus(tier: ServiceTierSetting): string {
" /gsd fast flex Set to flex (0.5x cost, slower)",
" /gsd fast off Disable service tier",
"",
"Only affects gpt-5.4 models.",
SERVICE_TIER_SCOPE_NOTE,
].join("\n");
}
@ -64,10 +66,18 @@ export function formatServiceTierStatus(tier: ServiceTierSetting): string {
" /gsd fast flex Set to flex (0.5x cost, slower)",
" /gsd fast off Disable service tier",
"",
"Only affects gpt-5.4 models.",
SERVICE_TIER_SCOPE_NOTE,
].join("\n");
}
export function formatServiceTierFooterStatus(
tier: ServiceTierSetting,
modelId: string | undefined,
): string | undefined {
if (!tier || !modelId || !supportsServiceTier(modelId)) return undefined;
return tier === "priority" ? "fast: ⚡ priority" : "fast: 💰 flex";
}
// ─── Icon Resolution ─────────────────────────────────────────────────────────
/**
@ -148,19 +158,22 @@ export async function handleFast(args: string, ctx: ExtensionCommandContext): Pr
if (trimmed === "on") {
await writeGlobalServiceTier(ctx, "priority");
ctx.ui.notify("Service tier set to priority (2x cost, faster responses). Only affects gpt-5.4 models.", "info");
ctx.ui.setStatus("gsd-fast", formatServiceTierFooterStatus("priority", ctx.model?.id));
ctx.ui.notify("Service tier set to priority (2x cost, faster responses). Only affects gpt-5.4 models, regardless of provider.", "info");
return;
}
if (trimmed === "off") {
await writeGlobalServiceTier(ctx, undefined);
ctx.ui.setStatus("gsd-fast", undefined);
ctx.ui.notify("Service tier disabled.", "info");
return;
}
if (trimmed === "flex") {
await writeGlobalServiceTier(ctx, "flex");
ctx.ui.notify("Service tier set to flex (0.5x cost, slower responses). Only affects gpt-5.4 models.", "info");
ctx.ui.setStatus("gsd-fast", formatServiceTierFooterStatus("flex", ctx.model?.id));
ctx.ui.notify("Service tier set to flex (0.5x cost, slower responses). Only affects gpt-5.4 models, regardless of provider.", "info");
return;
}

View file

@ -4,8 +4,8 @@ import assert from "node:assert/strict";
import {
supportsServiceTier,
formatServiceTierStatus,
formatServiceTierFooterStatus,
resolveServiceTierIcon,
type ServiceTierSetting,
} from "../service-tier.ts";
// ─── supportsServiceTier ─────────────────────────────────────────────────────
@ -27,6 +27,14 @@ describe("supportsServiceTier", () => {
assert.equal(supportsServiceTier("openai/gpt-5.4"), true);
});
test("returns true for vibeproxy-openai/gpt-5.4 (proxy provider-prefixed)", () => {
assert.equal(supportsServiceTier("vibeproxy-openai/gpt-5.4"), true);
});
test("returns false for provider-only identifier without gpt-5.4 model suffix", () => {
assert.equal(supportsServiceTier("vibeproxy-openai"), false);
});
test("returns false for claude-opus-4-6", () => {
assert.equal(supportsServiceTier("claude-opus-4-6"), false);
});
@ -52,6 +60,11 @@ describe("formatServiceTierStatus", () => {
assert.ok(output.includes("disabled"), `Expected 'disabled' in: ${output}`);
});
test("mentions provider-agnostic model gating", () => {
const output = formatServiceTierStatus("priority");
assert.ok(output.includes("regardless of provider"), `Expected provider note in: ${output}`);
});
test("shows priority when set to priority", () => {
const output = formatServiceTierStatus("priority");
assert.ok(output.includes("priority"), `Expected 'priority' in: ${output}`);
@ -63,6 +76,22 @@ describe("formatServiceTierStatus", () => {
});
});
// ─── formatServiceTierFooterStatus ───────────────────────────────────────────
describe("formatServiceTierFooterStatus", () => {
test("returns priority footer status for supported model", () => {
assert.equal(formatServiceTierFooterStatus("priority", "vibeproxy-openai/gpt-5.4"), "fast: ⚡ priority");
});
test("returns undefined for unsupported model", () => {
assert.equal(formatServiceTierFooterStatus("priority", "claude-opus-4-6"), undefined);
});
test("returns undefined when tier is disabled", () => {
assert.equal(formatServiceTierFooterStatus(undefined, "gpt-5.4"), undefined);
});
});
// ─── resolveServiceTierIcon ──────────────────────────────────────────────────
describe("resolveServiceTierIcon", () => {