@oh-my-pi/pi-coding-agent 14.0.4 → 14.1.0

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 (61) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/package.json +11 -8
  3. package/src/async/index.ts +1 -0
  4. package/src/async/support.ts +5 -0
  5. package/src/cli/list-models.ts +96 -57
  6. package/src/commit/model-selection.ts +16 -13
  7. package/src/config/model-equivalence.ts +674 -0
  8. package/src/config/model-registry.ts +182 -13
  9. package/src/config/model-resolver.ts +203 -74
  10. package/src/config/settings-schema.ts +23 -0
  11. package/src/config/settings.ts +9 -2
  12. package/src/dap/session.ts +31 -39
  13. package/src/debug/log-formatting.ts +2 -2
  14. package/src/edit/modes/chunk.ts +8 -3
  15. package/src/export/html/template.css +82 -0
  16. package/src/export/html/template.generated.ts +1 -1
  17. package/src/export/html/template.js +612 -97
  18. package/src/internal-urls/docs-index.generated.ts +1 -1
  19. package/src/internal-urls/jobs-protocol.ts +2 -1
  20. package/src/lsp/client.ts +5 -3
  21. package/src/lsp/index.ts +4 -9
  22. package/src/lsp/utils.ts +26 -0
  23. package/src/main.ts +6 -1
  24. package/src/memories/index.ts +7 -6
  25. package/src/modes/components/diff.ts +1 -1
  26. package/src/modes/components/model-selector.ts +221 -64
  27. package/src/modes/controllers/command-controller.ts +18 -0
  28. package/src/modes/controllers/event-controller.ts +438 -426
  29. package/src/modes/controllers/selector-controller.ts +13 -5
  30. package/src/modes/theme/mermaid-cache.ts +5 -7
  31. package/src/priority.json +8 -0
  32. package/src/prompts/agents/designer.md +1 -2
  33. package/src/prompts/system/system-prompt.md +5 -1
  34. package/src/prompts/tools/bash.md +15 -0
  35. package/src/prompts/tools/cancel-job.md +1 -1
  36. package/src/prompts/tools/chunk-edit.md +39 -40
  37. package/src/prompts/tools/read-chunk.md +13 -1
  38. package/src/prompts/tools/read.md +9 -0
  39. package/src/prompts/tools/write.md +1 -0
  40. package/src/sdk.ts +7 -4
  41. package/src/session/agent-session.ts +33 -6
  42. package/src/session/compaction/compaction.ts +1 -1
  43. package/src/task/executor.ts +5 -1
  44. package/src/tools/await-tool.ts +2 -1
  45. package/src/tools/bash.ts +221 -56
  46. package/src/tools/browser.ts +84 -21
  47. package/src/tools/cancel-job.ts +2 -1
  48. package/src/tools/fetch.ts +1 -1
  49. package/src/tools/find.ts +40 -94
  50. package/src/tools/gemini-image.ts +1 -0
  51. package/src/tools/inspect-image.ts +1 -1
  52. package/src/tools/read.ts +218 -1
  53. package/src/tools/render-utils.ts +1 -1
  54. package/src/tools/sqlite-reader.ts +623 -0
  55. package/src/tools/write.ts +187 -1
  56. package/src/utils/commit-message-generator.ts +1 -0
  57. package/src/utils/git.ts +24 -1
  58. package/src/utils/image-resize.ts +73 -37
  59. package/src/utils/title-generator.ts +1 -1
  60. package/src/web/scrapers/types.ts +50 -32
  61. package/src/web/search/providers/codex.ts +21 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,89 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [14.1.0] - 2026-04-11
