@oh-my-pi/pi-coding-agent 13.8.0 → 13.9.2
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 +52 -0
- package/package.json +7 -7
- package/src/capability/rule.ts +0 -4
- package/src/cli/agents-cli.ts +1 -1
- package/src/cli/args.ts +7 -12
- package/src/commands/launch.ts +3 -2
- package/src/config/model-resolver.ts +106 -33
- package/src/config/settings-schema.ts +14 -2
- package/src/config/settings.ts +1 -17
- package/src/discovery/helpers.ts +10 -17
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +37 -15
- package/src/extensibility/extensions/loader.ts +1 -2
- package/src/extensibility/extensions/types.ts +2 -1
- package/src/main.ts +20 -13
- package/src/modes/components/agent-dashboard.ts +12 -13
- package/src/modes/components/model-selector.ts +157 -59
- package/src/modes/components/read-tool-group.ts +36 -2
- package/src/modes/components/settings-defs.ts +11 -8
- package/src/modes/components/settings-selector.ts +1 -1
- package/src/modes/components/thinking-selector.ts +3 -15
- package/src/modes/controllers/selector-controller.ts +21 -7
- package/src/modes/rpc/rpc-client.ts +2 -2
- package/src/modes/rpc/rpc-types.ts +2 -2
- package/src/modes/theme/theme.ts +2 -1
- package/src/patch/hashline.ts +26 -3
- package/src/patch/index.ts +14 -16
- package/src/prompts/tools/read.md +2 -2
- package/src/sdk.ts +21 -29
- package/src/session/agent-session.ts +44 -37
- package/src/task/executor.ts +10 -8
- package/src/task/types.ts +1 -2
- package/src/tools/read.ts +88 -264
- package/src/utils/frontmatter.ts +25 -4
- package/src/web/scrapers/choosealicense.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [13.9.2] - 2026-03-05
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Support for Python code execution messages with output display and error handling
|
|
10
|
+
- Support for mode change entries in session exports
|
|
11
|
+
- Support for TTSR injection and session initialization entries in tree filtering
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Updated label lookup to use `targetId` field instead of `parentId` for label references
|
|
16
|
+
- Changed model change entry display to use `model` field instead of separate `provider` and `modelId` fields
|
|
17
|
+
- Simplified model change rendering by removing OpenAI Codex bridge prompt display
|
|
18
|
+
- Updated searchable text extraction to include Python code from `pythonExecution` messages
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
|
|
22
|
+
- Removed `codexInjectionInfo` from session data destructuring
|
|
23
|
+
- Removed OpenAI Codex-specific bridge prompt UI from model change entries
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Auto-corrected off-by-one range start errors in hashline edits that would duplicate preceding lines
|
|
28
|
+
|
|
29
|
+
## [13.9.0] - 2026-03-05
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Added `read.defaultLimit` setting to configure default number of lines returned by read tool when no limit is specified (default: 300 lines)
|
|
33
|
+
- Added preset options for read default limit (200, 300, 500, 1000, 5000 lines) in settings UI
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Updated read tool prompt to distinguish between default limit and maximum limit per call
|
|
38
|
+
- Moved `ThinkingLevel` type from `@oh-my-pi/pi-agent-core` to `@oh-my-pi/pi-ai` for centralized thinking level definitions
|
|
39
|
+
- Replaced local thinking level validation with `parseThinkingLevel()` and `ALL_THINKING_LEVELS` from `@oh-my-pi/pi-ai`
|
|
40
|
+
- Updated thinking level option providers to use `THINKING_MODE_DESCRIPTIONS` from `@oh-my-pi/pi-ai` for consistent descriptions
|
|
41
|
+
- Renamed `RoleThinkingMode` type to `ThinkingMode` and changed default value from `'default'` to `'inherit'` for clarity
|
|
42
|
+
- Replaced `formatThinkingEffortLabel()` utility with `formatThinking()` from `@oh-my-pi/pi-ai`
|
|
43
|
+
- Renamed `extractExplicitThinkingLevel()` to `extractExplicitThinkingSelector()` in model resolver
|
|
44
|
+
- Updated thinking level clamping to use `getAvailableThinkingLevel()` from `@oh-my-pi/pi-ai`
|
|
45
|
+
|
|
46
|
+
### Removed
|
|
47
|
+
|
|
48
|
+
- Removed `thinking-effort-label.ts` utility file (functionality moved to `@oh-my-pi/pi-ai`)
|
|
49
|
+
- Removed local `VALID_THINKING_LEVELS` constant definitions across multiple files
|
|
50
|
+
- Removed `isValidThinkingLevel()` function (replaced by `parseThinkingLevel()` from `@oh-my-pi/pi-ai`)
|
|
51
|
+
- Removed `parseThinkingLevel()` helper from discovery module (now uses centralized version from `@oh-my-pi/pi-ai`)
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- Fixed provider session state not being cleared when branching or navigating tree history, preventing resource leaks with codex provider sessions
|
|
56
|
+
|
|
5
57
|
## [13.8.0] - 2026-03-04
|
|
6
58
|
### Added
|
|
7
59
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "13.
|
|
4
|
+
"version": "13.9.2",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@mozilla/readability": "^0.6",
|
|
44
|
-
"@oh-my-pi/omp-stats": "13.
|
|
45
|
-
"@oh-my-pi/pi-agent-core": "13.
|
|
46
|
-
"@oh-my-pi/pi-ai": "13.
|
|
47
|
-
"@oh-my-pi/pi-natives": "13.
|
|
48
|
-
"@oh-my-pi/pi-tui": "13.
|
|
49
|
-
"@oh-my-pi/pi-utils": "13.
|
|
44
|
+
"@oh-my-pi/omp-stats": "13.9.2",
|
|
45
|
+
"@oh-my-pi/pi-agent-core": "13.9.2",
|
|
46
|
+
"@oh-my-pi/pi-ai": "13.9.2",
|
|
47
|
+
"@oh-my-pi/pi-natives": "13.9.2",
|
|
48
|
+
"@oh-my-pi/pi-tui": "13.9.2",
|
|
49
|
+
"@oh-my-pi/pi-utils": "13.9.2",
|
|
50
50
|
"@sinclair/typebox": "^0.34",
|
|
51
51
|
"@xterm/headless": "^6.0",
|
|
52
52
|
"ajv": "^8.18",
|
package/src/capability/rule.ts
CHANGED
|
@@ -20,10 +20,6 @@ export interface RuleFrontmatter {
|
|
|
20
20
|
condition?: string | string[];
|
|
21
21
|
/** New key for TTSR stream scope. */
|
|
22
22
|
scope?: string | string[];
|
|
23
|
-
/** Legacy key accepted for backward compatibility with existing rules. */
|
|
24
|
-
ttsr_trigger?: string | string[];
|
|
25
|
-
/** Legacy camelCase key accepted for backward compatibility with existing rules. */
|
|
26
|
-
ttsrTrigger?: string | string[];
|
|
27
23
|
[key: string]: unknown;
|
|
28
24
|
}
|
|
29
25
|
|
package/src/cli/agents-cli.ts
CHANGED
|
@@ -61,7 +61,7 @@ function toFrontmatter(agent: AgentDefinition): Record<string, unknown> {
|
|
|
61
61
|
if (agent.tools && agent.tools.length > 0) frontmatter.tools = agent.tools;
|
|
62
62
|
if (agent.spawns !== undefined) frontmatter.spawns = agent.spawns;
|
|
63
63
|
if (agent.model && agent.model.length > 0) frontmatter.model = agent.model;
|
|
64
|
-
if (agent.thinkingLevel) frontmatter
|
|
64
|
+
if (agent.thinkingLevel) frontmatter.thinkingLevel = agent.thinkingLevel;
|
|
65
65
|
if (agent.output !== undefined) frontmatter.output = agent.output;
|
|
66
66
|
if (agent.blocking) frontmatter.blocking = true;
|
|
67
67
|
|
package/src/cli/args.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI argument parsing and help display
|
|
3
3
|
*/
|
|
4
|
-
import type
|
|
4
|
+
import { getAvailableThinkingLevels, parseThinkingLevel, type ThinkingLevel } from "@oh-my-pi/pi-ai";
|
|
5
5
|
import { APP_NAME, CONFIG_DIR_NAME, logger } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import chalk from "chalk";
|
|
7
7
|
import { BUILTIN_TOOLS } from "../tools";
|
|
@@ -48,12 +48,6 @@ export interface Args {
|
|
|
48
48
|
unknownFlags: Map<string, boolean | string>;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
const VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const;
|
|
52
|
-
|
|
53
|
-
export function isValidThinkingLevel(level: string): level is ThinkingLevel {
|
|
54
|
-
return VALID_THINKING_LEVELS.includes(level as ThinkingLevel);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
51
|
export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "boolean" | "string" }>): Args {
|
|
58
52
|
const result: Args = {
|
|
59
53
|
messages: [],
|
|
@@ -127,13 +121,14 @@ export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "
|
|
|
127
121
|
}
|
|
128
122
|
result.tools = validTools;
|
|
129
123
|
} else if (arg === "--thinking" && i + 1 < args.length) {
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
124
|
+
const rawThinking = args[++i];
|
|
125
|
+
const thinking = parseThinkingLevel(rawThinking);
|
|
126
|
+
if (thinking !== undefined) {
|
|
127
|
+
result.thinking = thinking;
|
|
133
128
|
} else {
|
|
134
129
|
logger.warn("Invalid thinking level passed to --thinking", {
|
|
135
|
-
level,
|
|
136
|
-
validThinkingLevels:
|
|
130
|
+
level: rawThinking,
|
|
131
|
+
validThinkingLevels: getAvailableThinkingLevels(),
|
|
137
132
|
});
|
|
138
133
|
}
|
|
139
134
|
} else if (arg === "--print" || arg === "-p") {
|
package/src/commands/launch.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Root command for the coding agent CLI.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { getAvailableThinkingLevels } from "@oh-my-pi/pi-ai";
|
|
5
6
|
import { APP_NAME } from "@oh-my-pi/pi-utils";
|
|
6
7
|
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
|
|
7
8
|
import { parseArgs } from "../cli/args";
|
|
@@ -85,8 +86,8 @@ export default class Index extends Command {
|
|
|
85
86
|
description: "Comma-separated list of tools to enable (default: all)",
|
|
86
87
|
}),
|
|
87
88
|
thinking: Flags.string({
|
|
88
|
-
description:
|
|
89
|
-
options:
|
|
89
|
+
description: `Set thinking level: ${getAvailableThinkingLevels().join(", ")}`,
|
|
90
|
+
options: getAvailableThinkingLevels(),
|
|
90
91
|
}),
|
|
91
92
|
hook: Flags.string({
|
|
92
93
|
description: "Load a hook/extension file (can be used multiple times)",
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model resolution, scoping, and initial selection
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
type Api,
|
|
6
|
+
DEFAULT_MODEL_PER_PROVIDER,
|
|
7
|
+
type KnownProvider,
|
|
8
|
+
type Model,
|
|
9
|
+
modelsAreEqual,
|
|
10
|
+
parseThinkingLevel,
|
|
11
|
+
type ThinkingLevel,
|
|
12
|
+
} from "@oh-my-pi/pi-ai";
|
|
6
13
|
import chalk from "chalk";
|
|
7
|
-
import { isValidThinkingLevel } from "../cli/args";
|
|
8
14
|
import MODEL_PRIO from "../priority.json" with { type: "json" };
|
|
9
15
|
import { fuzzyMatch } from "../utils/fuzzy";
|
|
10
16
|
import { MODEL_ROLE_IDS, type ModelRegistry, type ModelRole } from "./model-registry";
|
|
@@ -34,8 +40,9 @@ export function parseModelString(
|
|
|
34
40
|
const colonIdx = id.lastIndexOf(":");
|
|
35
41
|
if (colonIdx !== -1) {
|
|
36
42
|
const suffix = id.slice(colonIdx + 1);
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
const thinkingLevel = parseThinkingLevel(suffix);
|
|
44
|
+
if (thinkingLevel) {
|
|
45
|
+
return { provider, id: id.slice(0, colonIdx), thinkingLevel };
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
48
|
return { provider, id };
|
|
@@ -242,7 +249,7 @@ function parseModelPatternWithContext(
|
|
|
242
249
|
pattern: string,
|
|
243
250
|
availableModels: Model<Api>[],
|
|
244
251
|
context: ModelPreferenceContext,
|
|
245
|
-
options?: {
|
|
252
|
+
options?: { allowInvalidThinkingSelectorFallback?: boolean },
|
|
246
253
|
): ParsedModelResult {
|
|
247
254
|
// Try exact match first
|
|
248
255
|
const exactMatch = tryMatchModel(pattern, availableModels, context);
|
|
@@ -260,7 +267,8 @@ function parseModelPatternWithContext(
|
|
|
260
267
|
const prefix = pattern.substring(0, lastColonIndex);
|
|
261
268
|
const suffix = pattern.substring(lastColonIndex + 1);
|
|
262
269
|
|
|
263
|
-
|
|
270
|
+
const parsedThinkingLevel = parseThinkingLevel(suffix);
|
|
271
|
+
if (parsedThinkingLevel) {
|
|
264
272
|
// Valid thinking level - recurse on prefix and use this level
|
|
265
273
|
const result = parseModelPatternWithContext(prefix, availableModels, context, options);
|
|
266
274
|
if (result.model) {
|
|
@@ -268,7 +276,7 @@ function parseModelPatternWithContext(
|
|
|
268
276
|
const explicitThinkingLevel = !result.warning;
|
|
269
277
|
return {
|
|
270
278
|
model: result.model,
|
|
271
|
-
thinkingLevel: explicitThinkingLevel ?
|
|
279
|
+
thinkingLevel: explicitThinkingLevel ? parsedThinkingLevel : undefined,
|
|
272
280
|
warning: result.warning,
|
|
273
281
|
explicitThinkingLevel,
|
|
274
282
|
};
|
|
@@ -276,7 +284,7 @@ function parseModelPatternWithContext(
|
|
|
276
284
|
return result;
|
|
277
285
|
}
|
|
278
286
|
|
|
279
|
-
const allowFallback = options?.
|
|
287
|
+
const allowFallback = options?.allowInvalidThinkingSelectorFallback ?? true;
|
|
280
288
|
if (!allowFallback) {
|
|
281
289
|
return { model: undefined, thinkingLevel: undefined, warning: undefined, explicitThinkingLevel: false };
|
|
282
290
|
}
|
|
@@ -298,7 +306,7 @@ export function parseModelPattern(
|
|
|
298
306
|
pattern: string,
|
|
299
307
|
availableModels: Model<Api>[],
|
|
300
308
|
preferences?: ModelMatchPreferences,
|
|
301
|
-
options?: {
|
|
309
|
+
options?: { allowInvalidThinkingSelectorFallback?: boolean },
|
|
302
310
|
): ParsedModelResult {
|
|
303
311
|
const context = buildPreferenceContext(availableModels, preferences);
|
|
304
312
|
return parseModelPatternWithContext(pattern, availableModels, context, options);
|
|
@@ -331,6 +339,74 @@ export function expandRoleAlias(value: string, settings?: Settings): string {
|
|
|
331
339
|
return settings?.getModelRole(role) ?? value;
|
|
332
340
|
}
|
|
333
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Resolve a model role value into a concrete model and thinking metadata.
|
|
344
|
+
*/
|
|
345
|
+
export interface ResolvedModelRoleValue {
|
|
346
|
+
model: Model<Api> | undefined;
|
|
347
|
+
thinkingLevel?: ThinkingLevel;
|
|
348
|
+
explicitThinkingLevel: boolean;
|
|
349
|
+
warning: string | undefined;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export function resolveModelRoleValue(
|
|
353
|
+
roleValue: string | undefined,
|
|
354
|
+
availableModels: Model<Api>[],
|
|
355
|
+
options?: { settings?: Settings; matchPreferences?: ModelMatchPreferences },
|
|
356
|
+
): ResolvedModelRoleValue {
|
|
357
|
+
if (!roleValue) {
|
|
358
|
+
return { model: undefined, thinkingLevel: undefined, explicitThinkingLevel: false, warning: undefined };
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const normalized = roleValue.trim();
|
|
362
|
+
if (!normalized || normalized === DEFAULT_MODEL_ROLE) {
|
|
363
|
+
return { model: undefined, thinkingLevel: undefined, explicitThinkingLevel: false, warning: undefined };
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const lastColonIndex = normalized.lastIndexOf(":");
|
|
367
|
+
const hasThinkingSuffix =
|
|
368
|
+
lastColonIndex > PREFIX_MODEL_ROLE.length && parseThinkingLevel(normalized.slice(lastColonIndex + 1));
|
|
369
|
+
const aliasCandidate = hasThinkingSuffix ? normalized.slice(0, lastColonIndex) : normalized;
|
|
370
|
+
const effectivePattern = expandRoleAlias(aliasCandidate, options?.settings);
|
|
371
|
+
const patternWithSuffix = hasThinkingSuffix
|
|
372
|
+
? `${effectivePattern}:${normalized.slice(lastColonIndex + 1)}`
|
|
373
|
+
: effectivePattern;
|
|
374
|
+
const { model, thinkingLevel, warning, explicitThinkingLevel } = parseModelPattern(
|
|
375
|
+
patternWithSuffix,
|
|
376
|
+
availableModels,
|
|
377
|
+
options?.matchPreferences,
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
return { model, thinkingLevel, explicitThinkingLevel, warning };
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export function extractExplicitThinkingSelector(
|
|
384
|
+
value: string | undefined,
|
|
385
|
+
settings?: Settings,
|
|
386
|
+
): ThinkingLevel | undefined {
|
|
387
|
+
if (!value) return undefined;
|
|
388
|
+
const normalized = value.trim();
|
|
389
|
+
if (!normalized || normalized === DEFAULT_MODEL_ROLE) return undefined;
|
|
390
|
+
|
|
391
|
+
const visited = new Set<string>();
|
|
392
|
+
let current = normalized;
|
|
393
|
+
while (!visited.has(current)) {
|
|
394
|
+
visited.add(current);
|
|
395
|
+
const lastColonIndex = current.lastIndexOf(":");
|
|
396
|
+
const hasThinkingSuffix =
|
|
397
|
+
lastColonIndex > PREFIX_MODEL_ROLE.length && parseThinkingLevel(current.slice(lastColonIndex + 1));
|
|
398
|
+
if (hasThinkingSuffix) {
|
|
399
|
+
return current.slice(lastColonIndex + 1) as ThinkingLevel;
|
|
400
|
+
}
|
|
401
|
+
const expanded = expandRoleAlias(current, settings).trim();
|
|
402
|
+
if (!expanded || expanded === current) break;
|
|
403
|
+
if (expanded === DEFAULT_MODEL_ROLE) return undefined;
|
|
404
|
+
current = expanded;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return undefined;
|
|
408
|
+
}
|
|
409
|
+
|
|
334
410
|
/**
|
|
335
411
|
* Resolve a model identifier or pattern to a Model instance.
|
|
336
412
|
*/
|
|
@@ -341,7 +417,8 @@ export function resolveModelFromString(
|
|
|
341
417
|
): Model<Api> | undefined {
|
|
342
418
|
const parsed = parseModelString(value);
|
|
343
419
|
if (parsed) {
|
|
344
|
-
|
|
420
|
+
const exact = available.find(model => model.provider === parsed.provider && model.id === parsed.id);
|
|
421
|
+
if (exact) return exact;
|
|
345
422
|
}
|
|
346
423
|
return parseModelPattern(value, available, matchPreferences).model;
|
|
347
424
|
}
|
|
@@ -373,25 +450,20 @@ export function resolveModelOverride(
|
|
|
373
450
|
modelPatterns: string[],
|
|
374
451
|
modelRegistry: ModelRegistry,
|
|
375
452
|
settings?: Settings,
|
|
376
|
-
): { model?: Model<Api>; thinkingLevel?: ThinkingLevel } {
|
|
377
|
-
if (modelPatterns.length === 0) return {};
|
|
453
|
+
): { model?: Model<Api>; thinkingLevel?: ThinkingLevel; explicitThinkingLevel: boolean } {
|
|
454
|
+
if (modelPatterns.length === 0) return { explicitThinkingLevel: false };
|
|
455
|
+
const availableModels = modelRegistry.getAvailable();
|
|
378
456
|
const matchPreferences = { usageOrder: settings?.getStorage()?.getModelUsageOrder() };
|
|
379
457
|
for (const pattern of modelPatterns) {
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
continue;
|
|
383
|
-
}
|
|
384
|
-
const effectivePattern = expandRoleAlias(pattern, settings);
|
|
385
|
-
const { model, thinkingLevel } = parseModelPattern(
|
|
386
|
-
effectivePattern,
|
|
387
|
-
modelRegistry.getAvailable(),
|
|
458
|
+
const { model, thinkingLevel, explicitThinkingLevel } = resolveModelRoleValue(pattern, availableModels, {
|
|
459
|
+
settings,
|
|
388
460
|
matchPreferences,
|
|
389
|
-
);
|
|
461
|
+
});
|
|
390
462
|
if (model) {
|
|
391
|
-
return { model, thinkingLevel
|
|
463
|
+
return { model, thinkingLevel, explicitThinkingLevel };
|
|
392
464
|
}
|
|
393
465
|
}
|
|
394
|
-
return {};
|
|
466
|
+
return { explicitThinkingLevel: false };
|
|
395
467
|
}
|
|
396
468
|
|
|
397
469
|
/**
|
|
@@ -425,8 +497,9 @@ export async function resolveModelScope(
|
|
|
425
497
|
|
|
426
498
|
if (colonIdx !== -1) {
|
|
427
499
|
const suffix = pattern.substring(colonIdx + 1);
|
|
428
|
-
|
|
429
|
-
|
|
500
|
+
const parsedThinkingLevel = parseThinkingLevel(suffix);
|
|
501
|
+
if (parsedThinkingLevel) {
|
|
502
|
+
thinkingLevel = parsedThinkingLevel;
|
|
430
503
|
explicitThinkingLevel = true;
|
|
431
504
|
globPattern = pattern.substring(0, colonIdx);
|
|
432
505
|
}
|
|
@@ -553,7 +626,7 @@ export function resolveCliModel(options: {
|
|
|
553
626
|
|
|
554
627
|
const candidates = provider ? availableModels.filter(model => model.provider === provider) : availableModels;
|
|
555
628
|
const { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, preferences, {
|
|
556
|
-
|
|
629
|
+
allowInvalidThinkingSelectorFallback: false,
|
|
557
630
|
});
|
|
558
631
|
|
|
559
632
|
if (!model) {
|
|
@@ -590,7 +663,7 @@ export async function findInitialModel(options: {
|
|
|
590
663
|
isContinuing: boolean;
|
|
591
664
|
defaultProvider?: string;
|
|
592
665
|
defaultModelId?: string;
|
|
593
|
-
|
|
666
|
+
defaultThinkingSelector?: ThinkingLevel;
|
|
594
667
|
modelRegistry: ModelRegistry;
|
|
595
668
|
}): Promise<InitialModelResult> {
|
|
596
669
|
const {
|
|
@@ -600,7 +673,7 @@ export async function findInitialModel(options: {
|
|
|
600
673
|
isContinuing,
|
|
601
674
|
defaultProvider,
|
|
602
675
|
defaultModelId,
|
|
603
|
-
|
|
676
|
+
defaultThinkingSelector,
|
|
604
677
|
modelRegistry,
|
|
605
678
|
} = options;
|
|
606
679
|
|
|
@@ -620,10 +693,10 @@ export async function findInitialModel(options: {
|
|
|
620
693
|
// 2. Use first model from scoped models (skip if continuing/resuming)
|
|
621
694
|
if (scopedModels.length > 0 && !isContinuing) {
|
|
622
695
|
const scoped = scopedModels[0];
|
|
623
|
-
const
|
|
696
|
+
const scopedThinkingSelector = scoped.thinkingLevel ?? defaultThinkingSelector ?? "off";
|
|
624
697
|
return {
|
|
625
698
|
model: scoped.model,
|
|
626
|
-
thinkingLevel:
|
|
699
|
+
thinkingLevel: scopedThinkingSelector,
|
|
627
700
|
fallbackMessage: undefined,
|
|
628
701
|
};
|
|
629
702
|
}
|
|
@@ -633,8 +706,8 @@ export async function findInitialModel(options: {
|
|
|
633
706
|
const found = modelRegistry.find(defaultProvider, defaultModelId);
|
|
634
707
|
if (found) {
|
|
635
708
|
model = found;
|
|
636
|
-
if (
|
|
637
|
-
thinkingLevel =
|
|
709
|
+
if (defaultThinkingSelector) {
|
|
710
|
+
thinkingLevel = defaultThinkingSelector;
|
|
638
711
|
}
|
|
639
712
|
return { model, thinkingLevel, fallbackMessage: undefined };
|
|
640
713
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { getAvailableThinkingLevels } from "@oh-my-pi/pi-ai";
|
|
2
|
+
|
|
3
|
+
/** Unified settings schema - single source of truth for all settings.
|
|
2
4
|
* Unified settings schema - single source of truth for all settings.
|
|
3
5
|
*
|
|
4
6
|
* Each setting is defined once here with:
|
|
@@ -190,7 +192,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
190
192
|
},
|
|
191
193
|
defaultThinkingLevel: {
|
|
192
194
|
type: "enum",
|
|
193
|
-
values:
|
|
195
|
+
values: getAvailableThinkingLevels(),
|
|
194
196
|
default: "high",
|
|
195
197
|
ui: {
|
|
196
198
|
tab: "agent",
|
|
@@ -283,6 +285,16 @@ export const SETTINGS_SCHEMA = {
|
|
|
283
285
|
description: "Include line hashes in read output for hashline edit mode (LINE#ID:content)",
|
|
284
286
|
},
|
|
285
287
|
},
|
|
288
|
+
"read.defaultLimit": {
|
|
289
|
+
type: "number",
|
|
290
|
+
default: 300,
|
|
291
|
+
ui: {
|
|
292
|
+
tab: "tools",
|
|
293
|
+
label: "Read default limit",
|
|
294
|
+
description: "Default number of lines returned when agent calls read without a limit",
|
|
295
|
+
submenu: true,
|
|
296
|
+
},
|
|
297
|
+
},
|
|
286
298
|
showHardwareCursor: {
|
|
287
299
|
type: "boolean",
|
|
288
300
|
default: true, // will be computed based on platform if undefined
|
package/src/config/settings.ts
CHANGED
|
@@ -318,21 +318,6 @@ export class Settings {
|
|
|
318
318
|
return result as unknown as GroupTypeMap[G];
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
/**
|
|
322
|
-
* Get edit model variants (typed accessor for complex nested config).
|
|
323
|
-
*/
|
|
324
|
-
getEditModelVariants(): Record<string, EditMode | null> {
|
|
325
|
-
const variants = (this.#merged.edit as { modelVariants?: Record<string, string> })?.modelVariants ?? {};
|
|
326
|
-
const result: Record<string, EditMode | null> = {};
|
|
327
|
-
for (const pattern in variants) {
|
|
328
|
-
const value = normalizeEditMode(variants[pattern]);
|
|
329
|
-
if (value) {
|
|
330
|
-
result[pattern] = value;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
return result;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
321
|
/**
|
|
337
322
|
* Get the edit variant for a specific model.
|
|
338
323
|
* Returns "patch", "replace", "hashline", or null (use global default).
|
|
@@ -341,9 +326,8 @@ export class Settings {
|
|
|
341
326
|
if (!model) return null;
|
|
342
327
|
const variants = (this.#merged.edit as { modelVariants?: Record<string, string> })?.modelVariants;
|
|
343
328
|
if (!variants) return null;
|
|
344
|
-
const modelLower = model.toLowerCase();
|
|
345
329
|
for (const pattern in variants) {
|
|
346
|
-
if (
|
|
330
|
+
if (model.includes(pattern)) {
|
|
347
331
|
const value = normalizeEditMode(variants[pattern]);
|
|
348
332
|
if (value) {
|
|
349
333
|
return value;
|
package/src/discovery/helpers.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import type { ThinkingLevel } from "@oh-my-pi/pi-
|
|
3
|
+
import type { ThinkingLevel } from "@oh-my-pi/pi-ai";
|
|
4
|
+
import { parseThinkingLevel } from "@oh-my-pi/pi-ai";
|
|
4
5
|
import { FileType, glob } from "@oh-my-pi/pi-natives";
|
|
5
6
|
import { CONFIG_DIR_NAME, tryParseJson } from "@oh-my-pi/pi-utils";
|
|
6
7
|
import { readFile } from "../capability/fs";
|
|
@@ -9,8 +10,6 @@ import type { Skill, SkillFrontmatter } from "../capability/skill";
|
|
|
9
10
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
10
11
|
import { parseFrontmatter } from "../utils/frontmatter";
|
|
11
12
|
|
|
12
|
-
const VALID_THINKING_LEVELS: readonly string[] = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
13
|
-
|
|
14
13
|
/**
|
|
15
14
|
* Standard paths for each config source.
|
|
16
15
|
*/
|
|
@@ -100,18 +99,6 @@ export function createSourceMeta(provider: string, filePath: string, level: "use
|
|
|
100
99
|
};
|
|
101
100
|
}
|
|
102
101
|
|
|
103
|
-
/**
|
|
104
|
-
* Parse thinking level from frontmatter.
|
|
105
|
-
* Supports keys: thinkingLevel, thinking-level, thinking
|
|
106
|
-
*/
|
|
107
|
-
export function parseThinkingLevel(frontmatter: Record<string, unknown>): ThinkingLevel | undefined {
|
|
108
|
-
const raw = frontmatter.thinkingLevel ?? frontmatter["thinking-level"] ?? frontmatter.thinking;
|
|
109
|
-
if (typeof raw === "string" && VALID_THINKING_LEVELS.includes(raw)) {
|
|
110
|
-
return raw as ThinkingLevel;
|
|
111
|
-
}
|
|
112
|
-
return undefined;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
102
|
export function parseBoolean(value: unknown): boolean | undefined {
|
|
116
103
|
if (typeof value === "boolean") return value;
|
|
117
104
|
if (typeof value === "string") {
|
|
@@ -247,10 +234,16 @@ export function parseAgentFields(frontmatter: Record<string, unknown>): ParsedAg
|
|
|
247
234
|
}
|
|
248
235
|
|
|
249
236
|
const output = frontmatter.output !== undefined ? frontmatter.output : undefined;
|
|
237
|
+
const rawThinkingLevel =
|
|
238
|
+
typeof frontmatter.thinkingLevel === "string"
|
|
239
|
+
? frontmatter.thinkingLevel
|
|
240
|
+
: typeof frontmatter.thinking === "string"
|
|
241
|
+
? frontmatter.thinking
|
|
242
|
+
: undefined;
|
|
243
|
+
|
|
244
|
+
const thinkingLevel = parseThinkingLevel(rawThinkingLevel);
|
|
250
245
|
const model = parseModelList(frontmatter.model);
|
|
251
|
-
const thinkingLevel = parseThinkingLevel(frontmatter);
|
|
252
246
|
const blocking = parseBoolean(frontmatter.blocking);
|
|
253
|
-
|
|
254
247
|
return { name, description, tools, spawns, model, output, thinkingLevel, blocking };
|
|
255
248
|
}
|
|
256
249
|
|