mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(ui): hide thinking options for non-reasoning models (#85406)
* fix(ui): hide thinking options for non-reasoning models * test(ui): satisfy thinking selector lint * chore(deps): refresh generated shrinkwraps * test(ui): remove redundant thinking selector assertion
This commit is contained in:
committed by
GitHub
parent
a03a8d91f6
commit
bb4d88e557
@@ -44,6 +44,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Gateway/LaunchAgent: wait for launchd reload bootout to finish and fall back to kickstart when bootstrap races, so reload handoff does not leave the service deregistered. Fixes #84630. (#84641) Thanks @NianJiuZst.
|
||||
- Gateway/LaunchAgent: treat a concurrent launchd bootstrap as a successful restart when the service is already loaded, avoiding false macOS Gateway restart failures. Fixes #84721. (#84722) Thanks @googlerest.
|
||||
- Gateway/service: include the active `openclaw` command bin directory in managed service PATH generation and doctor audit expectations for npm-global macOS installs. Fixes #84201. (#84475) Thanks @jbetala7.
|
||||
- Control UI/chat: disable the thinking selector for known non-reasoning models instead of showing duplicate Off choices. Fixes #84069. Thanks @DrippingMellow.
|
||||
- CLI/update: preserve managed Gateway service environment during package cutovers so macOS LaunchAgent repair/restart reads the pre-update service state instead of caller shell state. (#83026)
|
||||
- Agents/providers: honor per-model `api` and `baseUrl` overrides in custom provider auth hooks and transport selection. Fixes #80487. (#80488) Thanks @huveewomg.
|
||||
- Gateway/restart: eager-load the lifecycle runtime before in-place upgrade signal handling so package replacement does not deadlock restart imports. (#84890) Thanks @myps6415.
|
||||
|
||||
2
extensions/acpx/npm-shrinkwrap.json
generated
2
extensions/acpx/npm-shrinkwrap.json
generated
@@ -903,6 +903,7 @@
|
||||
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz",
|
||||
"integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"bare-abort-controller": "*"
|
||||
},
|
||||
@@ -2238,6 +2239,7 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
@@ -1314,6 +1314,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
|
||||
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@@ -1350,6 +1351,7 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
2
extensions/amazon-bedrock/npm-shrinkwrap.json
generated
2
extensions/amazon-bedrock/npm-shrinkwrap.json
generated
@@ -1188,6 +1188,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
|
||||
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@@ -1224,6 +1225,7 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
2
extensions/anthropic-vertex/npm-shrinkwrap.json
generated
2
extensions/anthropic-vertex/npm-shrinkwrap.json
generated
@@ -1321,6 +1321,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
|
||||
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@@ -1372,6 +1373,7 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
2
extensions/codex/npm-shrinkwrap.json
generated
2
extensions/codex/npm-shrinkwrap.json
generated
@@ -1866,6 +1866,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
|
||||
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@@ -1917,6 +1918,7 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
2
extensions/diagnostics-otel/npm-shrinkwrap.json
generated
2
extensions/diagnostics-otel/npm-shrinkwrap.json
generated
@@ -67,6 +67,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz",
|
||||
"integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
@@ -580,6 +581,7 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
||||
3
extensions/discord/npm-shrinkwrap.json
generated
3
extensions/discord/npm-shrinkwrap.json
generated
@@ -432,7 +432,8 @@
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/opusscript/-/opusscript-0.1.1.tgz",
|
||||
"integrity": "sha512-mL0fZZOUnXdZ78woRXp18lApwpp0lF5tozJOD1Wut0dgrA9WuQTgSels/CSmFleaAZrJi/nci5KOVtbuxeWoQA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/prism-media": {
|
||||
"version": "1.3.5",
|
||||
|
||||
1
extensions/memory-lancedb/npm-shrinkwrap.json
generated
1
extensions/memory-lancedb/npm-shrinkwrap.json
generated
@@ -209,6 +209,7 @@
|
||||
"resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-18.1.0.tgz",
|
||||
"integrity": "sha512-v/ShMp57iBnBp4lDgV8Jx3d3Q5/Hac25FWmQ98eMahUiHPXcvwIMKJD0hBIgclm/FCG+LwPkAKtkRO1O/W0YGg==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@swc/helpers": "^0.5.11",
|
||||
"@types/command-line-args": "^5.2.3",
|
||||
|
||||
2
extensions/twitch/npm-shrinkwrap.json
generated
2
extensions/twitch/npm-shrinkwrap.json
generated
@@ -168,6 +168,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@twurple/auth/-/auth-8.1.4.tgz",
|
||||
"integrity": "sha512-ylsJoPInCw9BwOqxKcx+1k2ce9QG3vJpKFzPdIyHh49HvM/ulQZ0CAGysydugDYXF0iO/TGryh7PluSwx5fIwA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@d-fischer/logger": "^4.2.1",
|
||||
"@d-fischer/shared-utils": "^3.6.1",
|
||||
@@ -288,6 +289,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
|
||||
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
|
||||
3
extensions/whatsapp/npm-shrinkwrap.json
generated
3
extensions/whatsapp/npm-shrinkwrap.json
generated
@@ -1178,6 +1178,7 @@
|
||||
"resolved": "https://registry.npmjs.org/audio-decode/-/audio-decode-2.2.3.tgz",
|
||||
"integrity": "sha512-Z0lHvMayR/Pad9+O9ddzaBJE0DrhZkQlStrC1RwcAHF3AhQAsdwKHeLGK8fYKyp2DDU6xHxzGb4CLMui12yVrg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@wasm-audio-decoders/flac": "^0.2.4",
|
||||
"@wasm-audio-decoders/ogg-vorbis": "^0.1.15",
|
||||
@@ -1417,6 +1418,7 @@
|
||||
"resolved": "https://registry.npmjs.org/jimp/-/jimp-1.6.1.tgz",
|
||||
"integrity": "sha512-hNQh6rZtWfSVWSNVmvq87N5BPJsNH7k7I7qyrXf9DOma9xATQk3fsyHazCQe51nCjdkoWdTmh0vD7bjVSLoxxw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.1",
|
||||
"@jimp/diff": "1.6.1",
|
||||
@@ -1461,6 +1463,7 @@
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz",
|
||||
"integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@keyv/serialize": "^1.1.1"
|
||||
}
|
||||
|
||||
6
npm-shrinkwrap.json
generated
6
npm-shrinkwrap.json
generated
@@ -1567,6 +1567,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz",
|
||||
"integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@hono/node-server": "^1.19.9",
|
||||
"ajv": "^8.17.1",
|
||||
@@ -2813,6 +2814,7 @@
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
||||
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"accepts": "^2.0.0",
|
||||
"body-parser": "^2.2.1",
|
||||
@@ -3230,6 +3232,7 @@
|
||||
"resolved": "https://registry.npmjs.org/grammy/-/grammy-1.43.0.tgz",
|
||||
"integrity": "sha512-7dYm06A945mXuIk/5HUlSjeyIYChW8vCEiU2dkOKKqJJzwAWxTkCc91Eqbz7TgODh2rtFFKWI/fekowWHOkmjQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@grammyjs/types": "3.27.3",
|
||||
"abort-controller": "^3.0.0",
|
||||
@@ -3298,6 +3301,7 @@
|
||||
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz",
|
||||
"integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
}
|
||||
@@ -5064,6 +5068,7 @@
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-8.3.0.tgz",
|
||||
"integrity": "sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
}
|
||||
@@ -5287,6 +5292,7 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
normalizeThinkingOptionValue,
|
||||
} from "../thinking-labels.ts";
|
||||
import {
|
||||
type ThinkingCatalogEntry,
|
||||
listThinkingLevelLabels,
|
||||
normalizeThinkLevel,
|
||||
resolveThinkingDefaultForModel,
|
||||
@@ -673,26 +674,51 @@ function buildThinkingOptions(
|
||||
return options;
|
||||
}
|
||||
|
||||
function isOffThinkingOption(value: string | null | undefined): boolean {
|
||||
return normalizeThinkingOptionValue(value ?? "") === "off";
|
||||
}
|
||||
|
||||
function isOffOnlyThinkingLevels(levels: readonly GatewayThinkingLevelOption[]): boolean {
|
||||
return levels.every((level) => isOffThinkingOption(level.id || level.label));
|
||||
}
|
||||
|
||||
function resolveThinkingLevelOptions(
|
||||
activeRow: SessionsListResult["sessions"][number] | undefined,
|
||||
defaults: SessionsListResult["defaults"] | undefined,
|
||||
provider: string | null,
|
||||
model: string | null,
|
||||
catalog: readonly ThinkingCatalogEntry[],
|
||||
): GatewayThinkingLevelOption[] {
|
||||
if (activeRow?.thinkingLevels?.length) {
|
||||
return activeRow.thinkingLevels;
|
||||
}
|
||||
const sessionModelMatchesDefaults =
|
||||
(!activeRow?.modelProvider || activeRow.modelProvider === defaults?.modelProvider) &&
|
||||
(!activeRow?.model || activeRow.model === defaults?.model);
|
||||
if (sessionModelMatchesDefaults && defaults?.thinkingLevels?.length) {
|
||||
return defaults.thinkingLevels;
|
||||
const catalogEntry =
|
||||
provider && model
|
||||
? catalog.find((entry) => entry.provider === provider && entry.id === model)
|
||||
: undefined;
|
||||
const explicitLevels =
|
||||
(activeRow?.thinkingLevels?.length ? activeRow.thinkingLevels : null) ??
|
||||
(sessionModelMatchesDefaults && defaults?.thinkingLevels?.length
|
||||
? defaults.thinkingLevels
|
||||
: null);
|
||||
if (explicitLevels) {
|
||||
if (catalogEntry?.reasoning === false && isOffOnlyThinkingLevels(explicitLevels)) {
|
||||
return [];
|
||||
}
|
||||
return explicitLevels;
|
||||
}
|
||||
const labels =
|
||||
const explicitLabels =
|
||||
(activeRow?.thinkingOptions?.length ? activeRow.thinkingOptions : null) ??
|
||||
(sessionModelMatchesDefaults && defaults?.thinkingOptions?.length
|
||||
? defaults.thinkingOptions
|
||||
: null) ??
|
||||
: null);
|
||||
if (catalogEntry?.reasoning === false) {
|
||||
if (!explicitLabels || explicitLabels.every(isOffThinkingOption)) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
const labels =
|
||||
explicitLabels ??
|
||||
(provider && model ? listThinkingLevelLabels(provider, model) : listThinkingLevelLabels());
|
||||
return labels.map((label) => ({
|
||||
id: normalizeThinkLevel(label) ?? normalizeLowercaseStringOrEmpty(label),
|
||||
@@ -713,6 +739,7 @@ export function resolveChatThinkingSelectState(state: AppViewState): ChatThinkin
|
||||
state.sessionsResult?.defaults,
|
||||
provider,
|
||||
model,
|
||||
state.chatModelCatalog ?? [],
|
||||
);
|
||||
const defaultLevel =
|
||||
activeRow?.thinkingDefault ??
|
||||
@@ -724,10 +751,11 @@ export function resolveChatThinkingSelectState(state: AppViewState): ChatThinkin
|
||||
catalog: state.chatModelCatalog ?? [],
|
||||
})
|
||||
: "off");
|
||||
const effectiveOverride = levels.length === 0 && currentOverride === "off" ? "" : currentOverride;
|
||||
return {
|
||||
currentOverride,
|
||||
currentOverride: effectiveOverride,
|
||||
defaultLabel: formatInheritedThinkingLabel(defaultLevel),
|
||||
options: buildThinkingOptions(levels, currentOverride),
|
||||
options: buildThinkingOptions(levels, effectiveOverride),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -735,7 +763,8 @@ export function renderChatThinkingSelect(state: AppViewState) {
|
||||
const { currentOverride, defaultLabel, options } = resolveChatThinkingSelectState(state);
|
||||
const busy =
|
||||
state.chatLoading || state.chatSending || Boolean(state.chatRunId) || state.chatStream !== null;
|
||||
const disabled = !state.connected || busy || !state.client;
|
||||
const disabled =
|
||||
!state.connected || busy || !state.client || (options.length === 0 && currentOverride === "");
|
||||
const selectedLabel =
|
||||
currentOverride === ""
|
||||
? defaultLabel
|
||||
|
||||
@@ -1675,6 +1675,48 @@ describe("chat session controls", () => {
|
||||
expect(thinkingSelect?.title).toBe("Inherited: Adaptive");
|
||||
});
|
||||
|
||||
it("disables thinking for known non-reasoning models without duplicate off options", () => {
|
||||
const { state } = createChatHeaderState({
|
||||
model: "mistral:v0.3",
|
||||
modelProvider: "ollama",
|
||||
models: [
|
||||
{
|
||||
id: "mistral:v0.3",
|
||||
name: "Mistral",
|
||||
provider: "ollama",
|
||||
reasoning: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
const session = state.sessionsResult!.sessions[0];
|
||||
state.sessionsResult = {
|
||||
...state.sessionsResult!,
|
||||
defaults: {
|
||||
...state.sessionsResult!.defaults,
|
||||
thinkingLevels: [{ id: "off", label: "off" }],
|
||||
},
|
||||
sessions: [
|
||||
{
|
||||
...session,
|
||||
thinkingLevel: "off",
|
||||
thinkingLevels: [{ id: "off", label: "off" }],
|
||||
},
|
||||
],
|
||||
};
|
||||
const container = document.createElement("div");
|
||||
render(renderChatSessionSelect(state), container);
|
||||
|
||||
const thinkingSelect = container.querySelector<HTMLSelectElement>(
|
||||
'select[data-chat-thinking-select="true"]',
|
||||
);
|
||||
|
||||
expect(thinkingSelect?.disabled).toBe(true);
|
||||
expect([...(thinkingSelect?.options ?? [])].map((option) => option.value)).toEqual([""]);
|
||||
expect(
|
||||
[...(thinkingSelect?.options ?? [])].map((option) => option.textContent?.trim()),
|
||||
).toEqual(["Inherited: Off"]);
|
||||
});
|
||||
|
||||
it("always renders full thinking labels", () => {
|
||||
const { state } = createChatHeaderState({
|
||||
model: "gpt-5.5",
|
||||
|
||||
Reference in New Issue
Block a user