6
+ ### Added
7
+
8
+ - Added richer tool rendering details in session export HTML, including metadata badges, argument formatting, and todo task tree styling for exported tool and workflow messages
9
+ - Added a persistent `js` tool backed by `node:vm`, with cross-session `highway` KV/pubsub, tool calls from inside JS cells, and `$` / `$$` interactive JavaScript execution
10
+ - Added SQLite database read support to the `read` tool for `.sqlite`, `.sqlite3`, `.db`, and `.db3` files with table listing, schema + sample output, row lookup, paginated query filtering, and read-only `q=SELECT` mode
11
+ - Added SQLite mutation support to the `write` tool so `db.sqlite:table` inserts JSON5 rows and `db.sqlite:table:key` updates or deletes rows via row key
12
+ - Added rendering of usage report entries for accounts with no usage limits, including account label and optional plan type with a `-- no limits` indicator
13
+ - Updated account label resolution to fall back to email or accountId so unlabeled unlimited-plan accounts display a meaningful name
14
+ - Added canonical model equivalence and provider coalescing across `models.yml`, `enabledModels`, `--models`, `/model`, and `--list-models`
15
+ - Added `equivalence` overrides/exclusions to `models.yml` and `modelProviderOrder` to `config.yml` for global canonical-provider preference
16
+
17
+ ### Changed
18
+
19
+ - Enabled `await` and `cancel_job` to be available when `bash.autoBackground.enabled` is set, so auto-backgrounded bash jobs can be awaited or cancelled without enabling `async.enabled`
20
+ - Updated bash auto-background behavior so short commands returned inline output when they completed before the configured threshold, while longer runs moved to background jobs automatically
21
+ - Replaced the LLM-callable Python execution path with JavaScript execution in the shared VM context, including updated renderers, prompts, session messages, and extension events
22
+ - Updated interactive and CLI model listings/selectors to work with canonical model ids while resolving them to concrete provider variants for actual execution
23
+ - Updated role assignment persistence so selected model settings now store the selector used by users, including thinking-level suffixes, while runtime continues to run against the resolved concrete provider model
24
+ - Updated model scope resolution to expand exact canonical model ids into all matching provider variants when filtering supported model sets
25
+ - Changed the agent to avoid giving time estimates or task-duration predictions in user responses, focusing on required work instead
26
+ - Changed generated code guidance to avoid speculative abstractions and extra compatibility scaffolding, favoring direct implementations that match current needs
27
+ - Changed model role resolution so roles can store either canonical model ids or explicit `provider/model` selectors while sessions continue to record the concrete model actually used
28
+ - Updated bash execution to optionally auto-background long-running commands through the existing background-job pipeline, with dedicated settings for enabling the behavior and adjusting the delay
29
+
30
+ ### Fixed
31
+
32
+ - Fixed session export rendering so JavaScript execution messages now use `jsExecution` labels and content instead of `pythonExecution`, matching current tool behavior
33
+ - Fixed JavaScript cell execution to auto-display returned values once and preserve persistent VM bindings across calls until reset
34
+ - Fixed `.db`/`.db3` reads to verify SQLite file headers and fall back to normal file reading when the extension matches but the content is not a SQLite database
35
+ - Fixed SQLite selector parsing and resolution to correctly route requests to database operations at the file-extension boundary instead of misrouting through plain file/archive handlers
36
+ - Fixed unsupported or unsafe selectors by rejecting missing tables, composite primary keys for row lookups, unknown query parameters, and row operations on non-existent tables
37
+ - Fixed model resolution for commit message generation, title generation, memory consolidation, and image inspection when role strings use canonical ids instead of raw provider/model values
38
+ - Fixed default-model updates so previously configured thinking levels were preserved when reassigning a role
39
+ - Fixed model scope and selection handling in CLI/session startup paths that previously failed to resolve aliases consistently across features
40
+ - Fixed short-lived git subprocesses to disable `core.fsmonitor` and `core.untrackedCache`, avoiding unnecessary repository watchers and cache work during agent git operations
41
+
42
+ ### Security
43
+
44
+ - Blocked destructive SQL execution in read-mode SQLite access by using read-only connections and rejecting bound-parameter raw SQL
45
+
46
+ ## [14.0.5] - 2026-04-11
47
+ ### Added
48
+
49
+ - Added `designer` model role for UI/UX design tasks with Gemini 3.1 Pro as default model
50
+ - Added support for model role fallback lists — roles can now resolve to multiple model patterns with automatic fallback to next available model
51
+ - Added `extractReadableFromHtml` utility function to extract readable content from HTML with Readability article extraction and CSS selector fallback
52
+ - Added support for GFM (GitHub Flavored Markdown) features including tables, strikethrough, and task lists in HTML-to-markdown conversion
53
+ - Added `resolveDiagnosticTargets` utility function to handle glob pattern resolution with fallback to literal file paths for bracket-style paths
54
+
55
+ ### Changed
56
+
57
+ - Clarified fenced code block editing behavior in markdown — the tool now preserves literal indentation inside fenced blocks, with content written verbatim as supplied
58
+ - Updated guidance for inserting content after markdown section headings to use `after` on the heading chunk rather than `before`/`prepend` on the section itself
59
+ - Reduced default image resize limits to 1568px (from 2000px) and 500KB (from 4.5MB) to match Anthropic's internal downscaling threshold and reduce payload sizes in tool calls
60
+ - Adjusted screenshot compression to use 1024px max dimensions and 150KB budget for more aggressive optimization of browser screenshots in LLM requests
61
+ - Updated JPEG quality defaults from 80 to 75 and refined quality ladder steps (70, 60, 50, 40) for tighter byte budgets
62
+ - Improved image resize fast-path to skip re-encoding when images are already within dimensions and at ≤25% of byte budget, avoiding unnecessary processing of small icons and diagrams
63
+ - Clarified that chunk names are truncated and must be copied from `read` or `?` output rather than constructed from source identifiers
64
+ - Enhanced guidance for editing fenced code blocks in markdown to preserve exact whitespace using `raw` reads, as the tool normalizes tabs to spaces which can damage indentation-sensitive content
65
+ - Updated designer agent to use `pi/designer` role alias instead of explicit model list
66
+ - Refactored model role resolution to support multiple fallback patterns per role, improving model availability handling
67
+ - Replaced regex-based HTML-to-markdown conversion with Turndown library and GFM plugin for more accurate formatting of complex HTML structures
68
+ - Simplified no-changes response to omit redundant response text when chunk content already matches
69
+ - Clarified region suffix behavior on leaf and compound statement chunks — `~` and `^` now fall back to whole-chunk replacement with explicit guidance to supply complete structural content
70
+ - Updated CRC refresh guidance to direct users to use CRCs from edit responses or run `read(path="file", sel="?")`
71
+ - Added clarification that region suffixes fall back to whole-chunk replacement for prose and data formats (markdown, YAML, JSON, fenced code blocks, frontmatter)
72
+ - Documented `L20` shorthand syntax for single-line reads extending to end-of-file, with `L20-L20` for one-line windows
73
+ - Refactored diagnostic target resolution to use new `resolveDiagnosticTargets` function, consolidating glob pattern detection and file matching logic
74
+ - Updated chunk selector syntax from `@region` format to `~` (body) and `^` (head) suffixes for more concise region targeting
75
+ - Simplified chunk edit documentation to use new `~` and `^` region syntax instead of `@head`, `@body`, `@tail`, `@decl` keywords
76
+ - Replaced internal `raceAbort` function with imported `raceWithAbort` utility from pi-utils
77
+ - Refactored cleanup timer to use async iterator pattern with `timers.setInterval` instead of `setInterval`
78
+ - Made `#cleanupIdleSessions` synchronous and moved async cleanup loop logic to new `#runCleanupLoop` method
79
+ - Replaced regex-based `htmlToBasicMarkdown` with a Turndown + GFM plugin pipeline (tables, strikethrough, task lists, nested lists now convert correctly). Added direct `turndown` and `turndown-plugin-gfm` dependencies
80
+
81
+ ### Fixed
82
+
83
+ - Fixed chunk edit tool to report file-not-found error distinctly when attempting to use chunk selectors on non-existent files, with guidance to use write tool or verify the path
84
+ - Fixed stale child selector reuse to correctly match chunks by checksum when multiple sibling chunks with the same name exist under the same parent
85
+ - Fixed stale diagnostics being reused after unrelated file publishes by clearing cached diagnostics before refreshing file state
86
+ - Fixed Codex search to use streamed answer text when final answer is an image placeholder or empty
87
+
5
88
  ## [14.0.4] - 2026-04-10
