@diegopetrucci/pi-extensions 0.1.60 → 0.1.62
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/.pi-fleet-tested-version +1 -1
- package/extensions/agent-workflow-audit/.pi-fleet-tested-version +1 -1
- package/extensions/agent-workflow-audit/index.ts +9 -6
- package/extensions/agent-workflow-audit/package.json +1 -1
- package/extensions/annotate-git-diff/.pi-fleet-tested-version +1 -1
- package/extensions/annotate-git-diff/package.json +1 -1
- package/extensions/annotate-last-message/.pi-fleet-tested-version +1 -1
- package/extensions/annotate-last-message/package.json +1 -1
- package/extensions/brrr/.pi-fleet-tested-version +1 -1
- package/extensions/brrr/package.json +1 -1
- package/extensions/claude-fast/.pi-fleet-tested-version +1 -1
- package/extensions/claude-fast/package.json +1 -1
- package/extensions/code-reviewer/.pi-fleet-tested-version +1 -1
- package/extensions/code-reviewer/README.md +1 -0
- package/extensions/code-reviewer/index.ts +28 -2
- package/extensions/code-reviewer/package.json +1 -1
- package/extensions/confirm-destructive/.pi-fleet-tested-version +1 -1
- package/extensions/confirm-destructive/package.json +1 -1
- package/extensions/context-cap/.pi-fleet-tested-version +1 -1
- package/extensions/context-cap/package.json +1 -1
- package/extensions/context-inspector/.pi-fleet-tested-version +1 -1
- package/extensions/context-inspector/package.json +1 -1
- package/extensions/contrarian/.pi-fleet-tested-version +1 -1
- package/extensions/contrarian/README.md +2 -0
- package/extensions/contrarian/index.ts +41 -18
- package/extensions/contrarian/package.json +1 -1
- package/extensions/dirty-repo-guard/.pi-fleet-tested-version +1 -1
- package/extensions/dirty-repo-guard/package.json +1 -1
- package/extensions/dynamic-context-pruning/.pi-fleet-tested-version +1 -1
- package/extensions/dynamic-context-pruning/package.json +1 -1
- package/extensions/git-footer/.pi-fleet-tested-version +1 -1
- package/extensions/git-footer/package.json +1 -1
- package/extensions/gnosis/.pi-fleet-tested-version +1 -1
- package/extensions/gnosis/package.json +1 -1
- package/extensions/illustrations-to-explain-things/.pi-fleet-tested-version +1 -1
- package/extensions/illustrations-to-explain-things/package.json +1 -1
- package/extensions/inline-bash/.pi-fleet-tested-version +1 -1
- package/extensions/inline-bash/package.json +1 -1
- package/extensions/librarian/.pi-fleet-tested-version +1 -1
- package/extensions/librarian/README.md +1 -1
- package/extensions/librarian/index.ts +34 -5
- package/extensions/librarian/package.json +1 -1
- package/extensions/minimal-footer/.pi-fleet-tested-version +1 -1
- package/extensions/minimal-footer/package.json +1 -1
- package/extensions/notify/.pi-fleet-tested-version +1 -1
- package/extensions/notify/package.json +1 -1
- package/extensions/openai-fast/.pi-fleet-tested-version +1 -1
- package/extensions/openai-fast/package.json +1 -1
- package/extensions/oracle/.pi-fleet-tested-version +1 -1
- package/extensions/oracle/README.md +2 -0
- package/extensions/oracle/index.ts +40 -18
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/.pi-fleet-tested-version +1 -1
- package/extensions/permission-gate/package.json +1 -1
- package/extensions/quiet-tools/.pi-fleet-tested-version +1 -1
- package/extensions/quiet-tools/package.json +1 -1
- package/extensions/review/.pi-fleet-tested-version +1 -1
- package/extensions/review/package.json +1 -1
- package/extensions/todo/.pi-fleet-tested-version +1 -1
- package/extensions/todo/package.json +1 -1
- package/extensions/triage-comments/.pi-fleet-tested-version +1 -1
- package/extensions/triage-comments/package.json +1 -1
- package/package.json +4 -4
package/.pi-fleet-tested-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1123,7 +1123,10 @@ export const __test__ = {
|
|
|
1123
1123
|
};
|
|
1124
1124
|
|
|
1125
1125
|
export default function agentWorkflowAuditExtension(pi: ExtensionAPI) {
|
|
1126
|
-
pi.registerMessageRenderer(CUSTOM_TYPE, (message,
|
|
1126
|
+
pi.registerMessageRenderer(CUSTOM_TYPE, (message, options, theme) => {
|
|
1127
|
+
const { expanded } = options;
|
|
1128
|
+
const rendererOptions = options as { outputPad?: number };
|
|
1129
|
+
const outputPad = rendererOptions.outputPad ?? 0;
|
|
1127
1130
|
const details = message.details as AuditDetails | undefined;
|
|
1128
1131
|
const report = messageContentToText(message.content) || "(no report)";
|
|
1129
1132
|
const status = details?.status ?? "done";
|
|
@@ -1143,15 +1146,15 @@ export default function agentWorkflowAuditExtension(pi: ExtensionAPI) {
|
|
|
1143
1146
|
const header = `${icon} ${theme.fg("toolTitle", theme.bold("agent-workflow-audit "))}${theme.fg("dim", meta)}`;
|
|
1144
1147
|
|
|
1145
1148
|
if (!expanded) {
|
|
1146
|
-
return new Text(`${header}\n\n${theme.fg("toolOutput", renderCollapsedReport(report))}`,
|
|
1149
|
+
return new Text(`${header}\n\n${theme.fg("toolOutput", renderCollapsedReport(report))}`, outputPad, 0);
|
|
1147
1150
|
}
|
|
1148
1151
|
|
|
1149
1152
|
const container = new Container();
|
|
1150
|
-
container.addChild(new Text(header,
|
|
1151
|
-
if (details?.cwd) container.addChild(new Text(theme.fg("dim", `cwd: ${details.cwd}`),
|
|
1152
|
-
if (details?.focus) container.addChild(new Text(theme.fg("dim", `focus: ${details.focus}`),
|
|
1153
|
+
container.addChild(new Text(header, outputPad, 0));
|
|
1154
|
+
if (details?.cwd) container.addChild(new Text(theme.fg("dim", `cwd: ${details.cwd}`), outputPad, 0));
|
|
1155
|
+
if (details?.focus) container.addChild(new Text(theme.fg("dim", `focus: ${details.focus}`), outputPad, 0));
|
|
1153
1156
|
container.addChild(new Spacer(1));
|
|
1154
|
-
container.addChild(new Markdown(report,
|
|
1157
|
+
container.addChild(new Markdown(report, outputPad, 0, getMarkdownTheme()));
|
|
1155
1158
|
return container;
|
|
1156
1159
|
});
|
|
1157
1160
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-annotate-git-diff",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "A standalone pi extension that adds /annotate-git-diff, a native Glimpse UI for annotating git diffs and sending feedback to the editor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-annotate-last-message",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "A standalone pi extension that adds /annotate-last-message, a native Glimpse UI for annotating the latest assistant reply.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -44,6 +44,7 @@ When called, it launches an isolated in-memory child agent with:
|
|
|
44
44
|
|
|
45
45
|
- no inherited extensions, skills, prompt templates, themes, context files, or agents files;
|
|
46
46
|
- an auto-selected review model that prefers contrarian-style opposite-provider and opposite-family candidates before same-provider fallbacks;
|
|
47
|
+
- automatic model candidates constrained to the current Pi session's model scope when that scope is non-empty;
|
|
47
48
|
- requested thinking taken from the active session when available, otherwise defaulting to `high` for reasoning models and `off` for non-reasoning models, then clamped to the selected model's supported level;
|
|
48
49
|
- read-only tools only: `read`, `grep`, `find`, `ls`, and guarded `bash`;
|
|
49
50
|
- a local-checkout path guard for file inspection;
|
|
@@ -27,6 +27,7 @@ const CODE_REVIEWER_MODEL_PREFERENCES = [
|
|
|
27
27
|
"gpt-5.6-terra",
|
|
28
28
|
"gpt-5.6-luna",
|
|
29
29
|
"gpt-5.5",
|
|
30
|
+
"claude-opus-5",
|
|
30
31
|
"claude-opus-4-8",
|
|
31
32
|
"claude-opus-4.8",
|
|
32
33
|
"claude-sonnet-5",
|
|
@@ -40,6 +41,7 @@ const CODE_REVIEWER_MODEL_PREFERENCES = [
|
|
|
40
41
|
];
|
|
41
42
|
const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
42
43
|
"amazon-bedrock": [
|
|
44
|
+
"claude-opus-5",
|
|
43
45
|
"claude-fable-5",
|
|
44
46
|
"claude-opus-4-8",
|
|
45
47
|
"claude-sonnet-5",
|
|
@@ -47,6 +49,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
47
49
|
"claude-sonnet-4-5",
|
|
48
50
|
],
|
|
49
51
|
anthropic: [
|
|
52
|
+
"claude-opus-5",
|
|
50
53
|
"claude-fable-5",
|
|
51
54
|
"claude-opus-4-8",
|
|
52
55
|
"claude-sonnet-5",
|
|
@@ -64,6 +67,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
64
67
|
"gpt-5.3-codex-spark",
|
|
65
68
|
],
|
|
66
69
|
"vercel-ai-gateway": [
|
|
70
|
+
"anthropic/claude-opus-5",
|
|
67
71
|
"anthropic/claude-fable-5",
|
|
68
72
|
"anthropic/claude-opus-4.8",
|
|
69
73
|
"anthropic/claude-opus-4.7",
|
|
@@ -220,8 +224,28 @@ type PiModel = {
|
|
|
220
224
|
type ModelRegistryContext = {
|
|
221
225
|
model?: PiModel;
|
|
222
226
|
modelRegistry: { getAvailable(): PiModel[] | Promise<PiModel[]> };
|
|
227
|
+
scopedModels?: ReadonlyArray<{ model: PiModel; thinkingLevel?: ThinkingLevel }>;
|
|
223
228
|
};
|
|
224
229
|
|
|
230
|
+
function modelKey(model: PiModel): string {
|
|
231
|
+
return `${model.provider}/${model.id}`.toLowerCase();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function hasModelScope(ctx: ModelRegistryContext): boolean {
|
|
235
|
+
return Array.isArray(ctx.scopedModels) && ctx.scopedModels.length > 0;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function isModelInScope(ctx: ModelRegistryContext, model: PiModel): boolean {
|
|
239
|
+
if (!hasModelScope(ctx)) return true;
|
|
240
|
+
const key = modelKey(model);
|
|
241
|
+
return ctx.scopedModels!.some((entry) => modelKey(entry.model) === key);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function getAutoSelectableModels(ctx: ModelRegistryContext): Promise<PiModel[]> {
|
|
245
|
+
const available = await ctx.modelRegistry.getAvailable();
|
|
246
|
+
return hasModelScope(ctx) ? available.filter((model) => isModelInScope(ctx, model)) : available;
|
|
247
|
+
}
|
|
248
|
+
|
|
225
249
|
type CreateAgentSessionOptions = NonNullable<Parameters<typeof createAgentSession>[0]>;
|
|
226
250
|
type CreateAgentSessionModel = CreateAgentSessionOptions["model"];
|
|
227
251
|
|
|
@@ -350,11 +374,13 @@ function appendOrderedCandidates(
|
|
|
350
374
|
async function selectCodeReviewerModel(
|
|
351
375
|
ctx: ModelRegistryContext,
|
|
352
376
|
): Promise<{ ok: true; selection: PiModel; ordered: PiModel[] } | { ok: false; error: string }> {
|
|
353
|
-
const available = await ctx
|
|
377
|
+
const available = await getAutoSelectableModels(ctx);
|
|
354
378
|
if (available.length === 0) {
|
|
355
379
|
return {
|
|
356
380
|
ok: false,
|
|
357
|
-
error:
|
|
381
|
+
error: hasModelScope(ctx)
|
|
382
|
+
? "No authenticated models are available in the current session model scope. Adjust the scope, log in, or configure an API key."
|
|
383
|
+
: "No authenticated models are available. Log in or configure an API key first.",
|
|
358
384
|
};
|
|
359
385
|
}
|
|
360
386
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -77,6 +77,8 @@ Tool-call parameters still win over these defaults. `auto` clears the configured
|
|
|
77
77
|
- `thinkingLevel` - optional reasoning/thinking override; falls back to the `/contrarian thinking` default, then built-in defaults
|
|
78
78
|
- `cwd` - optional working directory override
|
|
79
79
|
|
|
80
|
+
When the current Pi session has a non-empty model scope, Contrarian limits automatic model selection and automatic fallbacks to that scope. An explicit tool or `/contrarian model` override remains authoritative even when it is outside the session scope.
|
|
81
|
+
|
|
80
82
|
## Notes
|
|
81
83
|
|
|
82
84
|
- The contrarian is intentionally **read-only**.
|
|
@@ -20,6 +20,31 @@ type PiModel = {
|
|
|
20
20
|
thinkingLevelMap?: ThinkingLevelMap;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
type ModelSelectionContext = {
|
|
24
|
+
model?: PiModel;
|
|
25
|
+
modelRegistry: { getAvailable(): PiModel[] | Promise<PiModel[]> };
|
|
26
|
+
scopedModels?: ReadonlyArray<{ model: PiModel; thinkingLevel?: ThinkingLevel }>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function modelKey(model: PiModel): string {
|
|
30
|
+
return `${model.provider}/${model.id}`.toLowerCase();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function hasModelScope(ctx: ModelSelectionContext): boolean {
|
|
34
|
+
return Array.isArray(ctx.scopedModels) && ctx.scopedModels.length > 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isModelInScope(ctx: ModelSelectionContext, model: PiModel): boolean {
|
|
38
|
+
if (!hasModelScope(ctx)) return true;
|
|
39
|
+
const key = modelKey(model);
|
|
40
|
+
return ctx.scopedModels!.some((entry) => modelKey(entry.model) === key);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function getAutoSelectableModels(ctx: ModelSelectionContext): Promise<PiModel[]> {
|
|
44
|
+
const available = await ctx.modelRegistry.getAvailable();
|
|
45
|
+
return hasModelScope(ctx) ? available.filter((model) => isModelInScope(ctx, model)) : available;
|
|
46
|
+
}
|
|
47
|
+
|
|
23
48
|
interface UsageStats {
|
|
24
49
|
input: number;
|
|
25
50
|
output: number;
|
|
@@ -84,6 +109,7 @@ const CONTRARIAN_MODEL_PREFERENCES = [
|
|
|
84
109
|
"gpt-5.6-terra",
|
|
85
110
|
"gpt-5.6-luna",
|
|
86
111
|
"gpt-5.5",
|
|
112
|
+
"claude-opus-5",
|
|
87
113
|
"claude-opus-4-8",
|
|
88
114
|
"claude-opus-4.8",
|
|
89
115
|
"claude-sonnet-5",
|
|
@@ -98,6 +124,7 @@ const CONTRARIAN_MODEL_PREFERENCES = [
|
|
|
98
124
|
|
|
99
125
|
const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
100
126
|
"amazon-bedrock": [
|
|
127
|
+
"claude-opus-5",
|
|
101
128
|
"claude-fable-5",
|
|
102
129
|
"claude-opus-4-8",
|
|
103
130
|
"claude-opus-4-7",
|
|
@@ -117,6 +144,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
117
144
|
"zai.glm-5",
|
|
118
145
|
],
|
|
119
146
|
anthropic: [
|
|
147
|
+
"claude-opus-5",
|
|
120
148
|
"claude-fable-5",
|
|
121
149
|
"claude-opus-4-8",
|
|
122
150
|
"claude-opus-4-7",
|
|
@@ -141,13 +169,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
141
169
|
"gpt-5-chat-latest",
|
|
142
170
|
"gpt-5.2-pro",
|
|
143
171
|
"gpt-5.2",
|
|
144
|
-
"gpt-5.2-codex",
|
|
145
|
-
"gpt-5.1-codex-max",
|
|
146
|
-
"gpt-5.1-codex",
|
|
147
172
|
"gpt-5.1",
|
|
148
|
-
"gpt-5.1-chat-latest",
|
|
149
173
|
"o3-pro",
|
|
150
|
-
"o3-deep-research",
|
|
151
174
|
"o1-pro",
|
|
152
175
|
"gpt-5.4-mini",
|
|
153
176
|
"gpt-5-mini",
|
|
@@ -182,8 +205,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
182
205
|
"accounts/fireworks/models/glm-5p2",
|
|
183
206
|
"accounts/fireworks/routers/glm-5p2-fast",
|
|
184
207
|
"accounts/fireworks/models/minimax-m3",
|
|
185
|
-
"accounts/fireworks/models/glm-5p1",
|
|
186
|
-
"accounts/fireworks/routers/glm-5p1-fast",
|
|
187
208
|
"accounts/fireworks/models/kimi-k2p6",
|
|
188
209
|
"accounts/fireworks/routers/kimi-k2p6-turbo",
|
|
189
210
|
"accounts/fireworks/routers/kimi-k2p6-fast",
|
|
@@ -193,6 +214,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
193
214
|
"accounts/fireworks/models/gpt-oss-20b",
|
|
194
215
|
],
|
|
195
216
|
"github-copilot": [
|
|
217
|
+
"claude-opus-5",
|
|
196
218
|
"claude-fable-5",
|
|
197
219
|
"claude-opus-4.8",
|
|
198
220
|
"claude-opus-4.7",
|
|
@@ -282,13 +304,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
282
304
|
"gpt-5-chat-latest",
|
|
283
305
|
"gpt-5.2-pro",
|
|
284
306
|
"gpt-5.2",
|
|
285
|
-
"gpt-5.2-codex",
|
|
286
|
-
"gpt-5.1-codex-max",
|
|
287
|
-
"gpt-5.1-codex",
|
|
288
307
|
"gpt-5.1",
|
|
289
|
-
"gpt-5.1-chat-latest",
|
|
290
308
|
"o3-pro",
|
|
291
|
-
"o3-deep-research",
|
|
292
309
|
"o1-pro",
|
|
293
310
|
"gpt-5.4-mini",
|
|
294
311
|
"gpt-5-mini",
|
|
@@ -303,6 +320,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
303
320
|
"gpt-5.3-codex-spark",
|
|
304
321
|
],
|
|
305
322
|
opencode: [
|
|
323
|
+
"claude-opus-5",
|
|
306
324
|
"claude-fable-5",
|
|
307
325
|
"gpt-5.5-pro",
|
|
308
326
|
"gpt-5.5",
|
|
@@ -344,6 +362,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
344
362
|
"kimi-k2.6",
|
|
345
363
|
],
|
|
346
364
|
openrouter: [
|
|
365
|
+
"anthropic/claude-opus-5",
|
|
347
366
|
"anthropic/claude-fable-5",
|
|
348
367
|
"~anthropic/claude-fable-latest",
|
|
349
368
|
"anthropic/claude-opus-4.8",
|
|
@@ -417,6 +436,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
417
436
|
"google/gemma-4-31B-it",
|
|
418
437
|
],
|
|
419
438
|
"vercel-ai-gateway": [
|
|
439
|
+
"anthropic/claude-opus-5",
|
|
420
440
|
"anthropic/claude-fable-5",
|
|
421
441
|
"anthropic/claude-opus-4.8",
|
|
422
442
|
"anthropic/claude-opus-4.7",
|
|
@@ -921,7 +941,7 @@ function appendThinkingLevelClampReason(
|
|
|
921
941
|
}
|
|
922
942
|
|
|
923
943
|
async function findAvailableModel(
|
|
924
|
-
ctx:
|
|
944
|
+
ctx: ModelSelectionContext,
|
|
925
945
|
modelRef: string,
|
|
926
946
|
): Promise<PiModel | undefined> {
|
|
927
947
|
const available = await ctx.modelRegistry.getAvailable();
|
|
@@ -967,11 +987,11 @@ function toContrarianSelection(
|
|
|
967
987
|
}
|
|
968
988
|
|
|
969
989
|
function buildSessionFallbackSelection(
|
|
970
|
-
ctx:
|
|
990
|
+
ctx: ModelSelectionContext,
|
|
971
991
|
thinkingLevelOverride: ThinkingLevel | undefined,
|
|
972
992
|
): ContrarianSelection | undefined {
|
|
973
993
|
const model = ctx.model;
|
|
974
|
-
if (!model) return undefined;
|
|
994
|
+
if (!model || !isModelInScope(ctx, model)) return undefined;
|
|
975
995
|
return toContrarianSelection(
|
|
976
996
|
model,
|
|
977
997
|
thinkingLevelOverride,
|
|
@@ -987,14 +1007,16 @@ function withFallbackReason(selection: ContrarianSelection, previous: Contrarian
|
|
|
987
1007
|
}
|
|
988
1008
|
|
|
989
1009
|
async function selectContrarianModel(
|
|
990
|
-
ctx:
|
|
1010
|
+
ctx: ModelSelectionContext,
|
|
991
1011
|
thinkingLevelOverride?: ThinkingLevel,
|
|
992
1012
|
): Promise<{ ok: true; selection: ContrarianSelection; ordered: ContrarianSelection[] } | { ok: false; error: string }> {
|
|
993
|
-
const available = await ctx
|
|
1013
|
+
const available = await getAutoSelectableModels(ctx);
|
|
994
1014
|
if (available.length === 0) {
|
|
995
1015
|
return {
|
|
996
1016
|
ok: false,
|
|
997
|
-
error:
|
|
1017
|
+
error: hasModelScope(ctx)
|
|
1018
|
+
? "No authenticated models are available in the current session model scope. Adjust the scope, log in, or configure an API key."
|
|
1019
|
+
: "No authenticated models are available. Log in or configure an API key first.",
|
|
998
1020
|
};
|
|
999
1021
|
}
|
|
1000
1022
|
|
|
@@ -1343,6 +1365,7 @@ type ContrarianExtensionDeps = {
|
|
|
1343
1365
|
};
|
|
1344
1366
|
|
|
1345
1367
|
export const __test__ = {
|
|
1368
|
+
buildSessionFallbackSelection,
|
|
1346
1369
|
createContrarianExtension,
|
|
1347
1370
|
findAvailableModel,
|
|
1348
1371
|
isModelAvailabilityError,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-illustrations-to-explain-things",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "A pi skill for generating clean, absurd Xiaohei-style article illustrations, shot lists, and visual metaphors.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -4,7 +4,7 @@ A pi GitHub research scout inspired by `pi-librarian`, with a local checkout cac
|
|
|
4
4
|
|
|
5
5
|
When the `librarian` tool runs, it can cache/reuse repository checkouts locally. Use `/librarian-cache off` to force GitHub API/search and temporary fetched files only, or `/librarian-cache on` to re-enable cached local checkouts.
|
|
6
6
|
|
|
7
|
-
The internal librarian subagent uses a fast auto-selected model by default, requests `low` thinking, and prompts its scout to batch independent GitHub probes in parallel. Use `/librarian-config` to set a persistent internal model or thinking-level preference.
|
|
7
|
+
The internal librarian subagent uses a fast auto-selected model by default, requests `low` thinking, and prompts its scout to batch independent GitHub probes in parallel. Automatic candidates and fallbacks stay within the current Pi session's model scope when that scope is non-empty; an explicit tool or `/librarian-config` model remains authoritative. Use `/librarian-config` to set a persistent internal model or thinking-level preference.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -46,6 +46,31 @@ type PiModel = {
|
|
|
46
46
|
thinkingLevelMap?: ThinkingLevelMap;
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
+
type ModelSelectionContext = {
|
|
50
|
+
model?: any;
|
|
51
|
+
modelRegistry: { getAvailable(): any[] | Promise<any[]> };
|
|
52
|
+
scopedModels?: ReadonlyArray<{ model: any; thinkingLevel?: ThinkingLevel }>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
function modelKey(model: any): string {
|
|
56
|
+
return `${model.provider}/${model.id}`.toLowerCase();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function hasModelScope(ctx: ModelSelectionContext): boolean {
|
|
60
|
+
return Array.isArray(ctx.scopedModels) && ctx.scopedModels.length > 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isModelInScope(ctx: ModelSelectionContext, model: any): boolean {
|
|
64
|
+
if (!hasModelScope(ctx)) return true;
|
|
65
|
+
const key = modelKey(model);
|
|
66
|
+
return ctx.scopedModels!.some((entry) => modelKey(entry.model) === key);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function getAutoSelectableModels(ctx: ModelSelectionContext): Promise<any[]> {
|
|
70
|
+
const available = await ctx.modelRegistry.getAvailable();
|
|
71
|
+
return hasModelScope(ctx) ? available.filter((model) => isModelInScope(ctx, model)) : available;
|
|
72
|
+
}
|
|
73
|
+
|
|
49
74
|
type CreateAgentSessionOptions = NonNullable<Parameters<typeof createAgentSession>[0]>;
|
|
50
75
|
|
|
51
76
|
function getModelRuntimeOption(ctx: { modelRegistry?: unknown }): Pick<CreateAgentSessionOptions, "modelRuntime"> {
|
|
@@ -677,7 +702,7 @@ function rankPreferredFastLibrarianModel(model: any): number {
|
|
|
677
702
|
}
|
|
678
703
|
|
|
679
704
|
async function findAvailableModel(
|
|
680
|
-
ctx:
|
|
705
|
+
ctx: ModelSelectionContext,
|
|
681
706
|
modelPreference: string,
|
|
682
707
|
): Promise<any | undefined> {
|
|
683
708
|
const available = await ctx.modelRegistry.getAvailable();
|
|
@@ -732,7 +757,7 @@ function withLibrarianFallbackReason(candidate: LibrarianCandidate, previous: Li
|
|
|
732
757
|
// these in order and skip ones that fail with a model-availability error,
|
|
733
758
|
// ultimately falling back to the known-good current session model.
|
|
734
759
|
async function buildLibrarianCandidates(
|
|
735
|
-
ctx:
|
|
760
|
+
ctx: ModelSelectionContext,
|
|
736
761
|
modelPreference: string | undefined,
|
|
737
762
|
thinkingLevel: ThinkingLevel,
|
|
738
763
|
): Promise<LibrarianCandidate[]> {
|
|
@@ -762,7 +787,7 @@ async function buildLibrarianCandidates(
|
|
|
762
787
|
}
|
|
763
788
|
}
|
|
764
789
|
|
|
765
|
-
const available = await ctx
|
|
790
|
+
const available = await getAutoSelectableModels(ctx);
|
|
766
791
|
const preferred = available.filter(isPreferredFastLibrarianModel);
|
|
767
792
|
const ranked = preferred.length > 0
|
|
768
793
|
? [...preferred].sort((a, b) => rankPreferredFastLibrarianModel(a) - rankPreferredFastLibrarianModel(b))
|
|
@@ -785,7 +810,7 @@ async function buildLibrarianCandidates(
|
|
|
785
810
|
});
|
|
786
811
|
|
|
787
812
|
// Final fallback: the active session model is known to be servable.
|
|
788
|
-
if (ctx.model) {
|
|
813
|
+
if (ctx.model && isModelInScope(ctx, ctx.model)) {
|
|
789
814
|
push(ctx.model, {
|
|
790
815
|
modelRef: modelRef(ctx.model),
|
|
791
816
|
provider: ctx.model.provider,
|
|
@@ -797,7 +822,11 @@ async function buildLibrarianCandidates(
|
|
|
797
822
|
}
|
|
798
823
|
|
|
799
824
|
if (candidates.length === 0) {
|
|
800
|
-
throw new Error(
|
|
825
|
+
throw new Error(
|
|
826
|
+
hasModelScope(ctx)
|
|
827
|
+
? "No authenticated models are available for Librarian in the current session model scope. Adjust the scope, log in, or configure an API key."
|
|
828
|
+
: "No authenticated models are available for Librarian. Log in or configure an API key first.",
|
|
829
|
+
);
|
|
801
830
|
}
|
|
802
831
|
|
|
803
832
|
return candidates;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-openai-fast",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "A pi extension that enables OpenAI Codex Fast mode for ChatGPT-auth GPT-5.4, GPT-5.5, and GPT-5.6 Codex variants by injecting the priority service tier.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -106,6 +106,8 @@ Tool-call parameters still win over these defaults. `auto` clears the configured
|
|
|
106
106
|
- `thinkingLevel` - optional reasoning/thinking override; falls back to the `/oracle thinking` default, then built-in defaults
|
|
107
107
|
- `cwd` - optional working directory override
|
|
108
108
|
|
|
109
|
+
When the current Pi session has a non-empty model scope, Oracle limits automatic model selection and automatic fallbacks to that scope. An explicit tool or `/oracle model` override remains authoritative even when it is outside the session scope.
|
|
110
|
+
|
|
109
111
|
## Notes
|
|
110
112
|
|
|
111
113
|
- The oracle is intentionally **read-only by default**.
|
|
@@ -20,6 +20,31 @@ type PiModel = {
|
|
|
20
20
|
thinkingLevelMap?: ThinkingLevelMap;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
type ModelSelectionContext = {
|
|
24
|
+
model?: PiModel;
|
|
25
|
+
modelRegistry: { getAvailable(): PiModel[] | Promise<PiModel[]> };
|
|
26
|
+
scopedModels?: ReadonlyArray<{ model: PiModel; thinkingLevel?: ThinkingLevel }>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function modelKey(model: PiModel): string {
|
|
30
|
+
return `${model.provider}/${model.id}`.toLowerCase();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function hasModelScope(ctx: ModelSelectionContext): boolean {
|
|
34
|
+
return Array.isArray(ctx.scopedModels) && ctx.scopedModels.length > 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isModelInScope(ctx: ModelSelectionContext, model: PiModel): boolean {
|
|
38
|
+
if (!hasModelScope(ctx)) return true;
|
|
39
|
+
const key = modelKey(model);
|
|
40
|
+
return ctx.scopedModels!.some((entry) => modelKey(entry.model) === key);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function getAutoSelectableModels(ctx: ModelSelectionContext): Promise<PiModel[]> {
|
|
44
|
+
const available = await ctx.modelRegistry.getAvailable();
|
|
45
|
+
return hasModelScope(ctx) ? available.filter((model) => isModelInScope(ctx, model)) : available;
|
|
46
|
+
}
|
|
47
|
+
|
|
23
48
|
interface UsageStats {
|
|
24
49
|
input: number;
|
|
25
50
|
output: number;
|
|
@@ -82,6 +107,7 @@ const ORACLE_CONFIG_FILE = "oracle.json";
|
|
|
82
107
|
|
|
83
108
|
const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
84
109
|
"amazon-bedrock": [
|
|
110
|
+
"claude-opus-5",
|
|
85
111
|
"claude-fable-5",
|
|
86
112
|
"claude-opus-4-8",
|
|
87
113
|
"claude-opus-4-7",
|
|
@@ -101,6 +127,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
101
127
|
"zai.glm-5",
|
|
102
128
|
],
|
|
103
129
|
anthropic: [
|
|
130
|
+
"claude-opus-5",
|
|
104
131
|
"claude-fable-5",
|
|
105
132
|
"claude-opus-4-8",
|
|
106
133
|
"claude-opus-4-7",
|
|
@@ -125,13 +152,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
125
152
|
"gpt-5-chat-latest",
|
|
126
153
|
"gpt-5.2-pro",
|
|
127
154
|
"gpt-5.2",
|
|
128
|
-
"gpt-5.2-codex",
|
|
129
|
-
"gpt-5.1-codex-max",
|
|
130
|
-
"gpt-5.1-codex",
|
|
131
155
|
"gpt-5.1",
|
|
132
|
-
"gpt-5.1-chat-latest",
|
|
133
156
|
"o3-pro",
|
|
134
|
-
"o3-deep-research",
|
|
135
157
|
"o1-pro",
|
|
136
158
|
"gpt-5.4-mini",
|
|
137
159
|
"gpt-5-mini",
|
|
@@ -166,8 +188,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
166
188
|
"accounts/fireworks/models/glm-5p2",
|
|
167
189
|
"accounts/fireworks/routers/glm-5p2-fast",
|
|
168
190
|
"accounts/fireworks/models/minimax-m3",
|
|
169
|
-
"accounts/fireworks/models/glm-5p1",
|
|
170
|
-
"accounts/fireworks/routers/glm-5p1-fast",
|
|
171
191
|
"accounts/fireworks/models/kimi-k2p6",
|
|
172
192
|
"accounts/fireworks/routers/kimi-k2p6-turbo",
|
|
173
193
|
"accounts/fireworks/routers/kimi-k2p6-fast",
|
|
@@ -177,6 +197,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
177
197
|
"accounts/fireworks/models/gpt-oss-20b",
|
|
178
198
|
],
|
|
179
199
|
"github-copilot": [
|
|
200
|
+
"claude-opus-5",
|
|
180
201
|
"claude-fable-5",
|
|
181
202
|
"claude-opus-4.8",
|
|
182
203
|
"claude-opus-4.7",
|
|
@@ -266,13 +287,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
266
287
|
"gpt-5-chat-latest",
|
|
267
288
|
"gpt-5.2-pro",
|
|
268
289
|
"gpt-5.2",
|
|
269
|
-
"gpt-5.2-codex",
|
|
270
|
-
"gpt-5.1-codex-max",
|
|
271
|
-
"gpt-5.1-codex",
|
|
272
290
|
"gpt-5.1",
|
|
273
|
-
"gpt-5.1-chat-latest",
|
|
274
291
|
"o3-pro",
|
|
275
|
-
"o3-deep-research",
|
|
276
292
|
"o1-pro",
|
|
277
293
|
"gpt-5.4-mini",
|
|
278
294
|
"gpt-5-mini",
|
|
@@ -287,6 +303,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
287
303
|
"gpt-5.3-codex-spark",
|
|
288
304
|
],
|
|
289
305
|
opencode: [
|
|
306
|
+
"claude-opus-5",
|
|
290
307
|
"claude-fable-5",
|
|
291
308
|
"gpt-5.5-pro",
|
|
292
309
|
"gpt-5.5",
|
|
@@ -328,6 +345,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
328
345
|
"kimi-k2.6",
|
|
329
346
|
],
|
|
330
347
|
openrouter: [
|
|
348
|
+
"anthropic/claude-opus-5",
|
|
331
349
|
"anthropic/claude-fable-5",
|
|
332
350
|
"~anthropic/claude-fable-latest",
|
|
333
351
|
"anthropic/claude-opus-4.8",
|
|
@@ -401,6 +419,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
401
419
|
"google/gemma-4-31B-it",
|
|
402
420
|
],
|
|
403
421
|
"vercel-ai-gateway": [
|
|
422
|
+
"anthropic/claude-opus-5",
|
|
404
423
|
"anthropic/claude-fable-5",
|
|
405
424
|
"anthropic/claude-opus-4.8",
|
|
406
425
|
"anthropic/claude-opus-4.7",
|
|
@@ -877,7 +896,7 @@ function appendThinkingLevelClampReason(
|
|
|
877
896
|
}
|
|
878
897
|
|
|
879
898
|
async function findAvailableModel(
|
|
880
|
-
ctx:
|
|
899
|
+
ctx: ModelSelectionContext,
|
|
881
900
|
modelRef: string,
|
|
882
901
|
): Promise<PiModel | undefined> {
|
|
883
902
|
const available = await ctx.modelRegistry.getAvailable();
|
|
@@ -923,11 +942,11 @@ function toOracleSelection(
|
|
|
923
942
|
}
|
|
924
943
|
|
|
925
944
|
function buildSessionFallbackSelection(
|
|
926
|
-
ctx:
|
|
945
|
+
ctx: ModelSelectionContext,
|
|
927
946
|
thinkingLevelOverride: ThinkingLevel | undefined,
|
|
928
947
|
): OracleSelection | undefined {
|
|
929
948
|
const model = ctx.model;
|
|
930
|
-
if (!model) return undefined;
|
|
949
|
+
if (!model || !isModelInScope(ctx, model)) return undefined;
|
|
931
950
|
return toOracleSelection(
|
|
932
951
|
model,
|
|
933
952
|
thinkingLevelOverride,
|
|
@@ -943,14 +962,16 @@ function withFallbackReason(selection: OracleSelection, previous: OracleSelectio
|
|
|
943
962
|
}
|
|
944
963
|
|
|
945
964
|
async function selectOracleModel(
|
|
946
|
-
ctx:
|
|
965
|
+
ctx: ModelSelectionContext,
|
|
947
966
|
thinkingLevelOverride?: ThinkingLevel,
|
|
948
967
|
): Promise<{ ok: true; selection: OracleSelection; ordered: OracleSelection[] } | { ok: false; error: string }> {
|
|
949
|
-
const available = await ctx
|
|
968
|
+
const available = await getAutoSelectableModels(ctx);
|
|
950
969
|
if (available.length === 0) {
|
|
951
970
|
return {
|
|
952
971
|
ok: false,
|
|
953
|
-
error:
|
|
972
|
+
error: hasModelScope(ctx)
|
|
973
|
+
? "No authenticated models are available in the current session model scope. Adjust the scope, log in, or configure an API key."
|
|
974
|
+
: "No authenticated models are available. Log in or configure an API key first.",
|
|
954
975
|
};
|
|
955
976
|
}
|
|
956
977
|
|
|
@@ -1257,6 +1278,7 @@ type OracleExtensionDeps = {
|
|
|
1257
1278
|
};
|
|
1258
1279
|
|
|
1259
1280
|
export const __test__ = {
|
|
1281
|
+
buildSessionFallbackSelection,
|
|
1260
1282
|
createOracleExtension,
|
|
1261
1283
|
findAvailableModel,
|
|
1262
1284
|
isModelAvailabilityError,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-quiet-tools",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "A pi extension that visually compacts collapsed built-in tool rows in the TUI without changing tool results sent to the model.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.83.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-extensions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.62",
|
|
4
4
|
"description": "A collection of pi extensions and skills for annotation UIs, context management, workflow audits, contrarian review, review-comment triage, notifications, brrr push alerts, safety guards, GitHub research, repo-local knowledge, todos, tool rendering, model/provider helpers, and Xiaohei-style article illustrations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -72,9 +72,9 @@
|
|
|
72
72
|
]
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@earendil-works/pi-ai": "^0.
|
|
76
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
77
|
-
"@earendil-works/pi-tui": "^0.
|
|
75
|
+
"@earendil-works/pi-ai": "^0.83.0",
|
|
76
|
+
"@earendil-works/pi-coding-agent": "^0.83.0",
|
|
77
|
+
"@earendil-works/pi-tui": "^0.83.0",
|
|
78
78
|
"@types/node": "^25.9.1",
|
|
79
79
|
"husky": "^9.1.7",
|
|
80
80
|
"typebox": "^1.3.6",
|