pzero-operator 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -52,9 +52,9 @@ export function parseSkillBlock(text) {
52
52
  // Constants
53
53
  // ============================================================================
54
54
  /** Standard thinking levels */
55
- const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high"];
55
+ const THINKING_LEVELS = ["off", "low", "medium", "high"];
56
56
  /** Thinking levels including xhigh (for supported models) */
57
- const THINKING_LEVELS_WITH_XHIGH = ["off", "minimal", "low", "medium", "high", "xhigh"];
57
+ const THINKING_LEVELS_WITH_XHIGH = ["off", "low", "medium", "high", "xhigh"];
58
58
  // ============================================================================
59
59
  // AgentSession Class
60
60
  // ============================================================================
@@ -1887,7 +1887,7 @@ export class AgentSession {
1887
1887
  this._applyExtensionBindings(this._extensionRunner);
1888
1888
  const defaultActiveToolNames = this._baseToolsOverride
1889
1889
  ? Object.keys(this._baseToolsOverride)
1890
- : ["read", "bash", "edit", "write"];
1890
+ : ["read", "bash", "edit", "write", "web_search"];
1891
1891
  const baseActiveToolNames = options.activeToolNames ?? defaultActiveToolNames;
1892
1892
  this._refreshToolRegistry({
1893
1893
  activeToolNames: baseActiveToolNames,
@@ -25,6 +25,7 @@ export const KEYBINDINGS = {
25
25
  },
26
26
  "app.model.select": { defaultKeys: "ctrl+l", description: "Open model selector" },
27
27
  "app.tools.expand": { defaultKeys: "ctrl+o", description: "Toggle tool output" },
28
+ "app.history.full": { defaultKeys: "ctrl+r", description: "Toggle full conversation view" },
28
29
  "app.thinking.toggle": {
29
30
  defaultKeys: "ctrl+t",
30
31
  description: "Toggle thinking blocks",
package/dist/core/sdk.js CHANGED
@@ -13,12 +13,12 @@ import { getDefaultSessionDir, SessionManager } from "./session-manager.js";
13
13
  import { SettingsManager } from "./settings-manager.js";
14
14
  import { isInstallTelemetryEnabled } from "./telemetry.js";
15
15
  import { time } from "./timings.js";
16
- import { createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue, } from "./tools/index.js";
16
+ import { createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWebSearchTool, createWriteTool, withFileMutationQueue, } from "./tools/index.js";
17
17
  // Re-exports
18
18
  export * from "./agent-session-runtime.js";
19
19
  export { withFileMutationQueue,
20
20
  // Tool factories (for custom cwd)
21
- createCodingTools, createReadOnlyTools, createReadTool, createBashTool, createEditTool, createWriteTool, createGrepTool, createFindTool, createLsTool, };
21
+ createCodingTools, createReadOnlyTools, createReadTool, createBashTool, createEditTool, createWriteTool, createGrepTool, createFindTool, createLsTool, createWebSearchTool, };
22
22
  // Helper Functions
23
23
  function getDefaultAgentDir() {
24
24
  return getAgentDir();
@@ -135,7 +135,7 @@ export async function createAgentSession(options = {}) {
135
135
  if (!model || !model.reasoning) {
136
136
  thinkingLevel = "off";
137
137
  }
138
- const defaultActiveToolNames = ["read", "bash", "edit", "write"];
138
+ const defaultActiveToolNames = ["read", "bash", "edit", "write", "web_search"];
139
139
  const initialActiveToolNames = options.tools ? [...options.tools] : defaultActiveToolNames;
140
140
  let agent;
141
141
  // Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)
@@ -45,7 +45,7 @@ export function buildSystemPrompt(options) {
45
45
  const examplesPath = getExamplesPath();
46
46
  // Build tools list based on selected tools.
47
47
  // A tool appears in Available tools only when the caller provides a one-line snippet.
48
- const tools = selectedTools || ["read", "bash", "edit", "write"];
48
+ const tools = selectedTools || ["read", "bash", "edit", "write", "web_search"];
49
49
  const visibleTools = tools.filter((name) => !!toolSnippets?.[name]);
50
50
  const toolsList = visibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets[name]}`).join("\n") : "(none)";
51
51
  // Build guidelines based on which tools are actually available
@@ -63,6 +63,7 @@ export function buildSystemPrompt(options) {
63
63
  const hasFind = tools.includes("find");
64
64
  const hasLs = tools.includes("ls");
65
65
  const hasRead = tools.includes("read");
66
+ const hasWebSearch = tools.includes("web_search");
66
67
  // File exploration guidelines
67
68
  if (hasBash && !hasGrep && !hasFind && !hasLs) {
68
69
  addGuideline("Use bash for file operations like ls, rg, find");
@@ -70,6 +71,9 @@ export function buildSystemPrompt(options) {
70
71
  else if (hasBash && (hasGrep || hasFind || hasLs)) {
71
72
  addGuideline("Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)");
72
73
  }
74
+ if (hasWebSearch) {
75
+ addGuideline("Use web_search for current external information, public docs, and recent web content.");
76
+ }
73
77
  for (const guideline of promptGuidelines ?? []) {
74
78
  const normalized = guideline.trim();
75
79
  if (normalized.length > 0) {
@@ -36,7 +36,7 @@ export function createLocalBashOperations(options) {
36
36
  return new Promise((resolve, reject) => {
37
37
  const { shell, args } = getShellConfig(options?.shellPath);
38
38
  if (!existsSync(cwd)) {
39
- reject(new Error(`Working directory does not exist: ${cwd}\nCannot execute bash commands.`));
39
+ reject(new Error(`Working directory does not exist: ${cwd}\nCannot execute shell commands.`));
40
40
  return;
41
41
  }
42
42
  const child = spawn(shell, [...args, command], {
@@ -119,6 +119,30 @@ class BashResultRenderComponent extends Container {
119
119
  function formatDuration(ms) {
120
120
  return `${(ms / 1000).toFixed(1)}s`;
121
121
  }
122
+ function getShellPromptText(shellPath) {
123
+ try {
124
+ const shellConfig = getShellConfig(shellPath);
125
+ if (process.platform === "win32") {
126
+ if (shellConfig.kind === "powershell") {
127
+ return {
128
+ description: `Execute a ${shellConfig.displayName} command in the current working directory. Returns stdout and stderr. Prefer Windows-native commands and PowerShell syntax. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
129
+ promptSnippet: "Execute PowerShell commands on Windows (Get-ChildItem, Select-String, Test-Path, Remove-Item, etc.)",
130
+ };
131
+ }
132
+ return {
133
+ description: `Execute a shell command in the current working directory using ${shellConfig.displayName}. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
134
+ promptSnippet: "Execute shell commands on Windows using Bash (ls, grep, find, etc.)",
135
+ };
136
+ }
137
+ }
138
+ catch {
139
+ // Fall back to the default Unix-oriented prompt text if shell discovery fails.
140
+ }
141
+ return {
142
+ description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
143
+ promptSnippet: "Execute bash commands (ls, grep, find, etc.)",
144
+ };
145
+ }
122
146
  function formatBashCall(args) {
123
147
  const command = str(args?.command);
124
148
  const timeout = args?.timeout;
@@ -192,11 +216,12 @@ export function createBashToolDefinition(cwd, options) {
192
216
  const ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });
193
217
  const commandPrefix = options?.commandPrefix;
194
218
  const spawnHook = options?.spawnHook;
219
+ const promptText = getShellPromptText(options?.shellPath);
195
220
  return {
196
221
  name: "bash",
197
222
  label: "terminal.exec",
198
- description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
199
- promptSnippet: "Execute bash commands (ls, grep, find, etc.)",
223
+ description: promptText.description,
224
+ promptSnippet: promptText.promptSnippet,
200
225
  parameters: bashSchema,
201
226
  async execute(_toolCallId, { command, timeout }, signal, onUpdate, _ctx) {
202
227
  const resolvedCommand = commandPrefix ? `${commandPrefix}\n${command}` : command;
@@ -6,6 +6,7 @@ export { createGrepTool, createGrepToolDefinition, } from "./grep.js";
6
6
  export { createLsTool, createLsToolDefinition, } from "./ls.js";
7
7
  export { createReadTool, createReadToolDefinition, } from "./read.js";
8
8
  export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead, truncateLine, truncateTail, } from "./truncate.js";
9
+ export { createWebSearchTool, createWebSearchToolDefinition, } from "./web-search.js";
9
10
  export { createWriteTool, createWriteToolDefinition, } from "./write.js";
10
11
  import { createBashTool, createBashToolDefinition } from "./bash.js";
11
12
  import { createEditTool, createEditToolDefinition } from "./edit.js";
@@ -13,8 +14,9 @@ import { createFindTool, createFindToolDefinition } from "./find.js";
13
14
  import { createGrepTool, createGrepToolDefinition } from "./grep.js";
14
15
  import { createLsTool, createLsToolDefinition } from "./ls.js";
15
16
  import { createReadTool, createReadToolDefinition } from "./read.js";
17
+ import { createWebSearchTool, createWebSearchToolDefinition } from "./web-search.js";
16
18
  import { createWriteTool, createWriteToolDefinition } from "./write.js";
17
- export const allToolNames = new Set(["read", "bash", "edit", "write", "grep", "find", "ls"]);
19
+ export const allToolNames = new Set(["read", "bash", "edit", "write", "grep", "find", "ls", "web_search"]);
18
20
  export function createToolDefinition(toolName, cwd, options) {
19
21
  switch (toolName) {
20
22
  case "read":
@@ -31,6 +33,8 @@ export function createToolDefinition(toolName, cwd, options) {
31
33
  return createFindToolDefinition(cwd, options?.find);
32
34
  case "ls":
33
35
  return createLsToolDefinition(cwd, options?.ls);
36
+ case "web_search":
37
+ return createWebSearchToolDefinition(cwd, options?.web_search);
34
38
  default:
35
39
  throw new Error(`Unknown tool name: ${toolName}`);
36
40
  }
@@ -51,6 +55,8 @@ export function createTool(toolName, cwd, options) {
51
55
  return createFindTool(cwd, options?.find);
52
56
  case "ls":
53
57
  return createLsTool(cwd, options?.ls);
58
+ case "web_search":
59
+ return createWebSearchTool(cwd, options?.web_search);
54
60
  default:
55
61
  throw new Error(`Unknown tool name: ${toolName}`);
56
62
  }
@@ -61,6 +67,7 @@ export function createCodingToolDefinitions(cwd, options) {
61
67
  createBashToolDefinition(cwd, options?.bash),
62
68
  createEditToolDefinition(cwd, options?.edit),
63
69
  createWriteToolDefinition(cwd, options?.write),
70
+ createWebSearchToolDefinition(cwd, options?.web_search),
64
71
  ];
65
72
  }
66
73
  export function createReadOnlyToolDefinitions(cwd, options) {
@@ -80,6 +87,7 @@ export function createAllToolDefinitions(cwd, options) {
80
87
  grep: createGrepToolDefinition(cwd, options?.grep),
81
88
  find: createFindToolDefinition(cwd, options?.find),
82
89
  ls: createLsToolDefinition(cwd, options?.ls),
90
+ web_search: createWebSearchToolDefinition(cwd, options?.web_search),
83
91
  };
84
92
  }
85
93
  export function createCodingTools(cwd, options) {
@@ -88,6 +96,7 @@ export function createCodingTools(cwd, options) {
88
96
  createBashTool(cwd, options?.bash),
89
97
  createEditTool(cwd, options?.edit),
90
98
  createWriteTool(cwd, options?.write),
99
+ createWebSearchTool(cwd, options?.web_search),
91
100
  ];
92
101
  }
93
102
  export function createReadOnlyTools(cwd, options) {
@@ -107,6 +116,7 @@ export function createAllTools(cwd, options) {
107
116
  grep: createGrepTool(cwd, options?.grep),
108
117
  find: createFindTool(cwd, options?.find),
109
118
  ls: createLsTool(cwd, options?.ls),
119
+ web_search: createWebSearchTool(cwd, options?.web_search),
110
120
  };
111
121
  }
112
- //# sourceMappingURL=index.js.map
122
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,162 @@
1
+ import { Text } from "@operator/tui";
2
+ import { spawn } from "child_process";
3
+ import { existsSync } from "fs";
4
+ import { Type } from "typebox";
5
+ import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
6
+ import { getTextOutput, invalidArgText, str } from "./render-utils.js";
7
+ import { wrapToolDefinition } from "./tool-definition-wrapper.js";
8
+ import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from "./truncate.js";
9
+ const WEB_SEARCH_HELPER = `${process.env.HOME || ""}/.tools/web_search/search.cjs`;
10
+ const webSearchSchema = Type.Object({
11
+ query: Type.Optional(Type.String({ description: "Search query for full, ddg, instant, or wiki modes" })),
12
+ url: Type.Optional(Type.String({ description: "Page URL to extract when mode is 'page'" })),
13
+ mode: Type.Optional(Type.Union([
14
+ Type.Literal("full"),
15
+ Type.Literal("ddg"),
16
+ Type.Literal("instant"),
17
+ Type.Literal("wiki"),
18
+ Type.Literal("page"),
19
+ ], { description: "Search mode (default: full)" })),
20
+ limit: Type.Optional(Type.Number({ description: "Maximum number of results for ddg/wiki/full (default: 5)" })),
21
+ });
22
+ function formatWebSearchCall(args, theme) {
23
+ const mode = str(args?.mode) || "full";
24
+ const query = str(args?.query);
25
+ const url = str(args?.url);
26
+ const target = mode === "page" ? url : query;
27
+ const invalidArg = invalidArgText(theme);
28
+ return `${theme.fg("toolTitle", theme.bold("web.search"))} ${theme.fg("toolOutput", `[${mode}] `)}${target === null ? invalidArg : theme.fg("accent", target || "...")}`;
29
+ }
30
+ function formatWebSearchResult(result, options, theme, showImages) {
31
+ const output = getTextOutput(result, showImages).trim();
32
+ if (!output) {
33
+ return "";
34
+ }
35
+ const lines = output.split("\n");
36
+ const maxLines = options.expanded ? lines.length : 20;
37
+ const displayLines = lines.slice(0, maxLines);
38
+ const remaining = lines.length - maxLines;
39
+ let text = `\n${displayLines.map((line) => theme.fg("toolOutput", line)).join("\n")}`;
40
+ if (remaining > 0) {
41
+ text += `${theme.fg("muted", `\n... (${remaining} more lines,`)} ${keyHint("app.tools.expand", "to expand")})`;
42
+ }
43
+ const truncation = result.details?.truncation;
44
+ if (truncation?.truncated) {
45
+ text += `\n${theme.fg("warning", `[Truncated: ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`)}`;
46
+ }
47
+ return text;
48
+ }
49
+ export function createWebSearchToolDefinition(_cwd, _options) {
50
+ return {
51
+ name: "web_search",
52
+ label: "web.search",
53
+ description: `Search the web using DuckDuckGo and Wikipedia, or extract readable text from a web page. Best for current external information, documentation, and quick validation. Output is truncated to ${DEFAULT_MAX_BYTES / 1024}KB if needed.`,
54
+ promptSnippet: "Search the web for current external information or extract text from a URL",
55
+ promptGuidelines: [
56
+ "Use web_search when the user asks for current external information, recent updates, or public web content.",
57
+ ],
58
+ parameters: webSearchSchema,
59
+ async execute(_toolCallId, { query, url, mode, limit }, signal, _onUpdate, _ctx) {
60
+ return new Promise((resolve, reject) => {
61
+ if (signal?.aborted) {
62
+ reject(new Error("Operation aborted"));
63
+ return;
64
+ }
65
+ if (!existsSync(WEB_SEARCH_HELPER)) {
66
+ reject(new Error(`Web search helper not found: ${WEB_SEARCH_HELPER}`));
67
+ return;
68
+ }
69
+ const effectiveMode = mode || "full";
70
+ const target = effectiveMode === "page" ? url : query;
71
+ if (!target) {
72
+ reject(new Error(effectiveMode === "page" ? "url is required for page mode" : "query is required for search mode"));
73
+ return;
74
+ }
75
+ const args = [WEB_SEARCH_HELPER, "--json"];
76
+ if (effectiveMode === "page") {
77
+ args.push("--page", target);
78
+ }
79
+ else if (effectiveMode === "ddg") {
80
+ args.push("--ddg", target);
81
+ }
82
+ else if (effectiveMode === "instant") {
83
+ args.push("--instant", target);
84
+ }
85
+ else if (effectiveMode === "wiki") {
86
+ args.push("--wiki", target);
87
+ }
88
+ else {
89
+ args.push(target);
90
+ }
91
+ if (limit !== undefined && effectiveMode !== "page" && effectiveMode !== "instant") {
92
+ args.push("--limit", String(limit));
93
+ }
94
+ const child = spawn(process.execPath, args, {
95
+ stdio: ["ignore", "pipe", "pipe"],
96
+ });
97
+ let stdout = "";
98
+ let stderr = "";
99
+ let settled = false;
100
+ const settle = (fn) => {
101
+ if (settled)
102
+ return;
103
+ settled = true;
104
+ signal?.removeEventListener("abort", onAbort);
105
+ fn();
106
+ };
107
+ const onAbort = () => {
108
+ if (!child.killed) {
109
+ child.kill();
110
+ }
111
+ settle(() => reject(new Error("Operation aborted")));
112
+ };
113
+ signal?.addEventListener("abort", onAbort, { once: true });
114
+ child.stdout?.on("data", (chunk) => {
115
+ stdout += chunk.toString();
116
+ });
117
+ child.stderr?.on("data", (chunk) => {
118
+ stderr += chunk.toString();
119
+ });
120
+ child.on("error", (error) => {
121
+ settle(() => reject(new Error(`Failed to run web search helper: ${error.message}`)));
122
+ });
123
+ child.on("close", (code) => {
124
+ if (signal?.aborted) {
125
+ settle(() => reject(new Error("Operation aborted")));
126
+ return;
127
+ }
128
+ if (code !== 0) {
129
+ settle(() => reject(new Error(stderr.trim() || `web_search exited with code ${code}`)));
130
+ return;
131
+ }
132
+ const output = stdout.trim();
133
+ if (!output) {
134
+ settle(() => resolve({
135
+ content: [{ type: "text", text: "No web search results returned" }],
136
+ details: undefined,
137
+ }));
138
+ return;
139
+ }
140
+ const truncation = truncateHead(output, { maxLines: Number.MAX_SAFE_INTEGER });
141
+ settle(() => resolve({
142
+ content: [{ type: "text", text: truncation.content }],
143
+ details: truncation.truncated ? { truncation } : undefined,
144
+ }));
145
+ });
146
+ });
147
+ },
148
+ renderCall(args, theme, context) {
149
+ const text = context.lastComponent ?? new Text("", 0, 0);
150
+ text.setText(formatWebSearchCall(args, theme));
151
+ return text;
152
+ },
153
+ renderResult(result, options, theme, context) {
154
+ const text = context.lastComponent ?? new Text("", 0, 0);
155
+ text.setText(formatWebSearchResult(result, options, theme, context.showImages));
156
+ return text;
157
+ },
158
+ };
159
+ }
160
+ export function createWebSearchTool(cwd, options) {
161
+ return wrapToolDefinition(createWebSearchToolDefinition(cwd, options));
162
+ }
@@ -32,13 +32,14 @@ const DEFAULT_MODELS_CONFIG = {
32
32
  authHeader: true,
33
33
  compat: {
34
34
  supportsDeveloperRole: true,
35
- supportsReasoningEffort: false,
35
+ supportsReasoningEffort: true,
36
36
  },
37
37
  models: [
38
38
  {
39
39
  id: "qwen3-6",
40
40
  name: "qwen3.6 27b",
41
41
  reasoning: true,
42
+ input: ["text", "image"],
42
43
  },
43
44
  ],
44
45
  },
@@ -48,13 +49,14 @@ const DEFAULT_MODELS_CONFIG = {
48
49
  authHeader: true,
49
50
  compat: {
50
51
  supportsDeveloperRole: true,
51
- supportsReasoningEffort: false,
52
+ supportsReasoningEffort: true,
52
53
  },
53
54
  models: [
54
55
  {
55
56
  id: "gemma4",
56
57
  name: "gemma4",
57
58
  reasoning: true,
59
+ input: ["text", "image"],
58
60
  },
59
61
  ],
60
62
  },
@@ -107,6 +109,13 @@ function migrateAlemBaseUrls() {
107
109
  gptOssProvider.baseUrl = "https://llm.alem.ai";
108
110
  changed = true;
109
111
  }
112
+ if (!gptOssProvider.compat || typeof gptOssProvider.compat !== "object") {
113
+ gptOssProvider.compat = {};
114
+ }
115
+ if (gptOssProvider.compat.supportsReasoningEffort !== true) {
116
+ gptOssProvider.compat.supportsReasoningEffort = true;
117
+ changed = true;
118
+ }
110
119
  }
111
120
  for (const providerName of ["alem-ai-plus-qwen3-6", "alem-ai-plus-gemma4"]) {
112
121
  const provider = parsed.providers[providerName];
@@ -119,6 +128,31 @@ function migrateAlemBaseUrls() {
119
128
  provider.baseUrl = "https://llm.alem.ai/v1";
120
129
  changed = true;
121
130
  }
131
+ if (!provider.compat || typeof provider.compat !== "object") {
132
+ provider.compat = {};
133
+ }
134
+ if (provider.compat.supportsReasoningEffort !== true) {
135
+ provider.compat.supportsReasoningEffort = true;
136
+ changed = true;
137
+ }
138
+ if (Array.isArray(provider.models)) {
139
+ for (const model of provider.models) {
140
+ if (!model || typeof model !== "object") {
141
+ continue;
142
+ }
143
+ if (!model.compat || typeof model.compat !== "object") {
144
+ model.compat = {};
145
+ }
146
+ if (model.compat.supportsReasoningEffort !== true) {
147
+ model.compat.supportsReasoningEffort = true;
148
+ changed = true;
149
+ }
150
+ if (model.reasoning !== true) {
151
+ model.reasoning = true;
152
+ changed = true;
153
+ }
154
+ }
155
+ }
122
156
  }
123
157
  if (changed) {
124
158
  writeFileSync(modelsPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf-8");
@@ -134,7 +134,7 @@ export class FooterComponent {
134
134
  if (state.model?.reasoning) {
135
135
  const thinkingLevel = state.thinkingLevel || "off";
136
136
  rightSideWithoutProvider =
137
- thinkingLevel === "off" ? `${modelName} | reasoning off` : `${modelName} | reasoning ${thinkingLevel}`;
137
+ thinkingLevel === "off" ? `${modelName} | reasoning fast` : `${modelName} | reasoning ${thinkingLevel}`;
138
138
  }
139
139
  const providerName = state.model?.provider || "none";
140
140
  const sessionValue = sessionName || "unnamed";
@@ -6,11 +6,10 @@ const THINKING_SELECT_LIST_LAYOUT = {
6
6
  maxPrimaryColumnWidth: 32,
7
7
  };
8
8
  const LEVEL_DESCRIPTIONS = {
9
- off: "No analysis pass",
10
- minimal: "Tiny analysis pass (~1k tokens)",
11
- low: "Light analysis pass (~2k tokens)",
12
- medium: "Balanced analysis pass (~8k tokens)",
13
- high: "Deep analysis pass (~16k tokens)",
9
+ off: "Fast mode. Direct output, lowest latency.",
10
+ low: "Light analysis. Quick check before answering.",
11
+ medium: "Balanced analysis. Best default for most tasks.",
12
+ high: "Deep analysis. Slower, but stronger reasoning.",
14
13
  xhigh: "Maximum analysis pass (~32k tokens)",
15
14
  };
16
15
  /**
@@ -22,7 +21,7 @@ export class ThinkingSelectorComponent extends Container {
22
21
  super();
23
22
  const thinkingLevels = availableLevels.map((level) => ({
24
23
  value: level,
25
- label: level,
24
+ label: level === "off" ? "fast" : level,
26
25
  description: LEVEL_DESCRIPTIONS[level],
27
26
  }));
28
27
  // Add top border