Skip to content

Commit 009b338

Browse files
committed
fix: finish run control defaults (#79385) (thanks @VACInc)
1 parent 6d0a34c commit 009b338

5 files changed

Lines changed: 103 additions & 11 deletions

File tree

apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5819,6 +5819,7 @@ public struct ChatSendParams: Codable, Sendable {
58195819
public let sessionid: String?
58205820
public let message: String
58215821
public let thinking: String?
5822+
public let fastmode: Bool?
58225823
public let deliver: Bool?
58235824
public let originatingchannel: String?
58245825
public let originatingto: String?
@@ -5835,6 +5836,7 @@ public struct ChatSendParams: Codable, Sendable {
58355836
sessionid: String?,
58365837
message: String,
58375838
thinking: String?,
5839+
fastmode: Bool?,
58385840
deliver: Bool?,
58395841
originatingchannel: String?,
58405842
originatingto: String?,
@@ -5850,6 +5852,7 @@ public struct ChatSendParams: Codable, Sendable {
58505852
self.sessionid = sessionid
58515853
self.message = message
58525854
self.thinking = thinking
5855+
self.fastmode = fastmode
58535856
self.deliver = deliver
58545857
self.originatingchannel = originatingchannel
58555858
self.originatingto = originatingto
@@ -5867,6 +5870,7 @@ public struct ChatSendParams: Codable, Sendable {
58675870
case sessionid = "sessionId"
58685871
case message
58695872
case thinking
5873+
case fastmode = "fastMode"
58705874
case deliver
58715875
case originatingchannel = "originatingChannel"
58725876
case originatingto = "originatingTo"

src/agents/simple-completion-runtime.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ describe("completeWithPreparedSimpleCompletionModel", () => {
523523
id: "gpt-5.4",
524524
name: "gpt-5.4",
525525
api: "openai-responses",
526+
baseUrl: "https://api.openai.com/v1",
526527
reasoning: true,
527528
input: ["text"],
528529
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
@@ -563,6 +564,7 @@ describe("completeWithPreparedSimpleCompletionModel", () => {
563564
id: "gpt-5.4",
564565
name: "gpt-5.4",
565566
api: "openai-responses",
567+
baseUrl: "https://api.openai.com/v1",
566568
reasoning: true,
567569
input: ["text"],
568570
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },

src/auto-reply/reply.directive.directive-behavior.shows-current-verbose-level-verbose-has-no.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ describe("directive behavior", () => {
8888
} as OpenClawConfig,
8989
});
9090
expect(fastText).toContain("Current fast mode: on (config)");
91-
expect(fastText).toContain("Options: status, on, off.");
91+
expect(fastText).toContain("Options: status, on, off, default.");
9292

9393
const { text: verboseText } = await runDirectiveStatus("/verbose", {
9494
currentVerboseLevel: "on",
@@ -154,7 +154,7 @@ describe("directive behavior", () => {
154154
});
155155

156156
expect(statusText).toContain("Current fast mode: on (config)");
157-
expect(statusText).toContain("Options: status, on, off.");
157+
expect(statusText).toContain("Options: status, on, off, default.");
158158
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
159159
});
160160
it("enforces per-agent elevated restrictions and status visibility", async () => {

ui/src/ui/chat/slash-command-executor.node.test.ts

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ describe("executeSlashCommand directives", () => {
584584
);
585585

586586
expect(result.content).toBe(
587-
"Current thinking level: low.\nOptions: off, minimal, low, medium, high.",
587+
"Current thinking level: low.\nOptions: default, off, minimal, low, medium, high.",
588588
);
589589
expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
590590
expect(request).toHaveBeenNthCalledWith(2, "models.list", { view: "configured" });
@@ -634,6 +634,29 @@ describe("executeSlashCommand directives", () => {
634634
});
635635
});
636636

637+
it("clears thinking override for /think default", async () => {
638+
const request = vi.fn(async (method: string, payload?: unknown) => {
639+
if (method === "sessions.patch") {
640+
return { ok: true, ...((payload ?? {}) as object) };
641+
}
642+
throw new Error(`unexpected method: ${method}`);
643+
});
644+
645+
const result = await executeSlashCommand(
646+
{ request } as unknown as GatewayBrowserClient,
647+
"agent:main:main",
648+
"think",
649+
"default",
650+
);
651+
652+
expect(result.content).toBe("Thinking level reset to default.");
653+
expect(result.action).toBe("refresh");
654+
expect(request).toHaveBeenCalledWith("sessions.patch", {
655+
key: "agent:main:main",
656+
thinkingLevel: null,
657+
});
658+
});
659+
637660
it("uses default thinking options when the active session is absent", async () => {
638661
const request = vi.fn(async (method: string, payload?: unknown) => {
639662
if (method === "sessions.list") {
@@ -709,7 +732,7 @@ describe("executeSlashCommand directives", () => {
709732
);
710733

711734
expect(status.content).toBe(
712-
"Current thinking level: adaptive.\nOptions: off, minimal, low, medium, adaptive, high, xhigh, maximum.",
735+
"Current thinking level: adaptive.\nOptions: default, off, minimal, low, medium, adaptive, high, xhigh, maximum.",
713736
);
714737
expect(setXhigh.content).toBe("Thinking level set to **xhigh**.");
715738
expect(setMax.content).toBe("Thinking level set to **max**.");
@@ -788,7 +811,7 @@ describe("executeSlashCommand directives", () => {
788811
);
789812

790813
expect(status.content).toBe(
791-
"Current thinking level: off.\nOptions: off, minimal, low, medium, high, xhigh, max.",
814+
"Current thinking level: off.\nOptions: default, off, minimal, low, medium, high, xhigh, max.",
792815
);
793816
expect(setMax.content).toBe("Thinking level set to **max**.");
794817
});
@@ -882,7 +905,7 @@ describe("executeSlashCommand directives", () => {
882905
"",
883906
);
884907

885-
expect(result.content).toBe("Current fast mode: on.\nOptions: status, on, off.");
908+
expect(result.content).toBe("Current fast mode: on.\nOptions: status, on, off, default.");
886909
expect(request).toHaveBeenNthCalledWith(1, "sessions.list", {});
887910
});
888911

@@ -902,6 +925,29 @@ describe("executeSlashCommand directives", () => {
902925
fastMode: true,
903926
});
904927
});
928+
929+
it("clears fast mode override for /fast default", async () => {
930+
const request = vi.fn(async (method: string, payload?: unknown) => {
931+
if (method === "sessions.patch") {
932+
return { ok: true, ...((payload ?? {}) as object) };
933+
}
934+
throw new Error(`unexpected method: ${method}`);
935+
});
936+
937+
const result = await executeSlashCommand(
938+
{ request } as unknown as GatewayBrowserClient,
939+
"agent:main:main",
940+
"fast",
941+
"default",
942+
);
943+
944+
expect(result.content).toBe("Fast mode reset to default.");
945+
expect(result.action).toBe("refresh");
946+
expect(request).toHaveBeenCalledWith("sessions.patch", {
947+
key: "agent:main:main",
948+
fastMode: null,
949+
});
950+
});
905951
});
906952

907953
describe("executeSlashCommand /steer (soft inject)", () => {

ui/src/ui/chat/slash-command-executor.ts

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ function normalizeVerboseLevel(raw?: string | null): "off" | "on" | "full" | und
8181
return undefined;
8282
}
8383

84+
function isSessionDefaultDirectiveValue(raw?: string | null): boolean {
85+
const key = normalizeOptionalLowercaseString(raw);
86+
if (!key) {
87+
return false;
88+
}
89+
return ["default", "inherit", "inherited", "clear", "reset", "unpin"].includes(key);
90+
}
91+
8492
export async function executeSlashCommand(
8593
client: GatewayBrowserClient,
8694
sessionKey: string,
@@ -259,25 +267,37 @@ async function executeThink(
259267
return {
260268
content: formatDirectiveOptions(
261269
`Current thinking level: ${resolveCurrentThinkingLevel(session, defaults, models)}.`,
262-
formatThinkingOptionsForSession(session, defaults),
270+
formatThinkingCommandOptionsForSession(session, defaults),
263271
),
264272
};
265273
} catch (err) {
266274
return { content: `Failed to get thinking level: ${String(err)}` };
267275
}
268276
}
269277

278+
if (isSessionDefaultDirectiveValue(rawLevel)) {
279+
try {
280+
await client.request("sessions.patch", { key: sessionKey, thinkingLevel: null });
281+
return {
282+
content: "Thinking level reset to default.",
283+
action: "refresh",
284+
};
285+
} catch (err) {
286+
return { content: `Failed to reset thinking level: ${String(err)}` };
287+
}
288+
}
289+
270290
try {
271291
const { session, defaults } = await loadCurrentSessionState(client, sessionKey);
272292
const level = resolveThinkingLevelInput(rawLevel, session, defaults);
273293
if (!level) {
274294
return {
275-
content: `Unrecognized thinking level "${rawLevel}". Valid levels: ${formatThinkingOptionsForSession(session, defaults)}.`,
295+
content: `Unrecognized thinking level "${rawLevel}". Valid levels: ${formatThinkingCommandOptionsForSession(session, defaults)}.`,
276296
};
277297
}
278298
if (!isThinkingLevelOptionForSession(session, defaults, level)) {
279299
return {
280-
content: `Unsupported thinking level "${rawLevel}" for this model. Valid levels: ${formatThinkingOptionsForSession(session, defaults)}.`,
300+
content: `Unsupported thinking level "${rawLevel}" for this model. Valid levels: ${formatThinkingCommandOptionsForSession(session, defaults)}.`,
281301
};
282302
}
283303
await client.request("sessions.patch", { key: sessionKey, thinkingLevel: level });
@@ -342,17 +362,29 @@ async function executeFast(
342362
return {
343363
content: formatDirectiveOptions(
344364
`Current fast mode: ${resolveCurrentFastMode(session)}.`,
345-
"status, on, off",
365+
"status, on, off, default",
346366
),
347367
};
348368
} catch (err) {
349369
return { content: `Failed to get fast mode: ${String(err)}` };
350370
}
351371
}
352372

373+
if (isSessionDefaultDirectiveValue(rawMode)) {
374+
try {
375+
await client.request("sessions.patch", { key: sessionKey, fastMode: null });
376+
return {
377+
content: "Fast mode reset to default.",
378+
action: "refresh",
379+
};
380+
} catch (err) {
381+
return { content: `Failed to reset fast mode: ${String(err)}` };
382+
}
383+
}
384+
353385
if (rawMode !== "on" && rawMode !== "off") {
354386
return {
355-
content: `Unrecognized fast mode "${args.trim()}". Valid levels: status, on, off.`,
387+
content: `Unrecognized fast mode "${args.trim()}". Valid levels: status, on, off, default.`,
356388
};
357389
}
358390

@@ -619,6 +651,14 @@ function formatThinkingOptionsForSession(
619651
.join(separator);
620652
}
621653

654+
function formatThinkingCommandOptionsForSession(
655+
session: GatewaySessionRow | undefined,
656+
defaults?: SessionsListResult["defaults"],
657+
): string {
658+
const options = formatThinkingOptionsForSession(session, defaults);
659+
return options.split(", ").includes("default") ? options : `default, ${options}`;
660+
}
661+
622662
function resolveThinkingLevelInput(
623663
rawLevel: string,
624664
session: GatewaySessionRow | undefined,

0 commit comments

Comments
 (0)