@diegopetrucci/pi-oracle 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/index.ts +104 -26
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
An Amp-style oracle for [pi](https://github.com/
|
|
5
|
+
An Amp-style oracle for [pi](https://github.com/earendil-works/pi-mono).
|
|
6
6
|
|
|
7
7
|
It adds an `oracle` tool that spins up a separate read-only pi subprocess and sends it to the strongest reasoning model available on the **same provider/subscription** the user is currently using.
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ It adds an `oracle` tool that spins up a separate read-only pi subprocess and se
|
|
|
11
11
|
- creates an isolated read-only subprocess
|
|
12
12
|
- auto-picks the strongest reasoning model on the current provider
|
|
13
13
|
- uses provider-specific hardcoded rankings first, then a heuristic fallback
|
|
14
|
-
-
|
|
14
|
+
- requests `xhigh` by default for reasoning models, then clamps to the model-supported thinking level
|
|
15
15
|
- defaults to `read,grep,find,ls`
|
|
16
16
|
- can optionally allow non-mutating `bash` inspection
|
|
17
17
|
- shows a live oracle status line and widget while the subprocess is running
|
|
@@ -27,7 +27,7 @@ By default, the extension:
|
|
|
27
27
|
4. tries a provider-specific hardcoded priority list first
|
|
28
28
|
5. falls back to a heuristic that favors stronger tiers like `opus`, `pro`, newer versions, and penalizes `mini`, `flash`, `haiku`, `spark`, etc.
|
|
29
29
|
|
|
30
|
-
The hardcoded rankings now cover pi's built-in provider set, including
|
|
30
|
+
The hardcoded rankings now cover pi's built-in provider set, including Together; see the provider matrix for the current provider-by-provider top picks.
|
|
31
31
|
|
|
32
32
|
If no reasoning model exists on the current provider, it falls back to the best available model on that provider.
|
|
33
33
|
|
|
@@ -35,9 +35,9 @@ If no reasoning model exists on the current provider, it falls back to the best
|
|
|
35
35
|
|
|
36
36
|
Yes — the extension explicitly sets the oracle reasoning level.
|
|
37
37
|
|
|
38
|
-
- reasoning models
|
|
38
|
+
- reasoning models request `xhigh` by default, then use the Pi-compatible effective thinking level supported by the matched model
|
|
39
39
|
- non-reasoning models default to `off`
|
|
40
|
-
- you can override it with the tool's optional `thinkingLevel` parameter
|
|
40
|
+
- you can override it with the tool's optional `thinkingLevel` parameter; matched models still clamp unsupported overrides and report the effective level
|
|
41
41
|
|
|
42
42
|
Use `/oracle-model` inside pi to see what it would pick right now.
|
|
43
43
|
|
package/index.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { basename } from "node:path";
|
|
4
|
-
import { StringEnum } from "@
|
|
5
|
-
import { getMarkdownTheme, type ExtensionAPI } from "@
|
|
6
|
-
import { Container, Markdown, Spacer, Text } from "@
|
|
7
|
-
import { Type } from "
|
|
4
|
+
import { StringEnum } from "@earendil-works/pi-ai";
|
|
5
|
+
import { getMarkdownTheme, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import { Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
|
|
7
|
+
import { Type } from "typebox";
|
|
8
8
|
|
|
9
9
|
type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
10
|
+
type ThinkingLevelMap = Partial<Record<ThinkingLevel, unknown | null>>;
|
|
10
11
|
|
|
11
12
|
type PiModel = {
|
|
12
13
|
provider: string;
|
|
@@ -15,6 +16,7 @@ type PiModel = {
|
|
|
15
16
|
reasoning?: boolean;
|
|
16
17
|
contextWindow?: number;
|
|
17
18
|
maxTokens?: number;
|
|
19
|
+
thinkingLevelMap?: ThinkingLevelMap;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
interface UsageStats {
|
|
@@ -33,6 +35,8 @@ interface OracleSelection {
|
|
|
33
35
|
modelId: string;
|
|
34
36
|
modelName?: string;
|
|
35
37
|
thinkingLevel: ThinkingLevel;
|
|
38
|
+
requestedThinkingLevel?: ThinkingLevel;
|
|
39
|
+
thinkingLevelClamped?: boolean;
|
|
36
40
|
autoSelected: boolean;
|
|
37
41
|
selectionReason: string;
|
|
38
42
|
}
|
|
@@ -171,14 +175,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
171
175
|
"gemini-2.5-flash-lite-preview",
|
|
172
176
|
"gemini-2.5-flash-lite",
|
|
173
177
|
],
|
|
174
|
-
"google-antigravity": [
|
|
175
|
-
"claude-opus-4-6-thinking",
|
|
176
|
-
"claude-sonnet-4-5-thinking",
|
|
177
|
-
"gemini-3.1-pro-low",
|
|
178
|
-
"gemini-3-flash",
|
|
179
|
-
"gemini-2.0-flash",
|
|
180
|
-
],
|
|
181
|
-
"google-gemini-cli": ["gemini-3-pro-preview", "gemini-2.5-pro", "gemini-1.5-flash"],
|
|
182
178
|
"google-vertex": [
|
|
183
179
|
"gemini-3.1-pro-preview-customtools",
|
|
184
180
|
"gemini-3.1-pro-preview",
|
|
@@ -302,6 +298,20 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
302
298
|
"minimax/minimax-m2.1",
|
|
303
299
|
"z-ai/glm-5.1",
|
|
304
300
|
],
|
|
301
|
+
together: [
|
|
302
|
+
"deepseek-ai/DeepSeek-V4-Pro",
|
|
303
|
+
"zai-org/GLM-5.1",
|
|
304
|
+
"moonshotai/Kimi-K2.6",
|
|
305
|
+
"Qwen/Qwen3.6-Plus",
|
|
306
|
+
"MiniMaxAI/MiniMax-M2.7",
|
|
307
|
+
"Qwen/Qwen3.5-397B-A17B",
|
|
308
|
+
"Qwen/Qwen3-Coder-Next-FP8",
|
|
309
|
+
"Qwen/Qwen3-235B-A22B-Instruct-2507-tput",
|
|
310
|
+
"openai/gpt-oss-120b",
|
|
311
|
+
"moonshotai/Kimi-K2.5",
|
|
312
|
+
"deepseek-ai/DeepSeek-V3-1",
|
|
313
|
+
"MiniMaxAI/MiniMax-M2.5",
|
|
314
|
+
],
|
|
305
315
|
"vercel-ai-gateway": [
|
|
306
316
|
"anthropic/claude-opus-4.7",
|
|
307
317
|
"anthropic/claude-opus-4.6",
|
|
@@ -335,6 +345,28 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
335
345
|
"grok-3-mini-fast",
|
|
336
346
|
"grok-3-latest",
|
|
337
347
|
],
|
|
348
|
+
xiaomi: ["mimo-v2.5-pro", "mimo-v2.5", "mimo-v2-pro", "mimo-v2-omni", "mimo-v2-flash"],
|
|
349
|
+
"xiaomi-token-plan-ams": [
|
|
350
|
+
"mimo-v2.5-pro",
|
|
351
|
+
"mimo-v2.5",
|
|
352
|
+
"mimo-v2-pro",
|
|
353
|
+
"mimo-v2-omni",
|
|
354
|
+
"mimo-v2-flash",
|
|
355
|
+
],
|
|
356
|
+
"xiaomi-token-plan-cn": [
|
|
357
|
+
"mimo-v2.5-pro",
|
|
358
|
+
"mimo-v2.5",
|
|
359
|
+
"mimo-v2-pro",
|
|
360
|
+
"mimo-v2-omni",
|
|
361
|
+
"mimo-v2-flash",
|
|
362
|
+
],
|
|
363
|
+
"xiaomi-token-plan-sgp": [
|
|
364
|
+
"mimo-v2.5-pro",
|
|
365
|
+
"mimo-v2.5",
|
|
366
|
+
"mimo-v2-pro",
|
|
367
|
+
"mimo-v2-omni",
|
|
368
|
+
"mimo-v2-flash",
|
|
369
|
+
],
|
|
338
370
|
zai: [
|
|
339
371
|
"glm-5.1",
|
|
340
372
|
"glm-5-turbo",
|
|
@@ -348,7 +380,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
348
380
|
],
|
|
349
381
|
moonshotai: ["kimi-k2.6", "kimi-k2-thinking-turbo", "kimi-k2-thinking", "kimi-k2.5"],
|
|
350
382
|
"moonshotai-cn": ["kimi-k2.6", "kimi-k2-thinking-turbo", "kimi-k2-thinking", "kimi-k2.5"],
|
|
351
|
-
"gemini-cli": ["gemini-3-pro-preview", "gemini-2.5-pro", "gemini-1.5-flash"],
|
|
352
383
|
};
|
|
353
384
|
|
|
354
385
|
const ORACLE_SYSTEM_PROMPT = [
|
|
@@ -380,7 +411,7 @@ const OracleParams = Type.Object({
|
|
|
380
411
|
thinkingLevel: Type.Optional(
|
|
381
412
|
StringEnum(THINKING_LEVELS, {
|
|
382
413
|
description:
|
|
383
|
-
"Optional reasoning level override for the oracle subprocess.
|
|
414
|
+
"Optional reasoning level override for the oracle subprocess. Defaults request xhigh for reasoning models and off for non-reasoning models, then clamp to matched model capabilities.",
|
|
384
415
|
}),
|
|
385
416
|
),
|
|
386
417
|
cwd: Type.Optional(Type.String({ description: "Optional working directory for the oracle subprocess." })),
|
|
@@ -517,9 +548,48 @@ function withThinking(modelRef: string, thinkingLevel: ThinkingLevel): string {
|
|
|
517
548
|
return `${modelRef}:${thinkingLevel}`;
|
|
518
549
|
}
|
|
519
550
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
551
|
+
// Keep these local so the extension stays compatible with older pi peer installs that do not export clamp helpers.
|
|
552
|
+
function isThinkingLevelSupported(model: PiModel, level: ThinkingLevel): boolean {
|
|
553
|
+
if (!model.reasoning) return level === "off";
|
|
554
|
+
|
|
555
|
+
const map = model.thinkingLevelMap;
|
|
556
|
+
if (level === "xhigh") {
|
|
557
|
+
return !!map && Object.prototype.hasOwnProperty.call(map, "xhigh") && map.xhigh != null;
|
|
558
|
+
}
|
|
559
|
+
return map?.[level] !== null;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function clampThinkingLevel(model: PiModel, requested: ThinkingLevel): ThinkingLevel {
|
|
563
|
+
if (isThinkingLevelSupported(model, requested)) return requested;
|
|
564
|
+
|
|
565
|
+
const requestedIndex = THINKING_LEVELS.indexOf(requested);
|
|
566
|
+
for (let index = requestedIndex + 1; index < THINKING_LEVELS.length; index++) {
|
|
567
|
+
const level = THINKING_LEVELS[index];
|
|
568
|
+
if (isThinkingLevelSupported(model, level)) return level;
|
|
569
|
+
}
|
|
570
|
+
for (let index = requestedIndex - 1; index >= 0; index--) {
|
|
571
|
+
const level = THINKING_LEVELS[index];
|
|
572
|
+
if (isThinkingLevelSupported(model, level)) return level;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
return "off";
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function resolveThinkingLevel(
|
|
579
|
+
model: PiModel | undefined,
|
|
580
|
+
override: ThinkingLevel | undefined,
|
|
581
|
+
): { requested: ThinkingLevel; effective: ThinkingLevel; clamped: boolean } {
|
|
582
|
+
const requested = override ?? (model?.reasoning ? DEFAULT_THINKING_LEVEL : "off");
|
|
583
|
+
const effective = model ? clampThinkingLevel(model, requested) : requested;
|
|
584
|
+
return { requested, effective, clamped: effective !== requested };
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
function appendThinkingLevelClampReason(
|
|
588
|
+
reason: string,
|
|
589
|
+
resolution: { requested: ThinkingLevel; effective: ThinkingLevel; clamped: boolean },
|
|
590
|
+
): string {
|
|
591
|
+
if (!resolution.clamped) return reason;
|
|
592
|
+
return `${reason} Requested thinking level ${resolution.requested} was clamped to ${resolution.effective} based on the matched model's capabilities.`;
|
|
523
593
|
}
|
|
524
594
|
|
|
525
595
|
async function findAvailableModel(
|
|
@@ -586,9 +656,11 @@ async function selectOracleModel(
|
|
|
586
656
|
|
|
587
657
|
const preferred = selectPreferredModel(candidates, providerForPreferences);
|
|
588
658
|
const winner = preferred ?? [...candidates].sort((a, b) => rankModel(b) - rankModel(a))[0];
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
: reason
|
|
659
|
+
const thinking = resolveThinkingLevel(winner, thinkingLevelOverride);
|
|
660
|
+
const selectionReason = appendThinkingLevelClampReason(
|
|
661
|
+
preferred ? `Selected ${winner.id} via the hardcoded preference list for ${winner.provider}.` : reason,
|
|
662
|
+
thinking,
|
|
663
|
+
);
|
|
592
664
|
|
|
593
665
|
return {
|
|
594
666
|
ok: true,
|
|
@@ -597,7 +669,8 @@ async function selectOracleModel(
|
|
|
597
669
|
provider: winner.provider,
|
|
598
670
|
modelId: winner.id,
|
|
599
671
|
modelName: winner.name,
|
|
600
|
-
thinkingLevel:
|
|
672
|
+
thinkingLevel: thinking.effective,
|
|
673
|
+
...(thinking.clamped ? { requestedThinkingLevel: thinking.requested, thinkingLevelClamped: true } : {}),
|
|
601
674
|
autoSelected: true,
|
|
602
675
|
selectionReason,
|
|
603
676
|
},
|
|
@@ -854,7 +927,7 @@ export default function oracleExtension(pi: ExtensionAPI) {
|
|
|
854
927
|
"Use this tool sparingly when you want a second opinion, deeper analysis, code review, debugging help, or a higher-reasoning pass.",
|
|
855
928
|
"Do not use it for routine low-value work; it is slower than the main agent.",
|
|
856
929
|
"The oracle is read-only by default. Set includeBash only when shell-based inspection is genuinely useful.",
|
|
857
|
-
"The oracle
|
|
930
|
+
"The oracle requests xhigh by default for reasoning models; defaults and explicit thinkingLevel overrides are clamped to the effective model-supported level when the model is matched.",
|
|
858
931
|
],
|
|
859
932
|
parameters: OracleParams,
|
|
860
933
|
|
|
@@ -875,16 +948,21 @@ export default function oracleExtension(pi: ExtensionAPI) {
|
|
|
875
948
|
const provider =
|
|
876
949
|
matched?.provider ?? (modelRef.includes("/") ? modelRef.split("/")[0] : ctx.model?.provider ?? "unknown");
|
|
877
950
|
const modelId = matched?.id ?? (modelRef.includes("/") ? modelRef.split("/").slice(1).join("/") : modelRef);
|
|
951
|
+
const thinking = resolveThinkingLevel(matched, params.thinkingLevel);
|
|
952
|
+
const selectionReason = matched
|
|
953
|
+
? appendThinkingLevelClampReason("Used the explicit model override provided in the tool call.", thinking)
|
|
954
|
+
: "Used the explicit model override provided in the tool call. The model was not matched against the authenticated model list, so the reasoning level fallback was applied.";
|
|
878
955
|
selection = {
|
|
879
956
|
modelRef: matched ? `${matched.provider}/${matched.id}` : modelRef,
|
|
880
957
|
provider,
|
|
881
958
|
modelId,
|
|
882
959
|
modelName: matched?.name,
|
|
883
|
-
thinkingLevel:
|
|
960
|
+
thinkingLevel: thinking.effective,
|
|
961
|
+
...(matched && thinking.clamped
|
|
962
|
+
? { requestedThinkingLevel: thinking.requested, thinkingLevelClamped: true }
|
|
963
|
+
: {}),
|
|
884
964
|
autoSelected: false,
|
|
885
|
-
selectionReason
|
|
886
|
-
? "Used the explicit model override provided in the tool call."
|
|
887
|
-
: "Used the explicit model override provided in the tool call. The model was not matched against the authenticated model list, so the reasoning level fallback was applied.",
|
|
965
|
+
selectionReason,
|
|
888
966
|
};
|
|
889
967
|
} else {
|
|
890
968
|
const selectionResult = await selectOracleModel(ctx, params.thinkingLevel);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-oracle",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "An Amp-style oracle extension for pi that consults the strongest reasoning model on your current provider.",
|
|
5
5
|
"keywords": ["pi-package", "pi", "oracle", "reasoning", "subagent"],
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
"image": "https://raw.githubusercontent.com/diegopetrucci/pi-extensions/main/assets/oracle-preview.svg"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@
|
|
27
|
-
"@
|
|
26
|
+
"@earendil-works/pi-ai": "*",
|
|
27
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
28
|
+
"@earendil-works/pi-tui": "*",
|
|
29
|
+
"typebox": "*"
|
|
28
30
|
}
|
|
29
31
|
}
|