6
89
  ### Added
7
90
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-coding-agent",
4
- "version": "14.0.4",
4
+ "version": "14.1.0",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/can1357/oh-my-pi",
7
7
  "author": "Can Boluk",
@@ -46,12 +46,12 @@
46
46
  "dependencies": {
47
47
  "@agentclientprotocol/sdk": "0.16.1",
48
48
  "@mozilla/readability": "^0.6",
49
- "@oh-my-pi/omp-stats": "14.0.4",
50
- "@oh-my-pi/pi-agent-core": "14.0.4",
51
- "@oh-my-pi/pi-ai": "14.0.4",
52
- "@oh-my-pi/pi-natives": "14.0.4",
53
- "@oh-my-pi/pi-tui": "14.0.4",
54
- "@oh-my-pi/pi-utils": "14.0.4",
49
+ "@oh-my-pi/omp-stats": "14.1.0",
50
+ "@oh-my-pi/pi-agent-core": "14.1.0",
51
+ "@oh-my-pi/pi-ai": "14.1.0",
52
+ "@oh-my-pi/pi-natives": "14.1.0",
53
+ "@oh-my-pi/pi-tui": "14.1.0",
54
+ "@oh-my-pi/pi-utils": "14.1.0",
55
55
  "@sinclair/typebox": "^0.34",
56
56
  "@xterm/headless": "^6.0",
57
57
  "ajv": "^8.18",
@@ -63,10 +63,13 @@
63
63
  "lru-cache": "11.3.1",
64
64
  "markit-ai": "0.5.0",
65
65
  "puppeteer": "^24.37",
66
+ "turndown": "7.2.4",
67
+ "turndown-plugin-gfm": "1.0.2",
66
68
  "zod": "4.3.6"
67
69
  },
