feat: add /reasoning reasoning visibility
This commit is contained in:
@@ -603,6 +603,7 @@ Quick reference (send these in chat):
|
||||
| `/activation mention\|always` | Group activation (owner-only) |
|
||||
| `/think <level>` | Set thinking level (off\|minimal\|low\|medium\|high) |
|
||||
| `/verbose on\|off` | Toggle verbose mode |
|
||||
| `/reasoning on\|off` | Toggle reasoning visibility |
|
||||
| `/elevated on\|off` | Toggle elevated bash mode (approved senders only) |
|
||||
| `/model <name>` | Switch AI model (see below) |
|
||||
| `/queue <mode>` | Queue mode (see below) |
|
||||
|
||||
@@ -40,6 +40,7 @@ Text + native (when enabled):
|
||||
- `/reset` or `/new`
|
||||
- `/think <level>` (aliases: `/thinking`, `/t`)
|
||||
- `/verbose on|off` (alias: `/v`)
|
||||
- `/reasoning on|off` (alias: `/reason`)
|
||||
- `/elevated on|off` (alias: `/elev`)
|
||||
- `/model <name>`
|
||||
- `/queue <mode>` (plus options like `debounce:2s cap:25 drop:summarize`)
|
||||
|
||||
@@ -34,6 +34,12 @@ read_when:
|
||||
- Inline directive affects only that message; session/global defaults apply otherwise.
|
||||
- When verbose is on, agents that emit structured tool results (Pi, other JSON agents) send each tool result back as its own metadata-only message, prefixed with `<emoji> <tool-name>: <arg>` when available (path/command); the tool output itself is not forwarded. These tool summaries are sent as soon as each tool finishes (separate bubbles), not as streaming deltas. If you toggle `/verbose on|off` while a run is in-flight, subsequent tool bubbles honor the new setting.
|
||||
|
||||
## Reasoning visibility (/reasoning)
|
||||
- Levels: `on|off`.
|
||||
- Directive-only message toggles whether thinking blocks are shown as italic text in replies.
|
||||
- When enabled, any model-provided reasoning content is appended as a separate italic block.
|
||||
- Alias: `/reason`.
|
||||
|
||||
## Related
|
||||
- Elevated mode docs live in [`docs/elevated.md`](/tools/elevated).
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ Use SSH tunneling or Tailscale to reach the Gateway WS.
|
||||
- `/model <provider/model>` (or `/model list`, `/models`)
|
||||
- `/think <off|minimal|low|medium|high>`
|
||||
- `/verbose <on|off>`
|
||||
- `/reasoning <on|off>`
|
||||
- `/elevated <on|off>`
|
||||
- `/elev <on|off>`
|
||||
- `/activation <mention|always>`
|
||||
|
||||
@@ -13,7 +13,11 @@ import {
|
||||
type Skill,
|
||||
} from "@mariozechner/pi-coding-agent";
|
||||
import { resolveHeartbeatPrompt } from "../auto-reply/heartbeat.js";
|
||||
import type { ThinkLevel, VerboseLevel } from "../auto-reply/thinking.js";
|
||||
import type {
|
||||
ReasoningLevel,
|
||||
ThinkLevel,
|
||||
VerboseLevel,
|
||||
} from "../auto-reply/thinking.js";
|
||||
import { formatToolAggregate } from "../auto-reply/tool-meta.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import { getMachineDisplayName } from "../infra/machine-name.js";
|
||||
@@ -53,7 +57,11 @@ import {
|
||||
type BlockReplyChunking,
|
||||
subscribeEmbeddedPiSession,
|
||||
} from "./pi-embedded-subscribe.js";
|
||||
import { extractAssistantText } from "./pi-embedded-utils.js";
|
||||
import {
|
||||
extractAssistantText,
|
||||
extractAssistantThinking,
|
||||
formatReasoningMarkdown,
|
||||
} from "./pi-embedded-utils.js";
|
||||
import { toToolDefinitions } from "./pi-tool-definition-adapter.js";
|
||||
import { createClawdbotCodingTools } from "./pi-tools.js";
|
||||
import { resolveSandboxContext } from "./sandbox.js";
|
||||
@@ -575,6 +583,7 @@ export async function runEmbeddedPiAgent(params: {
|
||||
authProfileId?: string;
|
||||
thinkLevel?: ThinkLevel;
|
||||
verboseLevel?: VerboseLevel;
|
||||
reasoningLevel?: ReasoningLevel;
|
||||
bashElevated?: BashElevatedDefaults;
|
||||
timeoutMs: number;
|
||||
runId: string;
|
||||
@@ -846,6 +855,7 @@ export async function runEmbeddedPiAgent(params: {
|
||||
session,
|
||||
runId: params.runId,
|
||||
verboseLevel: params.verboseLevel,
|
||||
includeReasoning: params.reasoningLevel === "on",
|
||||
shouldEmitToolResult: params.shouldEmitToolResult,
|
||||
onToolResult: params.onToolResult,
|
||||
onBlockReply: params.onBlockReply,
|
||||
@@ -1064,10 +1074,22 @@ export async function runEmbeddedPiAgent(params: {
|
||||
}
|
||||
}
|
||||
|
||||
const fallbackText = lastAssistant
|
||||
? (() => {
|
||||
const base = extractAssistantText(lastAssistant);
|
||||
if (params.reasoningLevel !== "on") return base;
|
||||
const thinking = extractAssistantThinking(lastAssistant);
|
||||
const formatted = thinking
|
||||
? formatReasoningMarkdown(thinking)
|
||||
: "";
|
||||
if (!formatted) return base;
|
||||
return base ? `${base}\n\n${formatted}` : formatted;
|
||||
})()
|
||||
: "";
|
||||
for (const text of assistantTexts.length
|
||||
? assistantTexts
|
||||
: lastAssistant
|
||||
? [extractAssistantText(lastAssistant)]
|
||||
: fallbackText
|
||||
? [fallbackText]
|
||||
: []) {
|
||||
const { text: cleanedText, mediaUrls } = splitMediaFromOutput(text);
|
||||
if (!cleanedText && (!mediaUrls || mediaUrls.length === 0))
|
||||
|
||||
@@ -10,6 +10,8 @@ import type { BlockReplyChunking } from "./pi-embedded-block-chunker.js";
|
||||
import { EmbeddedBlockChunker } from "./pi-embedded-block-chunker.js";
|
||||
import {
|
||||
extractAssistantText,
|
||||
extractAssistantThinking,
|
||||
formatReasoningMarkdown,
|
||||
inferToolMetaFromArgs,
|
||||
} from "./pi-embedded-utils.js";
|
||||
|
||||
@@ -85,6 +87,7 @@ export function subscribeEmbeddedPiSession(params: {
|
||||
session: AgentSession;
|
||||
runId: string;
|
||||
verboseLevel?: "off" | "on";
|
||||
includeReasoning?: boolean;
|
||||
shouldEmitToolResult?: () => boolean;
|
||||
onToolResult?: (payload: {
|
||||
text?: string;
|
||||
@@ -120,6 +123,7 @@ export function subscribeEmbeddedPiSession(params: {
|
||||
let pendingCompactionRetry = 0;
|
||||
let compactionRetryResolve: (() => void) | undefined;
|
||||
let compactionRetryPromise: Promise<void> | null = null;
|
||||
let lastReasoningSent: string | undefined;
|
||||
|
||||
const ensureCompactionPromise = () => {
|
||||
if (!compactionRetryPromise) {
|
||||
@@ -216,6 +220,24 @@ export function subscribeEmbeddedPiSession(params: {
|
||||
});
|
||||
};
|
||||
|
||||
const extractThinkingFromText = (text: string): string => {
|
||||
if (!text || !THINKING_TAG_RE.test(text)) return "";
|
||||
THINKING_TAG_RE.lastIndex = 0;
|
||||
let result = "";
|
||||
let lastIndex = 0;
|
||||
let inThinking = false;
|
||||
for (const match of text.matchAll(THINKING_TAG_RE)) {
|
||||
const idx = match.index ?? 0;
|
||||
if (inThinking) {
|
||||
result += text.slice(lastIndex, idx);
|
||||
}
|
||||
const tag = match[0].toLowerCase();
|
||||
inThinking = !tag.includes("/");
|
||||
lastIndex = idx + match[0].length;
|
||||
}
|
||||
return result.trim();
|
||||
};
|
||||
|
||||
const resetForCompactionRetry = () => {
|
||||
assistantTexts.length = 0;
|
||||
toolMetas.length = 0;
|
||||
@@ -244,6 +266,7 @@ export function subscribeEmbeddedPiSession(params: {
|
||||
blockChunker?.reset();
|
||||
lastStreamedAssistant = undefined;
|
||||
lastBlockReplyText = undefined;
|
||||
lastReasoningSent = undefined;
|
||||
assistantTextBaseline = assistantTexts.length;
|
||||
}
|
||||
}
|
||||
@@ -470,19 +493,26 @@ export function subscribeEmbeddedPiSession(params: {
|
||||
if (evt.type === "message_end") {
|
||||
const msg = (evt as AgentEvent & { message: AgentMessage }).message;
|
||||
if (msg?.role === "assistant") {
|
||||
const assistantMessage = msg as AssistantMessage;
|
||||
const rawText = extractAssistantText(assistantMessage);
|
||||
const cleaned = params.enforceFinalTag
|
||||
? stripThinkingSegments(
|
||||
stripUnpairedThinkingTags(
|
||||
extractAssistantText(msg as AssistantMessage),
|
||||
),
|
||||
)
|
||||
: stripThinkingSegments(
|
||||
extractAssistantText(msg as AssistantMessage),
|
||||
);
|
||||
const text =
|
||||
? stripThinkingSegments(stripUnpairedThinkingTags(rawText))
|
||||
: stripThinkingSegments(rawText);
|
||||
const baseText =
|
||||
params.enforceFinalTag && cleaned
|
||||
? (extractFinalText(cleaned)?.trim() ?? cleaned)
|
||||
: cleaned;
|
||||
const rawThinking = params.includeReasoning
|
||||
? extractAssistantThinking(assistantMessage) ||
|
||||
extractThinkingFromText(rawText)
|
||||
: "";
|
||||
const formattedReasoning = rawThinking
|
||||
? formatReasoningMarkdown(rawThinking)
|
||||
: "";
|
||||
const text =
|
||||
baseText && formattedReasoning
|
||||
? `${baseText}\n\n${formattedReasoning}`
|
||||
: baseText || formattedReasoning;
|
||||
|
||||
const addedDuringMessage =
|
||||
assistantTexts.length > assistantTextBaseline;
|
||||
@@ -516,6 +546,16 @@ export function subscribeEmbeddedPiSession(params: {
|
||||
}
|
||||
}
|
||||
}
|
||||
const onBlockReply = params.onBlockReply;
|
||||
const shouldEmitReasoningBlock =
|
||||
Boolean(formattedReasoning) &&
|
||||
Boolean(onBlockReply) &&
|
||||
formattedReasoning !== lastReasoningSent &&
|
||||
(blockReplyBreak === "text_end" || Boolean(blockChunker));
|
||||
if (shouldEmitReasoningBlock && formattedReasoning && onBlockReply) {
|
||||
lastReasoningSent = formattedReasoning;
|
||||
void onBlockReply({ text: formattedReasoning });
|
||||
}
|
||||
deltaBuffer = "";
|
||||
blockBuffer = "";
|
||||
blockChunker?.reset();
|
||||
|
||||
@@ -19,6 +19,32 @@ export function extractAssistantText(msg: AssistantMessage): string {
|
||||
return blocks.join("\n").trim();
|
||||
}
|
||||
|
||||
export function extractAssistantThinking(msg: AssistantMessage): string {
|
||||
if (!Array.isArray(msg.content)) return "";
|
||||
const blocks = msg.content
|
||||
.map((block) => {
|
||||
if (!block || typeof block !== "object") return "";
|
||||
const record = block as unknown as Record<string, unknown>;
|
||||
if (record.type === "thinking" && typeof record.thinking === "string") {
|
||||
return record.thinking.trim();
|
||||
}
|
||||
return "";
|
||||
})
|
||||
.filter(Boolean);
|
||||
return blocks.join("\n").trim();
|
||||
}
|
||||
|
||||
export function formatReasoningMarkdown(text: string): string {
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed) return "";
|
||||
const lines = trimmed.split(/\r?\n/);
|
||||
const wrapped = lines
|
||||
.map((line) => line.trim())
|
||||
.map((line) => (line ? `_${line}_` : ""))
|
||||
.filter((line) => line.length > 0);
|
||||
return wrapped.length > 0 ? [`_Reasoning:_`, ...wrapped].join("\n") : "";
|
||||
}
|
||||
|
||||
export function inferToolMetaFromArgs(
|
||||
toolName: string,
|
||||
args: unknown,
|
||||
|
||||
@@ -79,6 +79,13 @@ const CHAT_COMMANDS: ChatCommandDefinition[] = [
|
||||
textAliases: ["/verbose", "/v"],
|
||||
acceptsArgs: true,
|
||||
},
|
||||
{
|
||||
key: "reasoning",
|
||||
nativeName: "reasoning",
|
||||
description: "Toggle reasoning visibility.",
|
||||
textAliases: ["/reasoning", "/reason"],
|
||||
acceptsArgs: true,
|
||||
},
|
||||
{
|
||||
key: "elevated",
|
||||
nativeName: "elevated",
|
||||
|
||||
@@ -15,6 +15,7 @@ import { drainSystemEvents } from "../infra/system-events.js";
|
||||
import {
|
||||
extractElevatedDirective,
|
||||
extractQueueDirective,
|
||||
extractReasoningDirective,
|
||||
extractReplyToTag,
|
||||
extractThinkDirective,
|
||||
extractVerboseDirective,
|
||||
@@ -99,6 +100,12 @@ describe("directive parsing", () => {
|
||||
expect(res.verboseLevel).toBe("on");
|
||||
});
|
||||
|
||||
it("matches reasoning directive", () => {
|
||||
const res = extractReasoningDirective("/reasoning on please");
|
||||
expect(res.hasDirective).toBe(true);
|
||||
expect(res.reasoningLevel).toBe("on");
|
||||
});
|
||||
|
||||
it("matches elevated with leading space", () => {
|
||||
const res = extractElevatedDirective(" please /elevated on now");
|
||||
expect(res.hasDirective).toBe(true);
|
||||
|
||||
@@ -66,6 +66,7 @@ import type { MsgContext, TemplateContext } from "./templating.js";
|
||||
import {
|
||||
type ElevatedLevel,
|
||||
normalizeThinkLevel,
|
||||
type ReasoningLevel,
|
||||
type ThinkLevel,
|
||||
type VerboseLevel,
|
||||
} from "./thinking.js";
|
||||
@@ -75,6 +76,7 @@ import type { GetReplyOptions, ReplyPayload } from "./types.js";
|
||||
|
||||
export {
|
||||
extractElevatedDirective,
|
||||
extractReasoningDirective,
|
||||
extractThinkDirective,
|
||||
extractVerboseDirective,
|
||||
} from "./reply/directives.js";
|
||||
@@ -288,6 +290,9 @@ export async function getReplyFromConfig(
|
||||
hasVerboseDirective: false,
|
||||
verboseLevel: undefined,
|
||||
rawVerboseLevel: undefined,
|
||||
hasReasoningDirective: false,
|
||||
reasoningLevel: undefined,
|
||||
rawReasoningLevel: undefined,
|
||||
hasElevatedDirective: false,
|
||||
elevatedLevel: undefined,
|
||||
rawElevatedLevel: undefined,
|
||||
@@ -310,6 +315,7 @@ export async function getReplyFromConfig(
|
||||
const hasDirective =
|
||||
parsedDirectives.hasThinkDirective ||
|
||||
parsedDirectives.hasVerboseDirective ||
|
||||
parsedDirectives.hasReasoningDirective ||
|
||||
parsedDirectives.hasElevatedDirective ||
|
||||
parsedDirectives.hasStatusDirective ||
|
||||
parsedDirectives.hasModelDirective ||
|
||||
@@ -327,6 +333,7 @@ export async function getReplyFromConfig(
|
||||
...parsedDirectives,
|
||||
hasThinkDirective: false,
|
||||
hasVerboseDirective: false,
|
||||
hasReasoningDirective: false,
|
||||
hasStatusDirective: false,
|
||||
hasModelDirective: false,
|
||||
hasQueueDirective: false,
|
||||
@@ -377,6 +384,10 @@ export async function getReplyFromConfig(
|
||||
(directives.verboseLevel as VerboseLevel | undefined) ??
|
||||
(sessionEntry?.verboseLevel as VerboseLevel | undefined) ??
|
||||
(agentCfg?.verboseDefault as VerboseLevel | undefined);
|
||||
const resolvedReasoningLevel: ReasoningLevel =
|
||||
(directives.reasoningLevel as ReasoningLevel | undefined) ??
|
||||
(sessionEntry?.reasoningLevel as ReasoningLevel | undefined) ??
|
||||
"off";
|
||||
const resolvedElevatedLevel = elevatedAllowed
|
||||
? ((directives.elevatedLevel as ElevatedLevel | undefined) ??
|
||||
(sessionEntry?.elevatedLevel as ElevatedLevel | undefined) ??
|
||||
@@ -542,6 +553,7 @@ export async function getReplyFromConfig(
|
||||
defaultGroupActivation: () => defaultActivation,
|
||||
resolvedThinkLevel,
|
||||
resolvedVerboseLevel: resolvedVerboseLevel ?? "off",
|
||||
resolvedReasoningLevel,
|
||||
resolvedElevatedLevel,
|
||||
resolveDefaultThinkingLevel: modelState.resolveDefaultThinkingLevel,
|
||||
provider,
|
||||
@@ -734,6 +746,7 @@ export async function getReplyFromConfig(
|
||||
authProfileId,
|
||||
thinkLevel: resolvedThinkLevel,
|
||||
verboseLevel: resolvedVerboseLevel,
|
||||
reasoningLevel: resolvedReasoningLevel,
|
||||
elevatedLevel: resolvedElevatedLevel,
|
||||
bashElevated: {
|
||||
enabled: elevatedEnabled,
|
||||
|
||||
@@ -221,6 +221,7 @@ export async function runReplyAgent(params: {
|
||||
authProfileId: followupRun.run.authProfileId,
|
||||
thinkLevel: followupRun.run.thinkLevel,
|
||||
verboseLevel: followupRun.run.verboseLevel,
|
||||
reasoningLevel: followupRun.run.reasoningLevel,
|
||||
bashElevated: followupRun.run.bashElevated,
|
||||
timeoutMs: followupRun.run.timeoutMs,
|
||||
runId,
|
||||
|
||||
@@ -41,7 +41,12 @@ import {
|
||||
formatTokenCount,
|
||||
} from "../status.js";
|
||||
import type { MsgContext } from "../templating.js";
|
||||
import type { ElevatedLevel, ThinkLevel, VerboseLevel } from "../thinking.js";
|
||||
import type {
|
||||
ElevatedLevel,
|
||||
ReasoningLevel,
|
||||
ThinkLevel,
|
||||
VerboseLevel,
|
||||
} from "../thinking.js";
|
||||
import type { ReplyPayload } from "../types.js";
|
||||
import { isAbortTrigger, setAbortMemory } from "./abort.js";
|
||||
import type { InlineDirectives } from "./directive-handling.js";
|
||||
@@ -202,6 +207,7 @@ export async function handleCommands(params: {
|
||||
defaultGroupActivation: () => "always" | "mention";
|
||||
resolvedThinkLevel?: ThinkLevel;
|
||||
resolvedVerboseLevel: VerboseLevel;
|
||||
resolvedReasoningLevel: ReasoningLevel;
|
||||
resolvedElevatedLevel?: ElevatedLevel;
|
||||
resolveDefaultThinkingLevel: () => Promise<ThinkLevel | undefined>;
|
||||
provider: string;
|
||||
@@ -226,6 +232,7 @@ export async function handleCommands(params: {
|
||||
defaultGroupActivation,
|
||||
resolvedThinkLevel,
|
||||
resolvedVerboseLevel,
|
||||
resolvedReasoningLevel,
|
||||
resolvedElevatedLevel,
|
||||
resolveDefaultThinkingLevel,
|
||||
provider,
|
||||
@@ -405,6 +412,7 @@ export async function handleCommands(params: {
|
||||
resolvedThink:
|
||||
resolvedThinkLevel ?? (await resolveDefaultThinkingLevel()),
|
||||
resolvedVerbose: resolvedVerboseLevel,
|
||||
resolvedReasoning: resolvedReasoningLevel,
|
||||
resolvedElevated: resolvedElevatedLevel,
|
||||
modelAuth: resolveModelAuthLabel(provider, cfg),
|
||||
webLinked,
|
||||
|
||||
@@ -32,9 +32,11 @@ import type { ReplyPayload } from "../types.js";
|
||||
import {
|
||||
type ElevatedLevel,
|
||||
extractElevatedDirective,
|
||||
extractReasoningDirective,
|
||||
extractStatusDirective,
|
||||
extractThinkDirective,
|
||||
extractVerboseDirective,
|
||||
type ReasoningLevel,
|
||||
type ThinkLevel,
|
||||
type VerboseLevel,
|
||||
} from "./directives.js";
|
||||
@@ -155,6 +157,9 @@ export type InlineDirectives = {
|
||||
hasVerboseDirective: boolean;
|
||||
verboseLevel?: VerboseLevel;
|
||||
rawVerboseLevel?: string;
|
||||
hasReasoningDirective: boolean;
|
||||
reasoningLevel?: ReasoningLevel;
|
||||
rawReasoningLevel?: string;
|
||||
hasElevatedDirective: boolean;
|
||||
elevatedLevel?: ElevatedLevel;
|
||||
rawElevatedLevel?: string;
|
||||
@@ -188,12 +193,18 @@ export function parseInlineDirectives(body: string): InlineDirectives {
|
||||
rawLevel: rawVerboseLevel,
|
||||
hasDirective: hasVerboseDirective,
|
||||
} = extractVerboseDirective(thinkCleaned);
|
||||
const {
|
||||
cleaned: reasoningCleaned,
|
||||
reasoningLevel,
|
||||
rawLevel: rawReasoningLevel,
|
||||
hasDirective: hasReasoningDirective,
|
||||
} = extractReasoningDirective(verboseCleaned);
|
||||
const {
|
||||
cleaned: elevatedCleaned,
|
||||
elevatedLevel,
|
||||
rawLevel: rawElevatedLevel,
|
||||
hasDirective: hasElevatedDirective,
|
||||
} = extractElevatedDirective(verboseCleaned);
|
||||
} = extractElevatedDirective(reasoningCleaned);
|
||||
const { cleaned: statusCleaned, hasDirective: hasStatusDirective } =
|
||||
extractStatusDirective(elevatedCleaned);
|
||||
const {
|
||||
@@ -225,6 +236,9 @@ export function parseInlineDirectives(body: string): InlineDirectives {
|
||||
hasVerboseDirective,
|
||||
verboseLevel,
|
||||
rawVerboseLevel,
|
||||
hasReasoningDirective,
|
||||
reasoningLevel,
|
||||
rawReasoningLevel,
|
||||
hasElevatedDirective,
|
||||
elevatedLevel,
|
||||
rawElevatedLevel,
|
||||
@@ -257,6 +271,7 @@ export function isDirectiveOnly(params: {
|
||||
if (
|
||||
!directives.hasThinkDirective &&
|
||||
!directives.hasVerboseDirective &&
|
||||
!directives.hasReasoningDirective &&
|
||||
!directives.hasElevatedDirective &&
|
||||
!directives.hasModelDirective &&
|
||||
!directives.hasQueueDirective
|
||||
@@ -367,6 +382,11 @@ export async function handleDirectiveOnly(params: {
|
||||
text: `Unrecognized verbose level "${directives.rawVerboseLevel ?? ""}". Valid levels: off, on.`,
|
||||
};
|
||||
}
|
||||
if (directives.hasReasoningDirective && !directives.reasoningLevel) {
|
||||
return {
|
||||
text: `Unrecognized reasoning level "${directives.rawReasoningLevel ?? ""}". Valid levels: on, off.`,
|
||||
};
|
||||
}
|
||||
if (directives.hasElevatedDirective && !directives.elevatedLevel) {
|
||||
return {
|
||||
text: `Unrecognized elevated level "${directives.rawElevatedLevel ?? ""}". Valid levels: off, on.`,
|
||||
@@ -476,6 +496,11 @@ export async function handleDirectiveOnly(params: {
|
||||
if (directives.verboseLevel === "off") delete sessionEntry.verboseLevel;
|
||||
else sessionEntry.verboseLevel = directives.verboseLevel;
|
||||
}
|
||||
if (directives.hasReasoningDirective && directives.reasoningLevel) {
|
||||
if (directives.reasoningLevel === "off")
|
||||
delete sessionEntry.reasoningLevel;
|
||||
else sessionEntry.reasoningLevel = directives.reasoningLevel;
|
||||
}
|
||||
if (directives.hasElevatedDirective && directives.elevatedLevel) {
|
||||
if (directives.elevatedLevel === "off") delete sessionEntry.elevatedLevel;
|
||||
else sessionEntry.elevatedLevel = directives.elevatedLevel;
|
||||
@@ -533,6 +558,13 @@ export async function handleDirectiveOnly(params: {
|
||||
: `${SYSTEM_MARK} Verbose logging enabled.`,
|
||||
);
|
||||
}
|
||||
if (directives.hasReasoningDirective && directives.reasoningLevel) {
|
||||
parts.push(
|
||||
directives.reasoningLevel === "off"
|
||||
? `${SYSTEM_MARK} Reasoning visibility disabled.`
|
||||
: `${SYSTEM_MARK} Reasoning visibility enabled.`,
|
||||
);
|
||||
}
|
||||
if (directives.hasElevatedDirective && directives.elevatedLevel) {
|
||||
parts.push(
|
||||
directives.elevatedLevel === "off"
|
||||
@@ -634,6 +666,14 @@ export async function persistInlineDirectives(params: {
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
if (directives.hasReasoningDirective && directives.reasoningLevel) {
|
||||
if (directives.reasoningLevel === "off") {
|
||||
delete sessionEntry.reasoningLevel;
|
||||
} else {
|
||||
sessionEntry.reasoningLevel = directives.reasoningLevel;
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
if (
|
||||
directives.hasElevatedDirective &&
|
||||
directives.elevatedLevel &&
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { ReasoningLevel } from "../thinking.js";
|
||||
import {
|
||||
type ElevatedLevel,
|
||||
normalizeElevatedLevel,
|
||||
normalizeReasoningLevel,
|
||||
normalizeThinkLevel,
|
||||
normalizeVerboseLevel,
|
||||
type ThinkLevel,
|
||||
@@ -74,6 +76,28 @@ export function extractElevatedDirective(body?: string): {
|
||||
};
|
||||
}
|
||||
|
||||
export function extractReasoningDirective(body?: string): {
|
||||
cleaned: string;
|
||||
reasoningLevel?: ReasoningLevel;
|
||||
rawLevel?: string;
|
||||
hasDirective: boolean;
|
||||
} {
|
||||
if (!body) return { cleaned: "", hasDirective: false };
|
||||
const match = body.match(
|
||||
/(?:^|\s)\/(?:reasoning|reason)(?=$|\s|:)\s*:?\s*([a-zA-Z-]+)\b/i,
|
||||
);
|
||||
const reasoningLevel = normalizeReasoningLevel(match?.[1]);
|
||||
const cleaned = match
|
||||
? body.replace(match[0], "").replace(/\s+/g, " ").trim()
|
||||
: body.trim();
|
||||
return {
|
||||
cleaned,
|
||||
reasoningLevel,
|
||||
rawLevel: match?.[1],
|
||||
hasDirective: !!match,
|
||||
};
|
||||
}
|
||||
|
||||
export function extractStatusDirective(body?: string): {
|
||||
cleaned: string;
|
||||
hasDirective: boolean;
|
||||
@@ -89,4 +113,4 @@ export function extractStatusDirective(body?: string): {
|
||||
};
|
||||
}
|
||||
|
||||
export type { ElevatedLevel, ThinkLevel, VerboseLevel };
|
||||
export type { ElevatedLevel, ReasoningLevel, ThinkLevel, VerboseLevel };
|
||||
|
||||
@@ -131,6 +131,7 @@ export function createFollowupRunner(params: {
|
||||
authProfileId: queued.run.authProfileId,
|
||||
thinkLevel: queued.run.thinkLevel,
|
||||
verboseLevel: queued.run.verboseLevel,
|
||||
reasoningLevel: queued.run.reasoningLevel,
|
||||
bashElevated: queued.run.bashElevated,
|
||||
timeoutMs: queued.run.timeoutMs,
|
||||
runId,
|
||||
|
||||
@@ -4,7 +4,12 @@ import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import type { OriginatingChannelType } from "../templating.js";
|
||||
import type { ElevatedLevel, ThinkLevel, VerboseLevel } from "./directives.js";
|
||||
import type {
|
||||
ElevatedLevel,
|
||||
ReasoningLevel,
|
||||
ThinkLevel,
|
||||
VerboseLevel,
|
||||
} from "./directives.js";
|
||||
import { isRoutableChannel } from "./route-reply.js";
|
||||
export type QueueMode =
|
||||
| "steer"
|
||||
@@ -54,6 +59,7 @@ export type FollowupRun = {
|
||||
authProfileId?: string;
|
||||
thinkLevel?: ThinkLevel;
|
||||
verboseLevel?: VerboseLevel;
|
||||
reasoningLevel?: ReasoningLevel;
|
||||
elevatedLevel?: ElevatedLevel;
|
||||
bashElevated?: {
|
||||
enabled: boolean;
|
||||
|
||||
@@ -20,7 +20,12 @@ import {
|
||||
type SessionScope,
|
||||
} from "../config/sessions.js";
|
||||
import { shortenHomePath } from "../utils.js";
|
||||
import type { ElevatedLevel, ThinkLevel, VerboseLevel } from "./thinking.js";
|
||||
import type {
|
||||
ElevatedLevel,
|
||||
ReasoningLevel,
|
||||
ThinkLevel,
|
||||
VerboseLevel,
|
||||
} from "./thinking.js";
|
||||
|
||||
type AgentConfig = NonNullable<ClawdbotConfig["agent"]>;
|
||||
|
||||
@@ -34,6 +39,7 @@ type StatusArgs = {
|
||||
groupActivation?: "mention" | "always";
|
||||
resolvedThink?: ThinkLevel;
|
||||
resolvedVerbose?: VerboseLevel;
|
||||
resolvedReasoning?: ReasoningLevel;
|
||||
resolvedElevated?: ElevatedLevel;
|
||||
modelAuth?: string;
|
||||
now?: number;
|
||||
@@ -173,6 +179,7 @@ export function buildStatusMessage(args: StatusArgs): string {
|
||||
const thinkLevel = args.resolvedThink ?? args.agent?.thinkingDefault ?? "off";
|
||||
const verboseLevel =
|
||||
args.resolvedVerbose ?? args.agent?.verboseDefault ?? "off";
|
||||
const reasoningLevel = args.resolvedReasoning ?? "off";
|
||||
const elevatedLevel =
|
||||
args.resolvedElevated ??
|
||||
args.sessionEntry?.elevatedLevel ??
|
||||
@@ -241,8 +248,8 @@ export function buildStatusMessage(args: StatusArgs): string {
|
||||
)}${entry?.abortedLastRun ? " • last run aborted" : ""}`;
|
||||
|
||||
const optionsLine = runtime.sandboxed
|
||||
? `Options: thinking=${thinkLevel} | verbose=${verboseLevel} | elevated=${elevatedLevel}`
|
||||
: `Options: thinking=${thinkLevel} | verbose=${verboseLevel}`;
|
||||
? `Options: thinking=${thinkLevel} | verbose=${verboseLevel} | reasoning=${reasoningLevel} | elevated=${elevatedLevel}`
|
||||
: `Options: thinking=${thinkLevel} | verbose=${verboseLevel} | reasoning=${reasoningLevel}`;
|
||||
|
||||
const modelLabel = model ? `${provider}/${model}` : "unknown";
|
||||
|
||||
@@ -273,6 +280,6 @@ export function buildHelpMessage(): string {
|
||||
return [
|
||||
"ℹ️ Help",
|
||||
"Shortcuts: /new reset | /compact [instructions] | /restart relink",
|
||||
"Options: /think <level> | /verbose on|off | /elevated on|off | /model <id>",
|
||||
"Options: /think <level> | /verbose on|off | /reasoning on|off | /elevated on|off | /model <id>",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeThinkLevel } from "./thinking.js";
|
||||
import { normalizeReasoningLevel, normalizeThinkLevel } from "./thinking.js";
|
||||
|
||||
describe("normalizeThinkLevel", () => {
|
||||
it("accepts mid as medium", () => {
|
||||
expect(normalizeThinkLevel("mid")).toBe("medium");
|
||||
});
|
||||
});
|
||||
|
||||
describe("normalizeReasoningLevel", () => {
|
||||
it("accepts on/off", () => {
|
||||
expect(normalizeReasoningLevel("on")).toBe("on");
|
||||
expect(normalizeReasoningLevel("off")).toBe("off");
|
||||
});
|
||||
|
||||
it("accepts show/hide", () => {
|
||||
expect(normalizeReasoningLevel("show")).toBe("on");
|
||||
expect(normalizeReasoningLevel("hide")).toBe("off");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export type ThinkLevel = "off" | "minimal" | "low" | "medium" | "high";
|
||||
export type VerboseLevel = "off" | "on";
|
||||
export type ElevatedLevel = "off" | "on";
|
||||
export type ReasoningLevel = "off" | "on";
|
||||
|
||||
// Normalize user-provided thinking level strings to the canonical enum.
|
||||
export function normalizeThinkLevel(
|
||||
@@ -55,3 +56,31 @@ export function normalizeElevatedLevel(
|
||||
if (["on", "true", "yes", "1"].includes(key)) return "on";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Normalize reasoning visibility flags used to toggle reasoning exposure.
|
||||
export function normalizeReasoningLevel(
|
||||
raw?: string | null,
|
||||
): ReasoningLevel | undefined {
|
||||
if (!raw) return undefined;
|
||||
const key = raw.toLowerCase();
|
||||
if (
|
||||
[
|
||||
"off",
|
||||
"false",
|
||||
"no",
|
||||
"0",
|
||||
"hide",
|
||||
"hidden",
|
||||
"disable",
|
||||
"disabled",
|
||||
].includes(key)
|
||||
)
|
||||
return "off";
|
||||
if (
|
||||
["on", "true", "yes", "1", "show", "visible", "enable", "enabled"].includes(
|
||||
key,
|
||||
)
|
||||
)
|
||||
return "on";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ type SessionRow = {
|
||||
abortedLastRun?: boolean;
|
||||
thinkingLevel?: string;
|
||||
verboseLevel?: string;
|
||||
reasoningLevel?: string;
|
||||
groupActivation?: string;
|
||||
inputTokens?: number;
|
||||
outputTokens?: number;
|
||||
@@ -99,6 +100,7 @@ const formatFlagsCell = (row: SessionRow, rich: boolean) => {
|
||||
const flags = [
|
||||
row.thinkingLevel ? `think:${row.thinkingLevel}` : null,
|
||||
row.verboseLevel ? `verbose:${row.verboseLevel}` : null,
|
||||
row.reasoningLevel ? `reasoning:${row.reasoningLevel}` : null,
|
||||
row.groupActivation ? `activation:${row.groupActivation}` : null,
|
||||
row.systemSent ? "system" : null,
|
||||
row.abortedLastRun ? "aborted" : null,
|
||||
@@ -147,6 +149,7 @@ function toRows(store: Record<string, SessionEntry>): SessionRow[] {
|
||||
abortedLastRun: entry?.abortedLastRun,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
groupActivation: entry?.groupActivation,
|
||||
inputTokens: entry?.inputTokens,
|
||||
outputTokens: entry?.outputTokens,
|
||||
|
||||
@@ -33,6 +33,7 @@ export type SessionStatus = {
|
||||
age: number | null;
|
||||
thinkingLevel?: string;
|
||||
verboseLevel?: string;
|
||||
reasoningLevel?: string;
|
||||
elevatedLevel?: string;
|
||||
systemSent?: boolean;
|
||||
abortedLastRun?: boolean;
|
||||
@@ -111,6 +112,7 @@ export async function getStatusSummary(): Promise<StatusSummary> {
|
||||
age,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
elevatedLevel: entry?.elevatedLevel,
|
||||
systemSent: entry?.systemSent,
|
||||
abortedLastRun: entry?.abortedLastRun,
|
||||
@@ -198,6 +200,9 @@ const buildFlags = (entry: SessionEntry): string[] => {
|
||||
const verbose = entry?.verboseLevel;
|
||||
if (typeof verbose === "string" && verbose.length > 0)
|
||||
flags.push(`verbose:${verbose}`);
|
||||
const reasoning = entry?.reasoningLevel;
|
||||
if (typeof reasoning === "string" && reasoning.length > 0)
|
||||
flags.push(`reasoning:${reasoning}`);
|
||||
const elevated = entry?.elevatedLevel;
|
||||
if (typeof elevated === "string" && elevated.length > 0)
|
||||
flags.push(`elevated:${elevated}`);
|
||||
|
||||
@@ -40,6 +40,7 @@ export type SessionEntry = {
|
||||
chatType?: SessionChatType;
|
||||
thinkingLevel?: string;
|
||||
verboseLevel?: string;
|
||||
reasoningLevel?: string;
|
||||
elevatedLevel?: string;
|
||||
providerOverride?: string;
|
||||
modelOverride?: string;
|
||||
|
||||
@@ -323,6 +323,7 @@ export const SessionsPatchParamsSchema = Type.Object(
|
||||
key: NonEmptyString,
|
||||
thinkingLevel: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
|
||||
verboseLevel: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
|
||||
reasoningLevel: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
|
||||
elevatedLevel: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
|
||||
model: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
|
||||
spawnedBy: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
|
||||
|
||||
@@ -20,6 +20,7 @@ import { resolveAgentTimeoutMs } from "../agents/timeout.js";
|
||||
import { normalizeGroupActivation } from "../auto-reply/group-activation.js";
|
||||
import {
|
||||
normalizeElevatedLevel,
|
||||
normalizeReasoningLevel,
|
||||
normalizeThinkLevel,
|
||||
normalizeVerboseLevel,
|
||||
} from "../auto-reply/thinking.js";
|
||||
@@ -434,6 +435,26 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
|
||||
}
|
||||
}
|
||||
|
||||
if ("reasoningLevel" in p) {
|
||||
const raw = p.reasoningLevel;
|
||||
if (raw === null) {
|
||||
delete next.reasoningLevel;
|
||||
} else if (raw !== undefined) {
|
||||
const normalized = normalizeReasoningLevel(String(raw));
|
||||
if (!normalized) {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.INVALID_REQUEST,
|
||||
message: `invalid reasoningLevel: ${String(raw)}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (normalized === "off") delete next.reasoningLevel;
|
||||
else next.reasoningLevel = normalized;
|
||||
}
|
||||
}
|
||||
|
||||
if ("elevatedLevel" in p) {
|
||||
const raw = p.elevatedLevel;
|
||||
if (raw === null) {
|
||||
@@ -602,6 +623,7 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
|
||||
abortedLastRun: false,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
model: entry?.model,
|
||||
contextTokens: entry?.contextTokens,
|
||||
sendPolicy: entry?.sendPolicy,
|
||||
@@ -986,6 +1008,7 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
|
||||
updatedAt: now,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
systemSent: entry?.systemSent,
|
||||
lastProvider: entry?.lastProvider,
|
||||
lastTo: entry?.lastTo,
|
||||
@@ -1125,6 +1148,7 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
|
||||
updatedAt: now,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
systemSent: entry?.systemSent,
|
||||
sendPolicy: entry?.sendPolicy,
|
||||
lastProvider: entry?.lastProvider,
|
||||
@@ -1207,6 +1231,7 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
|
||||
updatedAt: now,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
systemSent: entry?.systemSent,
|
||||
sendPolicy: entry?.sendPolicy,
|
||||
lastProvider: entry?.lastProvider,
|
||||
|
||||
@@ -82,6 +82,7 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
updatedAt: now,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
systemSent: entry?.systemSent,
|
||||
sendPolicy: entry?.sendPolicy,
|
||||
skillsSnapshot: entry?.skillsSnapshot,
|
||||
|
||||
@@ -200,6 +200,7 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
updatedAt: now,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
systemSent: entry?.systemSent,
|
||||
sendPolicy: entry?.sendPolicy,
|
||||
lastProvider: entry?.lastProvider,
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
} from "../../agents/pi-embedded.js";
|
||||
import { normalizeGroupActivation } from "../../auto-reply/group-activation.js";
|
||||
import {
|
||||
normalizeReasoningLevel,
|
||||
normalizeThinkLevel,
|
||||
normalizeVerboseLevel,
|
||||
} from "../../auto-reply/thinking.js";
|
||||
@@ -211,6 +212,28 @@ export const sessionsHandlers: GatewayRequestHandlers = {
|
||||
}
|
||||
}
|
||||
|
||||
if ("reasoningLevel" in p) {
|
||||
const raw = p.reasoningLevel;
|
||||
if (raw === null) {
|
||||
delete next.reasoningLevel;
|
||||
} else if (raw !== undefined) {
|
||||
const normalized = normalizeReasoningLevel(String(raw));
|
||||
if (!normalized) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
'invalid reasoningLevel (use "on"|"off")',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (normalized === "off") delete next.reasoningLevel;
|
||||
else next.reasoningLevel = normalized;
|
||||
}
|
||||
}
|
||||
|
||||
if ("model" in p) {
|
||||
const raw = p.model;
|
||||
if (raw === null) {
|
||||
@@ -370,6 +393,7 @@ export const sessionsHandlers: GatewayRequestHandlers = {
|
||||
abortedLastRun: false,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
model: entry?.model,
|
||||
contextTokens: entry?.contextTokens,
|
||||
sendPolicy: entry?.sendPolicy,
|
||||
|
||||
@@ -43,6 +43,7 @@ export type GatewaySessionRow = {
|
||||
abortedLastRun?: boolean;
|
||||
thinkingLevel?: string;
|
||||
verboseLevel?: string;
|
||||
reasoningLevel?: string;
|
||||
elevatedLevel?: string;
|
||||
sendPolicy?: "allow" | "deny";
|
||||
inputTokens?: number;
|
||||
@@ -441,6 +442,7 @@ export function listSessionsFromStore(params: {
|
||||
abortedLastRun: entry?.abortedLastRun,
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
elevatedLevel: entry?.elevatedLevel,
|
||||
sendPolicy: entry?.sendPolicy,
|
||||
inputTokens: entry?.inputTokens,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { SlashCommand } from "@mariozechner/pi-tui";
|
||||
|
||||
const THINK_LEVELS = ["off", "minimal", "low", "medium", "high"];
|
||||
const VERBOSE_LEVELS = ["on", "off"];
|
||||
const REASONING_LEVELS = ["on", "off"];
|
||||
const ELEVATED_LEVELS = ["on", "off"];
|
||||
const ACTIVATION_LEVELS = ["mention", "always"];
|
||||
const TOGGLE = ["on", "off"];
|
||||
@@ -53,6 +54,14 @@ export function getSlashCommands(): SlashCommand[] {
|
||||
(value) => ({ value, label: value }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "reasoning",
|
||||
description: "Set reasoning on/off",
|
||||
getArgumentCompletions: (prefix) =>
|
||||
REASONING_LEVELS.filter((v) => v.startsWith(prefix.toLowerCase())).map(
|
||||
(value) => ({ value, label: value }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "elevated",
|
||||
description: "Set elevated on/off",
|
||||
@@ -103,6 +112,7 @@ export function helpText(): string {
|
||||
"/model <provider/model> (or /models)",
|
||||
"/think <off|minimal|low|medium|high>",
|
||||
"/verbose <on|off>",
|
||||
"/reasoning <on|off>",
|
||||
"/elevated <on|off>",
|
||||
"/elev <on|off>",
|
||||
"/activation <mention|always>",
|
||||
|
||||
@@ -40,6 +40,7 @@ export type GatewaySessionList = {
|
||||
updatedAt?: number | null;
|
||||
thinkingLevel?: string;
|
||||
verboseLevel?: string;
|
||||
reasoningLevel?: string;
|
||||
sendPolicy?: string;
|
||||
model?: string;
|
||||
contextTokens?: number | null;
|
||||
|
||||
@@ -45,6 +45,7 @@ type AgentEvent = {
|
||||
type SessionInfo = {
|
||||
thinkingLevel?: string;
|
||||
verboseLevel?: string;
|
||||
reasoningLevel?: string;
|
||||
model?: string;
|
||||
contextTokens?: number | null;
|
||||
totalTokens?: number | null;
|
||||
@@ -167,10 +168,11 @@ export async function runTui(opts: TuiOptions) {
|
||||
);
|
||||
const think = sessionInfo.thinkingLevel ?? "off";
|
||||
const verbose = sessionInfo.verboseLevel ?? "off";
|
||||
const reasoning = sessionInfo.reasoningLevel ?? "off";
|
||||
const deliver = deliverDefault ? "on" : "off";
|
||||
footer.setText(
|
||||
theme.dim(
|
||||
`${connection} | session ${sessionLabel} | model ${modelLabel} | think ${think} | verbose ${verbose} | ${tokens} | deliver ${deliver}`,
|
||||
`${connection} | session ${sessionLabel} | model ${modelLabel} | think ${think} | verbose ${verbose} | reasoning ${reasoning} | ${tokens} | deliver ${deliver}`,
|
||||
),
|
||||
);
|
||||
};
|
||||
@@ -198,6 +200,7 @@ export async function runTui(opts: TuiOptions) {
|
||||
sessionInfo = {
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
reasoningLevel: entry?.reasoningLevel,
|
||||
model: entry?.model ?? result.defaults?.model ?? undefined,
|
||||
contextTokens: entry?.contextTokens ?? result.defaults?.contextTokens,
|
||||
totalTokens: entry?.totalTokens ?? null,
|
||||
@@ -586,6 +589,22 @@ export async function runTui(opts: TuiOptions) {
|
||||
chatLog.addSystem(`verbose failed: ${String(err)}`);
|
||||
}
|
||||
break;
|
||||
case "reasoning":
|
||||
if (!args) {
|
||||
chatLog.addSystem("usage: /reasoning <on|off>");
|
||||
break;
|
||||
}
|
||||
try {
|
||||
await client.patchSession({
|
||||
key: currentSessionKey,
|
||||
reasoningLevel: args,
|
||||
});
|
||||
chatLog.addSystem(`reasoning set to ${args}`);
|
||||
await refreshSessionInfo();
|
||||
} catch (err) {
|
||||
chatLog.addSystem(`reasoning failed: ${String(err)}`);
|
||||
}
|
||||
break;
|
||||
case "elevated":
|
||||
if (!args) {
|
||||
chatLog.addSystem("usage: /elevated <on|off>");
|
||||
|
||||
@@ -226,6 +226,7 @@ export type GatewaySessionRow = {
|
||||
abortedLastRun?: boolean;
|
||||
thinkingLevel?: string;
|
||||
verboseLevel?: string;
|
||||
reasoningLevel?: string;
|
||||
elevatedLevel?: string;
|
||||
inputTokens?: number;
|
||||
outputTokens?: number;
|
||||
@@ -251,6 +252,7 @@ export type SessionsPatchResult = {
|
||||
updatedAt?: number;
|
||||
thinkingLevel?: string;
|
||||
verboseLevel?: string;
|
||||
reasoningLevel?: string;
|
||||
elevatedLevel?: string;
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user