@oh-my-pi/pi-coding-agent 13.9.2 → 13.9.4
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 +64 -0
- package/examples/sdk/02-custom-model.ts +2 -1
- package/package.json +7 -7
- package/src/cli/args.ts +10 -6
- package/src/cli/list-models.ts +2 -2
- package/src/commands/launch.ts +3 -3
- package/src/config/model-registry.ts +136 -38
- package/src/config/model-resolver.ts +47 -21
- package/src/config/settings-schema.ts +56 -2
- package/src/discovery/helpers.ts +3 -3
- package/src/extensibility/custom-tools/types.ts +2 -0
- package/src/extensibility/extensions/loader.ts +3 -2
- package/src/extensibility/extensions/types.ts +10 -7
- package/src/extensibility/hooks/types.ts +2 -0
- package/src/main.ts +5 -22
- package/src/memories/index.ts +7 -3
- package/src/modes/components/footer.ts +10 -8
- package/src/modes/components/model-selector.ts +33 -38
- package/src/modes/components/settings-defs.ts +32 -3
- package/src/modes/components/settings-selector.ts +16 -5
- package/src/modes/components/status-line/context-thresholds.ts +68 -0
- package/src/modes/components/status-line/segments.ts +11 -12
- package/src/modes/components/status-line.ts +2 -6
- package/src/modes/components/thinking-selector.ts +7 -7
- package/src/modes/components/tree-selector.ts +3 -2
- package/src/modes/controllers/command-controller.ts +11 -26
- package/src/modes/controllers/event-controller.ts +16 -3
- package/src/modes/controllers/input-controller.ts +4 -2
- package/src/modes/controllers/selector-controller.ts +5 -4
- package/src/modes/interactive-mode.ts +2 -2
- package/src/modes/rpc/rpc-client.ts +5 -10
- package/src/modes/rpc/rpc-types.ts +5 -5
- package/src/modes/theme/theme.ts +8 -3
- package/src/priority.json +1 -0
- package/src/prompts/system/auto-handoff-threshold-focus.md +1 -0
- package/src/prompts/system/system-prompt.md +18 -2
- package/src/prompts/tools/hashline.md +139 -83
- package/src/sdk.ts +24 -16
- package/src/session/agent-session.ts +261 -118
- package/src/session/agent-storage.ts +14 -14
- package/src/session/compaction/compaction.ts +500 -13
- package/src/session/messages.ts +12 -1
- package/src/session/session-manager.ts +77 -19
- package/src/slash-commands/builtin-registry.ts +48 -0
- package/src/task/agents.ts +3 -2
- package/src/task/executor.ts +2 -2
- package/src/task/types.ts +2 -1
- package/src/thinking.ts +87 -0
- package/src/tools/browser.ts +15 -6
- package/src/tools/fetch.ts +118 -100
- package/src/tools/index.ts +2 -1
- package/src/web/kagi.ts +62 -7
- package/src/web/search/providers/exa.ts +74 -3
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model resolution, scoping, and initial selection
|
|
3
3
|
*/
|
|
4
|
+
|
|
5
|
+
import { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
4
6
|
import {
|
|
5
7
|
type Api,
|
|
8
|
+
clampThinkingLevelForModel,
|
|
6
9
|
DEFAULT_MODEL_PER_PROVIDER,
|
|
10
|
+
type Effort,
|
|
7
11
|
type KnownProvider,
|
|
8
12
|
type Model,
|
|
9
13
|
modelsAreEqual,
|
|
10
|
-
parseThinkingLevel,
|
|
11
|
-
type ThinkingLevel,
|
|
12
14
|
} from "@oh-my-pi/pi-ai";
|
|
13
15
|
import chalk from "chalk";
|
|
14
16
|
import MODEL_PRIO from "../priority.json" with { type: "json" };
|
|
17
|
+
import { parseThinkingLevel, resolveThinkingLevelForModel } from "../thinking";
|
|
15
18
|
import { fuzzyMatch } from "../utils/fuzzy";
|
|
16
19
|
import { MODEL_ROLE_IDS, type ModelRegistry, type ModelRole } from "./model-registry";
|
|
17
20
|
import type { Settings } from "./settings";
|
|
@@ -377,7 +380,14 @@ export function resolveModelRoleValue(
|
|
|
377
380
|
options?.matchPreferences,
|
|
378
381
|
);
|
|
379
382
|
|
|
380
|
-
return {
|
|
383
|
+
return {
|
|
384
|
+
model,
|
|
385
|
+
thinkingLevel: explicitThinkingLevel
|
|
386
|
+
? (resolveThinkingLevelForModel(model, thinkingLevel) ?? thinkingLevel)
|
|
387
|
+
: thinkingLevel,
|
|
388
|
+
explicitThinkingLevel,
|
|
389
|
+
warning,
|
|
390
|
+
};
|
|
381
391
|
}
|
|
382
392
|
|
|
383
393
|
export function extractExplicitThinkingSelector(
|
|
@@ -393,10 +403,10 @@ export function extractExplicitThinkingSelector(
|
|
|
393
403
|
while (!visited.has(current)) {
|
|
394
404
|
visited.add(current);
|
|
395
405
|
const lastColonIndex = current.lastIndexOf(":");
|
|
396
|
-
const
|
|
397
|
-
lastColonIndex > PREFIX_MODEL_ROLE.length
|
|
398
|
-
if (
|
|
399
|
-
return
|
|
406
|
+
const thinkingSelector =
|
|
407
|
+
lastColonIndex > PREFIX_MODEL_ROLE.length ? parseThinkingLevel(current.slice(lastColonIndex + 1)) : undefined;
|
|
408
|
+
if (thinkingSelector) {
|
|
409
|
+
return thinkingSelector;
|
|
400
410
|
}
|
|
401
411
|
const expanded = expandRoleAlias(current, settings).trim();
|
|
402
412
|
if (!expanded || expanded === current) break;
|
|
@@ -520,7 +530,13 @@ export async function resolveModelScope(
|
|
|
520
530
|
|
|
521
531
|
for (const model of matchingModels) {
|
|
522
532
|
if (!scopedModels.find(sm => modelsAreEqual(sm.model, model))) {
|
|
523
|
-
scopedModels.push({
|
|
533
|
+
scopedModels.push({
|
|
534
|
+
model,
|
|
535
|
+
thinkingLevel: explicitThinkingLevel
|
|
536
|
+
? (resolveThinkingLevelForModel(model, thinkingLevel) ?? thinkingLevel)
|
|
537
|
+
: thinkingLevel,
|
|
538
|
+
explicitThinkingLevel,
|
|
539
|
+
});
|
|
524
540
|
}
|
|
525
541
|
}
|
|
526
542
|
continue;
|
|
@@ -543,7 +559,13 @@ export async function resolveModelScope(
|
|
|
543
559
|
|
|
544
560
|
// Avoid duplicates
|
|
545
561
|
if (!scopedModels.find(sm => modelsAreEqual(sm.model, model))) {
|
|
546
|
-
scopedModels.push({
|
|
562
|
+
scopedModels.push({
|
|
563
|
+
model,
|
|
564
|
+
thinkingLevel: explicitThinkingLevel
|
|
565
|
+
? (resolveThinkingLevelForModel(model, thinkingLevel) ?? thinkingLevel)
|
|
566
|
+
: thinkingLevel,
|
|
567
|
+
explicitThinkingLevel,
|
|
568
|
+
});
|
|
547
569
|
}
|
|
548
570
|
}
|
|
549
571
|
|
|
@@ -644,7 +666,7 @@ export function resolveCliModel(options: {
|
|
|
644
666
|
|
|
645
667
|
export interface InitialModelResult {
|
|
646
668
|
model: Model<Api> | undefined;
|
|
647
|
-
thinkingLevel
|
|
669
|
+
thinkingLevel?: ThinkingLevel;
|
|
648
670
|
fallbackMessage: string | undefined;
|
|
649
671
|
}
|
|
650
672
|
|
|
@@ -663,7 +685,7 @@ export async function findInitialModel(options: {
|
|
|
663
685
|
isContinuing: boolean;
|
|
664
686
|
defaultProvider?: string;
|
|
665
687
|
defaultModelId?: string;
|
|
666
|
-
defaultThinkingSelector?:
|
|
688
|
+
defaultThinkingSelector?: Effort;
|
|
667
689
|
modelRegistry: ModelRegistry;
|
|
668
690
|
}): Promise<InitialModelResult> {
|
|
669
691
|
const {
|
|
@@ -678,7 +700,7 @@ export async function findInitialModel(options: {
|
|
|
678
700
|
} = options;
|
|
679
701
|
|
|
680
702
|
let model: Model<Api> | undefined;
|
|
681
|
-
let thinkingLevel:
|
|
703
|
+
let thinkingLevel: Effort | undefined;
|
|
682
704
|
|
|
683
705
|
// 1. CLI args take priority
|
|
684
706
|
if (cliProvider && cliModel) {
|
|
@@ -687,16 +709,22 @@ export async function findInitialModel(options: {
|
|
|
687
709
|
console.error(chalk.red(`Model ${cliProvider}/${cliModel} not found`));
|
|
688
710
|
process.exit(1);
|
|
689
711
|
}
|
|
690
|
-
return { model: found, thinkingLevel:
|
|
712
|
+
return { model: found, thinkingLevel: undefined, fallbackMessage: undefined };
|
|
691
713
|
}
|
|
692
714
|
|
|
693
715
|
// 2. Use first model from scoped models (skip if continuing/resuming)
|
|
694
716
|
if (scopedModels.length > 0 && !isContinuing) {
|
|
695
717
|
const scoped = scopedModels[0];
|
|
696
|
-
const scopedThinkingSelector =
|
|
718
|
+
const scopedThinkingSelector =
|
|
719
|
+
scoped.thinkingLevel === ThinkingLevel.Inherit
|
|
720
|
+
? defaultThinkingSelector
|
|
721
|
+
: (scoped.thinkingLevel ?? defaultThinkingSelector);
|
|
697
722
|
return {
|
|
698
723
|
model: scoped.model,
|
|
699
|
-
thinkingLevel:
|
|
724
|
+
thinkingLevel:
|
|
725
|
+
scopedThinkingSelector === ThinkingLevel.Off
|
|
726
|
+
? ThinkingLevel.Off
|
|
727
|
+
: clampThinkingLevelForModel(scoped.model, scopedThinkingSelector),
|
|
700
728
|
fallbackMessage: undefined,
|
|
701
729
|
};
|
|
702
730
|
}
|
|
@@ -706,9 +734,7 @@ export async function findInitialModel(options: {
|
|
|
706
734
|
const found = modelRegistry.find(defaultProvider, defaultModelId);
|
|
707
735
|
if (found) {
|
|
708
736
|
model = found;
|
|
709
|
-
|
|
710
|
-
thinkingLevel = defaultThinkingSelector;
|
|
711
|
-
}
|
|
737
|
+
thinkingLevel = clampThinkingLevelForModel(found, defaultThinkingSelector);
|
|
712
738
|
return { model, thinkingLevel, fallbackMessage: undefined };
|
|
713
739
|
}
|
|
714
740
|
}
|
|
@@ -722,16 +748,16 @@ export async function findInitialModel(options: {
|
|
|
722
748
|
const defaultId = defaultModelPerProvider[provider];
|
|
723
749
|
const match = availableModels.find(m => m.provider === provider && m.id === defaultId);
|
|
724
750
|
if (match) {
|
|
725
|
-
return { model: match, thinkingLevel:
|
|
751
|
+
return { model: match, thinkingLevel: undefined, fallbackMessage: undefined };
|
|
726
752
|
}
|
|
727
753
|
}
|
|
728
754
|
|
|
729
755
|
// If no default found, use first available
|
|
730
|
-
return { model: availableModels[0], thinkingLevel:
|
|
756
|
+
return { model: availableModels[0], thinkingLevel: undefined, fallbackMessage: undefined };
|
|
731
757
|
}
|
|
732
758
|
|
|
733
759
|
// 5. No model found
|
|
734
|
-
return { model: undefined, thinkingLevel:
|
|
760
|
+
return { model: undefined, thinkingLevel: undefined, fallbackMessage: undefined };
|
|
735
761
|
}
|
|
736
762
|
|
|
737
763
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { THINKING_EFFORTS } from "@oh-my-pi/pi-ai";
|
|
2
2
|
|
|
3
3
|
/** Unified settings schema - single source of truth for all settings.
|
|
4
4
|
* Unified settings schema - single source of truth for all settings.
|
|
@@ -192,7 +192,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
192
192
|
},
|
|
193
193
|
defaultThinkingLevel: {
|
|
194
194
|
type: "enum",
|
|
195
|
-
values:
|
|
195
|
+
values: THINKING_EFFORTS,
|
|
196
196
|
default: "high",
|
|
197
197
|
ui: {
|
|
198
198
|
tab: "agent",
|
|
@@ -345,9 +345,48 @@ export const SETTINGS_SCHEMA = {
|
|
|
345
345
|
description: "Automatically compact context when it gets too large",
|
|
346
346
|
},
|
|
347
347
|
},
|
|
348
|
+
"compaction.strategy": {
|
|
349
|
+
type: "enum",
|
|
350
|
+
values: ["context-full", "handoff", "off"] as const,
|
|
351
|
+
default: "context-full",
|
|
352
|
+
ui: {
|
|
353
|
+
tab: "agent",
|
|
354
|
+
label: "Context-full strategy",
|
|
355
|
+
description: "Choose in-place context-full maintenance, auto-handoff, or disable auto maintenance (off)",
|
|
356
|
+
submenu: true,
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
"compaction.thresholdPercent": {
|
|
360
|
+
type: "number",
|
|
361
|
+
default: -1,
|
|
362
|
+
ui: {
|
|
363
|
+
tab: "agent",
|
|
364
|
+
label: "Context threshold",
|
|
365
|
+
description: "Percent threshold for context maintenance; set to Default to use legacy reserve-based behavior",
|
|
366
|
+
submenu: true,
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
"compaction.handoffSaveToDisk": {
|
|
370
|
+
type: "boolean",
|
|
371
|
+
default: false,
|
|
372
|
+
ui: {
|
|
373
|
+
tab: "agent",
|
|
374
|
+
label: "Save auto-handoff docs",
|
|
375
|
+
description: "Save generated handoff documents to markdown files for the auto-handoff flow",
|
|
376
|
+
},
|
|
377
|
+
},
|
|
348
378
|
"compaction.reserveTokens": { type: "number", default: 16384 },
|
|
349
379
|
"compaction.keepRecentTokens": { type: "number", default: 20000 },
|
|
350
380
|
"compaction.autoContinue": { type: "boolean", default: true },
|
|
381
|
+
"compaction.remoteEnabled": {
|
|
382
|
+
type: "boolean",
|
|
383
|
+
default: true,
|
|
384
|
+
ui: {
|
|
385
|
+
tab: "agent",
|
|
386
|
+
label: "Remote compaction",
|
|
387
|
+
description: "Use remote compaction endpoints when available instead of local summarization",
|
|
388
|
+
},
|
|
389
|
+
},
|
|
351
390
|
"compaction.remoteEndpoint": { type: "string", default: undefined },
|
|
352
391
|
|
|
353
392
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -1186,6 +1225,17 @@ export const SETTINGS_SCHEMA = {
|
|
|
1186
1225
|
submenu: true,
|
|
1187
1226
|
},
|
|
1188
1227
|
},
|
|
1228
|
+
serviceTier: {
|
|
1229
|
+
type: "enum",
|
|
1230
|
+
values: ["none", "auto", "default", "flex", "scale", "priority"] as const,
|
|
1231
|
+
default: "none",
|
|
1232
|
+
ui: {
|
|
1233
|
+
tab: "agent",
|
|
1234
|
+
label: "Service tier",
|
|
1235
|
+
description: "OpenAI processing priority (none = omit parameter)",
|
|
1236
|
+
submenu: true,
|
|
1237
|
+
},
|
|
1238
|
+
},
|
|
1189
1239
|
} as const;
|
|
1190
1240
|
|
|
1191
1241
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -1265,9 +1315,13 @@ export type StatusLineSeparatorStyle = SettingValue<"statusLine.separator">;
|
|
|
1265
1315
|
|
|
1266
1316
|
export interface CompactionSettings {
|
|
1267
1317
|
enabled: boolean;
|
|
1318
|
+
strategy: "context-full" | "handoff" | "off";
|
|
1319
|
+
thresholdPercent: number;
|
|
1268
1320
|
reserveTokens: number;
|
|
1269
1321
|
keepRecentTokens: number;
|
|
1322
|
+
handoffSaveToDisk: boolean;
|
|
1270
1323
|
autoContinue: boolean;
|
|
1324
|
+
remoteEnabled: boolean;
|
|
1271
1325
|
remoteEndpoint: string | undefined;
|
|
1272
1326
|
}
|
|
1273
1327
|
|
package/src/discovery/helpers.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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-
|
|
4
|
-
import { parseThinkingLevel } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
5
4
|
import { FileType, glob } from "@oh-my-pi/pi-natives";
|
|
6
5
|
import { CONFIG_DIR_NAME, tryParseJson } from "@oh-my-pi/pi-utils";
|
|
7
6
|
import { readFile } from "../capability/fs";
|
|
8
7
|
import { parseRuleConditionAndScope, type Rule, type RuleFrontmatter } from "../capability/rule";
|
|
9
8
|
import type { Skill, SkillFrontmatter } from "../capability/skill";
|
|
10
9
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
10
|
+
import { parseThinkingLevel } from "../thinking";
|
|
11
11
|
import { parseFrontmatter } from "../utils/frontmatter";
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -206,7 +206,7 @@ export function parseAgentFields(frontmatter: Record<string, unknown>): ParsedAg
|
|
|
206
206
|
return null;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
let tools = parseArrayOrCSV(frontmatter.tools);
|
|
209
|
+
let tools = parseArrayOrCSV(frontmatter.tools)?.map(tool => tool.toLowerCase());
|
|
210
210
|
|
|
211
211
|
// Subagents with explicit tool lists always need submit_result
|
|
212
212
|
if (tools && !tools.includes("submit_result")) {
|
|
@@ -90,9 +90,11 @@ export type CustomToolSessionEvent =
|
|
|
90
90
|
| {
|
|
91
91
|
reason: "auto_compaction_start";
|
|
92
92
|
trigger: "threshold" | "overflow";
|
|
93
|
+
action: "context-full" | "handoff";
|
|
93
94
|
}
|
|
94
95
|
| {
|
|
95
96
|
reason: "auto_compaction_end";
|
|
97
|
+
action: "context-full" | "handoff";
|
|
96
98
|
result: CompactionResult | undefined;
|
|
97
99
|
aborted: boolean;
|
|
98
100
|
willRetry: boolean;
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
import type * as fs1 from "node:fs";
|
|
5
5
|
import * as fs from "node:fs/promises";
|
|
6
6
|
import * as path from "node:path";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
8
|
+
import type { ImageContent, Model, TextContent } from "@oh-my-pi/pi-ai";
|
|
8
9
|
import * as piCodingAgent from "@oh-my-pi/pi-coding-agent";
|
|
9
10
|
import type { KeyId } from "@oh-my-pi/pi-tui";
|
|
10
11
|
import { hasFsCode, isEacces, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
@@ -214,7 +215,7 @@ class ConcreteExtensionAPI implements ExtensionAPI, IExtensionRuntime {
|
|
|
214
215
|
return this.runtime.setModel(model);
|
|
215
216
|
}
|
|
216
217
|
|
|
217
|
-
getThinkingLevel(): ThinkingLevel {
|
|
218
|
+
getThinkingLevel(): ThinkingLevel | undefined {
|
|
218
219
|
return this.runtime.getThinkingLevel();
|
|
219
220
|
}
|
|
220
221
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - Register commands, keyboard shortcuts, and CLI flags
|
|
8
8
|
* - Interact with the user via UI primitives
|
|
9
9
|
*/
|
|
10
|
-
import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
10
|
+
import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
11
11
|
import type {
|
|
12
12
|
Api,
|
|
13
13
|
AssistantMessageEvent,
|
|
@@ -19,7 +19,6 @@ import type {
|
|
|
19
19
|
OAuthLoginCallbacks,
|
|
20
20
|
SimpleStreamOptions,
|
|
21
21
|
TextContent,
|
|
22
|
-
ThinkingLevel,
|
|
23
22
|
ToolResultMessage,
|
|
24
23
|
} from "@oh-my-pi/pi-ai";
|
|
25
24
|
import type * as piCodingAgent from "@oh-my-pi/pi-coding-agent";
|
|
@@ -538,11 +537,13 @@ export interface ToolExecutionEndEvent {
|
|
|
538
537
|
export interface AutoCompactionStartEvent {
|
|
539
538
|
type: "auto_compaction_start";
|
|
540
539
|
reason: "threshold" | "overflow";
|
|
540
|
+
action: "context-full" | "handoff";
|
|
541
541
|
}
|
|
542
542
|
|
|
543
543
|
/** Fired when auto-compaction ends */
|
|
544
544
|
export interface AutoCompactionEndEvent {
|
|
545
545
|
type: "auto_compaction_end";
|
|
546
|
+
action: "context-full" | "handoff";
|
|
546
547
|
result: CompactionResult | undefined;
|
|
547
548
|
aborted: boolean;
|
|
548
549
|
willRetry: boolean;
|
|
@@ -1056,9 +1057,9 @@ export interface ExtensionAPI {
|
|
|
1056
1057
|
setModel(model: Model): Promise<boolean>;
|
|
1057
1058
|
|
|
1058
1059
|
/** Get current thinking level. */
|
|
1059
|
-
getThinkingLevel(): ThinkingLevel;
|
|
1060
|
+
getThinkingLevel(): ThinkingLevel | undefined;
|
|
1060
1061
|
|
|
1061
|
-
/** Set thinking level
|
|
1062
|
+
/** Set thinking level for the current session. */
|
|
1062
1063
|
setThinkingLevel(level: ThinkingLevel): void;
|
|
1063
1064
|
|
|
1064
1065
|
// =========================================================================
|
|
@@ -1084,11 +1085,11 @@ export interface ExtensionAPI {
|
|
|
1084
1085
|
* id: "claude-sonnet-4@20250514",
|
|
1085
1086
|
* name: "Claude Sonnet 4 (Vertex)",
|
|
1086
1087
|
* reasoning: true,
|
|
1088
|
+
* thinking: { mode: "anthropic-adaptive", minLevel: "minimal", maxLevel: "high" },
|
|
1087
1089
|
* input: ["text", "image"],
|
|
1088
1090
|
* cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
1089
1091
|
* contextWindow: 200000,
|
|
1090
1092
|
* maxTokens: 64000,
|
|
1091
|
-
* }
|
|
1092
1093
|
* ]
|
|
1093
1094
|
* });
|
|
1094
1095
|
*
|
|
@@ -1147,8 +1148,10 @@ export interface ProviderModelConfig {
|
|
|
1147
1148
|
name: string;
|
|
1148
1149
|
/** API type override for this model. */
|
|
1149
1150
|
api?: Api;
|
|
1150
|
-
/** Whether the model supports extended thinking. */
|
|
1151
|
+
/** Whether the model supports extended thinking at all. */
|
|
1151
1152
|
reasoning: boolean;
|
|
1153
|
+
/** Optional canonical thinking capability metadata for per-model effort support. */
|
|
1154
|
+
thinking?: Model["thinking"];
|
|
1152
1155
|
/** Supported input types. */
|
|
1153
1156
|
input: ("text" | "image")[];
|
|
1154
1157
|
/** Cost per million tokens. */
|
|
@@ -1216,7 +1219,7 @@ export type SetActiveToolsHandler = (toolNames: string[]) => Promise<void>;
|
|
|
1216
1219
|
|
|
1217
1220
|
export type SetModelHandler = (model: Model) => Promise<boolean>;
|
|
1218
1221
|
|
|
1219
|
-
export type GetThinkingLevelHandler = () => ThinkingLevel;
|
|
1222
|
+
export type GetThinkingLevelHandler = () => ThinkingLevel | undefined;
|
|
1220
1223
|
|
|
1221
1224
|
export type SetThinkingLevelHandler = (level: ThinkingLevel, persist?: boolean) => void;
|
|
1222
1225
|
|
|
@@ -395,11 +395,13 @@ export interface TurnEndEvent {
|
|
|
395
395
|
export interface AutoCompactionStartEvent {
|
|
396
396
|
type: "auto_compaction_start";
|
|
397
397
|
reason: "threshold" | "overflow";
|
|
398
|
+
action: "context-full" | "handoff";
|
|
398
399
|
}
|
|
399
400
|
|
|
400
401
|
/** Event data for auto_compaction_end event. */
|
|
401
402
|
export interface AutoCompactionEndEvent {
|
|
402
403
|
type: "auto_compaction_end";
|
|
404
|
+
action: "context-full" | "handoff";
|
|
403
405
|
result: CompactionResult | undefined;
|
|
404
406
|
aborted: boolean;
|
|
405
407
|
willRetry: boolean;
|
package/src/main.ts
CHANGED
|
@@ -10,7 +10,7 @@ import * as fs from "node:fs/promises";
|
|
|
10
10
|
import * as os from "node:os";
|
|
11
11
|
import * as path from "node:path";
|
|
12
12
|
import { createInterface } from "node:readline/promises";
|
|
13
|
-
import {
|
|
13
|
+
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
14
14
|
import { $env, getProjectDir, logger, postmortem, setProjectDir, VERSION } from "@oh-my-pi/pi-utils";
|
|
15
15
|
import chalk from "chalk";
|
|
16
16
|
import type { Args } from "./cli/args";
|
|
@@ -334,11 +334,10 @@ async function buildSessionOptions(
|
|
|
334
334
|
scopedModels: ScopedModel[],
|
|
335
335
|
sessionManager: SessionManager | undefined,
|
|
336
336
|
modelRegistry: ModelRegistry,
|
|
337
|
-
): Promise<{ options: CreateAgentSessionOptions
|
|
337
|
+
): Promise<{ options: CreateAgentSessionOptions }> {
|
|
338
338
|
const options: CreateAgentSessionOptions = {
|
|
339
339
|
cwd: parsed.cwd ?? getProjectDir(),
|
|
340
340
|
};
|
|
341
|
-
let cliThinkingFromModel = false;
|
|
342
341
|
|
|
343
342
|
// Auto-discover SYSTEM.md if no CLI system prompt provided
|
|
344
343
|
const systemPromptSource = parsed.systemPrompt ?? discoverSystemPromptFile();
|
|
@@ -380,7 +379,6 @@ async function buildSessionOptions(
|
|
|
380
379
|
settings.overrideModelRoles({ default: `${resolved.model.provider}/${resolved.model.id}` });
|
|
381
380
|
if (!parsed.thinking && resolved.thinkingLevel) {
|
|
382
381
|
options.thinkingLevel = resolved.thinkingLevel;
|
|
383
|
-
cliThinkingFromModel = true;
|
|
384
382
|
}
|
|
385
383
|
}
|
|
386
384
|
} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {
|
|
@@ -483,7 +481,7 @@ async function buildSessionOptions(
|
|
|
483
481
|
options.additionalExtensionPaths = [];
|
|
484
482
|
}
|
|
485
483
|
|
|
486
|
-
return { options
|
|
484
|
+
return { options };
|
|
487
485
|
}
|
|
488
486
|
|
|
489
487
|
export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<void> {
|
|
@@ -618,7 +616,7 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
618
616
|
sessionManager = await SessionManager.open(selectedPath);
|
|
619
617
|
}
|
|
620
618
|
|
|
621
|
-
const { options: sessionOptions
|
|
619
|
+
const { options: sessionOptions } = await logger.timeAsync("buildSessionOptions", () =>
|
|
622
620
|
buildSessionOptions(parsedArgs, scopedModels, sessionManager, modelRegistry),
|
|
623
621
|
);
|
|
624
622
|
sessionOptions.authStorage = authStorage;
|
|
@@ -692,21 +690,6 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
692
690
|
process.exit(1);
|
|
693
691
|
}
|
|
694
692
|
|
|
695
|
-
// Clamp thinking level to model capabilities for CLI-provided thinking levels.
|
|
696
|
-
// This covers both --thinking <level> and --model <pattern>:<thinking>.
|
|
697
|
-
const cliThinkingOverride = parsedArgs.thinking !== undefined || cliThinkingFromModel;
|
|
698
|
-
if (session.model && cliThinkingOverride) {
|
|
699
|
-
let effectiveThinking = session.thinkingLevel;
|
|
700
|
-
if (!session.model.reasoning) {
|
|
701
|
-
effectiveThinking = "off";
|
|
702
|
-
} else if (effectiveThinking === "xhigh" && !supportsXhigh(session.model)) {
|
|
703
|
-
effectiveThinking = "high";
|
|
704
|
-
}
|
|
705
|
-
if (effectiveThinking !== session.thinkingLevel) {
|
|
706
|
-
session.setThinkingLevel(effectiveThinking);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
|
|
710
693
|
if (mode === "rpc") {
|
|
711
694
|
await runRpcMode(session);
|
|
712
695
|
} else if (isInteractive) {
|
|
@@ -717,7 +700,7 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
717
700
|
if (scopedModelsForDisplay.length > 0) {
|
|
718
701
|
const modelList = scopedModelsForDisplay
|
|
719
702
|
.map(scopedModel => {
|
|
720
|
-
const thinkingStr = scopedModel.thinkingLevel
|
|
703
|
+
const thinkingStr = !scopedModel.thinkingLevel ? `:${scopedModel.thinkingLevel}` : "";
|
|
721
704
|
return `${scopedModel.model.id}${thinkingStr}`;
|
|
722
705
|
})
|
|
723
706
|
.join(", ");
|
package/src/memories/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type * as fsNode from "node:fs";
|
|
|
3
3
|
import * as fs from "node:fs/promises";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
6
|
-
import { completeSimple, type Model } from "@oh-my-pi/pi-ai";
|
|
6
|
+
import { completeSimple, Effort, type Model } from "@oh-my-pi/pi-ai";
|
|
7
7
|
import { getAgentDbPath, logger, parseJsonlLenient } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import type { ModelRegistry } from "../config/model-registry";
|
|
9
9
|
import { parseModelString } from "../config/model-resolver";
|
|
@@ -583,7 +583,11 @@ async function runStage1Job(options: {
|
|
|
583
583
|
systemPrompt: stageOneSystemTemplate,
|
|
584
584
|
messages: [{ role: "user", content: [{ type: "text", text: inputPrompt }], timestamp: Date.now() }],
|
|
585
585
|
},
|
|
586
|
-
{
|
|
586
|
+
{
|
|
587
|
+
apiKey,
|
|
588
|
+
maxTokens: Math.max(1024, Math.min(4096, Math.floor(modelMaxTokens * 0.2))),
|
|
589
|
+
reasoning: Effort.Low,
|
|
590
|
+
},
|
|
587
591
|
);
|
|
588
592
|
|
|
589
593
|
if (response.stopReason === "error") {
|
|
@@ -709,7 +713,7 @@ async function runConsolidationModel(options: { memoryRoot: string; model: Model
|
|
|
709
713
|
{
|
|
710
714
|
messages: [{ role: "user", content: [{ type: "text", text: input }], timestamp: Date.now() }],
|
|
711
715
|
},
|
|
712
|
-
{ apiKey, maxTokens: 8192, reasoning:
|
|
716
|
+
{ apiKey, maxTokens: 8192, reasoning: Effort.Medium },
|
|
713
717
|
);
|
|
714
718
|
if (response.stopReason === "error") {
|
|
715
719
|
throw new Error(response.errorMessage || "phase2 model error");
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
+
import { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
3
|
import { type Component, padding, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
3
4
|
import { formatNumber, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
4
5
|
import { theme } from "../../modes/theme/theme";
|
|
5
6
|
import type { AgentSession } from "../../session/agent-session";
|
|
6
7
|
import { shortenPath } from "../../tools/render-utils";
|
|
7
8
|
import { findGitHeadPathAsync, sanitizeStatusText } from "../shared";
|
|
9
|
+
import { getContextUsageLevel, getContextUsageThemeColor } from "./status-line/context-thresholds";
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Footer component that shows pwd, token stats, and context usage
|
|
@@ -197,10 +199,10 @@ export class FooterComponent implements Component {
|
|
|
197
199
|
contextPercent === "?"
|
|
198
200
|
? `?/${formatNumber(contextWindow)}${autoIndicator}`
|
|
199
201
|
: `${contextPercent}%/${formatNumber(contextWindow)}${autoIndicator}`;
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
if (contextUsage?.percent !== null && contextUsage?.percent !== undefined) {
|
|
203
|
+
const color = getContextUsageThemeColor(getContextUsageLevel(contextPercentValue, contextWindow));
|
|
204
|
+
contextPercentStr =
|
|
205
|
+
color === "statusLineContext" ? contextPercentDisplay : theme.fg(color, contextPercentDisplay);
|
|
204
206
|
} else {
|
|
205
207
|
contextPercentStr = contextPercentDisplay;
|
|
206
208
|
}
|
|
@@ -211,11 +213,11 @@ export class FooterComponent implements Component {
|
|
|
211
213
|
// Add model name on the right side, plus thinking level if model supports it
|
|
212
214
|
const modelName = state.model?.id || "no-model";
|
|
213
215
|
|
|
214
|
-
// Add thinking level hint
|
|
216
|
+
// Add thinking level hint when the current model advertises supported efforts
|
|
215
217
|
let rightSide = modelName;
|
|
216
|
-
if (state.model?.
|
|
217
|
-
const thinkingLevel = state.thinkingLevel
|
|
218
|
-
if (thinkingLevel !==
|
|
218
|
+
if (state.model?.thinking) {
|
|
219
|
+
const thinkingLevel = state.thinkingLevel ?? ThinkingLevel.Off;
|
|
220
|
+
if (thinkingLevel !== ThinkingLevel.Off) {
|
|
219
221
|
rightSide = `${modelName} • ${thinkingLevel}`;
|
|
220
222
|
}
|
|
221
223
|
}
|