68
70
  "devDependencies": {
69
- "@types/bun": "^1.3"
71
+ "@types/bun": "^1.3",
72
+ "@types/turndown": "5.0.6"
70
73
  },
71
74
  "engines": {
72
75
  "bun": ">=1.3.7"
@@ -1 +1,2 @@
1
1
  export * from "./job-manager";
2
+ export * from "./support";
@@ -0,0 +1,5 @@
1
+ import type { Settings } from "../config/settings";
2
+
3
+ export function isBackgroundJobSupportEnabled(settings: Pick<Settings, "get">): boolean {
4
+ return settings.get("async.enabled") || settings.get("bash.autoBackground.enabled");
5
+ }
@@ -6,6 +6,45 @@ import { formatNumber } from "@oh-my-pi/pi-utils";
6
6
  import type { ModelRegistry } from "../config/model-registry";
7
7
  import { fuzzyFilter } from "../utils/fuzzy";
8
8
 
9
+ interface ProviderRow {
10
+ provider: string;
11
+ model: string;
12
+ context: string;
13
+ maxOut: string;
14
+ thinking: string;
15
+ images: string;
16
+ }
17
+
18
+ interface CanonicalRow {
19
+ canonical: string;
20
+ selected: string;
21
+ variants: string;
22
+ context: string;
23
+ maxOut: string;
24
+ }
25
+
26
+ function writeLine(line = ""): void {
27
+ process.stdout.write(`${line}\n`);
28
+ }
29
+
30
+ function renderTable<T extends Record<string, string>>(rows: T[], headers: T): void {
31
+ const widths = Object.fromEntries(
32
+ Object.keys(headers).map(key => [key, Math.max(headers[key]!.length, ...rows.map(row => row[key]!.length))]),
33
+ ) as Record<keyof T, number>;
34
+
35
+ const headerLine = Object.keys(headers)
36
+ .map(key => headers[key as keyof T]!.padEnd(widths[key as keyof T]))
37
+ .join(" ");
38
+ writeLine(headerLine);
39
+
40
+ for (const row of rows) {
41
+ const line = Object.keys(headers)
42
+ .map(key => row[key as keyof T]!.padEnd(widths[key as keyof T]))
43
+ .join(" ");
44
+ writeLine(line);
45
+ }
46
+ }
47
+
9
48
  /**
10
49
  * List available models, optionally filtered by search pattern
11
50
  */
@@ -13,77 +52,77 @@ export async function listModels(modelRegistry: ModelRegistry, searchPattern?: s
13
52
  const models = modelRegistry.getAvailable();
14
53
 
15
54
  if (models.length === 0) {
16
- console.log("No models available. Set API keys in environment variables.");
55
+ writeLine("No models available. Set API keys in environment variables.");
17
56
  return;
18
57
  }
19
58
 
20
- // Apply fuzzy filter if search pattern provided
21
59
  let filteredModels: Model<Api>[] = models;
22
60
  if (searchPattern) {
23
- filteredModels = fuzzyFilter(models, searchPattern, m => `${m.provider} ${m.id}`);
61
+ filteredModels = fuzzyFilter(models, searchPattern, model => `${model.provider} ${model.id}`);
24
62
  }
25
63
 
26
- if (filteredModels.length === 0) {
27
- console.log(`No models matching "${searchPattern}"`);
64
+ const filteredCanonical = modelRegistry
65
+ .getCanonicalModels({ availableOnly: true, candidates: filteredModels })
66
+ .map(record => {
67
+ const selected = modelRegistry.resolveCanonicalModel(record.id, {
68
+ availableOnly: true,
69
+ candidates: filteredModels,
70
+ });
71
+ if (!selected) return undefined;
72
+ return {
73
+ canonical: record.id,
74
+ selected: `${selected.provider}/${selected.id}`,
75
+ variants: String(record.variants.length),
76
+ context: formatNumber(selected.contextWindow),
77
+ maxOut: formatNumber(selected.maxTokens),
78
+ } satisfies CanonicalRow;
79
+ })
80
+ .filter((row): row is CanonicalRow => row !== undefined)
81
+ .sort((left, right) => left.canonical.localeCompare(right.canonical));
82
+
83
+ if (filteredModels.length === 0 && filteredCanonical.length === 0) {
84
+ writeLine(`No models matching "${searchPattern}"`);
28
85
  return;
29
86
  }
30
87
 
31
- // Sort by provider, then by model id
32
- filteredModels.sort((a, b) => {
33
- const providerCmp = a.provider.localeCompare(b.provider);
88
+ filteredModels.sort((left, right) => {
89
+ const providerCmp = left.provider.localeCompare(right.provider);
34
90
  if (providerCmp !== 0) return providerCmp;
35
- return a.id.localeCompare(b.id);
91
+ return left.id.localeCompare(right.id);
36
92
  });
37
93
 
38
- // Calculate column widths
39
- const rows = filteredModels.map(m => ({
40
- provider: m.provider,
41
- model: m.id,
42
- context: formatNumber(m.contextWindow),
43
- maxOut: formatNumber(m.maxTokens),
44
- thinking: m.thinking ? getSupportedEfforts(m).join(",") : m.reasoning ? "yes" : "-",
45
- images: m.input.includes("image") ? "yes" : "no",
46
- }));
94
+ const providerRows = filteredModels.map(model => ({
95
+ provider: model.provider,
96
+ model: model.id,
97
+ context: formatNumber(model.contextWindow),
98
+ maxOut: formatNumber(model.maxTokens),
99
+ thinking: model.thinking ? getSupportedEfforts(model).join(",") : model.reasoning ? "yes" : "-",
100
+ images: model.input.includes("image") ? "yes" : "no",
101
+ })) satisfies ProviderRow[];
47
102
 
48
- const headers = {
49
- provider: "provider",
50
- model: "model",
51
- context: "context",
52
- maxOut: "max-out",
53
- thinking: "thinking",
54
- images: "images",
55
- };
56
-
57
- const widths = {
58
- provider: Math.max(headers.provider.length, ...rows.map(r => r.provider.length)),
59
- model: Math.max(headers.model.length, ...rows.map(r => r.model.length)),
60
- context: Math.max(headers.context.length, ...rows.map(r => r.context.length)),
61
- maxOut: Math.max(headers.maxOut.length, ...rows.map(r => r.maxOut.length)),
62
- thinking: Math.max(headers.thinking.length, ...rows.map(r => r.thinking.length)),
63
- images: Math.max(headers.images.length, ...rows.map(r => r.images.length)),
64
- };
65
-
66
- // Print header
67
- const headerLine = [
68
- headers.provider.padEnd(widths.provider),
69
- headers.model.padEnd(widths.model),
70
- headers.context.padEnd(widths.context),
71
- headers.maxOut.padEnd(widths.maxOut),
72
- headers.thinking.padEnd(widths.thinking),
73
- headers.images.padEnd(widths.images),
74
- ].join(" ");
75
- console.log(headerLine);
103
+ if (filteredCanonical.length > 0) {
104
+ writeLine("Canonical models");
105
+ renderTable(filteredCanonical, {
106
+ canonical: "canonical",
107
+ selected: "selected",
108
+ variants: "variants",
109
+ context: "context",
110
+ maxOut: "max-out",
111
+ });
112
+ if (providerRows.length > 0) {
113
+ writeLine();
114
+ }
115
+ }
76
116
 
77
- // Print rows
78
- for (const row of rows) {
79
- const line = [
80
- row.provider.padEnd(widths.provider),
81
- row.model.padEnd(widths.model),
82
- row.context.padEnd(widths.context),
83
- row.maxOut.padEnd(widths.maxOut),
84
- row.thinking.padEnd(widths.thinking),
85
- row.images.padEnd(widths.images),
86
- ].join(" ");
87
- console.log(line);
117
+ if (providerRows.length > 0) {
118
+ writeLine("Provider models");
119
+ renderTable(providerRows, {
120
+ provider: "provider",
121
+ model: "model",
122
+ context: "context",
123
+ maxOut: "max-out",
124
+ thinking: "thinking",
125
+ images: "images",
126
+ });
88
127
  }
89
128
  }
@@ -1,7 +1,12 @@
1
1
  import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
2
  import type { Api, Model } from "@oh-my-pi/pi-ai";
3
3
  import { MODEL_ROLE_IDS } from "../config/model-registry";
4
- import { parseModelPattern, resolveModelRoleValue, resolveRoleSelection } from "../config/model-resolver";
4
+ import {
5
+ type ModelLookupRegistry,
6
+ parseModelPattern,
7
+ resolveModelRoleValue,
8
+ resolveRoleSelection,
9
+ } from "../config/model-resolver";
5
10
  import type { Settings } from "../config/settings";
6
11
  import MODEL_PRIO from "../priority.json" with { type: "json" };
7
12
 
@@ -11,19 +16,20 @@ export interface ResolvedCommitModel {
11
16
  thinkingLevel?: ThinkingLevel;
12
17
  }
13
18
 
19
+ type CommitModelRegistry = ModelLookupRegistry & {
20
+ getApiKey: (model: Model<Api>) => Promise<string | undefined>;
21
+ };
22
+
14
23
  export async function resolvePrimaryModel(
15
24
  override: string | undefined,
16
25
  settings: Settings,
17
- modelRegistry: {
18
- getAvailable: () => Model<Api>[];
19
- getApiKey: (model: Model<Api>) => Promise<string | undefined>;
20
- },
26
+ modelRegistry: CommitModelRegistry,
21
27
  ): Promise<ResolvedCommitModel> {
22
28
  const available = modelRegistry.getAvailable();
23
29
  const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
24
30
  const resolved = override
25
- ? resolveModelRoleValue(override, available, { settings, matchPreferences })
26
- : resolveRoleSelection(["commit", "smol", ...MODEL_ROLE_IDS], settings, available);
31
+ ? resolveModelRoleValue(override, available, { settings, matchPreferences, modelRegistry })
32
+ : resolveRoleSelection(["commit", "smol", ...MODEL_ROLE_IDS], settings, available, modelRegistry);
27
33
  const model = resolved?.model;
28
34
  if (!model) {
29
35
  throw new Error("No model available for commit generation");
@@ -37,15 +43,12 @@ export async function resolvePrimaryModel(
37
43
 
38
44
  export async function resolveSmolModel(
39
45
  settings: Settings,
40
- modelRegistry: {
41
- getAvailable: () => Model<Api>[];
42
- getApiKey: (model: Model<Api>) => Promise<string | undefined>;
43
- },
46
+ modelRegistry: CommitModelRegistry,
44
47
  fallbackModel: Model<Api>,
45
48
  fallbackApiKey: string,
46
49
  ): Promise<ResolvedCommitModel> {
47
50
  const available = modelRegistry.getAvailable();
48
- const resolvedSmol = resolveRoleSelection(["smol"], settings, available);
51
+ const resolvedSmol = resolveRoleSelection(["smol"], settings, available, modelRegistry);
49
52
  if (resolvedSmol?.model) {
50
53
  const apiKey = await modelRegistry.getApiKey(resolvedSmol.model);
51
54
  if (apiKey) return { model: resolvedSmol.model, apiKey, thinkingLevel: resolvedSmol.thinkingLevel };
@@ -53,7 +56,7 @@ export async function resolveSmolModel(
53
56
 
54
57
  const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
55
58
  for (const pattern of MODEL_PRIO.smol) {
56
- const candidate = parseModelPattern(pattern, available, matchPreferences).model;
59
+ const candidate = parseModelPattern(pattern, available, matchPreferences, { modelRegistry }).model;
57
60
  if (!candidate) continue;
58
61
  const apiKey = await modelRegistry.getApiKey(candidate);
59
62
  if (apiKey) return { model: candidate, apiKey };