mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-08 19:12:22 +00:00
fix: hide adaptive think option for GPT models
This commit is contained in:
@@ -22,6 +22,7 @@ Docs: https://docs.openclaw.ai
|
||||
- fix(qqbot): add SSRF guard to direct-upload URL paths in uploadC2CMedia and uploadGroupMedia [AI-assisted]. (#69595) Thanks @pgondhi987.
|
||||
- fix(gateway): enforce allowRequestSessionKey gate on template-rendered mapping sessionKeys. (#69381) Thanks @pgondhi987.
|
||||
- Webchat/images: treat inline image attachments as media for empty-turn gating while still ignoring metadata-only blank turns. (#69474) Thanks @Jaswir.
|
||||
- Discord/think: only show `adaptive` in `/think` autocomplete for provider/model pairs that actually support provider-managed adaptive thinking, so GPT/OpenAI models no longer advertise an Anthropic-only option.
|
||||
- OpenAI/Responses: resolve `/think` levels against each GPT model's supported reasoning efforts so `/think off` no longer becomes high reasoning or sends unsupported `reasoning.effort: "none"` payloads.
|
||||
- Lobster/TaskFlow: allow managed approval resumes to use `approvalId` without a resume token, and persist that id in approval wait state. (#69559) Thanks @kirkluokun.
|
||||
- Plugins/startup: install bundled runtime dependencies into each plugin's own runtime directory, reuse source-checkout repair caches after rebuilds, and log only packages that were actually installed so repeated Gateway starts stay quiet once deps are present.
|
||||
|
||||
@@ -43,6 +43,7 @@ For model selection rules, see [/concepts/models](/concepts/models).
|
||||
`matchesContextOverflowError`, `classifyFailoverReason`,
|
||||
`isCacheTtlEligible`, `buildMissingAuthMessage`, `suppressBuiltInModel`,
|
||||
`augmentModelCatalog`, `isBinaryThinking`, `supportsXHighThinking`,
|
||||
`supportsAdaptiveThinking`,
|
||||
`resolveDefaultThinkingLevel`, `applyConfigDefaults`, `isModernModelRef`,
|
||||
`prepareRuntimeAuth`, `resolveUsageAuth`, `fetchUsageSnapshot`, and
|
||||
`onModelSelected`.
|
||||
@@ -133,6 +134,7 @@ Typical split:
|
||||
discovery and config merging
|
||||
- `isBinaryThinking`: provider owns binary on/off thinking UX
|
||||
- `supportsXHighThinking`: provider opts selected models into `xhigh`
|
||||
- `supportsAdaptiveThinking`: provider opts selected models into `adaptive`
|
||||
- `resolveDefaultThinkingLevel`: provider owns default `/think` policy for a
|
||||
model family
|
||||
- `applyConfigDefaults`: provider applies provider-specific global defaults
|
||||
|
||||
@@ -658,7 +658,7 @@ Provider plugins now have two layers:
|
||||
`buildAuthDoctorHint`, `matchesContextOverflowError`,
|
||||
`classifyFailoverReason`, `isCacheTtlEligible`,
|
||||
`buildMissingAuthMessage`, `suppressBuiltInModel`, `augmentModelCatalog`,
|
||||
`isBinaryThinking`, `supportsXHighThinking`,
|
||||
`isBinaryThinking`, `supportsXHighThinking`, `supportsAdaptiveThinking`,
|
||||
`resolveDefaultThinkingLevel`, `isModernModelRef`, `prepareRuntimeAuth`,
|
||||
`resolveUsageAuth`, `fetchUsageSnapshot`, `createEmbeddingProvider`,
|
||||
`buildReplayPolicy`,
|
||||
@@ -724,16 +724,17 @@ The "When to use" column is the quick decision guide.
|
||||
| 32 | `augmentModelCatalog` | Synthetic/final catalog rows appended after discovery | Provider needs synthetic forward-compat rows in `models list` and pickers |
|
||||
| 33 | `isBinaryThinking` | On/off reasoning toggle for binary-thinking providers | Provider exposes only binary thinking on/off |
|
||||
| 34 | `supportsXHighThinking` | `xhigh` reasoning support for selected models | Provider wants `xhigh` on only a subset of models |
|
||||
| 35 | `resolveDefaultThinkingLevel` | Default `/think` level for a specific model family | Provider owns default `/think` policy for a model family |
|
||||
| 36 | `isModernModelRef` | Modern-model matcher for live profile filters and smoke selection | Provider owns live/smoke preferred-model matching |
|
||||
| 37 | `prepareRuntimeAuth` | Exchange a configured credential into the actual runtime token/key just before inference | Provider needs a token exchange or short-lived request credential |
|
||||
| 38 | `resolveUsageAuth` | Resolve usage/billing credentials for `/usage` and related status surfaces | Provider needs custom usage/quota token parsing or a different usage credential |
|
||||
| 39 | `fetchUsageSnapshot` | Fetch and normalize provider-specific usage/quota snapshots after auth is resolved | Provider needs a provider-specific usage endpoint or payload parser |
|
||||
| 40 | `createEmbeddingProvider` | Build a provider-owned embedding adapter for memory/search | Memory embedding behavior belongs with the provider plugin |
|
||||
| 41 | `buildReplayPolicy` | Return a replay policy controlling transcript handling for the provider | Provider needs custom transcript policy (for example, thinking-block stripping) |
|
||||
| 42 | `sanitizeReplayHistory` | Rewrite replay history after generic transcript cleanup | Provider needs provider-specific replay rewrites beyond shared compaction helpers |
|
||||
| 43 | `validateReplayTurns` | Final replay-turn validation or reshaping before the embedded runner | Provider transport needs stricter turn validation after generic sanitation |
|
||||
| 44 | `onModelSelected` | Run provider-owned post-selection side effects | Provider needs telemetry or provider-owned state when a model becomes active |
|
||||
| 35 | `supportsAdaptiveThinking` | `adaptive` thinking support for selected models | Provider wants `adaptive` shown only for models with provider-managed adaptive thinking |
|
||||
| 36 | `resolveDefaultThinkingLevel` | Default `/think` level for a specific model family | Provider owns default `/think` policy for a model family |
|
||||
| 37 | `isModernModelRef` | Modern-model matcher for live profile filters and smoke selection | Provider owns live/smoke preferred-model matching |
|
||||
| 38 | `prepareRuntimeAuth` | Exchange a configured credential into the actual runtime token/key just before inference | Provider needs a token exchange or short-lived request credential |
|
||||
| 39 | `resolveUsageAuth` | Resolve usage/billing credentials for `/usage` and related status surfaces | Provider needs custom usage/quota token parsing or a different usage credential |
|
||||
| 40 | `fetchUsageSnapshot` | Fetch and normalize provider-specific usage/quota snapshots after auth is resolved | Provider needs a provider-specific usage endpoint or payload parser |
|
||||
| 41 | `createEmbeddingProvider` | Build a provider-owned embedding adapter for memory/search | Memory embedding behavior belongs with the provider plugin |
|
||||
| 42 | `buildReplayPolicy` | Return a replay policy controlling transcript handling for the provider | Provider needs custom transcript policy (for example, thinking-block stripping) |
|
||||
| 43 | `sanitizeReplayHistory` | Rewrite replay history after generic transcript cleanup | Provider needs provider-specific replay rewrites beyond shared compaction helpers |
|
||||
| 44 | `validateReplayTurns` | Final replay-turn validation or reshaping before the embedded runner | Provider transport needs stricter turn validation after generic sanitation |
|
||||
| 45 | `onModelSelected` | Run provider-owned post-selection side effects | Provider needs telemetry or provider-owned state when a model becomes active |
|
||||
|
||||
`normalizeModelId`, `normalizeTransport`, and `normalizeConfig` first check the
|
||||
matched provider plugin, then fall through other hook-capable provider plugins
|
||||
@@ -805,7 +806,7 @@ api.registerProvider({
|
||||
|
||||
- Anthropic uses `resolveDynamicModel`, `capabilities`, `buildAuthDoctorHint`,
|
||||
`resolveUsageAuth`, `fetchUsageSnapshot`, `isCacheTtlEligible`,
|
||||
`resolveDefaultThinkingLevel`, `applyConfigDefaults`, `isModernModelRef`,
|
||||
`supportsAdaptiveThinking`, `resolveDefaultThinkingLevel`, `applyConfigDefaults`, `isModernModelRef`,
|
||||
and `wrapStreamFn` because it owns Claude 4.6 forward-compat,
|
||||
provider-family hints, auth repair guidance, usage endpoint integration,
|
||||
prompt-cache eligibility, auth-aware config defaults, Claude
|
||||
|
||||
@@ -535,16 +535,17 @@ API key auth, and dynamic model resolution.
|
||||
| 31 | `augmentModelCatalog` | Synthetic forward-compat rows |
|
||||
| 32 | `isBinaryThinking` | Binary thinking on/off |
|
||||
| 33 | `supportsXHighThinking` | `xhigh` reasoning support |
|
||||
| 34 | `resolveDefaultThinkingLevel` | Default `/think` policy |
|
||||
| 35 | `isModernModelRef` | Live/smoke model matching |
|
||||
| 36 | `prepareRuntimeAuth` | Token exchange before inference |
|
||||
| 37 | `resolveUsageAuth` | Custom usage credential parsing |
|
||||
| 38 | `fetchUsageSnapshot` | Custom usage endpoint |
|
||||
| 39 | `createEmbeddingProvider` | Provider-owned embedding adapter for memory/search |
|
||||
| 40 | `buildReplayPolicy` | Custom transcript replay/compaction policy |
|
||||
| 41 | `sanitizeReplayHistory` | Provider-specific replay rewrites after generic cleanup |
|
||||
| 42 | `validateReplayTurns` | Strict replay-turn validation before the embedded runner |
|
||||
| 43 | `onModelSelected` | Post-selection callback (e.g. telemetry) |
|
||||
| 34 | `supportsAdaptiveThinking` | Adaptive thinking support |
|
||||
| 35 | `resolveDefaultThinkingLevel` | Default `/think` policy |
|
||||
| 36 | `isModernModelRef` | Live/smoke model matching |
|
||||
| 37 | `prepareRuntimeAuth` | Token exchange before inference |
|
||||
| 38 | `resolveUsageAuth` | Custom usage credential parsing |
|
||||
| 39 | `fetchUsageSnapshot` | Custom usage endpoint |
|
||||
| 40 | `createEmbeddingProvider` | Provider-owned embedding adapter for memory/search |
|
||||
| 41 | `buildReplayPolicy` | Custom transcript replay/compaction policy |
|
||||
| 42 | `sanitizeReplayHistory` | Provider-specific replay rewrites after generic cleanup |
|
||||
| 43 | `validateReplayTurns` | Strict replay-turn validation before the embedded runner |
|
||||
| 44 | `onModelSelected` | Post-selection callback (e.g. telemetry) |
|
||||
|
||||
Prompt tuning note:
|
||||
|
||||
|
||||
@@ -16,10 +16,11 @@ title: "Thinking Levels"
|
||||
- medium → “think harder”
|
||||
- high → “ultrathink” (max budget)
|
||||
- xhigh → “ultrathink+” (GPT-5.2 + Codex models and Anthropic Claude Opus 4.7 effort)
|
||||
- adaptive → provider-managed adaptive thinking (supported for Anthropic Claude 4.6 and Opus 4.7)
|
||||
- adaptive → provider-managed adaptive thinking (supported for Claude 4.6 on Anthropic/Bedrock and Anthropic Claude Opus 4.7)
|
||||
- `x-high`, `x_high`, `extra-high`, `extra high`, and `extra_high` map to `xhigh`.
|
||||
- `highest`, `max` map to `high`.
|
||||
- Provider notes:
|
||||
- `adaptive` is only advertised in native command menus and pickers for providers/models that declare adaptive thinking support. It remains accepted as a typed directive for compatibility with existing configs and aliases.
|
||||
- Anthropic Claude 4.6 models default to `adaptive` when no explicit thinking level is set.
|
||||
- Anthropic Claude Opus 4.7 does not default to adaptive thinking. Its API effort default remains provider-owned unless you explicitly set a thinking level.
|
||||
- Anthropic Claude Opus 4.7 maps `/think xhigh` to adaptive thinking plus `output_config.effort: "xhigh"`, because `/think` is a thinking directive and `xhigh` is the Opus 4.7 effort setting.
|
||||
@@ -109,7 +110,8 @@ title: "Thinking Levels"
|
||||
- Picking another level writes the session override immediately via `sessions.patch`; it does not wait for the next send and it is not a one-shot `thinkingOnce` override.
|
||||
- The first option is always `Default (<resolved level>)`, where the resolved default comes from the active session model: `adaptive` for Claude 4.6 on Anthropic, `off` for Anthropic Claude Opus 4.7 unless configured, `low` for other reasoning-capable models, `off` otherwise.
|
||||
- The picker stays provider-aware:
|
||||
- most providers show `off | minimal | low | medium | high | adaptive`
|
||||
- most providers show `off | minimal | low | medium | high`
|
||||
- Anthropic/Bedrock Claude 4.6 shows `off | minimal | low | medium | high | adaptive`
|
||||
- Anthropic Claude Opus 4.7 shows `off | minimal | low | medium | high | xhigh | adaptive`
|
||||
- Z.AI shows binary `off | on`
|
||||
- `/think:<level>` still works and updates the same stored session level, so chat directives and the picker stay in sync.
|
||||
|
||||
@@ -107,6 +107,12 @@ describe("amazon-bedrock provider plugin", () => {
|
||||
modelId: "amazon.nova-micro-v1:0",
|
||||
} as never),
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
provider.supportsAdaptiveThinking?.({
|
||||
provider: "amazon-bedrock",
|
||||
modelId: "us.anthropic.claude-opus-4-6-v1",
|
||||
} as never),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("owns Anthropic-style replay policy for Claude Bedrock models", async () => {
|
||||
|
||||
@@ -191,6 +191,7 @@ export function registerAmazonBedrockPlugin(api: OpenClawPluginApi): void {
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
supportsAdaptiveThinking: ({ modelId }) => claude46ModelRe.test(modelId.trim()),
|
||||
resolveDefaultThinkingLevel: ({ modelId }) =>
|
||||
claude46ModelRe.test(modelId.trim()) ? "adaptive" : undefined,
|
||||
});
|
||||
|
||||
@@ -218,6 +218,18 @@ describe("anthropic provider replay hooks", () => {
|
||||
modelId: "claude-opus-4-6",
|
||||
} as never),
|
||||
).toBe(false);
|
||||
expect(
|
||||
provider.supportsAdaptiveThinking?.({
|
||||
provider: "anthropic",
|
||||
modelId: "claude-opus-4-7",
|
||||
} as never),
|
||||
).toBe(true);
|
||||
expect(
|
||||
provider.supportsAdaptiveThinking?.({
|
||||
provider: "anthropic",
|
||||
modelId: "claude-opus-4-6",
|
||||
} as never),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("resolves claude-cli synthetic oauth auth", async () => {
|
||||
|
||||
@@ -278,6 +278,10 @@ function isAnthropicOpus47Model(modelId: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function supportsAnthropicAdaptiveThinking(modelId: string): boolean {
|
||||
return shouldUseAnthropicAdaptiveThinkingDefault(modelId) || isAnthropicOpus47Model(modelId);
|
||||
}
|
||||
|
||||
function matchesAnthropicModernModel(modelId: string): boolean {
|
||||
const lower = normalizeLowercaseStringOrEmpty(modelId);
|
||||
return ANTHROPIC_MODERN_MODEL_PREFIXES.some((prefix) => lower.startsWith(prefix));
|
||||
@@ -490,6 +494,7 @@ export function buildAnthropicProvider(): ProviderPlugin {
|
||||
isModernModelRef: ({ modelId }) => matchesAnthropicModernModel(modelId),
|
||||
resolveReasoningOutputMode: () => "native",
|
||||
supportsXHighThinking: ({ modelId }) => isAnthropicOpus47Model(modelId),
|
||||
supportsAdaptiveThinking: ({ modelId }) => supportsAnthropicAdaptiveThinking(modelId),
|
||||
wrapStreamFn: wrapAnthropicProviderStream,
|
||||
resolveDefaultThinkingLevel: ({ modelId }) =>
|
||||
isAnthropicOpus47Model(modelId)
|
||||
|
||||
@@ -34,6 +34,7 @@ const resolveConfiguredBindingRouteMock = vi.hoisted(() =>
|
||||
vi.fn<ResolveConfiguredBindingRoute>(() => createUnboundConfiguredRouteResult()),
|
||||
);
|
||||
const providerThinkingMocks = vi.hoisted(() => ({
|
||||
resolveProviderAdaptiveThinking: vi.fn(),
|
||||
resolveProviderBinaryThinking: vi.fn(),
|
||||
resolveProviderDefaultThinkingLevel: vi.fn(),
|
||||
resolveProviderXHighThinking: vi.fn(),
|
||||
@@ -127,6 +128,7 @@ let resolveDiscordNativeChoiceContext: typeof import("./native-command-ui.js").r
|
||||
async function loadDiscordThinkAutocompleteModulesForTest() {
|
||||
vi.resetModules();
|
||||
vi.doMock("../../../../src/plugins/provider-thinking.js", () => ({
|
||||
resolveProviderAdaptiveThinking: providerThinkingMocks.resolveProviderAdaptiveThinking,
|
||||
resolveProviderBinaryThinking: providerThinkingMocks.resolveProviderBinaryThinking,
|
||||
resolveProviderDefaultThinkingLevel: providerThinkingMocks.resolveProviderDefaultThinkingLevel,
|
||||
resolveProviderXHighThinking: providerThinkingMocks.resolveProviderXHighThinking,
|
||||
@@ -143,6 +145,7 @@ async function loadDiscordThinkAutocompleteModulesForTest() {
|
||||
describe("discord native /think autocomplete", () => {
|
||||
beforeAll(async () => {
|
||||
providerThinkingMocks.resolveProviderBinaryThinking.mockReturnValue(undefined);
|
||||
providerThinkingMocks.resolveProviderAdaptiveThinking.mockReturnValue(undefined);
|
||||
providerThinkingMocks.resolveProviderDefaultThinkingLevel.mockReturnValue(undefined);
|
||||
providerThinkingMocks.resolveProviderXHighThinking.mockImplementation(({ provider, context }) =>
|
||||
provider === "openai-codex" && ["gpt-5.4", "gpt-5.4-pro"].includes(context.modelId)
|
||||
@@ -170,6 +173,8 @@ describe("discord native /think autocomplete", () => {
|
||||
resolveConfiguredBindingRouteMock.mockReturnValue(createUnboundConfiguredRouteResult());
|
||||
providerThinkingMocks.resolveProviderBinaryThinking.mockReset();
|
||||
providerThinkingMocks.resolveProviderBinaryThinking.mockReturnValue(undefined);
|
||||
providerThinkingMocks.resolveProviderAdaptiveThinking.mockReset();
|
||||
providerThinkingMocks.resolveProviderAdaptiveThinking.mockReturnValue(undefined);
|
||||
providerThinkingMocks.resolveProviderDefaultThinkingLevel.mockReset();
|
||||
providerThinkingMocks.resolveProviderDefaultThinkingLevel.mockReturnValue(undefined);
|
||||
providerThinkingMocks.resolveProviderXHighThinking.mockReset();
|
||||
@@ -258,6 +263,7 @@ describe("discord native /think autocomplete", () => {
|
||||
});
|
||||
const values = choices.map((choice) => choice.value);
|
||||
expect(values).toContain("xhigh");
|
||||
expect(values).not.toContain("adaptive");
|
||||
});
|
||||
|
||||
it("falls back when a configured binding is unavailable", async () => {
|
||||
|
||||
@@ -811,7 +811,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, high, adaptive.");
|
||||
expect(result?.text).toContain("Options: off, minimal, low, medium, high.");
|
||||
});
|
||||
|
||||
it("persists verbose on and off directives", async () => {
|
||||
|
||||
@@ -20,7 +20,7 @@ export type ThinkingCatalogEntry = {
|
||||
reasoning?: boolean;
|
||||
};
|
||||
|
||||
const BASE_THINKING_LEVELS: ThinkLevel[] = ["off", "minimal", "low", "medium", "high", "adaptive"];
|
||||
const BASE_THINKING_LEVELS: ThinkLevel[] = ["off", "minimal", "low", "medium", "high"];
|
||||
const NO_THINKING_LEVELS: ThinkLevel[] = [...BASE_THINKING_LEVELS];
|
||||
|
||||
export function isBinaryThinkingProvider(provider?: string | null): boolean {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const providerRuntimeMocks = vi.hoisted(() => ({
|
||||
resolveProviderAdaptiveThinking: vi.fn(),
|
||||
resolveProviderBinaryThinking: vi.fn(),
|
||||
resolveProviderDefaultThinkingLevel: vi.fn(),
|
||||
resolveProviderXHighThinking: vi.fn(),
|
||||
@@ -15,6 +16,7 @@ let resolveThinkingDefaultForModel: typeof import("./thinking.js").resolveThinki
|
||||
async function loadFreshThinkingModuleForTest() {
|
||||
vi.resetModules();
|
||||
vi.doMock("../plugins/provider-thinking.js", () => ({
|
||||
resolveProviderAdaptiveThinking: providerRuntimeMocks.resolveProviderAdaptiveThinking,
|
||||
resolveProviderBinaryThinking: providerRuntimeMocks.resolveProviderBinaryThinking,
|
||||
resolveProviderDefaultThinkingLevel: providerRuntimeMocks.resolveProviderDefaultThinkingLevel,
|
||||
resolveProviderXHighThinking: providerRuntimeMocks.resolveProviderXHighThinking,
|
||||
@@ -23,6 +25,8 @@ async function loadFreshThinkingModuleForTest() {
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
providerRuntimeMocks.resolveProviderAdaptiveThinking.mockReset();
|
||||
providerRuntimeMocks.resolveProviderAdaptiveThinking.mockReturnValue(undefined);
|
||||
providerRuntimeMocks.resolveProviderBinaryThinking.mockReset();
|
||||
providerRuntimeMocks.resolveProviderBinaryThinking.mockReturnValue(undefined);
|
||||
providerRuntimeMocks.resolveProviderDefaultThinkingLevel.mockReset();
|
||||
@@ -113,8 +117,23 @@ describe("listThinkingLevels", () => {
|
||||
expect(listThinkingLevels(undefined, "gpt-4.1-mini")).not.toContain("xhigh");
|
||||
});
|
||||
|
||||
it("always includes adaptive", () => {
|
||||
expect(listThinkingLevels(undefined, "gpt-4.1-mini")).toContain("adaptive");
|
||||
it("uses provider runtime hooks for adaptive support", () => {
|
||||
providerRuntimeMocks.resolveProviderAdaptiveThinking.mockReturnValue(true);
|
||||
|
||||
expect(listThinkingLevels("demo", "demo-model")).toContain("adaptive");
|
||||
});
|
||||
|
||||
it("does not include adaptive without provider support", () => {
|
||||
expect(listThinkingLevels(undefined, "gpt-4.1-mini")).not.toContain("adaptive");
|
||||
expect(listThinkingLevels("openai", "gpt-5.4")).not.toContain("adaptive");
|
||||
});
|
||||
|
||||
it("includes adaptive for provider-advertised models", () => {
|
||||
providerRuntimeMocks.resolveProviderAdaptiveThinking.mockImplementation(
|
||||
({ provider, context }) =>
|
||||
provider === "anthropic" && context.modelId === "claude-opus-4-6" ? true : undefined,
|
||||
);
|
||||
|
||||
expect(listThinkingLevels("anthropic", "claude-opus-4-6")).toContain("adaptive");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { normalizeProviderId } from "../agents/provider-id.js";
|
||||
import {
|
||||
formatThinkingLevels as formatThinkingLevelsFallback,
|
||||
listThinkingLevelLabels as listThinkingLevelLabelsFallback,
|
||||
listThinkingLevels as listThinkingLevelsFallback,
|
||||
resolveThinkingDefaultForModel as resolveThinkingDefaultForModelFallback,
|
||||
} from "./thinking.shared.js";
|
||||
@@ -31,6 +29,7 @@ export type {
|
||||
VerboseLevel,
|
||||
} from "./thinking.shared.js";
|
||||
import {
|
||||
resolveProviderAdaptiveThinking,
|
||||
resolveProviderBinaryThinking,
|
||||
resolveProviderDefaultThinkingLevel,
|
||||
resolveProviderXHighThinking,
|
||||
@@ -82,10 +81,33 @@ export function supportsXHighThinking(provider?: string | null, model?: string |
|
||||
return false;
|
||||
}
|
||||
|
||||
export function supportsAdaptiveThinking(provider?: string | null, model?: string | null): boolean {
|
||||
const modelKey = normalizeOptionalLowercaseString(model);
|
||||
if (!modelKey) {
|
||||
return false;
|
||||
}
|
||||
const providerRaw = normalizeOptionalString(provider);
|
||||
const providerKey = providerRaw ? normalizeProviderId(providerRaw) : "";
|
||||
if (!providerKey) {
|
||||
return false;
|
||||
}
|
||||
const pluginDecision = resolveProviderAdaptiveThinking({
|
||||
provider: providerKey,
|
||||
context: {
|
||||
provider: providerKey,
|
||||
modelId: modelKey,
|
||||
},
|
||||
});
|
||||
return pluginDecision === true;
|
||||
}
|
||||
|
||||
export function listThinkingLevels(provider?: string | null, model?: string | null): ThinkLevel[] {
|
||||
const levels = listThinkingLevelsFallback(provider, model);
|
||||
if (supportsXHighThinking(provider, model)) {
|
||||
levels.splice(levels.length - 1, 0, "xhigh");
|
||||
levels.push("xhigh");
|
||||
}
|
||||
if (supportsAdaptiveThinking(provider, model)) {
|
||||
levels.push("adaptive");
|
||||
}
|
||||
return levels;
|
||||
}
|
||||
@@ -94,10 +116,7 @@ export function listThinkingLevelLabels(provider?: string | null, model?: string
|
||||
if (isBinaryThinkingProvider(provider, model)) {
|
||||
return ["off", "on"];
|
||||
}
|
||||
if (supportsXHighThinking(provider, model)) {
|
||||
return listThinkingLevels(provider, model);
|
||||
}
|
||||
return listThinkingLevelLabelsFallback(provider, model);
|
||||
return listThinkingLevels(provider, model);
|
||||
}
|
||||
|
||||
export function formatThinkingLevels(
|
||||
@@ -105,9 +124,7 @@ export function formatThinkingLevels(
|
||||
model?: string | null,
|
||||
separator = ", ",
|
||||
): string {
|
||||
return supportsXHighThinking(provider, model)
|
||||
? listThinkingLevelLabels(provider, model).join(separator)
|
||||
: formatThinkingLevelsFallback(provider, model, separator);
|
||||
return listThinkingLevelLabels(provider, model).join(separator);
|
||||
}
|
||||
|
||||
export function resolveThinkingDefaultForModel(params: {
|
||||
|
||||
@@ -640,6 +640,16 @@ export function resolveProviderXHighThinking(params: {
|
||||
return resolveProviderRuntimePlugin(params)?.supportsXHighThinking?.(params.context);
|
||||
}
|
||||
|
||||
export function resolveProviderAdaptiveThinking(params: {
|
||||
provider: string;
|
||||
config?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
context: ProviderThinkingPolicyContext;
|
||||
}) {
|
||||
return resolveProviderRuntimePlugin(params)?.supportsAdaptiveThinking?.(params.context);
|
||||
}
|
||||
|
||||
export function resolveProviderDefaultThinkingLevel(params: {
|
||||
provider: string;
|
||||
config?: OpenClawConfig;
|
||||
|
||||
@@ -8,6 +8,7 @@ type ThinkingProviderPlugin = {
|
||||
id: string;
|
||||
aliases?: string[];
|
||||
isBinaryThinking?: (ctx: ProviderThinkingPolicyContext) => boolean | undefined;
|
||||
supportsAdaptiveThinking?: (ctx: ProviderThinkingPolicyContext) => boolean | undefined;
|
||||
supportsXHighThinking?: (ctx: ProviderThinkingPolicyContext) => boolean | undefined;
|
||||
resolveDefaultThinkingLevel?: (
|
||||
ctx: ProviderDefaultThinkingPolicyContext,
|
||||
@@ -61,6 +62,12 @@ export function resolveProviderXHighThinking(
|
||||
return resolveActiveThinkingProvider(params.provider)?.supportsXHighThinking?.(params.context);
|
||||
}
|
||||
|
||||
export function resolveProviderAdaptiveThinking(
|
||||
params: ThinkingHookParams<ProviderThinkingPolicyContext>,
|
||||
) {
|
||||
return resolveActiveThinkingProvider(params.provider)?.supportsAdaptiveThinking?.(params.context);
|
||||
}
|
||||
|
||||
export function resolveProviderDefaultThinkingLevel(
|
||||
params: ThinkingHookParams<ProviderDefaultThinkingPolicyContext>,
|
||||
) {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* Provider-owned thinking policy input.
|
||||
*
|
||||
* Used by shared `/think`, ACP controls, and directive parsing to ask a
|
||||
* provider whether a model supports special reasoning UX such as xhigh or a
|
||||
* binary on/off toggle.
|
||||
* provider whether a model supports special reasoning UX such as adaptive,
|
||||
* xhigh, or a binary on/off toggle.
|
||||
*/
|
||||
export type ProviderThinkingPolicyContext = {
|
||||
provider: string;
|
||||
|
||||
@@ -1407,6 +1407,12 @@ export type ProviderPlugin = {
|
||||
* Return true only for models that should expose the `xhigh` thinking level.
|
||||
*/
|
||||
supportsXHighThinking?: (ctx: ProviderThinkingPolicyContext) => boolean | undefined;
|
||||
/**
|
||||
* Provider-owned adaptive thinking support.
|
||||
*
|
||||
* Return true only for models that should expose the `adaptive` thinking level.
|
||||
*/
|
||||
supportsAdaptiveThinking?: (ctx: ProviderThinkingPolicyContext) => boolean | undefined;
|
||||
/**
|
||||
* Provider-owned default thinking level.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user