mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 06:40:43 +00:00
chat: clear thinking and fast defaults
This commit is contained in:
committed by
Peter Steinberger
parent
5ac1fee4de
commit
b8e2f648a7
@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Changes
|
||||
|
||||
- Chat commands: add `/think default` and `/fast default` to clear session overrides and inherit configured/provider defaults. (#79385) Thanks @VACInc.
|
||||
- Dependencies: refresh workspace dependency pins and lockfile, including `@openai/codex` `0.130.0`, `acpx` `0.7.0`, AWS SDK `3.1044.0`, OpenTelemetry `0.217.0`, `typebox` `1.1.38`, `vite` `8.0.11`, `oxfmt` `0.48.0`, and `oxlint` `1.63.0`, and update the Codex harness model snapshot for the new bundled app-server catalog.
|
||||
- Plugins/install: add guarded plugin install overrides so onboarding and repair tests can route specific plugins to registry specs or local `npm pack` artifacts via environment variables.
|
||||
- Tests/Docker: add Codex on-demand install and live plugin-tool dependency E2E lanes for packaged onboarding and npm-pack plugin proof.
|
||||
|
||||
@@ -135,10 +135,10 @@ Current source-of-truth:
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Model and run controls">
|
||||
- `/think <level>` sets the thinking level. Options come from the active model's provider profile; common levels are `off`, `minimal`, `low`, `medium`, and `high`, with custom levels such as `xhigh`, `adaptive`, `max`, or binary `on` only where supported. Aliases: `/thinking`, `/t`.
|
||||
- `/think <level|default>` sets the thinking level or clears the session override. Options come from the active model's provider profile; common levels are `off`, `minimal`, `low`, `medium`, and `high`, with custom levels such as `xhigh`, `adaptive`, `max`, or binary `on` only where supported. Aliases: `/thinking`, `/t`.
|
||||
- `/verbose on|off|full` toggles verbose output. Alias: `/v`.
|
||||
- `/trace on|off` toggles plugin trace output for the current session.
|
||||
- `/fast [status|on|off]` shows or sets fast mode.
|
||||
- `/fast [status|on|off|default]` shows, sets, or clears fast mode.
|
||||
- `/reasoning [on|off|stream]` toggles reasoning visibility. Alias: `/reason`.
|
||||
- `/elevated [on|off|ask|full]` toggles elevated mode. Alias: `/elev`.
|
||||
- `/exec host=<auto|sandbox|gateway|node> security=<deny|allowlist|full> ask=<off|on-miss|always> node=<id>` shows or sets exec defaults.
|
||||
|
||||
@@ -48,7 +48,8 @@ title: "Thinking levels"
|
||||
## Setting a session default
|
||||
|
||||
- Send a message that is **only** the directive (whitespace allowed), e.g. `/think:medium` or `/t high`.
|
||||
- That sticks for the current session (per-sender by default); cleared by `/think:off` or session idle reset.
|
||||
- That sticks for the current session (per-sender by default). Use `/think default` to clear the session override and inherit the configured/provider default; aliases include `inherit`, `clear`, `reset`, and `unpin`.
|
||||
- `/think off` stores an explicit off override. It disables thinking until you change or clear the session override.
|
||||
- Confirmation reply is sent (`Thinking level set to high.` / `Thinking disabled.`). If the level is invalid (e.g. `/thinking big`), the command is rejected with a hint and the session state is left unchanged.
|
||||
- Send `/think` (or `/think:`) with no argument to see the current thinking level.
|
||||
|
||||
@@ -59,11 +60,11 @@ title: "Thinking levels"
|
||||
|
||||
## Fast mode (/fast)
|
||||
|
||||
- Levels: `on|off`.
|
||||
- Directive-only message toggles a session fast-mode override and replies `Fast mode enabled.` / `Fast mode disabled.`.
|
||||
- Levels: `on|off|default`.
|
||||
- Directive-only message toggles a session fast-mode override and replies `Fast mode enabled.` / `Fast mode disabled.`. Use `/fast default` to clear the session override and inherit the configured default; aliases include `inherit`, `clear`, `reset`, and `unpin`.
|
||||
- Send `/fast` (or `/fast status`) with no mode to see the current effective fast-mode state.
|
||||
- OpenClaw resolves fast mode in this order:
|
||||
1. Inline/directive-only `/fast on|off`
|
||||
1. Inline/directive-only `/fast on|off` override (`/fast default` clears this layer)
|
||||
2. Session override
|
||||
3. Per-agent default (`agents.list[].fastModeDefault`)
|
||||
4. Per-model config: `agents.defaults.models["<provider>/<model>"].params.fastMode`
|
||||
|
||||
@@ -59,9 +59,9 @@ export function buildHelpMessage(cfg?: OpenClawConfig): string {
|
||||
lines.push("");
|
||||
|
||||
const optionParts = [
|
||||
"/think <level>",
|
||||
"/think <level|default>",
|
||||
"/model <id>",
|
||||
"/fast status|on|off",
|
||||
"/fast status|on|off|default",
|
||||
"/verbose on|off|full",
|
||||
"/trace on|off|raw",
|
||||
];
|
||||
|
||||
@@ -13,7 +13,7 @@ type ListThinkingLevels = (
|
||||
provider?: string | null,
|
||||
model?: string | null,
|
||||
catalog?: CommandArgChoiceContext["catalog"],
|
||||
) => ThinkLevel[];
|
||||
) => string[];
|
||||
|
||||
const BROWSER_SAFE_THINKING_LEVELS: ThinkLevel[] = [
|
||||
...BASE_THINKING_LEVELS,
|
||||
@@ -147,8 +147,12 @@ export function assertCommandRegistry(commands: ChatCommandDefinition[]): void {
|
||||
export function buildBuiltinChatCommands(
|
||||
params: { listThinkingLevels?: ListThinkingLevels } = {},
|
||||
): ChatCommandDefinition[] {
|
||||
const listThinkingLevelChoices =
|
||||
const configuredThinkingLevels =
|
||||
params.listThinkingLevels ?? (() => BROWSER_SAFE_THINKING_LEVELS);
|
||||
const listThinkingLevelChoices: ListThinkingLevels = (provider, model, catalog) => {
|
||||
const levels = configuredThinkingLevels(provider, model, catalog);
|
||||
return ["default", ...levels.filter((level) => level !== "default")];
|
||||
};
|
||||
const commands: ChatCommandDefinition[] = [
|
||||
defineChatCommand({
|
||||
key: "help",
|
||||
@@ -799,9 +803,9 @@ export function buildBuiltinChatCommands(
|
||||
args: [
|
||||
{
|
||||
name: "mode",
|
||||
description: "status, on, or off",
|
||||
description: "status, on, off, or default",
|
||||
type: "string",
|
||||
choices: ["status", "on", "off"],
|
||||
choices: ["status", "on", "off", "default"],
|
||||
},
|
||||
],
|
||||
argsMenu: "auto",
|
||||
|
||||
@@ -377,7 +377,7 @@ describe("commands registry", () => {
|
||||
category: "options",
|
||||
});
|
||||
const modeArg = requireCommandArg(fast, "mode");
|
||||
expect(modeArg.choices).toEqual(["status", "on", "off"]);
|
||||
expect(modeArg.choices).toEqual(["status", "on", "off", "default"]);
|
||||
});
|
||||
|
||||
it("detects known text commands", () => {
|
||||
@@ -633,6 +633,7 @@ describe("commands registry args", () => {
|
||||
|
||||
expect(menu.arg.name).toBe("level");
|
||||
expect(menu.choices.map((choice) => choice.value)).toEqual([
|
||||
"default",
|
||||
"off",
|
||||
"low",
|
||||
"medium",
|
||||
@@ -640,7 +641,7 @@ describe("commands registry args", () => {
|
||||
"max",
|
||||
]);
|
||||
expect(formatCommandArgMenuTitle({ command, menu })).toBe(
|
||||
"Choose level for /think.\nOptions: off, low, medium, high, max.",
|
||||
"Choose level for /think.\nOptions: default, off, low, medium, high, max.",
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -69,6 +69,21 @@ describe("directive parsing", () => {
|
||||
expect(res.fastMode).toBe(true);
|
||||
});
|
||||
|
||||
it("parses default thinking and fast directives as override clears", () => {
|
||||
expect(parseInlineDirectives("/think default")).toMatchObject({
|
||||
hasThinkDirective: true,
|
||||
thinkLevel: undefined,
|
||||
rawThinkLevel: "default",
|
||||
clearThinkLevel: true,
|
||||
});
|
||||
expect(parseInlineDirectives("/fast inherit")).toMatchObject({
|
||||
hasFastDirective: true,
|
||||
fastMode: undefined,
|
||||
rawFastMode: "inherit",
|
||||
clearFastMode: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("matches elevated with leading space", () => {
|
||||
const res = extractElevatedDirective(" please /elevated on now");
|
||||
expect(res.hasDirective).toBe(true);
|
||||
|
||||
@@ -241,4 +241,45 @@ describe("handleFastCommand", () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("clears fast mode for /fast default", async () => {
|
||||
const params = buildUsageParams();
|
||||
params.command.commandBodyNormalized = "/fast default";
|
||||
params.sessionEntry = {
|
||||
sessionId: "target-session",
|
||||
updatedAt: Date.now(),
|
||||
fastMode: true,
|
||||
};
|
||||
params.sessionStore = { [params.sessionKey]: params.sessionEntry };
|
||||
|
||||
const result = await handleFastCommand(params, true);
|
||||
|
||||
expect(result?.shouldContinue).toBe(false);
|
||||
expect(result?.reply?.text).toBe("⚙️ Fast mode reset to default.");
|
||||
expect(params.sessionEntry.fastMode).toBeUndefined();
|
||||
expect(params.sessionStore[params.sessionKey]?.fastMode).toBeUndefined();
|
||||
});
|
||||
|
||||
it("clears fast mode on the target store entry for /fast default", async () => {
|
||||
const params = buildUsageParams();
|
||||
params.command.commandBodyNormalized = "/fast default";
|
||||
params.sessionEntry = {
|
||||
sessionId: "wrapper-session",
|
||||
updatedAt: Date.now(),
|
||||
fastMode: false,
|
||||
};
|
||||
params.sessionStore = {
|
||||
[params.sessionKey]: {
|
||||
sessionId: "target-session",
|
||||
updatedAt: Date.now(),
|
||||
fastMode: true,
|
||||
},
|
||||
};
|
||||
|
||||
const result = await handleFastCommand(params, true);
|
||||
|
||||
expect(result?.reply?.text).toBe("⚙️ Fast mode reset to default.");
|
||||
expect(params.sessionEntry.fastMode).toBe(false);
|
||||
expect(params.sessionStore[params.sessionKey]?.fastMode).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,7 +29,12 @@ import {
|
||||
import { formatTokenCount, formatUsd } from "../../utils/usage-format.js";
|
||||
import { parseActivationCommand } from "../group-activation.js";
|
||||
import { parseSendPolicyCommand } from "../send-policy.js";
|
||||
import { normalizeFastMode, normalizeUsageDisplay, resolveResponseUsageMode } from "../thinking.js";
|
||||
import {
|
||||
isSessionDefaultDirectiveValue,
|
||||
normalizeFastMode,
|
||||
normalizeUsageDisplay,
|
||||
resolveResponseUsageMode,
|
||||
} from "../thinking.js";
|
||||
import { resolveCommandSurfaceChannel } from "./channel-context.js";
|
||||
import { rejectNonOwnerCommand, rejectUnauthorizedCommand } from "./command-gates.js";
|
||||
import { handleAbortTrigger, handleStopCommand } from "./commands-session-abort.js";
|
||||
@@ -412,17 +417,29 @@ export const handleFastCommand: CommandHandler = async (params, allowTextCommand
|
||||
};
|
||||
}
|
||||
|
||||
const nextMode = normalizeFastMode(rawMode);
|
||||
const targetSessionEntry = params.sessionStore?.[params.sessionKey] ?? params.sessionEntry;
|
||||
const resetsToDefault = isSessionDefaultDirectiveValue(rawMode);
|
||||
const nextMode = resetsToDefault ? undefined : normalizeFastMode(rawMode);
|
||||
if (nextMode === undefined) {
|
||||
if (resetsToDefault) {
|
||||
if (targetSessionEntry && params.sessionStore && params.sessionKey) {
|
||||
delete targetSessionEntry.fastMode;
|
||||
await persistSessionEntry({ ...params, sessionEntry: targetSessionEntry });
|
||||
}
|
||||
return {
|
||||
shouldContinue: false,
|
||||
reply: { text: "⚙️ Fast mode reset to default." },
|
||||
};
|
||||
}
|
||||
return {
|
||||
shouldContinue: false,
|
||||
reply: { text: "⚙️ Usage: /fast status|on|off" },
|
||||
reply: { text: "⚙️ Usage: /fast status|on|off|default" },
|
||||
};
|
||||
}
|
||||
|
||||
if (params.sessionEntry && params.sessionStore && params.sessionKey) {
|
||||
params.sessionEntry.fastMode = nextMode;
|
||||
await persistSessionEntry(params);
|
||||
if (targetSessionEntry && params.sessionStore && params.sessionKey) {
|
||||
targetSessionEntry.fastMode = nextMode;
|
||||
await persistSessionEntry({ ...params, sessionEntry: targetSessionEntry });
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -48,8 +48,10 @@ export function createEmptyInlineDirectives(): InlineDirectives {
|
||||
return {
|
||||
cleaned: "",
|
||||
hasThinkDirective: false,
|
||||
clearThinkLevel: false,
|
||||
hasVerboseDirective: false,
|
||||
hasFastDirective: false,
|
||||
clearFastMode: false,
|
||||
hasReasoningDirective: false,
|
||||
hasTraceDirective: false,
|
||||
hasElevatedDirective: false,
|
||||
|
||||
@@ -142,25 +142,28 @@ export async function handleDirectiveOnly(
|
||||
provider: resolvedProvider,
|
||||
model: resolvedModel,
|
||||
agentId: activeAgentId,
|
||||
sessionEntry,
|
||||
sessionEntry: directives.clearFastMode ? undefined : sessionEntry,
|
||||
});
|
||||
const effectiveFastMode = directives.fastMode ?? currentFastMode ?? fastModeState.enabled;
|
||||
const effectiveFastMode =
|
||||
directives.fastMode ??
|
||||
(directives.clearFastMode ? fastModeState.enabled : currentFastMode) ??
|
||||
fastModeState.enabled;
|
||||
const effectiveFastModeSource =
|
||||
directives.fastMode !== undefined ? "session" : fastModeState.source;
|
||||
|
||||
if (directives.hasThinkDirective && !directives.thinkLevel) {
|
||||
if (directives.hasThinkDirective && !directives.thinkLevel && !directives.clearThinkLevel) {
|
||||
// If no argument was provided, show the current level
|
||||
if (!directives.rawThinkLevel) {
|
||||
const level = currentThinkLevel ?? "off";
|
||||
return {
|
||||
text: withOptions(
|
||||
`Current thinking level: ${level}.`,
|
||||
formatThinkingLevels(resolvedProvider, resolvedModel, ", ", thinkingCatalog),
|
||||
`default, ${formatThinkingLevels(resolvedProvider, resolvedModel, ", ", thinkingCatalog)}`,
|
||||
),
|
||||
};
|
||||
}
|
||||
return {
|
||||
text: `Unrecognized thinking level "${directives.rawThinkLevel}". Valid levels: ${formatThinkingLevels(resolvedProvider, resolvedModel, ", ", thinkingCatalog)}.`,
|
||||
text: `Unrecognized thinking level "${directives.rawThinkLevel}". Valid levels: default, ${formatThinkingLevels(resolvedProvider, resolvedModel, ", ", thinkingCatalog)}.`,
|
||||
};
|
||||
}
|
||||
if (directives.hasVerboseDirective && !directives.verboseLevel) {
|
||||
@@ -185,7 +188,11 @@ export async function handleDirectiveOnly(
|
||||
text: `Unrecognized trace level "${directives.rawTraceLevel}". Valid levels: off, on, raw.`,
|
||||
};
|
||||
}
|
||||
if (directives.hasFastDirective && directives.fastMode === undefined) {
|
||||
if (
|
||||
directives.hasFastDirective &&
|
||||
directives.fastMode === undefined &&
|
||||
!directives.clearFastMode
|
||||
) {
|
||||
if (
|
||||
!directives.rawFastMode ||
|
||||
normalizeLowercaseStringOrEmpty(directives.rawFastMode) === "status"
|
||||
@@ -199,12 +206,12 @@ export async function handleDirectiveOnly(
|
||||
return {
|
||||
text: withOptions(
|
||||
`Current fast mode: ${effectiveFastMode ? "on" : "off"}${sourceSuffix}.`,
|
||||
"status, on, off",
|
||||
"status, on, off, default",
|
||||
),
|
||||
};
|
||||
}
|
||||
return {
|
||||
text: `Unrecognized fast mode "${directives.rawFastMode}". Valid levels: status, on, off.`,
|
||||
text: `Unrecognized fast mode "${directives.rawFastMode}". Valid levels: status, on, off, default.`,
|
||||
};
|
||||
}
|
||||
if (directives.hasReasoningDirective && !directives.reasoningLevel) {
|
||||
@@ -351,8 +358,10 @@ export async function handleDirectiveOnly(
|
||||
elevatedAllowed;
|
||||
let modelSelectionUpdated = false;
|
||||
const shouldPersistSessionEntry =
|
||||
(directives.hasThinkDirective && Boolean(directives.thinkLevel)) ||
|
||||
(directives.hasFastDirective && directives.fastMode !== undefined) ||
|
||||
(directives.hasThinkDirective &&
|
||||
(Boolean(directives.thinkLevel) || directives.clearThinkLevel)) ||
|
||||
(directives.hasFastDirective &&
|
||||
(directives.fastMode !== undefined || directives.clearFastMode)) ||
|
||||
(directives.hasVerboseDirective &&
|
||||
Boolean(directives.verboseLevel) &&
|
||||
allowInternalVerbosePersistence) ||
|
||||
@@ -364,16 +373,25 @@ export async function handleDirectiveOnly(
|
||||
directives.hasQueueDirective ||
|
||||
shouldRemapUnsupportedThinkLevel;
|
||||
const fastModeChanged =
|
||||
directives.hasFastDirective &&
|
||||
directives.fastMode !== undefined &&
|
||||
directives.fastMode !== currentFastMode;
|
||||
(directives.hasFastDirective &&
|
||||
directives.fastMode !== undefined &&
|
||||
directives.fastMode !== currentFastMode) ||
|
||||
(directives.clearFastMode && currentFastMode !== fastModeState.enabled);
|
||||
let reasoningChanged =
|
||||
directives.hasReasoningDirective && directives.reasoningLevel !== undefined;
|
||||
if (shouldPersistSessionEntry) {
|
||||
if (directives.hasThinkDirective && directives.thinkLevel && resolvedDirectiveThinkLevel) {
|
||||
if (directives.clearThinkLevel) {
|
||||
delete sessionEntry.thinkingLevel;
|
||||
} else if (
|
||||
directives.hasThinkDirective &&
|
||||
directives.thinkLevel &&
|
||||
resolvedDirectiveThinkLevel
|
||||
) {
|
||||
sessionEntry.thinkingLevel = resolvedDirectiveThinkLevel;
|
||||
}
|
||||
if (directives.hasFastDirective && directives.fastMode !== undefined) {
|
||||
if (directives.clearFastMode) {
|
||||
delete sessionEntry.fastMode;
|
||||
} else if (directives.hasFastDirective && directives.fastMode !== undefined) {
|
||||
sessionEntry.fastMode = directives.fastMode;
|
||||
}
|
||||
if (shouldRemapUnsupportedThinkLevel && remappedUnsupportedThinkLevel) {
|
||||
@@ -488,7 +506,9 @@ export async function handleDirectiveOnly(
|
||||
});
|
||||
|
||||
const parts: string[] = [];
|
||||
if (directives.hasThinkDirective && directives.thinkLevel) {
|
||||
if (directives.clearThinkLevel) {
|
||||
parts.push("Thinking level reset to default.");
|
||||
} else if (directives.hasThinkDirective && directives.thinkLevel) {
|
||||
const displayedThinkLevel = resolvedDirectiveThinkLevel ?? directives.thinkLevel;
|
||||
parts.push(
|
||||
displayedThinkLevel === "off"
|
||||
@@ -501,7 +521,9 @@ export async function handleDirectiveOnly(
|
||||
);
|
||||
}
|
||||
}
|
||||
if (directives.hasFastDirective && directives.fastMode !== undefined) {
|
||||
if (directives.clearFastMode) {
|
||||
parts.push(formatDirectiveAck("Fast mode reset to default."));
|
||||
} else if (directives.hasFastDirective && directives.fastMode !== undefined) {
|
||||
parts.push(
|
||||
directives.fastMode
|
||||
? formatDirectiveAck("Fast mode enabled.")
|
||||
@@ -617,9 +639,10 @@ export async function handleDirectiveOnly(
|
||||
parts.push(formatDirectiveAck(`Queue drop set to ${directives.dropPolicy}.`));
|
||||
}
|
||||
if (fastModeChanged) {
|
||||
enqueueSystemEvent(`Fast mode ${sessionEntry.fastMode ? "enabled" : "disabled"}.`, {
|
||||
const nextFastMode = directives.clearFastMode ? fastModeState.enabled : sessionEntry.fastMode;
|
||||
enqueueSystemEvent(`Fast mode ${nextFastMode ? "enabled" : "disabled"}.`, {
|
||||
sessionKey,
|
||||
contextKey: `fast:${sessionEntry.fastMode ? "on" : "off"}`,
|
||||
contextKey: `fast:${nextFastMode ? "on" : "off"}`,
|
||||
});
|
||||
}
|
||||
const ack = parts.join(" ").trim();
|
||||
|
||||
@@ -1331,6 +1331,22 @@ describe("handleDirectiveOnly model persist behavior (fixes #1435)", () => {
|
||||
expect(sessionStore["agent:main:dm:1"]?.thinkingLevel).toBe("off");
|
||||
});
|
||||
|
||||
it("clears thinking override for default directives", async () => {
|
||||
const sessionEntry = createSessionEntry({ thinkingLevel: "high" });
|
||||
const sessionStore = { [sessionKey]: sessionEntry };
|
||||
const result = await handleDirectiveOnly(
|
||||
createHandleParams({
|
||||
directives: parseInlineDirectives("/think default"),
|
||||
sessionEntry,
|
||||
sessionStore,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result?.text).toContain("Thinking level reset to default.");
|
||||
expect(sessionEntry.thinkingLevel).toBeUndefined();
|
||||
expect(sessionStore["agent:main:dm:1"]?.thinkingLevel).toBeUndefined();
|
||||
});
|
||||
|
||||
it("reports current thinking status", async () => {
|
||||
setDirectiveTestProviders([
|
||||
{
|
||||
@@ -1358,7 +1374,7 @@ describe("handleDirectiveOnly model persist behavior (fixes #1435)", () => {
|
||||
);
|
||||
|
||||
expect(result?.text).toContain("Current thinking level: low");
|
||||
expect(result?.text).toContain("Options: off, minimal, low, medium, adaptive, high.");
|
||||
expect(result?.text).toContain("Options: default, off, minimal, low, medium, adaptive, high.");
|
||||
});
|
||||
|
||||
it("uses catalog reasoning metadata for provider-owned thinking levels", async () => {
|
||||
@@ -1468,6 +1484,17 @@ describe("handleDirectiveOnly model persist behavior (fixes #1435)", () => {
|
||||
);
|
||||
expect(offReply?.text).toContain("Fast mode disabled");
|
||||
expect(sessionEntry.fastMode).toBe(false);
|
||||
|
||||
const defaultReply = await handleDirectiveOnly(
|
||||
createHandleParams({
|
||||
directives: parseInlineDirectives("/fast default"),
|
||||
sessionEntry,
|
||||
sessionStore,
|
||||
currentFastMode: sessionEntry.fastMode,
|
||||
}),
|
||||
);
|
||||
expect(defaultReply?.text).toContain("Fast mode reset to default");
|
||||
expect(sessionEntry.fastMode).toBeUndefined();
|
||||
});
|
||||
|
||||
it("persists and reports elevated-mode directives when allowed", async () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ExecAsk, ExecSecurity, ExecTarget } from "../../infra/exec-approvals.js";
|
||||
import { extractModelDirective } from "../model.js";
|
||||
import { isSessionDefaultDirectiveValue } from "../thinking.js";
|
||||
import type {
|
||||
ElevatedLevel,
|
||||
ReasoningLevel,
|
||||
@@ -25,6 +26,7 @@ export type InlineDirectives = {
|
||||
hasThinkDirective: boolean;
|
||||
thinkLevel?: ThinkLevel;
|
||||
rawThinkLevel?: string;
|
||||
clearThinkLevel: boolean;
|
||||
hasVerboseDirective: boolean;
|
||||
verboseLevel?: VerboseLevel;
|
||||
rawVerboseLevel?: string;
|
||||
@@ -34,6 +36,7 @@ export type InlineDirectives = {
|
||||
hasFastDirective: boolean;
|
||||
fastMode?: boolean;
|
||||
rawFastMode?: string;
|
||||
clearFastMode: boolean;
|
||||
hasReasoningDirective: boolean;
|
||||
reasoningLevel?: ReasoningLevel;
|
||||
rawReasoningLevel?: string;
|
||||
@@ -173,6 +176,7 @@ export function parseInlineDirectives(
|
||||
hasThinkDirective,
|
||||
thinkLevel,
|
||||
rawThinkLevel,
|
||||
clearThinkLevel: hasThinkDirective && isSessionDefaultDirectiveValue(rawThinkLevel),
|
||||
hasVerboseDirective,
|
||||
verboseLevel,
|
||||
rawVerboseLevel,
|
||||
@@ -182,6 +186,7 @@ export function parseInlineDirectives(
|
||||
hasFastDirective,
|
||||
fastMode,
|
||||
rawFastMode,
|
||||
clearFastMode: hasFastDirective && isSessionDefaultDirectiveValue(rawFastMode),
|
||||
hasReasoningDirective,
|
||||
reasoningLevel,
|
||||
rawReasoningLevel,
|
||||
|
||||
@@ -166,10 +166,21 @@ export async function persistInlineDirectives(params: {
|
||||
directives.hasReasoningDirective && directives.reasoningLevel !== undefined;
|
||||
let updated = false;
|
||||
|
||||
if (directives.hasThinkDirective && directives.thinkLevel) {
|
||||
if (directives.clearThinkLevel) {
|
||||
if (sessionEntry.thinkingLevel) {
|
||||
delete sessionEntry.thinkingLevel;
|
||||
updated = true;
|
||||
}
|
||||
} else if (directives.hasThinkDirective && directives.thinkLevel) {
|
||||
sessionEntry.thinkingLevel = directives.thinkLevel;
|
||||
updated = true;
|
||||
}
|
||||
if (directives.clearFastMode) {
|
||||
if (sessionEntry.fastMode !== undefined) {
|
||||
delete sessionEntry.fastMode;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
directives.hasVerboseDirective &&
|
||||
directives.verboseLevel &&
|
||||
|
||||
@@ -23,6 +23,7 @@ export function clearInlineDirectives(cleaned: string): InlineDirectives {
|
||||
hasThinkDirective: false,
|
||||
thinkLevel: undefined,
|
||||
rawThinkLevel: undefined,
|
||||
clearThinkLevel: false,
|
||||
hasVerboseDirective: false,
|
||||
verboseLevel: undefined,
|
||||
rawVerboseLevel: undefined,
|
||||
@@ -32,6 +33,7 @@ export function clearInlineDirectives(cleaned: string): InlineDirectives {
|
||||
hasFastDirective: false,
|
||||
fastMode: undefined,
|
||||
rawFastMode: undefined,
|
||||
clearFastMode: false,
|
||||
hasReasoningDirective: false,
|
||||
reasoningLevel: undefined,
|
||||
rawReasoningLevel: undefined,
|
||||
|
||||
@@ -334,8 +334,10 @@ export async function resolveReplyDirectives(params: {
|
||||
: {
|
||||
...parsedDirectives,
|
||||
hasThinkDirective: false,
|
||||
clearThinkLevel: false,
|
||||
hasVerboseDirective: false,
|
||||
hasFastDirective: false,
|
||||
clearFastMode: false,
|
||||
hasReasoningDirective: false,
|
||||
reasoningLevel: undefined,
|
||||
rawReasoningLevel: undefined,
|
||||
@@ -422,10 +424,11 @@ export async function resolveReplyDirectives(params: {
|
||||
groupResolution,
|
||||
});
|
||||
const defaultActivation = defaultGroupActivation(requireMention);
|
||||
const sessionThinkLevel = directives.clearThinkLevel
|
||||
? undefined
|
||||
: (targetSessionEntry?.thinkingLevel as ThinkLevel | undefined);
|
||||
const resolvedThinkLevel =
|
||||
normalizeThinkLevel(opts?.thinkingLevelOverride) ??
|
||||
directives.thinkLevel ??
|
||||
(targetSessionEntry?.thinkingLevel as ThinkLevel | undefined);
|
||||
normalizeThinkLevel(opts?.thinkingLevelOverride) ?? directives.thinkLevel ?? sessionThinkLevel;
|
||||
const resolvedFastMode =
|
||||
opts?.fastModeOverride ??
|
||||
directives.fastMode ??
|
||||
@@ -434,7 +437,7 @@ export async function resolveReplyDirectives(params: {
|
||||
provider,
|
||||
model,
|
||||
agentId,
|
||||
sessionEntry: targetSessionEntry,
|
||||
sessionEntry: directives.clearFastMode ? undefined : targetSessionEntry,
|
||||
}).enabled;
|
||||
|
||||
const resolvedVerboseLevel =
|
||||
@@ -537,7 +540,7 @@ export async function resolveReplyDirectives(params: {
|
||||
|
||||
const thinkingExplicitlySet =
|
||||
directives.thinkLevel !== undefined ||
|
||||
targetSessionEntry?.thinkingLevel !== undefined ||
|
||||
sessionThinkLevel !== undefined ||
|
||||
agentCfg?.thinkingDefault !== undefined;
|
||||
|
||||
// When neither directive nor session nor agent set reasoning, default to model capability
|
||||
|
||||
@@ -2103,7 +2103,7 @@ describe("buildHelpMessage", () => {
|
||||
});
|
||||
|
||||
it("includes /fast in help output", () => {
|
||||
expect(buildHelpMessage()).toContain("/fast status|on|off");
|
||||
expect(buildHelpMessage()).toContain("/fast status|on|off|default");
|
||||
});
|
||||
|
||||
it("includes raw trace mode in help output", () => {
|
||||
|
||||
@@ -83,6 +83,14 @@ export function normalizeThinkLevel(raw?: string | null): ThinkLevel | undefined
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function isSessionDefaultDirectiveValue(raw?: string | null): boolean {
|
||||
const key = normalizeOptionalLowercaseString(raw);
|
||||
if (!key) {
|
||||
return false;
|
||||
}
|
||||
return ["default", "inherit", "inherited", "clear", "reset", "unpin"].includes(key);
|
||||
}
|
||||
|
||||
export function formatXHighModelHint(): string {
|
||||
return "provider models that advertise xhigh reasoning";
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import type { ThinkLevel, ThinkingCatalogEntry } from "./thinking.shared.js";
|
||||
export {
|
||||
formatXHighModelHint,
|
||||
isSessionDefaultDirectiveValue,
|
||||
normalizeElevatedLevel,
|
||||
normalizeFastMode,
|
||||
normalizeNoticeLevel,
|
||||
|
||||
Reference in New Issue
Block a user