@oh-my-pi/pi-coding-agent 15.11.3 → 15.11.4
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 +54 -0
- package/dist/cli.js +353 -294
- package/dist/types/config/api-key-resolver.d.ts +9 -3
- package/dist/types/config/keybindings.d.ts +1 -1
- package/dist/types/config/model-discovery.d.ts +6 -4
- package/dist/types/config/model-registry.d.ts +7 -4
- package/dist/types/config/settings-schema.d.ts +458 -155
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/mnemopi/config.d.ts +3 -1
- package/dist/types/modes/components/settings-defs.d.ts +9 -2
- package/dist/types/modes/components/settings-selector.d.ts +9 -4
- package/dist/types/modes/components/tool-execution.d.ts +12 -1
- package/dist/types/modes/components/transcript-container.d.ts +12 -0
- package/dist/types/modes/controllers/input-controller.d.ts +9 -1
- package/dist/types/modes/theme/theme.d.ts +23 -3
- package/dist/types/session/agent-session.d.ts +14 -7
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/session/snapcompact-inline.d.ts +28 -0
- package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +14 -0
- package/dist/types/system-prompt.d.ts +3 -1
- package/dist/types/task/render.d.ts +16 -6
- package/dist/types/tools/gh.d.ts +3 -0
- package/dist/types/tools/render-utils.d.ts +8 -16
- package/dist/types/utils/session-color.d.ts +15 -3
- package/dist/types/web/kagi.d.ts +1 -2
- package/dist/types/web/search/providers/codex.d.ts +1 -1
- package/dist/types/web/search/providers/gemini.d.ts +9 -6
- package/package.json +11 -11
- package/src/auto-thinking/classifier.ts +1 -5
- package/src/commit/model-selection.ts +3 -6
- package/src/config/api-key-resolver.ts +10 -3
- package/src/config/keybindings.ts +1 -1
- package/src/config/model-discovery.ts +60 -46
- package/src/config/model-registry.ts +21 -8
- package/src/config/model-resolver.ts +57 -3
- package/src/config/settings-schema.ts +601 -153
- package/src/eval/completion-bridge.ts +1 -5
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +13 -6
- package/src/internal-urls/docs-index.generated.ts +5 -5
- package/src/internal-urls/issue-pr-protocol.ts +10 -4
- package/src/memories/index.ts +2 -10
- package/src/mnemopi/backend.ts +30 -8
- package/src/mnemopi/config.ts +6 -1
- package/src/mnemopi/state.ts +6 -0
- package/src/modes/components/extensions/inspector-panel.ts +6 -2
- package/src/modes/components/plan-review-overlay.ts +15 -17
- package/src/modes/components/plugin-settings.ts +22 -5
- package/src/modes/components/settings-defs.ts +19 -4
- package/src/modes/components/settings-selector.ts +493 -93
- package/src/modes/components/status-line/component.ts +3 -1
- package/src/modes/components/status-line/segments.ts +3 -1
- package/src/modes/components/tool-execution.ts +69 -12
- package/src/modes/components/transcript-container.ts +26 -0
- package/src/modes/components/tree-selector.ts +16 -6
- package/src/modes/controllers/command-controller.ts +37 -7
- package/src/modes/controllers/event-controller.ts +1 -0
- package/src/modes/controllers/input-controller.ts +68 -6
- package/src/modes/controllers/selector-controller.ts +81 -61
- package/src/modes/interactive-mode.ts +4 -2
- package/src/modes/rpc/rpc-mode.ts +2 -1
- package/src/modes/shared.ts +2 -0
- package/src/modes/theme/theme.ts +100 -7
- package/src/modes/utils/context-usage.ts +3 -1
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/modes/utils/ui-helpers.ts +9 -5
- package/src/prompts/system/personalities/default.md +26 -0
- package/src/prompts/system/personalities/friendly.md +17 -0
- package/src/prompts/system/personalities/pragmatic.md +15 -0
- package/src/prompts/system/snapcompact-system-frames-note.md +1 -0
- package/src/prompts/system/snapcompact-system-stub.md +1 -0
- package/src/prompts/system/snapcompact-toolresult-note.md +1 -0
- package/src/prompts/system/system-prompt.md +5 -22
- package/src/prompts/tools/task.md +3 -3
- package/src/sdk.ts +22 -1
- package/src/session/agent-session.ts +91 -24
- package/src/session/auth-storage.ts +1 -0
- package/src/session/session-dump-format.ts +8 -1
- package/src/session/session-manager.ts +5 -5
- package/src/session/snapcompact-inline.ts +187 -0
- package/src/slash-commands/helpers/active-oauth-account.ts +44 -0
- package/src/slash-commands/helpers/usage-report.ts +24 -3
- package/src/system-prompt.ts +15 -1
- package/src/task/render.ts +29 -19
- package/src/tool-discovery/tool-index.ts +2 -0
- package/src/tools/bash.ts +10 -3
- package/src/tools/eval-render.ts +13 -8
- package/src/tools/gh.ts +39 -1
- package/src/tools/image-gen.ts +114 -78
- package/src/tools/inspect-image.ts +1 -5
- package/src/tools/job.ts +25 -5
- package/src/tools/read.ts +1 -57
- package/src/tools/render-utils.ts +29 -31
- package/src/tools/ssh.ts +3 -3
- package/src/tools/tts.ts +40 -20
- package/src/utils/clipboard.ts +56 -4
- package/src/utils/commit-message-generator.ts +1 -5
- package/src/utils/session-color.ts +83 -9
- package/src/utils/title-generator.ts +1 -1
- package/src/web/kagi.ts +26 -27
- package/src/web/search/providers/codex.ts +42 -40
- package/src/web/search/providers/gemini.ts +42 -22
- package/src/web/search/providers/perplexity.ts +22 -10
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* `discoverModelsByProviderType` with a `DiscoveryContext`; built-in provider
|
|
6
6
|
* discovery lives in pi-catalog's provider-models.
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
8
|
+
import { type ApiKey, type FetchImpl, withAuth } from "@oh-my-pi/pi-ai";
|
|
9
9
|
import type { Api, Model } from "@oh-my-pi/pi-ai/types";
|
|
10
10
|
import { buildModel } from "@oh-my-pi/pi-catalog/build";
|
|
11
11
|
import {
|
|
@@ -97,10 +97,12 @@ export interface DiscoveryContext {
|
|
|
97
97
|
/** Injected fetch implementation (tests stub this). */
|
|
98
98
|
fetch: FetchImpl;
|
|
99
99
|
/**
|
|
100
|
-
* Resolve a provider's
|
|
101
|
-
* undefined when no key is stored or it is a local/no-auth
|
|
100
|
+
* Resolve a provider's bearer credential for `Authorization: Bearer …`.
|
|
101
|
+
* Returns undefined when no key is stored or it is a local/no-auth
|
|
102
|
+
* sentinel; otherwise an {@link ApiKey} whose resolver participates in the
|
|
103
|
+
* central force-refresh/rotate auth-retry policy on 401/usage-limit.
|
|
102
104
|
*/
|
|
103
|
-
|
|
105
|
+
getBearerApiKeyResolver(provider: string): Promise<ApiKey | undefined>;
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
type OllamaDiscoveredModelMetadata = {
|
|
@@ -314,22 +316,26 @@ export async function discoverLlamaCppModels(
|
|
|
314
316
|
const baseUrl = normalizeLlamaCppBaseUrl(providerConfig.baseUrl);
|
|
315
317
|
const modelsUrl = `${baseUrl}/models`;
|
|
316
318
|
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
319
|
+
const baseHeaders: Record<string, string> = { ...(providerConfig.headers ?? {}) };
|
|
320
|
+
let headers = baseHeaders;
|
|
321
|
+
const attempt = async (h: Record<string, string>) => {
|
|
322
|
+
const [response, metadata] = await Promise.all([
|
|
323
|
+
ctx.fetch(modelsUrl, {
|
|
324
|
+
headers: h,
|
|
325
|
+
signal: AbortSignal.timeout(250),
|
|
326
|
+
}),
|
|
327
|
+
discoverLlamaCppServerMetadata(ctx, baseUrl, h),
|
|
328
|
+
]);
|
|
329
|
+
if (!response.ok) {
|
|
330
|
+
throw new Error(`HTTP ${response.status} from ${modelsUrl}`);
|
|
331
|
+
}
|
|
332
|
+
headers = h;
|
|
333
|
+
return [response, metadata] as const;
|
|
334
|
+
};
|
|
335
|
+
const apiKey = await ctx.getBearerApiKeyResolver(providerConfig.provider);
|
|
336
|
+
const [response, serverMetadata] = apiKey
|
|
337
|
+
? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
|
|
338
|
+
: await attempt(baseHeaders);
|
|
333
339
|
const payload = (await response.json()) as { data?: Array<{ id: string }> };
|
|
334
340
|
const models = payload.data ?? [];
|
|
335
341
|
const discovered: Model<Api>[] = [];
|
|
@@ -370,19 +376,23 @@ export async function discoverOpenAIModelsList(
|
|
|
370
376
|
const baseUrl = normalizeOpenAIModelsListBaseUrl(providerConfig.baseUrl);
|
|
371
377
|
const modelsUrl = `${baseUrl}/models`;
|
|
372
378
|
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
379
|
+
const baseHeaders: Record<string, string> = { ...(providerConfig.headers ?? {}) };
|
|
380
|
+
let headers = baseHeaders;
|
|
381
|
+
const attempt = async (h: Record<string, string>) => {
|
|
382
|
+
const res = await ctx.fetch(modelsUrl, {
|
|
383
|
+
headers: h,
|
|
384
|
+
signal: AbortSignal.timeout(10_000),
|
|
385
|
+
});
|
|
386
|
+
if (!res.ok) {
|
|
387
|
+
throw new Error(`HTTP ${res.status} from ${modelsUrl}`);
|
|
388
|
+
}
|
|
389
|
+
headers = h;
|
|
390
|
+
return res;
|
|
391
|
+
};
|
|
392
|
+
const apiKey = await ctx.getBearerApiKeyResolver(providerConfig.provider);
|
|
393
|
+
const response = apiKey
|
|
394
|
+
? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
|
|
395
|
+
: await attempt(baseHeaders);
|
|
386
396
|
const payload = (await response.json()) as { data?: Array<{ id: string }> };
|
|
387
397
|
const models = payload.data ?? [];
|
|
388
398
|
const discovered: Model<Api>[] = [];
|
|
@@ -435,19 +445,23 @@ export async function discoverProxyModels(
|
|
|
435
445
|
const baseUrl = normalizeOpenAIModelsListBaseUrl(providerConfig.baseUrl);
|
|
436
446
|
const modelsUrl = `${baseUrl}/models`;
|
|
437
447
|
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
448
|
+
const baseHeaders: Record<string, string> = { ...(providerConfig.headers ?? {}) };
|
|
449
|
+
let headers = baseHeaders;
|
|
450
|
+
const attempt = async (h: Record<string, string>) => {
|
|
451
|
+
const res = await ctx.fetch(modelsUrl, {
|
|
452
|
+
headers: h,
|
|
453
|
+
signal: AbortSignal.timeout(10_000),
|
|
454
|
+
});
|
|
455
|
+
if (!res.ok) {
|
|
456
|
+
throw new Error(`HTTP ${res.status} from ${modelsUrl}`);
|
|
457
|
+
}
|
|
458
|
+
headers = h;
|
|
459
|
+
return res;
|
|
460
|
+
};
|
|
461
|
+
const apiKey = await ctx.getBearerApiKeyResolver(providerConfig.provider);
|
|
462
|
+
const response = apiKey
|
|
463
|
+
? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
|
|
464
|
+
: await attempt(baseHeaders);
|
|
451
465
|
const payload = (await response.json()) as {
|
|
452
466
|
data?: Array<{ id?: string; name?: string; supported_endpoint_types?: string[] }>;
|
|
453
467
|
};
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
import { isRecord, logger } from "@oh-my-pi/pi-utils";
|
|
58
58
|
import { parseModelString, resolveProviderModelReference } from "../config/model-resolver";
|
|
59
59
|
import type { AuthStorage, OAuthCredential } from "../session/auth-storage";
|
|
60
|
-
import { type ApiKeyResolverOptions, createApiKeyResolver } from "./api-key-resolver";
|
|
60
|
+
import { type ApiKeyResolverModel, type ApiKeyResolverOptions, createApiKeyResolver } from "./api-key-resolver";
|
|
61
61
|
import type { ConfigError, ConfigFile } from "./config-file";
|
|
62
62
|
import {
|
|
63
63
|
DISCOVERY_DEFAULT_MAX_TOKENS,
|
|
@@ -1238,9 +1238,10 @@ export class ModelRegistry {
|
|
|
1238
1238
|
#discoveryContext(): DiscoveryContext {
|
|
1239
1239
|
return {
|
|
1240
1240
|
fetch: this.#fetch,
|
|
1241
|
-
|
|
1241
|
+
getBearerApiKeyResolver: async provider => {
|
|
1242
1242
|
const apiKey = await this.getApiKeyForProvider(provider);
|
|
1243
|
-
|
|
1243
|
+
if (!apiKey || apiKey === DEFAULT_LOCAL_TOKEN || apiKey === kNoAuth) return undefined;
|
|
1244
|
+
return this.resolver(provider);
|
|
1244
1245
|
},
|
|
1245
1246
|
};
|
|
1246
1247
|
}
|
|
@@ -1754,12 +1755,24 @@ export class ModelRegistry {
|
|
|
1754
1755
|
}
|
|
1755
1756
|
|
|
1756
1757
|
/**
|
|
1757
|
-
* Build an {@link ApiKeyResolver}
|
|
1758
|
-
*
|
|
1759
|
-
*
|
|
1758
|
+
* Build an {@link ApiKeyResolver} implementing the central a/b/c auth-retry
|
|
1759
|
+
* policy. Accepts a provider id with options, or a model with an optional
|
|
1760
|
+
* session id (`resolver(model, sessionId)`) which derives `baseUrl`/`modelId`
|
|
1761
|
+
* from the model. Callers that need the initial key for a guard can call
|
|
1762
|
+
* `resolveApiKeyOnce(resolver)`.
|
|
1760
1763
|
*/
|
|
1761
|
-
resolver(provider: string, options?: ApiKeyResolverOptions): ApiKeyResolver
|
|
1762
|
-
|
|
1764
|
+
resolver(provider: string, options?: ApiKeyResolverOptions): ApiKeyResolver;
|
|
1765
|
+
resolver(model: ApiKeyResolverModel, sessionId?: string): ApiKeyResolver;
|
|
1766
|
+
resolver(target: string | ApiKeyResolverModel, optionsOrSessionId?: ApiKeyResolverOptions | string): ApiKeyResolver {
|
|
1767
|
+
const options = typeof optionsOrSessionId === "string" ? { sessionId: optionsOrSessionId } : optionsOrSessionId;
|
|
1768
|
+
if (typeof target === "string") {
|
|
1769
|
+
return createApiKeyResolver(this, target, options);
|
|
1770
|
+
}
|
|
1771
|
+
return createApiKeyResolver(this, target.provider, {
|
|
1772
|
+
...options,
|
|
1773
|
+
baseUrl: target.baseUrl,
|
|
1774
|
+
modelId: target.id,
|
|
1775
|
+
});
|
|
1763
1776
|
}
|
|
1764
1777
|
|
|
1765
1778
|
async #peekApiKeyForProvider(provider: string): Promise<string | undefined> {
|
|
@@ -633,18 +633,72 @@ function isSessionInheritedAgentPattern(value: string): boolean {
|
|
|
633
633
|
return value === DEFAULT_MODEL_ROLE || value === `${PREFIX_MODEL_ROLE}${DEFAULT_MODEL_ROLE}` || value === "pi/task";
|
|
634
634
|
}
|
|
635
635
|
|
|
636
|
-
function
|
|
636
|
+
function shouldInheritDefaultBeforePriority(role: ModelRole): boolean {
|
|
637
|
+
return role === "smol" || role === "slow" || role === "designer";
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function resolveDefaultInheritedPatterns(
|
|
641
|
+
role: ModelRole,
|
|
642
|
+
configuredDefault: string | undefined,
|
|
643
|
+
roleDefaults: string[],
|
|
644
|
+
settings: Settings | undefined,
|
|
645
|
+
visited: Set<ModelRole>,
|
|
646
|
+
): string[] {
|
|
647
|
+
if (!shouldInheritDefaultBeforePriority(role) || !configuredDefault) return [];
|
|
648
|
+
|
|
649
|
+
const resolved: string[] = [];
|
|
650
|
+
for (const pattern of normalizeModelPatternList(configuredDefault)) {
|
|
651
|
+
const { base: aliasCandidate, level: thinkingLevel } = splitThinkingSuffix(pattern, PREFIX_MODEL_ROLE.length);
|
|
652
|
+
const aliasRole = getModelRoleAlias(aliasCandidate);
|
|
653
|
+
if (aliasRole === role) {
|
|
654
|
+
// Self-alias (e.g. modelRoles.default = "pi/smol") would loop back to the
|
|
655
|
+
// same unset role; collapse straight to the built-in priority chain.
|
|
656
|
+
resolved.push(
|
|
657
|
+
...(thinkingLevel
|
|
658
|
+
? roleDefaults.map(defaultPattern => `${defaultPattern}:${thinkingLevel}`)
|
|
659
|
+
: roleDefaults),
|
|
660
|
+
);
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
if (aliasRole && !visited.has(aliasRole)) {
|
|
664
|
+
// Cross-role alias (e.g. modelRoles.default = "pi/slow"): resolve the
|
|
665
|
+
// target role's patterns now so downstream one-layer expanders see
|
|
666
|
+
// concrete model patterns instead of another role alias.
|
|
667
|
+
const recursed = resolveConfiguredRolePattern(pattern, settings, new Set(visited));
|
|
668
|
+
if (recursed && recursed.length > 0) {
|
|
669
|
+
resolved.push(...recursed);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
resolved.push(pattern);
|
|
674
|
+
}
|
|
675
|
+
return resolved;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function resolveConfiguredRolePattern(
|
|
679
|
+
value: string,
|
|
680
|
+
settings?: Settings,
|
|
681
|
+
visited: Set<ModelRole> = new Set(),
|
|
682
|
+
): string[] | undefined {
|
|
637
683
|
const normalized = value.trim();
|
|
638
684
|
if (!normalized) return undefined;
|
|
639
685
|
|
|
640
686
|
const { base: aliasCandidate, level: thinkingLevel } = splitThinkingSuffix(normalized, PREFIX_MODEL_ROLE.length);
|
|
641
687
|
const role = getModelRoleAlias(aliasCandidate);
|
|
642
688
|
if (!role) return [normalized];
|
|
689
|
+
if (visited.has(role)) return undefined;
|
|
690
|
+
visited.add(role);
|
|
643
691
|
|
|
644
692
|
const configured = settings?.getModelRole(role)?.trim();
|
|
693
|
+
const configuredDefault = settings?.getModelRole(DEFAULT_MODEL_ROLE)?.trim();
|
|
645
694
|
const roleDefaults = normalizeModelPatternList(MODEL_PRIO[role as keyof typeof MODEL_PRIO]);
|
|
646
|
-
const resolved = configured
|
|
647
|
-
|
|
695
|
+
const resolved = configured
|
|
696
|
+
? normalizeModelPatternList(configured)
|
|
697
|
+
: resolveDefaultInheritedPatterns(role, configuredDefault, roleDefaults, settings, visited);
|
|
698
|
+
if (resolved.length === 0) {
|
|
699
|
+
resolved.push(...roleDefaults);
|
|
700
|
+
}
|
|
701
|
+
if (resolved.length === 0) {
|
|
648
702
|
return undefined;
|
|
649
703
|
}
|
|
650
704
|
|