@oh-my-pi/pi-coding-agent 15.4.1 → 15.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/package.json +7 -7
- package/src/config/model-registry.ts +31 -2
- package/src/modes/components/settings-selector.ts +10 -1
- package/src/modes/theme/theme.ts +4 -2
- package/src/sdk.ts +16 -3
- package/src/tools/gh.ts +7 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [15.4.3] - 2026-05-26
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed Google Vertex cached project discovery replacing the bundled fallback catalog so `/models` does not keep showing outdated Gemini entries after authoritative Vertex discovery ([#1412](https://github.com/can1357/oh-my-pi/issues/1412)).
|
|
10
|
+
|
|
11
|
+
## [15.4.2] - 2026-05-26
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Fixed plan-mode subagents being unable to terminate because `yield` was registered but missing from the active tool set when `requireYieldTool` was combined with an explicit `toolNames` list ([#1408](https://github.com/can1357/oh-my-pi/issues/1408))
|
|
16
|
+
|
|
5
17
|
## [15.4.1] - 2026-05-26
|
|
6
18
|
|
|
7
19
|
### Breaking Changes
|
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": "15.4.
|
|
4
|
+
"version": "15.4.3",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
48
48
|
"@babel/parser": "^7.29.3",
|
|
49
49
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/omp-stats": "15.4.
|
|
51
|
-
"@oh-my-pi/pi-agent-core": "15.4.
|
|
52
|
-
"@oh-my-pi/pi-ai": "15.4.
|
|
53
|
-
"@oh-my-pi/pi-natives": "15.4.
|
|
54
|
-
"@oh-my-pi/pi-tui": "15.4.
|
|
55
|
-
"@oh-my-pi/pi-utils": "15.4.
|
|
50
|
+
"@oh-my-pi/omp-stats": "15.4.3",
|
|
51
|
+
"@oh-my-pi/pi-agent-core": "15.4.3",
|
|
52
|
+
"@oh-my-pi/pi-ai": "15.4.3",
|
|
53
|
+
"@oh-my-pi/pi-natives": "15.4.3",
|
|
54
|
+
"@oh-my-pi/pi-tui": "15.4.3",
|
|
55
|
+
"@oh-my-pi/pi-utils": "15.4.3",
|
|
56
56
|
"@puppeteer/browsers": "^2.13.0",
|
|
57
57
|
"@types/turndown": "5.0.6",
|
|
58
58
|
"@xterm/headless": "^6.0.0",
|
|
@@ -291,6 +291,28 @@ export function mergeDiscoveredModel<TApi extends Api>(
|
|
|
291
291
|
return model;
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
function isAuthoritativeProjectCatalogModel(model: Model<Api>): boolean {
|
|
295
|
+
return (
|
|
296
|
+
model.provider === "google-vertex" &&
|
|
297
|
+
model.api === "openai-completions" &&
|
|
298
|
+
model.baseUrl.includes("/endpoints/openapi")
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function providersWithAuthoritativeProjectCatalog(models: readonly Model<Api>[]): Set<string> {
|
|
303
|
+
const providers = new Set<string>();
|
|
304
|
+
for (const model of models) {
|
|
305
|
+
if (isAuthoritativeProjectCatalogModel(model)) {
|
|
306
|
+
providers.add(model.provider);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return providers;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function dropProviderModels(models: readonly Model<Api>[], providers: ReadonlySet<string>): Model<Api>[] {
|
|
313
|
+
return models.filter(model => !providers.has(model.provider));
|
|
314
|
+
}
|
|
315
|
+
|
|
294
316
|
interface DiscoveryProviderConfig {
|
|
295
317
|
provider: string;
|
|
296
318
|
api: Api;
|
|
@@ -877,9 +899,13 @@ export class ModelRegistry {
|
|
|
877
899
|
this.#equivalenceConfig = equivalence;
|
|
878
900
|
|
|
879
901
|
this.#addImplicitDiscoverableProviders(configuredProviders);
|
|
880
|
-
|
|
902
|
+
let builtInModels = this.#applyHardcodedModelPolicies(this.#loadBuiltInModels(overrides));
|
|
881
903
|
const cachedStandardModels = this.#applyHardcodedModelPolicies(this.#loadCachedStandardProviderModels());
|
|
882
904
|
const cachedDiscoveries = this.#applyHardcodedModelPolicies(this.#loadCachedDiscoverableModels());
|
|
905
|
+
const cachedAuthoritativeProviders = providersWithAuthoritativeProjectCatalog(cachedStandardModels);
|
|
906
|
+
if (cachedAuthoritativeProviders.size > 0) {
|
|
907
|
+
builtInModels = dropProviderModels(builtInModels, cachedAuthoritativeProviders);
|
|
908
|
+
}
|
|
883
909
|
const resolvedDefaults = this.#mergeResolvedModels(
|
|
884
910
|
this.#mergeResolvedModels(builtInModels, cachedStandardModels),
|
|
885
911
|
cachedDiscoveries,
|
|
@@ -1229,7 +1255,10 @@ export class ModelRegistry {
|
|
|
1229
1255
|
),
|
|
1230
1256
|
),
|
|
1231
1257
|
);
|
|
1232
|
-
const
|
|
1258
|
+
const authoritativeProviders = providersWithAuthoritativeProjectCatalog(discoveredModels);
|
|
1259
|
+
const baseModels =
|
|
1260
|
+
authoritativeProviders.size > 0 ? dropProviderModels(this.#models, authoritativeProviders) : this.#models;
|
|
1261
|
+
const resolved = this.#mergeResolvedModels(baseModels, discoveredModels);
|
|
1233
1262
|
const withConfigModels = this.#mergeCustomModels(resolved, this.#customModelOverlays);
|
|
1234
1263
|
// Merge runtime extension models so they survive online discovery completion
|
|
1235
1264
|
const combined = this.#mergeCustomModels(withConfigModels, this.#runtimeModelOverlays);
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
TabBar,
|
|
14
14
|
Text,
|
|
15
15
|
} from "@oh-my-pi/pi-tui";
|
|
16
|
-
import { type SettingPath, settings } from "../../config/settings";
|
|
16
|
+
import { getDefault, type SettingPath, settings } from "../../config/settings";
|
|
17
17
|
import type {
|
|
18
18
|
SettingTab,
|
|
19
19
|
StatusLinePreset,
|
|
@@ -294,6 +294,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
const currentValue = this.#getCurrentValue(def);
|
|
297
|
+
const changed = this.#isChanged(def, currentValue);
|
|
297
298
|
|
|
298
299
|
switch (def.type) {
|
|
299
300
|
case "boolean":
|
|
@@ -303,6 +304,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
303
304
|
description: def.description,
|
|
304
305
|
currentValue: currentValue ? "true" : "false",
|
|
305
306
|
values: ["true", "false"],
|
|
307
|
+
changed,
|
|
306
308
|
};
|
|
307
309
|
|
|
308
310
|
case "enum":
|
|
@@ -312,6 +314,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
312
314
|
description: def.description,
|
|
313
315
|
currentValue: currentValue as string,
|
|
314
316
|
values: [...def.values],
|
|
317
|
+
changed,
|
|
315
318
|
};
|
|
316
319
|
|
|
317
320
|
case "submenu":
|
|
@@ -321,6 +324,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
321
324
|
description: def.description,
|
|
322
325
|
currentValue: this.#getSubmenuCurrentValue(def.path, currentValue),
|
|
323
326
|
submenu: (cv, done) => this.#createSubmenu(def, cv, done),
|
|
327
|
+
changed,
|
|
324
328
|
};
|
|
325
329
|
|
|
326
330
|
case "text":
|
|
@@ -330,6 +334,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
330
334
|
description: def.description,
|
|
331
335
|
currentValue: (currentValue as string) ?? "",
|
|
332
336
|
submenu: (cv, done) => this.#createTextInput(def, cv, done),
|
|
337
|
+
changed,
|
|
333
338
|
};
|
|
334
339
|
}
|
|
335
340
|
}
|
|
@@ -341,6 +346,10 @@ export class SettingsSelectorComponent extends Container {
|
|
|
341
346
|
return settings.get(def.path);
|
|
342
347
|
}
|
|
343
348
|
|
|
349
|
+
#isChanged(def: SettingDef, currentValue: unknown): boolean {
|
|
350
|
+
return !Object.is(currentValue, getDefault(def.path));
|
|
351
|
+
}
|
|
352
|
+
|
|
344
353
|
#getSubmenuCurrentValue(path: SettingPath, value: unknown): string {
|
|
345
354
|
const rawValue = String(value ?? "");
|
|
346
355
|
if (path === "compaction.thresholdPercent" && (rawValue === "-1" || rawValue === "")) {
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -2404,8 +2404,10 @@ export function getEditorTheme(): EditorTheme {
|
|
|
2404
2404
|
|
|
2405
2405
|
export function getSettingsListTheme(): import("@oh-my-pi/pi-tui").SettingsListTheme {
|
|
2406
2406
|
return {
|
|
2407
|
-
label: (text: string, selected: boolean
|
|
2408
|
-
|
|
2407
|
+
label: (text: string, selected: boolean, changed: boolean) =>
|
|
2408
|
+
changed ? theme.fg("statusLineGitDirty", text) : selected ? theme.fg("accent", text) : text,
|
|
2409
|
+
value: (text: string, selected: boolean, changed: boolean) =>
|
|
2410
|
+
selected ? theme.fg("accent", text) : changed ? theme.fg("statusLineGitDirty", text) : theme.fg("muted", text),
|
|
2409
2411
|
description: (text: string) => theme.fg("dim", text),
|
|
2410
2412
|
cursor: theme.fg("accent", `${theme.nav.cursor} `),
|
|
2411
2413
|
hint: (text: string) => theme.fg("dim", text),
|
package/src/sdk.ts
CHANGED
|
@@ -1658,9 +1658,22 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1658
1658
|
};
|
|
1659
1659
|
|
|
1660
1660
|
const toolNamesFromRegistry = Array.from(toolRegistry.keys());
|
|
1661
|
-
const
|
|
1662
|
-
|
|
1663
|
-
|
|
1661
|
+
const explicitlyRequestedToolNames = options.toolNames
|
|
1662
|
+
? [...new Set(options.toolNames.map(name => name.toLowerCase()))]
|
|
1663
|
+
: undefined;
|
|
1664
|
+
// When `requireYieldTool` is set, the subagent's prompts and idle-reminders demand a
|
|
1665
|
+
// `yield` call to terminate. The tool registry already includes `yield` (see
|
|
1666
|
+
// `createTools`), but an explicit `toolNames` list would otherwise drop it from the
|
|
1667
|
+
// active set — leaving the model unable to satisfy the contract. Mirror the same
|
|
1668
|
+
// invariant `parseAgentFields` enforces on frontmatter `tools`.
|
|
1669
|
+
if (
|
|
1670
|
+
options.requireYieldTool === true &&
|
|
1671
|
+
explicitlyRequestedToolNames &&
|
|
1672
|
+
!explicitlyRequestedToolNames.includes("yield")
|
|
1673
|
+
) {
|
|
1674
|
+
explicitlyRequestedToolNames.push("yield");
|
|
1675
|
+
}
|
|
1676
|
+
const requestedToolNames = explicitlyRequestedToolNames ?? toolNamesFromRegistry;
|
|
1664
1677
|
const normalizedRequested = requestedToolNames.filter(name => toolRegistry.has(name));
|
|
1665
1678
|
const requestedToolNameSet = new Set(normalizedRequested);
|
|
1666
1679
|
// Effective discovery mode: tools.discoveryMode takes precedence; mcp.discoveryMode is back-compat alias.
|
package/src/tools/gh.ts
CHANGED
|
@@ -1748,9 +1748,13 @@ async function fetchRunsForCommit(
|
|
|
1748
1748
|
cwd: string,
|
|
1749
1749
|
repo: string,
|
|
1750
1750
|
headSha: string,
|
|
1751
|
-
branch: string | undefined,
|
|
1752
1751
|
signal?: AbortSignal,
|
|
1753
1752
|
): Promise<GhRunSnapshot[]> {
|
|
1753
|
+
// Filter only by `head_sha`. The SHA uniquely identifies the commit, so
|
|
1754
|
+
// adding the GitHub `branch=` filter would wrongly exclude workflow runs
|
|
1755
|
+
// whose `head_branch` is not the local checkout — e.g. tag-push triggered
|
|
1756
|
+
// release workflows (`head_branch=v1.2.3`) or PR-triggered runs
|
|
1757
|
+
// (`head_branch=<pr head>`). See coding-agent issue tracker for details.
|
|
1754
1758
|
const response = await git.github.json<GhActionsRunListResponse>(
|
|
1755
1759
|
cwd,
|
|
1756
1760
|
[
|
|
@@ -1762,7 +1766,6 @@ async function fetchRunsForCommit(
|
|
|
1762
1766
|
`head_sha=${headSha}`,
|
|
1763
1767
|
"-F",
|
|
1764
1768
|
`per_page=${RUN_JOBS_PAGE_SIZE}`,
|
|
1765
|
-
...(branch ? ["-F", `branch=${branch}`] : []),
|
|
1766
1769
|
],
|
|
1767
1770
|
signal,
|
|
1768
1771
|
{ repoProvided: true },
|
|
@@ -3406,7 +3409,7 @@ async function executeRunWatch(
|
|
|
3406
3409
|
throwIfAborted(signal);
|
|
3407
3410
|
pollCount += 1;
|
|
3408
3411
|
|
|
3409
|
-
let runs = await fetchRunsForCommit(session.cwd, repo, headSha,
|
|
3412
|
+
let runs = await fetchRunsForCommit(session.cwd, repo, headSha, signal);
|
|
3410
3413
|
const details = buildCommitRunWatchDetails(repo, headSha, branch, runs, {
|
|
3411
3414
|
state: "watching",
|
|
3412
3415
|
pollCount,
|
|
@@ -3434,7 +3437,7 @@ async function executeRunWatch(
|
|
|
3434
3437
|
}),
|
|
3435
3438
|
});
|
|
3436
3439
|
await scheduler.wait(graceSeconds * 1000, { signal });
|
|
3437
|
-
runs = await fetchRunsForCommit(session.cwd, repo, headSha,
|
|
3440
|
+
runs = await fetchRunsForCommit(session.cwd, repo, headSha, signal);
|
|
3438
3441
|
}
|
|
3439
3442
|
|
|
3440
3443
|
const failedJobLogs = await fetchFailedJobLogs(
|