mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 11:25:50 -06:00
feat(auto-reply): show thinking level in model summary
- Add thinking level display to /model summary output - Resolve effective thinking level from provider catalog and runtime - Move thinkingCatalog construction before maybeHandleModelDirectiveInfo call - Align thinkingCatalog type to ThinkingCatalogEntry[] - Make runtimePolicySessionKey optional - Add tests for thinking level in model summary and channel-specific summaries Rebased from PR #111709 (commits addba5549ba, a9f9f46406e, 72e75e994c6) onto origin/main.
This commit is contained in:
@@ -119,7 +119,12 @@ export async function handleDirectiveOnly(
|
||||
commandAuthorized: params.commandAuthorized,
|
||||
senderIsOwner: params.senderIsOwner,
|
||||
});
|
||||
|
||||
const thinkingCatalog =
|
||||
params.thinkingCatalog && params.thinkingCatalog.length > 0
|
||||
? params.thinkingCatalog
|
||||
: allowedModelCatalog.length > 0
|
||||
? allowedModelCatalog
|
||||
: undefined;
|
||||
const modelInfo = await maybeHandleModelDirectiveInfo({
|
||||
directives,
|
||||
cfg: params.cfg,
|
||||
@@ -133,6 +138,9 @@ export async function handleDirectiveOnly(
|
||||
policyAliasIndex,
|
||||
allowedModelKeys,
|
||||
allowedModelCatalog,
|
||||
currentThinkLevel: currentThinkLevel ?? "off",
|
||||
thinkingCatalog,
|
||||
runtimePolicySessionKey,
|
||||
resetModelOverride,
|
||||
workspaceDir: params.workspaceDir,
|
||||
surface: params.surface,
|
||||
@@ -186,12 +194,6 @@ export async function handleDirectiveOnly(
|
||||
sessionKey: runtimePolicySessionKey,
|
||||
sessionEntry: prospectiveSessionEntry,
|
||||
});
|
||||
const thinkingCatalog =
|
||||
params.thinkingCatalog && params.thinkingCatalog.length > 0
|
||||
? params.thinkingCatalog
|
||||
: allowedModelCatalog.length > 0
|
||||
? allowedModelCatalog
|
||||
: undefined;
|
||||
const fastModeState = resolveFastModeState({
|
||||
cfg: params.cfg,
|
||||
provider: resolvedProvider,
|
||||
|
||||
@@ -638,6 +638,8 @@ async function resolveModelInfoReply(
|
||||
aliasIndex: baseAliasIndex(),
|
||||
allowedModelKeys: new Set(),
|
||||
allowedModelCatalog: [],
|
||||
currentThinkLevel: "medium",
|
||||
runtimePolicySessionKey: "agent:main:main",
|
||||
resetModelOverride: false,
|
||||
...overrides,
|
||||
});
|
||||
@@ -648,10 +650,65 @@ describe("/model chat UX", () => {
|
||||
const reply = await resolveModelInfoReply();
|
||||
|
||||
expect(reply?.text).toContain("Current:");
|
||||
expect(reply?.text).toContain("Think: medium (change with /think <level>)");
|
||||
expect(reply?.text).toContain("Browse: /models");
|
||||
expect(reply?.text).toContain("Switch: /model <provider/model>");
|
||||
});
|
||||
|
||||
it("includes the thinking level in channel-specific model summaries", async () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
registry.channels = [
|
||||
{
|
||||
pluginId: "test",
|
||||
plugin: {
|
||||
id: "telegram",
|
||||
commands: {
|
||||
buildModelBrowseChannelData: () => ({ telegram: { inlineKeyboard: [] } }),
|
||||
},
|
||||
},
|
||||
source: "test",
|
||||
},
|
||||
] as never;
|
||||
setActivePluginRegistry(registry);
|
||||
|
||||
const reply = await resolveModelInfoReply({ surface: "telegram" });
|
||||
|
||||
expect(reply?.channelData).toBeDefined();
|
||||
expect(reply?.text).toContain("Think: medium (change with /think <level>)");
|
||||
});
|
||||
|
||||
it("shows the effective thinking level for the selected runtime", async () => {
|
||||
setDirectiveTestProviders([
|
||||
{
|
||||
id: "openai",
|
||||
label: "OpenAI",
|
||||
auth: [],
|
||||
resolveThinkingProfile: ({ agentRuntime }) => ({
|
||||
levels: [
|
||||
{ id: "off" },
|
||||
{ id: "low" },
|
||||
{ id: "medium" },
|
||||
{ id: "high" },
|
||||
{ id: "max" },
|
||||
...(agentRuntime === "openclaw" ? ([{ id: "ultra" }] as const) : []),
|
||||
],
|
||||
}),
|
||||
},
|
||||
]);
|
||||
|
||||
const reply = await resolveModelInfoReply({
|
||||
provider: "openai",
|
||||
model: "gpt-5.6-luna",
|
||||
defaultProvider: "openai",
|
||||
defaultModel: "gpt-5.6-luna",
|
||||
currentThinkLevel: "ultra",
|
||||
sessionEntry: { agentRuntimeOverride: "codex" },
|
||||
});
|
||||
|
||||
expect(reply?.text).toContain("Think: max (change with /think <level>)");
|
||||
expect(reply?.text).not.toContain("Think: ultra");
|
||||
});
|
||||
|
||||
it("treats /model list as a models browser alias, not a model id", async () => {
|
||||
const reply = await resolveModelInfoReply({
|
||||
directives: parseInlineDirectives("/model list"),
|
||||
|
||||
@@ -21,11 +21,14 @@ import {
|
||||
import { RUNTIME_MODEL_VISIBILITY_NORMALIZATION } from "../../agents/model-visibility-policy.js";
|
||||
import { buildAgentRuntimeAuthPlan } from "../../agents/runtime-plan/auth.js";
|
||||
import { resolveSessionRuntimeOverrideForProvider } from "../../agents/session-runtime-compat.js";
|
||||
import { resolveEffectiveAgentRuntime } from "../../agents/thinking-runtime.js";
|
||||
import { getChannelPlugin } from "../../channels/plugins/index.js";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { shortenHomePath } from "../../utils.js";
|
||||
import { resolveSelectedAndActiveModel } from "../model-runtime.js";
|
||||
import { resolveSupportedThinkingLevel } from "../thinking.js";
|
||||
import type { ThinkingCatalogEntry } from "../thinking.shared.js";
|
||||
import type { ReplyPayload } from "../types.js";
|
||||
import { resolveModelsCommandReply } from "./commands-models.js";
|
||||
import {
|
||||
@@ -38,6 +41,7 @@ import {
|
||||
resolveProviderEndpointLabel,
|
||||
} from "./directive-handling.model-picker.js";
|
||||
import type { InlineDirectives } from "./directive-handling.parse.js";
|
||||
import type { ThinkLevel } from "./directives.js";
|
||||
|
||||
function isMissingAuthLabel(auth: { label: string; source: string }): boolean {
|
||||
return auth.label === "missing" && auth.source === "missing";
|
||||
@@ -380,6 +384,9 @@ export async function maybeHandleModelDirectiveInfo(params: {
|
||||
policyAliasIndex?: ModelAliasIndex;
|
||||
allowedModelKeys: ReadonlySet<string>;
|
||||
allowedModelCatalog: Array<{ provider: string; id?: string; name?: string }>;
|
||||
currentThinkLevel: ThinkLevel;
|
||||
thinkingCatalog?: ThinkingCatalogEntry[];
|
||||
runtimePolicySessionKey?: string;
|
||||
resetModelOverride: boolean;
|
||||
workspaceDir?: string;
|
||||
surface?: string;
|
||||
@@ -435,6 +442,22 @@ export async function maybeHandleModelDirectiveInfo(params: {
|
||||
sessionEntry: params.sessionEntry,
|
||||
});
|
||||
const current = modelRefs.selected.label;
|
||||
const thinkingRuntime = resolveEffectiveAgentRuntime({
|
||||
cfg: params.cfg,
|
||||
provider: params.provider,
|
||||
modelId: params.model,
|
||||
agentId: params.activeAgentId,
|
||||
sessionKey: params.runtimePolicySessionKey,
|
||||
sessionEntry: params.sessionEntry,
|
||||
});
|
||||
const effectiveThinkLevel = resolveSupportedThinkingLevel({
|
||||
provider: params.provider,
|
||||
model: params.model,
|
||||
level: params.currentThinkLevel,
|
||||
catalog: params.thinkingCatalog,
|
||||
agentRuntime: thinkingRuntime,
|
||||
});
|
||||
const thinkingLine = `Think: ${effectiveThinkLevel} (change with /think <level>)`;
|
||||
const activeRuntimeLine = modelRefs.activeDiffers
|
||||
? `Active: ${modelRefs.active.label} (runtime)`
|
||||
: null;
|
||||
@@ -445,6 +468,7 @@ export async function maybeHandleModelDirectiveInfo(params: {
|
||||
text: [
|
||||
`Current: ${current}${modelRefs.activeDiffers ? " (selected)" : ""}`,
|
||||
activeRuntimeLine,
|
||||
thinkingLine,
|
||||
"",
|
||||
"Tap below to browse models, or use:",
|
||||
"/model <provider/model> to switch",
|
||||
@@ -461,6 +485,7 @@ export async function maybeHandleModelDirectiveInfo(params: {
|
||||
text: [
|
||||
`Current: ${current}${modelRefs.activeDiffers ? " (selected)" : ""}`,
|
||||
activeRuntimeLine,
|
||||
thinkingLine,
|
||||
"",
|
||||
"Switch: /model <provider/model>",
|
||||
"Runtime: /model <provider/model> --runtime <runtime>",
|
||||
|
||||
Reference in New Issue
Block a user