@oh-my-pi/pi-coding-agent 15.7.1 → 15.7.3
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.
- package/CHANGELOG.md +95 -6
- package/dist/types/auto-thinking/classifier.d.ts +35 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/extension-flags.d.ts +36 -0
- package/dist/types/config/config-file.d.ts +4 -0
- package/dist/types/config/file-lock.d.ts +23 -0
- package/dist/types/config/keybindings.d.ts +2 -1
- package/dist/types/config/model-registry.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +112 -69
- package/dist/types/edit/hashline/diff.d.ts +9 -3
- package/dist/types/eval/__tests__/agent-bridge.test.d.ts +1 -0
- package/dist/types/eval/__tests__/budget-bridge.test.d.ts +1 -0
- package/dist/types/eval/__tests__/idle-timeout.test.d.ts +1 -0
- package/dist/types/eval/agent-bridge.d.ts +25 -0
- package/dist/types/eval/backend.d.ts +17 -2
- package/dist/types/eval/budget-bridge.d.ts +29 -0
- package/dist/types/eval/idle-timeout.d.ts +28 -0
- package/dist/types/eval/js/executor.d.ts +8 -0
- package/dist/types/eval/js/tool-bridge.d.ts +2 -1
- package/dist/types/eval/py/executor.d.ts +13 -0
- package/dist/types/exec/bash-executor.d.ts +1 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/runner.d.ts +7 -0
- package/dist/types/extensibility/plugins/git-url.d.ts +11 -1
- package/dist/types/extensibility/plugins/manager.d.ts +12 -1
- package/dist/types/extensibility/shared-events.d.ts +2 -2
- package/dist/types/memory-backend/index.d.ts +1 -1
- package/dist/types/memory-backend/resolve.d.ts +1 -1
- package/dist/types/memory-backend/types.d.ts +3 -3
- package/dist/types/mnemopi/backend.d.ts +4 -0
- package/dist/types/mnemopi/config.d.ts +29 -0
- package/dist/types/mnemopi/state.d.ts +72 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -2
- package/dist/types/modes/components/model-selector.d.ts +3 -2
- package/dist/types/modes/components/omfg-panel.d.ts +19 -0
- package/dist/types/modes/controllers/command-controller.d.ts +7 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/controllers/omfg-controller.d.ts +10 -0
- package/dist/types/modes/controllers/omfg-rule.d.ts +26 -0
- package/dist/types/modes/gradient-highlight.d.ts +5 -1
- package/dist/types/modes/interactive-mode.d.ts +7 -3
- package/dist/types/modes/magic-keywords.d.ts +14 -0
- package/dist/types/modes/markdown-prose.d.ts +27 -0
- package/dist/types/modes/orchestrate.d.ts +7 -2
- package/dist/types/modes/shared.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/modes/turn-budget.d.ts +18 -0
- package/dist/types/modes/types.d.ts +7 -3
- package/dist/types/modes/ultrathink.d.ts +7 -2
- package/dist/types/modes/workflow.d.ts +15 -0
- package/dist/types/sdk.d.ts +15 -4
- package/dist/types/session/agent-session.d.ts +59 -23
- package/dist/types/session/session-manager.d.ts +18 -0
- package/dist/types/session/session-storage.d.ts +6 -0
- package/dist/types/session/shake-types.d.ts +24 -0
- package/dist/types/task/executor.d.ts +2 -2
- package/dist/types/thinking.d.ts +39 -1
- package/dist/types/tiny/device.d.ts +3 -3
- package/dist/types/tiny/models.d.ts +34 -1
- package/dist/types/tiny/title-protocol.d.ts +4 -0
- package/dist/types/tools/index.d.ts +19 -3
- package/dist/types/tools/memory-edit.d.ts +1 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/package.json +10 -10
- package/src/auto-thinking/classifier.ts +180 -0
- package/src/autoresearch/tools/run-experiment.ts +45 -113
- package/src/cli/args.ts +39 -16
- package/src/cli/extension-flags.ts +48 -0
- package/src/cli/plugin-cli.ts +11 -2
- package/src/config/config-file.ts +98 -13
- package/src/config/file-lock.ts +60 -17
- package/src/config/keybindings.ts +78 -27
- package/src/config/model-registry.ts +7 -1
- package/src/config/settings-schema.ts +118 -71
- package/src/config/settings.ts +12 -0
- package/src/edit/hashline/diff.ts +87 -22
- package/src/edit/renderer.ts +16 -12
- package/src/edit/streaming.ts +17 -6
- package/src/eval/__tests__/agent-bridge.test.ts +433 -0
- package/src/eval/__tests__/budget-bridge.test.ts +69 -0
- package/src/eval/__tests__/idle-timeout.test.ts +66 -0
- package/src/eval/__tests__/shared-executors.test.ts +53 -0
- package/src/eval/agent-bridge.ts +295 -0
- package/src/eval/backend.ts +17 -2
- package/src/eval/budget-bridge.ts +48 -0
- package/src/eval/idle-timeout.ts +80 -0
- package/src/eval/js/executor.ts +35 -7
- package/src/eval/js/index.ts +2 -1
- package/src/eval/js/shared/local-module-loader.ts +75 -10
- package/src/eval/js/shared/prelude.txt +85 -1
- package/src/eval/js/tool-bridge.ts +9 -0
- package/src/eval/py/executor.ts +41 -14
- package/src/eval/py/index.ts +2 -1
- package/src/eval/py/prelude.py +132 -1
- package/src/exec/bash-executor.ts +2 -3
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/runner.ts +12 -2
- package/src/extensibility/plugins/git-url.ts +90 -4
- package/src/extensibility/plugins/manager.ts +103 -7
- package/src/extensibility/shared-events.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +88 -88
- package/src/main.ts +50 -56
- package/src/memory-backend/index.ts +1 -1
- package/src/memory-backend/resolve.ts +3 -3
- package/src/memory-backend/types.ts +3 -3
- package/src/{mnemosyne → mnemopi}/backend.ts +70 -70
- package/src/{mnemosyne → mnemopi}/config.ts +36 -36
- package/src/{mnemosyne → mnemopi}/state.ts +67 -67
- package/src/modes/acp/acp-agent.ts +13 -3
- package/src/modes/components/agent-dashboard.ts +6 -6
- package/src/modes/components/custom-editor.ts +4 -11
- package/src/modes/components/extensions/state-manager.ts +3 -4
- package/src/modes/components/footer.ts +18 -12
- package/src/modes/components/hook-selector.ts +86 -20
- package/src/modes/components/model-selector.ts +20 -11
- package/src/modes/components/oauth-selector.ts +93 -21
- package/src/modes/components/omfg-panel.ts +141 -0
- package/src/modes/components/settings-defs.ts +9 -2
- package/src/modes/components/settings-selector.ts +4 -1
- package/src/modes/components/status-line/segments.ts +13 -5
- package/src/modes/components/tips.txt +2 -1
- package/src/modes/components/tool-execution.ts +38 -19
- package/src/modes/components/tree-selector.ts +4 -3
- package/src/modes/components/user-message-selector.ts +94 -19
- package/src/modes/components/user-message.ts +8 -1
- package/src/modes/controllers/command-controller.ts +57 -0
- package/src/modes/controllers/event-controller.ts +65 -3
- package/src/modes/controllers/input-controller.ts +14 -11
- package/src/modes/controllers/omfg-controller.ts +283 -0
- package/src/modes/controllers/omfg-rule.ts +647 -0
- package/src/modes/controllers/selector-controller.ts +21 -6
- package/src/modes/gradient-highlight.ts +23 -6
- package/src/modes/interactive-mode.ts +41 -7
- package/src/modes/magic-keywords.ts +20 -0
- package/src/modes/markdown-prose.ts +247 -0
- package/src/modes/orchestrate.ts +17 -11
- package/src/modes/shared.ts +3 -11
- package/src/modes/theme/theme.ts +6 -0
- package/src/modes/turn-budget.ts +31 -0
- package/src/modes/types.ts +7 -1
- package/src/modes/ultrathink.ts +16 -10
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/modes/workflow.ts +42 -0
- package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
- package/src/prompts/system/auto-thinking-difficulty.md +12 -0
- package/src/prompts/system/omfg-user.md +51 -0
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/prompts/system/workflow-notice.md +70 -0
- package/src/prompts/tools/eval.md +13 -1
- package/src/prompts/tools/memory-edit.md +1 -1
- package/src/sdk.ts +86 -38
- package/src/session/agent-session.ts +558 -80
- package/src/session/session-manager.ts +32 -0
- package/src/session/session-storage.ts +68 -8
- package/src/session/shake-types.ts +44 -0
- package/src/slash-commands/builtin-registry.ts +41 -16
- package/src/task/executor.ts +3 -3
- package/src/task/index.ts +6 -6
- package/src/thinking.ts +73 -1
- package/src/tiny/device.ts +4 -10
- package/src/tiny/models.ts +54 -2
- package/src/tiny/title-protocol.ts +11 -1
- package/src/tiny/worker.ts +19 -7
- package/src/tools/eval.ts +202 -26
- package/src/tools/grouped-file-output.ts +9 -2
- package/src/tools/index.ts +17 -5
- package/src/tools/memory-edit.ts +4 -4
- package/src/tools/memory-recall.ts +5 -5
- package/src/tools/memory-reflect.ts +5 -5
- package/src/tools/memory-retain.ts +4 -4
- package/src/tools/render-utils.ts +2 -1
- package/src/tools/search.ts +480 -76
- package/dist/types/mnemosyne/backend.d.ts +0 -4
- package/dist/types/mnemosyne/config.d.ts +0 -29
- package/dist/types/mnemosyne/state.d.ts +0 -72
- /package/dist/types/{mnemosyne → mnemopi}/index.d.ts +0 -0
- /package/src/{mnemosyne → mnemopi}/index.ts +0 -0
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import {
|
|
6
6
|
Container,
|
|
7
|
+
extractPrintableText,
|
|
8
|
+
fuzzyFilter,
|
|
7
9
|
Markdown,
|
|
8
10
|
matchesKey,
|
|
9
11
|
padding,
|
|
@@ -91,6 +93,8 @@ class OutlinedList extends Container {
|
|
|
91
93
|
|
|
92
94
|
export class HookSelectorComponent extends Container {
|
|
93
95
|
#options: string[];
|
|
96
|
+
#filteredOptions: string[];
|
|
97
|
+
#searchQuery = "";
|
|
94
98
|
#selectedIndex: number;
|
|
95
99
|
#maxVisible: number;
|
|
96
100
|
#listContainer: Container | undefined;
|
|
@@ -116,7 +120,8 @@ export class HookSelectorComponent extends Container {
|
|
|
116
120
|
super();
|
|
117
121
|
|
|
118
122
|
this.#options = options;
|
|
119
|
-
this.#
|
|
123
|
+
this.#filteredOptions = options;
|
|
124
|
+
this.#selectedIndex = Math.min(opts?.initialIndex ?? 0, this.#filteredOptions.length - 1);
|
|
120
125
|
this.#maxVisible = Math.max(3, opts?.maxVisible ?? 12);
|
|
121
126
|
this.#onSelectCallback = onSelect;
|
|
122
127
|
this.#onCancelCallback = onCancel;
|
|
@@ -149,8 +154,7 @@ export class HookSelectorComponent extends Container {
|
|
|
149
154
|
s => this.#titleComponent.setText(`${this.#baseTitle} (${s}s)`),
|
|
150
155
|
() => {
|
|
151
156
|
opts?.onTimeout?.();
|
|
152
|
-
|
|
153
|
-
const selected = this.#options[this.#selectedIndex];
|
|
157
|
+
const selected = this.#filteredOptions[this.#selectedIndex];
|
|
154
158
|
if (selected) {
|
|
155
159
|
this.#onSelectCallback(selected);
|
|
156
160
|
} else {
|
|
@@ -178,24 +182,31 @@ export class HookSelectorComponent extends Container {
|
|
|
178
182
|
|
|
179
183
|
#updateList(): void {
|
|
180
184
|
const lines: string[] = [];
|
|
185
|
+
const total = this.#filteredOptions.length;
|
|
181
186
|
const startIndex = Math.max(
|
|
182
187
|
0,
|
|
183
|
-
Math.min(this.#selectedIndex - Math.floor(this.#maxVisible / 2),
|
|
188
|
+
Math.min(this.#selectedIndex - Math.floor(this.#maxVisible / 2), total - this.#maxVisible),
|
|
184
189
|
);
|
|
185
|
-
const endIndex = Math.min(startIndex + this.#maxVisible,
|
|
190
|
+
const endIndex = Math.min(startIndex + this.#maxVisible, total);
|
|
186
191
|
|
|
187
192
|
const mdTheme = getMarkdownTheme();
|
|
188
193
|
for (let i = startIndex; i < endIndex; i++) {
|
|
194
|
+
const option = this.#filteredOptions[i];
|
|
195
|
+
if (option === undefined) continue;
|
|
189
196
|
const isSelected = i === this.#selectedIndex;
|
|
190
197
|
const label = isSelected
|
|
191
|
-
? renderInlineMarkdown(
|
|
192
|
-
: renderInlineMarkdown(
|
|
198
|
+
? renderInlineMarkdown(option, mdTheme, t => theme.fg("accent", t))
|
|
199
|
+
: renderInlineMarkdown(option, mdTheme, t => theme.fg("text", t));
|
|
193
200
|
const prefix = isSelected ? theme.fg("accent", `${theme.nav.cursor} `) : " ";
|
|
194
201
|
lines.push(prefix + label);
|
|
195
202
|
}
|
|
196
203
|
|
|
197
|
-
if (
|
|
198
|
-
lines.push(theme.fg("dim",
|
|
204
|
+
if (total === 0) {
|
|
205
|
+
lines.push(theme.fg("dim", " No matching options"));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (startIndex > 0 || endIndex < total || this.#shouldRenderSearchStatus()) {
|
|
209
|
+
lines.push(this.#renderStatusLine(total));
|
|
199
210
|
}
|
|
200
211
|
if (this.#outlinedList) {
|
|
201
212
|
this.#outlinedList.setLines(lines);
|
|
@@ -242,29 +253,84 @@ export class HookSelectorComponent extends Container {
|
|
|
242
253
|
slider.onChange?.(next);
|
|
243
254
|
}
|
|
244
255
|
|
|
256
|
+
#isSearchEnabled(): boolean {
|
|
257
|
+
return this.#options.length > this.#maxVisible;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
#shouldRenderSearchStatus(): boolean {
|
|
261
|
+
return this.#isSearchEnabled() || this.#searchQuery.length > 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
#renderStatusLine(total: number): string {
|
|
265
|
+
const selectedCount = total === 0 ? 0 : this.#selectedIndex + 1;
|
|
266
|
+
const count =
|
|
267
|
+
this.#searchQuery.trim() && total !== this.#options.length
|
|
268
|
+
? `${selectedCount}/${total} of ${this.#options.length}`
|
|
269
|
+
: `${selectedCount}/${total}`;
|
|
270
|
+
const suffix = this.#searchQuery.trim() ? ` Search: ${this.#searchQuery}` : " Type to search";
|
|
271
|
+
return theme.fg("dim", ` (${count})${suffix}`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
#setSearchQuery(query: string): void {
|
|
275
|
+
this.#searchQuery = query;
|
|
276
|
+
this.#filteredOptions = query.trim() ? fuzzyFilter(this.#options, query, option => option) : this.#options;
|
|
277
|
+
this.#selectedIndex = 0;
|
|
278
|
+
this.#updateList();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
#handleSearchInput(keyData: string): boolean {
|
|
282
|
+
if (!this.#isSearchEnabled()) return false;
|
|
283
|
+
|
|
284
|
+
if (matchesKey(keyData, "backspace")) {
|
|
285
|
+
if (this.#searchQuery.length === 0) return false;
|
|
286
|
+
const chars = [...this.#searchQuery];
|
|
287
|
+
chars.pop();
|
|
288
|
+
this.#setSearchQuery(chars.join(""));
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const printableText = extractPrintableText(keyData);
|
|
293
|
+
if (printableText === undefined) return false;
|
|
294
|
+
if (this.#searchQuery.length === 0 && printableText.trim().length === 0) return false;
|
|
295
|
+
|
|
296
|
+
this.#setSearchQuery(this.#searchQuery + printableText);
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
|
|
245
300
|
handleInput(keyData: string): void {
|
|
246
301
|
// Reset countdown on any interaction
|
|
247
302
|
this.#countdown?.reset();
|
|
248
303
|
|
|
249
|
-
if (
|
|
250
|
-
this.#
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
304
|
+
if (matchesSelectCancel(keyData)) {
|
|
305
|
+
this.#onCancelCallback();
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (this.#handleSearchInput(keyData)) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (matchesSelectUp(keyData) || (!this.#isSearchEnabled() && keyData === "k")) {
|
|
314
|
+
if (this.#filteredOptions.length > 0) {
|
|
315
|
+
this.#selectedIndex = Math.max(0, this.#selectedIndex - 1);
|
|
316
|
+
this.#updateList();
|
|
317
|
+
}
|
|
318
|
+
} else if (matchesSelectDown(keyData) || (!this.#isSearchEnabled() && keyData === "j")) {
|
|
319
|
+
if (this.#filteredOptions.length > 0) {
|
|
320
|
+
this.#selectedIndex = Math.min(this.#filteredOptions.length - 1, this.#selectedIndex + 1);
|
|
321
|
+
this.#updateList();
|
|
322
|
+
}
|
|
255
323
|
} else if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
|
|
256
|
-
const selected = this.#
|
|
324
|
+
const selected = this.#filteredOptions[this.#selectedIndex];
|
|
257
325
|
if (selected) this.#onSelectCallback(selected);
|
|
258
|
-
} else if (matchesKey(keyData, "left") || (this.#slider && keyData === "h")) {
|
|
326
|
+
} else if (matchesKey(keyData, "left") || (this.#slider && !this.#isSearchEnabled() && keyData === "h")) {
|
|
259
327
|
if (this.#slider) this.#moveSlider(-1);
|
|
260
328
|
else this.#onLeftCallback?.();
|
|
261
|
-
} else if (matchesKey(keyData, "right") || (this.#slider && keyData === "l")) {
|
|
329
|
+
} else if (matchesKey(keyData, "right") || (this.#slider && !this.#isSearchEnabled() && keyData === "l")) {
|
|
262
330
|
if (this.#slider) this.#moveSlider(1);
|
|
263
331
|
else this.#onRightCallback?.();
|
|
264
332
|
} else if (this.#onExternalEditorCallback && matchesAppExternalEditor(keyData)) {
|
|
265
333
|
this.#onExternalEditorCallback();
|
|
266
|
-
} else if (matchesSelectCancel(keyData)) {
|
|
267
|
-
this.#onCancelCallback();
|
|
268
334
|
}
|
|
269
335
|
}
|
|
270
336
|
|
|
@@ -19,7 +19,7 @@ import { resolveModelRoleValue } from "../../config/model-resolver";
|
|
|
19
19
|
import type { Settings } from "../../config/settings";
|
|
20
20
|
import { type ThemeColor, theme } from "../../modes/theme/theme";
|
|
21
21
|
import { matchesSelectDown, matchesSelectUp } from "../../modes/utils/keybinding-matchers";
|
|
22
|
-
import {
|
|
22
|
+
import { AUTO_THINKING, type ConfiguredThinkingLevel, getConfiguredThinkingLevelMetadata } from "../../thinking";
|
|
23
23
|
import { getTabBarTheme } from "../shared";
|
|
24
24
|
import { DynamicBorder } from "./dynamic-border";
|
|
25
25
|
|
|
@@ -83,10 +83,15 @@ interface ScopedModelItem {
|
|
|
83
83
|
|
|
84
84
|
interface RoleAssignment {
|
|
85
85
|
model: Model;
|
|
86
|
-
thinkingLevel:
|
|
86
|
+
thinkingLevel: ConfiguredThinkingLevel;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
type RoleSelectCallback = (
|
|
89
|
+
type RoleSelectCallback = (
|
|
90
|
+
model: Model,
|
|
91
|
+
role: string | null,
|
|
92
|
+
thinkingLevel?: ConfiguredThinkingLevel,
|
|
93
|
+
selector?: string,
|
|
94
|
+
) => void;
|
|
90
95
|
type CancelCallback = () => void;
|
|
91
96
|
interface MenuRoleAction {
|
|
92
97
|
label: string;
|
|
@@ -165,7 +170,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
165
170
|
settings: Settings,
|
|
166
171
|
modelRegistry: ModelRegistry,
|
|
167
172
|
scopedModels: ReadonlyArray<ScopedModelItem>,
|
|
168
|
-
onSelect:
|
|
173
|
+
onSelect: RoleSelectCallback,
|
|
169
174
|
onCancel: () => void,
|
|
170
175
|
options?: { temporaryOnly?: boolean; initialSearchInput?: string },
|
|
171
176
|
) {
|
|
@@ -790,7 +795,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
790
795
|
if (!tag || !assigned || !modelsAreEqual(assigned.model, item.model)) continue;
|
|
791
796
|
|
|
792
797
|
const badge = makeInvertedBadge(tag, color ?? "success");
|
|
793
|
-
const thinkingLabel =
|
|
798
|
+
const thinkingLabel = getConfiguredThinkingLevelMetadata(assigned.thinkingLevel).label;
|
|
794
799
|
roleBadgeTokens.push(`${badge} ${theme.fg("dim", `(${thinkingLabel})`)}`);
|
|
795
800
|
}
|
|
796
801
|
// Custom role badges
|
|
@@ -799,7 +804,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
799
804
|
const roleInfo = getRoleInfo(role, this.#settings);
|
|
800
805
|
const badgeLabel = roleInfo.tag ?? roleInfo.name;
|
|
801
806
|
const badge = makeInvertedBadge(badgeLabel, roleInfo.color ?? "muted");
|
|
802
|
-
const thinkingLabel =
|
|
807
|
+
const thinkingLabel = getConfiguredThinkingLevelMetadata(assigned.thinkingLevel).label;
|
|
803
808
|
roleBadgeTokens.push(`${badge} ${theme.fg("dim", `(${thinkingLabel})`)}`);
|
|
804
809
|
}
|
|
805
810
|
const badgeText = roleBadgeTokens.length > 0 ? ` ${roleBadgeTokens.join(" ")}` : "";
|
|
@@ -863,11 +868,11 @@ export class ModelSelectorComponent extends Container {
|
|
|
863
868
|
);
|
|
864
869
|
}
|
|
865
870
|
}
|
|
866
|
-
#getThinkingLevelsForModel(model: Model): ReadonlyArray<
|
|
867
|
-
return [ThinkingLevel.Inherit, ThinkingLevel.Off, ...getSupportedEfforts(model)];
|
|
871
|
+
#getThinkingLevelsForModel(model: Model): ReadonlyArray<ConfiguredThinkingLevel> {
|
|
872
|
+
return [ThinkingLevel.Inherit, ThinkingLevel.Off, AUTO_THINKING, ...getSupportedEfforts(model)];
|
|
868
873
|
}
|
|
869
874
|
|
|
870
|
-
#getCurrentRoleThinkingLevel(role: string):
|
|
875
|
+
#getCurrentRoleThinkingLevel(role: string): ConfiguredThinkingLevel {
|
|
871
876
|
return this.#roles[role]?.thinkingLevel ?? ThinkingLevel.Inherit;
|
|
872
877
|
}
|
|
873
878
|
|
|
@@ -912,7 +917,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
912
917
|
const optionLines = showingThinking
|
|
913
918
|
? thinkingOptions.map((thinkingLevel, index) => {
|
|
914
919
|
const prefix = index === this.#menuSelectedIndex ? ` ${theme.nav.cursor} ` : " ";
|
|
915
|
-
const label =
|
|
920
|
+
const label = getConfiguredThinkingLevelMetadata(thinkingLevel).label;
|
|
916
921
|
return `${prefix}${label}`;
|
|
917
922
|
})
|
|
918
923
|
: this.#menuRoleActions.map((action, index) => {
|
|
@@ -1069,7 +1074,11 @@ export class ModelSelectorComponent extends Container {
|
|
|
1069
1074
|
}
|
|
1070
1075
|
}
|
|
1071
1076
|
|
|
1072
|
-
#handleSelect(
|
|
1077
|
+
#handleSelect(
|
|
1078
|
+
item: ModelItem | CanonicalModelItem,
|
|
1079
|
+
role: string | null,
|
|
1080
|
+
thinkingLevel?: ConfiguredThinkingLevel,
|
|
1081
|
+
): void {
|
|
1073
1082
|
// For temporary role, don't save to settings - just notify caller
|
|
1074
1083
|
if (role === null) {
|
|
1075
1084
|
this.#onSelectCallback(item.model, null, undefined, item.selector);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getOAuthProviders } from "@oh-my-pi/pi-ai/utils/oauth";
|
|
2
2
|
import type { OAuthProviderInfo } from "@oh-my-pi/pi-ai/utils/oauth/types";
|
|
3
|
-
import { Container, matchesKey, Spacer, TruncatedText } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import { Container, extractPrintableText, fuzzyFilter, matchesKey, Spacer, TruncatedText } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { theme } from "../../modes/theme/theme";
|
|
5
5
|
import { matchesSelectCancel, matchesSelectDown, matchesSelectUp } from "../../modes/utils/keybinding-matchers";
|
|
6
6
|
import type { AuthStorage } from "../../session/auth-storage";
|
|
@@ -13,6 +13,8 @@ const OAUTH_SELECTOR_MAX_VISIBLE = 10;
|
|
|
13
13
|
export class OAuthSelectorComponent extends Container {
|
|
14
14
|
#listContainer: Container;
|
|
15
15
|
#allProviders: OAuthProviderInfo[] = [];
|
|
16
|
+
#filteredProviders: OAuthProviderInfo[] = [];
|
|
17
|
+
#searchQuery = "";
|
|
16
18
|
#selectedIndex: number = 0;
|
|
17
19
|
#mode: "login" | "logout";
|
|
18
20
|
#authStorage: AuthStorage;
|
|
@@ -67,6 +69,7 @@ export class OAuthSelectorComponent extends Container {
|
|
|
67
69
|
}
|
|
68
70
|
#loadProviders(): void {
|
|
69
71
|
this.#allProviders = getOAuthProviders();
|
|
72
|
+
this.#filteredProviders = this.#allProviders;
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
#startValidation(): void {
|
|
@@ -144,10 +147,68 @@ export class OAuthSelectorComponent extends Container {
|
|
|
144
147
|
}
|
|
145
148
|
return this.#authStorage.hasAuth(providerId) ? theme.fg("success", ` ${theme.status.success} logged in`) : "";
|
|
146
149
|
}
|
|
150
|
+
#isSearchEnabled(): boolean {
|
|
151
|
+
return this.#allProviders.length > OAUTH_SELECTOR_MAX_VISIBLE;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#shouldRenderSearchStatus(): boolean {
|
|
155
|
+
return this.#isSearchEnabled() || this.#searchQuery.length > 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
#renderStatusLine(total: number): string {
|
|
159
|
+
const selectedCount = total === 0 ? 0 : this.#selectedIndex + 1;
|
|
160
|
+
const count =
|
|
161
|
+
this.#searchQuery.trim() && total !== this.#allProviders.length
|
|
162
|
+
? `${selectedCount}/${total} of ${this.#allProviders.length}`
|
|
163
|
+
: `${selectedCount}/${total}`;
|
|
164
|
+
const suffix = this.#searchQuery.trim() ? ` Search: ${this.#searchQuery}` : " Type to search";
|
|
165
|
+
return theme.fg("muted", ` (${count})${suffix}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
#getProviderSearchText(provider: OAuthProviderInfo): string {
|
|
169
|
+
let text = `${provider.name} ${provider.id}`;
|
|
170
|
+
if (this.#authStorage.hasAuth(provider.id)) {
|
|
171
|
+
text += " logged in authenticated";
|
|
172
|
+
}
|
|
173
|
+
if (!provider.available) {
|
|
174
|
+
text += " unavailable";
|
|
175
|
+
}
|
|
176
|
+
return text;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
#setSearchQuery(query: string): void {
|
|
180
|
+
this.#searchQuery = query;
|
|
181
|
+
this.#filteredProviders = query.trim()
|
|
182
|
+
? fuzzyFilter(this.#allProviders, query, provider => this.#getProviderSearchText(provider))
|
|
183
|
+
: this.#allProviders;
|
|
184
|
+
this.#selectedIndex = 0;
|
|
185
|
+
this.#statusMessage = undefined;
|
|
186
|
+
this.#updateList();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
#handleSearchInput(keyData: string): boolean {
|
|
190
|
+
if (!this.#isSearchEnabled()) return false;
|
|
191
|
+
|
|
192
|
+
if (matchesKey(keyData, "backspace")) {
|
|
193
|
+
if (this.#searchQuery.length === 0) return false;
|
|
194
|
+
const chars = [...this.#searchQuery];
|
|
195
|
+
chars.pop();
|
|
196
|
+
this.#setSearchQuery(chars.join(""));
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const printableText = extractPrintableText(keyData);
|
|
201
|
+
if (printableText === undefined) return false;
|
|
202
|
+
if (this.#searchQuery.length === 0 && printableText.trim().length === 0) return false;
|
|
203
|
+
|
|
204
|
+
this.#setSearchQuery(this.#searchQuery + printableText);
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
|
|
147
208
|
#updateList(): void {
|
|
148
209
|
this.#listContainer.clear();
|
|
149
210
|
|
|
150
|
-
const total = this.#
|
|
211
|
+
const total = this.#filteredProviders.length;
|
|
151
212
|
const maxVisible = OAUTH_SELECTOR_MAX_VISIBLE;
|
|
152
213
|
const startIndex =
|
|
153
214
|
total <= maxVisible
|
|
@@ -156,7 +217,7 @@ export class OAuthSelectorComponent extends Container {
|
|
|
156
217
|
const endIndex = Math.min(startIndex + maxVisible, total);
|
|
157
218
|
|
|
158
219
|
for (let i = startIndex; i < endIndex; i++) {
|
|
159
|
-
const provider = this.#
|
|
220
|
+
const provider = this.#filteredProviders[i];
|
|
160
221
|
if (!provider) continue;
|
|
161
222
|
const isSelected = i === this.#selectedIndex;
|
|
162
223
|
const isAvailable = provider.available;
|
|
@@ -174,16 +235,19 @@ export class OAuthSelectorComponent extends Container {
|
|
|
174
235
|
this.#listContainer.addChild(new TruncatedText(line, 0, 0));
|
|
175
236
|
}
|
|
176
237
|
|
|
177
|
-
// Scroll indicator when list is windowed
|
|
178
|
-
if (startIndex > 0 || endIndex < total) {
|
|
179
|
-
|
|
180
|
-
this.#listContainer.addChild(new TruncatedText(scrollInfo, 0, 0));
|
|
238
|
+
// Scroll/search indicator when list is windowed or searchable
|
|
239
|
+
if (startIndex > 0 || endIndex < total || this.#shouldRenderSearchStatus()) {
|
|
240
|
+
this.#listContainer.addChild(new TruncatedText(this.#renderStatusLine(total), 0, 0));
|
|
181
241
|
}
|
|
182
242
|
|
|
183
243
|
// Show "no providers" if empty
|
|
184
244
|
if (total === 0) {
|
|
185
245
|
const message =
|
|
186
|
-
this.#
|
|
246
|
+
this.#allProviders.length === 0
|
|
247
|
+
? this.#mode === "login"
|
|
248
|
+
? "No OAuth providers available"
|
|
249
|
+
: "No OAuth providers logged in. Use /login first."
|
|
250
|
+
: "No matching providers";
|
|
187
251
|
this.#listContainer.addChild(new TruncatedText(theme.fg("muted", ` ${message}`), 0, 0));
|
|
188
252
|
}
|
|
189
253
|
if (this.#statusMessage) {
|
|
@@ -192,25 +256,38 @@ export class OAuthSelectorComponent extends Container {
|
|
|
192
256
|
}
|
|
193
257
|
}
|
|
194
258
|
handleInput(keyData: string): void {
|
|
259
|
+
// Escape or Ctrl+C
|
|
260
|
+
if (matchesSelectCancel(keyData)) {
|
|
261
|
+
this.stopValidation();
|
|
262
|
+
this.#onCancelCallback();
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (this.#handleSearchInput(keyData)) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
195
270
|
// Up arrow
|
|
196
271
|
if (matchesSelectUp(keyData)) {
|
|
197
|
-
if (this.#
|
|
198
|
-
this.#selectedIndex =
|
|
272
|
+
if (this.#filteredProviders.length > 0) {
|
|
273
|
+
this.#selectedIndex =
|
|
274
|
+
this.#selectedIndex === 0 ? this.#filteredProviders.length - 1 : this.#selectedIndex - 1;
|
|
199
275
|
}
|
|
200
276
|
this.#statusMessage = undefined;
|
|
201
277
|
this.#updateList();
|
|
202
278
|
}
|
|
203
279
|
// Down arrow
|
|
204
280
|
else if (matchesSelectDown(keyData)) {
|
|
205
|
-
if (this.#
|
|
206
|
-
this.#selectedIndex =
|
|
281
|
+
if (this.#filteredProviders.length > 0) {
|
|
282
|
+
this.#selectedIndex =
|
|
283
|
+
this.#selectedIndex === this.#filteredProviders.length - 1 ? 0 : this.#selectedIndex + 1;
|
|
207
284
|
}
|
|
208
285
|
this.#statusMessage = undefined;
|
|
209
286
|
this.#updateList();
|
|
210
287
|
}
|
|
211
288
|
// Page up - jump up by one visible page
|
|
212
289
|
else if (matchesKey(keyData, "pageUp")) {
|
|
213
|
-
if (this.#
|
|
290
|
+
if (this.#filteredProviders.length > 0) {
|
|
214
291
|
this.#selectedIndex = Math.max(0, this.#selectedIndex - OAUTH_SELECTOR_MAX_VISIBLE);
|
|
215
292
|
}
|
|
216
293
|
this.#statusMessage = undefined;
|
|
@@ -218,9 +295,9 @@ export class OAuthSelectorComponent extends Container {
|
|
|
218
295
|
}
|
|
219
296
|
// Page down - jump down by one visible page
|
|
220
297
|
else if (matchesKey(keyData, "pageDown")) {
|
|
221
|
-
if (this.#
|
|
298
|
+
if (this.#filteredProviders.length > 0) {
|
|
222
299
|
this.#selectedIndex = Math.min(
|
|
223
|
-
this.#
|
|
300
|
+
this.#filteredProviders.length - 1,
|
|
224
301
|
this.#selectedIndex + OAUTH_SELECTOR_MAX_VISIBLE,
|
|
225
302
|
);
|
|
226
303
|
}
|
|
@@ -229,7 +306,7 @@ export class OAuthSelectorComponent extends Container {
|
|
|
229
306
|
}
|
|
230
307
|
// Enter
|
|
231
308
|
else if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
|
|
232
|
-
const selectedProvider = this.#
|
|
309
|
+
const selectedProvider = this.#filteredProviders[this.#selectedIndex];
|
|
233
310
|
if (selectedProvider?.available) {
|
|
234
311
|
this.#statusMessage = undefined;
|
|
235
312
|
this.stopValidation();
|
|
@@ -239,10 +316,5 @@ export class OAuthSelectorComponent extends Container {
|
|
|
239
316
|
this.#updateList();
|
|
240
317
|
}
|
|
241
318
|
}
|
|
242
|
-
// Escape or Ctrl+C
|
|
243
|
-
else if (matchesSelectCancel(keyData)) {
|
|
244
|
-
this.stopValidation();
|
|
245
|
-
this.#onCancelCallback();
|
|
246
|
-
}
|
|
247
319
|
}
|
|
248
320
|
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { type Component, Container, Markdown, Spacer, Text, type TUI } from "@oh-my-pi/pi-tui";
|
|
2
|
+
import { replaceTabs } from "../../tools/render-utils";
|
|
3
|
+
import { getMarkdownTheme, theme } from "../theme/theme";
|
|
4
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
5
|
+
|
|
6
|
+
export type OmfgPanelState =
|
|
7
|
+
| "generating"
|
|
8
|
+
| "validating"
|
|
9
|
+
| "confirming"
|
|
10
|
+
| "saving"
|
|
11
|
+
| "saved"
|
|
12
|
+
| "rejected"
|
|
13
|
+
| "aborted"
|
|
14
|
+
| "error";
|
|
15
|
+
|
|
16
|
+
interface OmfgPanelComponentOptions {
|
|
17
|
+
complaint: string;
|
|
18
|
+
tui: TUI;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class OmfgPanelComponent extends Container {
|
|
22
|
+
#complaint: string;
|
|
23
|
+
#tui: TUI;
|
|
24
|
+
#state: OmfgPanelState = "generating";
|
|
25
|
+
#status = "Generating TTSR rule…";
|
|
26
|
+
#preview = "";
|
|
27
|
+
#savedPath: string | undefined;
|
|
28
|
+
#errorMessage: string | undefined;
|
|
29
|
+
#closed = false;
|
|
30
|
+
|
|
31
|
+
constructor(options: OmfgPanelComponentOptions) {
|
|
32
|
+
super();
|
|
33
|
+
this.#complaint = options.complaint;
|
|
34
|
+
this.#tui = options.tui;
|
|
35
|
+
this.#rebuild();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
appendDraft(delta: string): void {
|
|
39
|
+
if (!delta || this.#closed) return;
|
|
40
|
+
this.#preview += delta;
|
|
41
|
+
this.#rebuild();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setRule(text: string): void {
|
|
45
|
+
if (this.#closed) return;
|
|
46
|
+
this.#preview = text;
|
|
47
|
+
this.#rebuild();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setStatus(state: OmfgPanelState, status: string): void {
|
|
51
|
+
if (this.#closed) return;
|
|
52
|
+
this.#state = state;
|
|
53
|
+
this.#status = status;
|
|
54
|
+
this.#errorMessage = undefined;
|
|
55
|
+
this.#rebuild();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
markSaved(path: string): void {
|
|
59
|
+
if (this.#closed) return;
|
|
60
|
+
this.#state = "saved";
|
|
61
|
+
this.#savedPath = path;
|
|
62
|
+
this.#status = `Saved ${path}`;
|
|
63
|
+
this.#errorMessage = undefined;
|
|
64
|
+
this.#rebuild();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
markRejected(): void {
|
|
68
|
+
if (this.#closed) return;
|
|
69
|
+
this.#state = "rejected";
|
|
70
|
+
this.#status = "Rule was not saved.";
|
|
71
|
+
this.#errorMessage = undefined;
|
|
72
|
+
this.#rebuild();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
markAborted(): void {
|
|
76
|
+
if (this.#closed) return;
|
|
77
|
+
this.#state = "aborted";
|
|
78
|
+
this.#status = "Cancelled.";
|
|
79
|
+
this.#errorMessage = undefined;
|
|
80
|
+
this.#rebuild();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
markError(message: string): void {
|
|
84
|
+
if (this.#closed) return;
|
|
85
|
+
this.#state = "error";
|
|
86
|
+
this.#status = "Could not create rule.";
|
|
87
|
+
this.#errorMessage = message;
|
|
88
|
+
this.#rebuild();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
close(): void {
|
|
92
|
+
this.#closed = true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#rebuild(): void {
|
|
96
|
+
this.clear();
|
|
97
|
+
this.addChild(new DynamicBorder(str => theme.fg("dim", str)));
|
|
98
|
+
this.addChild(new Spacer(1));
|
|
99
|
+
this.addChild(new Text(theme.fg("accent", replaceTabs(`/omfg ${this.#complaint}`)), 1, 0));
|
|
100
|
+
this.addChild(new Text(theme.fg("muted", replaceTabs(this.#status)), 1, 0));
|
|
101
|
+
this.addChild(new Spacer(1));
|
|
102
|
+
this.addChild(this.#contentComponent());
|
|
103
|
+
this.addChild(new Spacer(1));
|
|
104
|
+
this.addChild(new Text(this.#footerLine(), 1, 0));
|
|
105
|
+
this.addChild(new Spacer(1));
|
|
106
|
+
this.addChild(new DynamicBorder(str => theme.fg("dim", str)));
|
|
107
|
+
this.#tui.requestRender();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
#footerLine(): string {
|
|
111
|
+
switch (this.#state) {
|
|
112
|
+
case "generating":
|
|
113
|
+
case "validating":
|
|
114
|
+
case "confirming":
|
|
115
|
+
case "saving":
|
|
116
|
+
return theme.fg("muted", "Esc cancel /omfg");
|
|
117
|
+
case "saved":
|
|
118
|
+
return theme.fg(
|
|
119
|
+
"success",
|
|
120
|
+
`${theme.status.success} Registered live · ${replaceTabs(this.#savedPath ?? "saved")}`,
|
|
121
|
+
);
|
|
122
|
+
case "rejected":
|
|
123
|
+
return theme.fg("warning", `${theme.status.warning} Not saved · Esc dismiss`);
|
|
124
|
+
case "aborted":
|
|
125
|
+
return theme.fg("warning", `${theme.status.warning} Cancelled · Esc dismiss`);
|
|
126
|
+
case "error":
|
|
127
|
+
return theme.fg("error", `${theme.status.error} Error · Esc dismiss`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#contentComponent(): Component {
|
|
132
|
+
if (this.#state === "error") {
|
|
133
|
+
return new Text(theme.fg("error", replaceTabs(this.#errorMessage ?? "Unknown error")), 1, 0);
|
|
134
|
+
}
|
|
135
|
+
const text = replaceTabs(this.#preview).trim();
|
|
136
|
+
if (!text) {
|
|
137
|
+
return new Text(theme.fg("dim", `${theme.status.pending} Waiting for candidate rule…`), 1, 0);
|
|
138
|
+
}
|
|
139
|
+
return new Markdown(text, 1, 0, getMarkdownTheme());
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -79,9 +79,16 @@ const CONDITIONS: Record<string, () => boolean> = {
|
|
|
79
79
|
return false;
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
|
-
|
|
82
|
+
mnemopiActive: () => {
|
|
83
83
|
try {
|
|
84
|
-
return Settings.instance.get("memory.backend") === "
|
|
84
|
+
return Settings.instance.get("memory.backend") === "mnemopi";
|
|
85
|
+
} catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
autoThinkingActive: () => {
|
|
90
|
+
try {
|
|
91
|
+
return Settings.instance.get("defaultThinkingLevel") === "auto";
|
|
85
92
|
} catch {
|
|
86
93
|
return false;
|
|
87
94
|
}
|
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
import { SETTING_TABS, TAB_METADATA } from "../../config/settings-schema";
|
|
24
24
|
import { getCurrentThemeName, getSelectListTheme, getSettingsListTheme, theme } from "../../modes/theme/theme";
|
|
25
25
|
import { matchesAppInterrupt } from "../../modes/utils/keybinding-matchers";
|
|
26
|
+
import { AUTO_THINKING, type ConfiguredThinkingLevel } from "../../thinking";
|
|
26
27
|
import { getTabBarTheme } from "../shared";
|
|
27
28
|
import { DynamicBorder } from "./dynamic-border";
|
|
28
29
|
import { handleInputOrEscape, PluginSettingsComponent } from "./plugin-settings";
|
|
@@ -373,7 +374,9 @@ export class SettingsSelectorComponent extends Container {
|
|
|
373
374
|
|
|
374
375
|
// Special case: inject runtime options for thinking level
|
|
375
376
|
if (def.path === "defaultThinkingLevel") {
|
|
376
|
-
|
|
377
|
+
// Prepend `auto`; the rest are the model's runtime-supported efforts.
|
|
378
|
+
const levels: ConfiguredThinkingLevel[] = [AUTO_THINKING, ...this.context.availableThinkingLevels];
|
|
379
|
+
options = levels.map(level => {
|
|
377
380
|
const baseOpt = options.find(o => o.value === level);
|
|
378
381
|
return baseOpt || { value: level, label: level };
|
|
379
382
|
});
|
|
@@ -90,11 +90,19 @@ const modelSegment: StatusLineSegment = {
|
|
|
90
90
|
|
|
91
91
|
// Add thinking level with dot separator
|
|
92
92
|
if (opts.showThinkingLevel !== false && state.model?.thinking) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
if (ctx.session.isAutoThinking) {
|
|
94
|
+
// Pending (no turn classified yet / classifying) shows a symbol-theme
|
|
95
|
+
// question-box marker; once resolved it shows `<level>`.
|
|
96
|
+
const resolved = ctx.session.autoResolvedThinkingLevel();
|
|
97
|
+
const resolvedText = resolved ? (theme.thinking[resolved as keyof typeof theme.thinking] ?? resolved) : "";
|
|
98
|
+
content += `${theme.sep.dot}${resolved ? resolvedText : `${theme.thinking.autoPending} auto`}`;
|
|
99
|
+
} else {
|
|
100
|
+
const level = state.thinkingLevel ?? ThinkingLevel.Off;
|
|
101
|
+
if (level !== ThinkingLevel.Off) {
|
|
102
|
+
const thinkingText = theme.thinking[level as keyof typeof theme.thinking];
|
|
103
|
+
if (thinkingText) {
|
|
104
|
+
content += `${theme.sep.dot}${thinkingText}`;
|
|
105
|
+
}
|
|
98
106
|
}
|
|
99
107
|
}
|
|
100
108
|
}
|
|
@@ -4,10 +4,11 @@ Ctrl+D can be used to exit, but with your draft saved!
|
|
|
4
4
|
Find out which model you emotionally abuse the most with `omp stats`
|
|
5
5
|
Try task isolation to create CoW worktrees
|
|
6
6
|
Your LLM can call an LLM using `llm(x...)`. Have a big batch of tasks? Ask clanker to use it!
|
|
7
|
-
|
|
7
|
+
Spaghetti code? Try complaining with /omfg
|
|
8
8
|
Did you know? Each kitty/tmux split keeps its own session — `omp -c` resumes the right one
|
|
9
9
|
Drop the word `ultrathink` in your message for harder multi-step reasoning — watch it glow rainbow as you type
|
|
10
10
|
Say `orchestrate` in your message to drive a multi-phase task with parallel subagents — watch it glow as you type
|
|
11
|
+
Say `workflow` in your message to drive the task with parallel subagents in eval — watch it glow as you type
|
|
11
12
|
Log in to several accounts of the same provider — `/login` again — and omp load-balances across them automatically
|
|
12
13
|
Run `omp auth-broker serve` once and every machine pulls live tokens over the wire — refresh keys never leave the host; `omp auth-gateway` fronts it as a drop-in proxy any OpenAI-compatible client can hit
|
|
13
14
|
Press alt+p (or /switch) to switch provider, and ctrl+p to cycle role models smol -> slow -> etc
|