@diegopetrucci/pi-extensions 0.1.61 → 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.
Files changed (62) hide show
  1. package/.pi-fleet-tested-version +1 -1
  2. package/extensions/agent-workflow-audit/.pi-fleet-tested-version +1 -1
  3. package/extensions/agent-workflow-audit/package.json +1 -1
  4. package/extensions/annotate-git-diff/.pi-fleet-tested-version +1 -1
  5. package/extensions/annotate-git-diff/package.json +1 -1
  6. package/extensions/annotate-last-message/.pi-fleet-tested-version +1 -1
  7. package/extensions/annotate-last-message/package.json +1 -1
  8. package/extensions/brrr/.pi-fleet-tested-version +1 -1
  9. package/extensions/brrr/package.json +1 -1
  10. package/extensions/claude-fast/.pi-fleet-tested-version +1 -1
  11. package/extensions/claude-fast/package.json +1 -1
  12. package/extensions/code-reviewer/.pi-fleet-tested-version +1 -1
  13. package/extensions/code-reviewer/README.md +1 -0
  14. package/extensions/code-reviewer/index.ts +24 -2
  15. package/extensions/code-reviewer/package.json +1 -1
  16. package/extensions/confirm-destructive/.pi-fleet-tested-version +1 -1
  17. package/extensions/confirm-destructive/package.json +1 -1
  18. package/extensions/context-cap/.pi-fleet-tested-version +1 -1
  19. package/extensions/context-cap/package.json +1 -1
  20. package/extensions/context-inspector/.pi-fleet-tested-version +1 -1
  21. package/extensions/context-inspector/package.json +1 -1
  22. package/extensions/contrarian/.pi-fleet-tested-version +1 -1
  23. package/extensions/contrarian/README.md +2 -0
  24. package/extensions/contrarian/index.ts +34 -8
  25. package/extensions/contrarian/package.json +1 -1
  26. package/extensions/dirty-repo-guard/.pi-fleet-tested-version +1 -1
  27. package/extensions/dirty-repo-guard/package.json +1 -1
  28. package/extensions/dynamic-context-pruning/.pi-fleet-tested-version +1 -1
  29. package/extensions/dynamic-context-pruning/package.json +1 -1
  30. package/extensions/git-footer/.pi-fleet-tested-version +1 -1
  31. package/extensions/git-footer/package.json +1 -1
  32. package/extensions/gnosis/.pi-fleet-tested-version +1 -1
  33. package/extensions/gnosis/package.json +1 -1
  34. package/extensions/illustrations-to-explain-things/.pi-fleet-tested-version +1 -1
  35. package/extensions/illustrations-to-explain-things/package.json +1 -1
  36. package/extensions/inline-bash/.pi-fleet-tested-version +1 -1
  37. package/extensions/inline-bash/package.json +1 -1
  38. package/extensions/librarian/.pi-fleet-tested-version +1 -1
  39. package/extensions/librarian/README.md +1 -1
  40. package/extensions/librarian/index.ts +34 -5
  41. package/extensions/librarian/package.json +1 -1
  42. package/extensions/minimal-footer/.pi-fleet-tested-version +1 -1
  43. package/extensions/minimal-footer/package.json +1 -1
  44. package/extensions/notify/.pi-fleet-tested-version +1 -1
  45. package/extensions/notify/package.json +1 -1
  46. package/extensions/openai-fast/.pi-fleet-tested-version +1 -1
  47. package/extensions/openai-fast/package.json +1 -1
  48. package/extensions/oracle/.pi-fleet-tested-version +1 -1
  49. package/extensions/oracle/README.md +2 -0
  50. package/extensions/oracle/index.ts +34 -8
  51. package/extensions/oracle/package.json +1 -1
  52. package/extensions/permission-gate/.pi-fleet-tested-version +1 -1
  53. package/extensions/permission-gate/package.json +1 -1
  54. package/extensions/quiet-tools/.pi-fleet-tested-version +1 -1
  55. package/extensions/quiet-tools/package.json +1 -1
  56. package/extensions/review/.pi-fleet-tested-version +1 -1
  57. package/extensions/review/package.json +1 -1
  58. package/extensions/todo/.pi-fleet-tested-version +1 -1
  59. package/extensions/todo/package.json +1 -1
  60. package/extensions/triage-comments/.pi-fleet-tested-version +1 -1
  61. package/extensions/triage-comments/package.json +1 -1
  62. package/package.json +4 -4
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-agent-workflow-audit",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "A pi extension that runs an isolated repo workflow audit and returns only the final report to the main session.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-annotate-git-diff",
3
- "version": "0.1.8",
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.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-annotate-last-message",
3
- "version": "0.1.6",
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.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-brrr",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "A pi extension that sends brrr push notifications when pi is ready for input.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-claude-fast",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "A pi extension that enables Anthropic Claude Fast mode for supported Claude Opus models by injecting speed=fast.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
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;
@@ -224,8 +224,28 @@ type PiModel = {
224
224
  type ModelRegistryContext = {
225
225
  model?: PiModel;
226
226
  modelRegistry: { getAvailable(): PiModel[] | Promise<PiModel[]> };
227
+ scopedModels?: ReadonlyArray<{ model: PiModel; thinkingLevel?: ThinkingLevel }>;
227
228
  };
228
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
+
229
249
  type CreateAgentSessionOptions = NonNullable<Parameters<typeof createAgentSession>[0]>;
230
250
  type CreateAgentSessionModel = CreateAgentSessionOptions["model"];
231
251
 
@@ -354,11 +374,13 @@ function appendOrderedCandidates(
354
374
  async function selectCodeReviewerModel(
355
375
  ctx: ModelRegistryContext,
356
376
  ): Promise<{ ok: true; selection: PiModel; ordered: PiModel[] } | { ok: false; error: string }> {
357
- const available = await ctx.modelRegistry.getAvailable();
377
+ const available = await getAutoSelectableModels(ctx);
358
378
  if (available.length === 0) {
359
379
  return {
360
380
  ok: false,
361
- error: "No authenticated models are available. Log in or configure an API key first.",
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.",
362
384
  };
363
385
  }
364
386
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-code-reviewer",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "A standalone pi extension that adds a read-only code_reviewer subagent tool for isolated code reviews.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-confirm-destructive",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "A pi extension that confirms destructive session actions.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-context-cap",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "A pi extension that caps effective model context windows at 200k tokens for earlier auto-compaction.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-context-inspector",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "A pi extension that opens a local HTML dashboard explaining where the current session context is going.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
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;
@@ -180,8 +205,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
180
205
  "accounts/fireworks/models/glm-5p2",
181
206
  "accounts/fireworks/routers/glm-5p2-fast",
182
207
  "accounts/fireworks/models/minimax-m3",
183
- "accounts/fireworks/models/glm-5p1",
184
- "accounts/fireworks/routers/glm-5p1-fast",
185
208
  "accounts/fireworks/models/kimi-k2p6",
186
209
  "accounts/fireworks/routers/kimi-k2p6-turbo",
187
210
  "accounts/fireworks/routers/kimi-k2p6-fast",
@@ -918,7 +941,7 @@ function appendThinkingLevelClampReason(
918
941
  }
919
942
 
920
943
  async function findAvailableModel(
921
- ctx: { model?: PiModel; modelRegistry: { getAvailable(): PiModel[] | Promise<PiModel[]> } },
944
+ ctx: ModelSelectionContext,
922
945
  modelRef: string,
923
946
  ): Promise<PiModel | undefined> {
924
947
  const available = await ctx.modelRegistry.getAvailable();
@@ -964,11 +987,11 @@ function toContrarianSelection(
964
987
  }
965
988
 
966
989
  function buildSessionFallbackSelection(
967
- ctx: { model?: PiModel },
990
+ ctx: ModelSelectionContext,
968
991
  thinkingLevelOverride: ThinkingLevel | undefined,
969
992
  ): ContrarianSelection | undefined {
970
993
  const model = ctx.model;
971
- if (!model) return undefined;
994
+ if (!model || !isModelInScope(ctx, model)) return undefined;
972
995
  return toContrarianSelection(
973
996
  model,
974
997
  thinkingLevelOverride,
@@ -984,14 +1007,16 @@ function withFallbackReason(selection: ContrarianSelection, previous: Contrarian
984
1007
  }
985
1008
 
986
1009
  async function selectContrarianModel(
987
- ctx: { model?: PiModel; modelRegistry: { getAvailable(): PiModel[] | Promise<PiModel[]> } },
1010
+ ctx: ModelSelectionContext,
988
1011
  thinkingLevelOverride?: ThinkingLevel,
989
1012
  ): Promise<{ ok: true; selection: ContrarianSelection; ordered: ContrarianSelection[] } | { ok: false; error: string }> {
990
- const available = await ctx.modelRegistry.getAvailable();
1013
+ const available = await getAutoSelectableModels(ctx);
991
1014
  if (available.length === 0) {
992
1015
  return {
993
1016
  ok: false,
994
- error: "No authenticated models are available. Log in or configure an API key first.",
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.",
995
1020
  };
996
1021
  }
997
1022
 
@@ -1340,6 +1365,7 @@ type ContrarianExtensionDeps = {
1340
1365
  };
1341
1366
 
1342
1367
  export const __test__ = {
1368
+ buildSessionFallbackSelection,
1343
1369
  createContrarianExtension,
1344
1370
  findAvailableModel,
1345
1371
  isModelAvailabilityError,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-contrarian",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "A read-only contrarian subagent extension for pi that stress-tests plans, designs, assumptions, and conclusions.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-dirty-repo-guard",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "A pi extension that prompts before session changes when the current git repo has uncommitted changes.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-dynamic-context-pruning",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "A pi extension that dynamically prunes stale context to keep sessions lean.",
6
6
  "keywords": [
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-git-footer",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "A TLH-style git status add-on for pi's built-in footer.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-gnosis",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "A pi extension that exposes the gnosis repo-local knowledge base CLI as an agent tool.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-illustrations-to-explain-things",
3
- "version": "0.1.6",
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.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-inline-bash",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "A pi extension that expands inline bash commands in user prompts.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
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: { model?: any; modelRegistry: { getAvailable(): any[] | Promise<any[]> } },
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: { model?: any; modelRegistry: { getAvailable(): any[] | Promise<any[]> } },
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.modelRegistry.getAvailable();
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("No authenticated models are available for Librarian. Log in or configure an API key first.");
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-librarian",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "A pi GitHub research scout with a toggleable local repo checkout cache under the user's OS cache directory.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-minimal-footer",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "A minimal custom footer for pi.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-notify",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "A pi extension that sends a notification when the agent is ready for input.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-openai-fast",
3
- "version": "0.1.13",
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.82.1
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;
@@ -163,8 +188,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
163
188
  "accounts/fireworks/models/glm-5p2",
164
189
  "accounts/fireworks/routers/glm-5p2-fast",
165
190
  "accounts/fireworks/models/minimax-m3",
166
- "accounts/fireworks/models/glm-5p1",
167
- "accounts/fireworks/routers/glm-5p1-fast",
168
191
  "accounts/fireworks/models/kimi-k2p6",
169
192
  "accounts/fireworks/routers/kimi-k2p6-turbo",
170
193
  "accounts/fireworks/routers/kimi-k2p6-fast",
@@ -873,7 +896,7 @@ function appendThinkingLevelClampReason(
873
896
  }
874
897
 
875
898
  async function findAvailableModel(
876
- ctx: { model?: PiModel; modelRegistry: { getAvailable(): PiModel[] | Promise<PiModel[]> } },
899
+ ctx: ModelSelectionContext,
877
900
  modelRef: string,
878
901
  ): Promise<PiModel | undefined> {
879
902
  const available = await ctx.modelRegistry.getAvailable();
@@ -919,11 +942,11 @@ function toOracleSelection(
919
942
  }
920
943
 
921
944
  function buildSessionFallbackSelection(
922
- ctx: { model?: PiModel },
945
+ ctx: ModelSelectionContext,
923
946
  thinkingLevelOverride: ThinkingLevel | undefined,
924
947
  ): OracleSelection | undefined {
925
948
  const model = ctx.model;
926
- if (!model) return undefined;
949
+ if (!model || !isModelInScope(ctx, model)) return undefined;
927
950
  return toOracleSelection(
928
951
  model,
929
952
  thinkingLevelOverride,
@@ -939,14 +962,16 @@ function withFallbackReason(selection: OracleSelection, previous: OracleSelectio
939
962
  }
940
963
 
941
964
  async function selectOracleModel(
942
- ctx: { model?: PiModel; modelRegistry: { getAvailable(): PiModel[] | Promise<PiModel[]> } },
965
+ ctx: ModelSelectionContext,
943
966
  thinkingLevelOverride?: ThinkingLevel,
944
967
  ): Promise<{ ok: true; selection: OracleSelection; ordered: OracleSelection[] } | { ok: false; error: string }> {
945
- const available = await ctx.modelRegistry.getAvailable();
968
+ const available = await getAutoSelectableModels(ctx);
946
969
  if (available.length === 0) {
947
970
  return {
948
971
  ok: false,
949
- error: "No authenticated models are available. Log in or configure an API key first.",
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.",
950
975
  };
951
976
  }
952
977
 
@@ -1253,6 +1278,7 @@ type OracleExtensionDeps = {
1253
1278
  };
1254
1279
 
1255
1280
  export const __test__ = {
1281
+ buildSessionFallbackSelection,
1256
1282
  createOracleExtension,
1257
1283
  findAvailableModel,
1258
1284
  isModelAvailabilityError,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-oracle",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "An Amp-style oracle extension for pi that consults the strongest reasoning model on your current provider.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-permission-gate",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "A pi extension that prompts before dangerous bash commands and protected file writes.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-quiet-tools",
3
- "version": "0.1.9",
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.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-review",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "A standalone pi extension that adds /review and /end-review commands adapted from mitsuhiko/agent-stuff.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-todo",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "A pi extension that adds a branch-aware todo tool and /todos viewer.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1 +1 @@
1
- 0.82.1
1
+ 0.83.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-triage-comments",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "A pi extension that adds /triage-comments and a read-only triage_comments subagent tool for review-comment triage.",
5
5
  "keywords": [
6
6
  "pi-package",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-extensions",
3
- "version": "0.1.61",
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.82.1",
76
- "@earendil-works/pi-coding-agent": "^0.82.1",
77
- "@earendil-works/pi-tui": "^0.82.1",
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",