@oh-my-pi/pi-coding-agent 15.5.13 → 15.6.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.
- package/CHANGELOG.md +77 -0
- package/dist/types/cli/classify-install-target.d.ts +0 -10
- package/dist/types/cli/initial-message.d.ts +1 -1
- package/dist/types/cli/tiny-models-cli.d.ts +9 -0
- package/dist/types/commands/tiny-models.d.ts +22 -0
- package/dist/types/commit/analysis/conventional.d.ts +1 -1
- package/dist/types/commit/analysis/summary.d.ts +1 -1
- package/dist/types/commit/changelog/generate.d.ts +1 -1
- package/dist/types/commit/changelog/index.d.ts +2 -2
- package/dist/types/commit/map-reduce/map-phase.d.ts +1 -1
- package/dist/types/commit/map-reduce/reduce-phase.d.ts +1 -1
- package/dist/types/config/model-id-affixes.d.ts +10 -0
- package/dist/types/config/model-registry.d.ts +1 -1
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +233 -17
- package/dist/types/discovery/helpers.d.ts +1 -1
- package/dist/types/discovery/substitute-plugin-root.d.ts +0 -4
- package/dist/types/eval/__tests__/llm-bridge.test.d.ts +1 -0
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +16 -1
- package/dist/types/eval/llm-bridge.d.ts +25 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +15 -0
- package/dist/types/internal-urls/agent-protocol.d.ts +2 -1
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -1
- package/dist/types/internal-urls/local-protocol.d.ts +2 -1
- package/dist/types/internal-urls/memory-protocol.d.ts +2 -1
- package/dist/types/internal-urls/omp-protocol.d.ts +2 -1
- package/dist/types/internal-urls/router.d.ts +8 -1
- package/dist/types/internal-urls/rule-protocol.d.ts +2 -1
- package/dist/types/internal-urls/skill-protocol.d.ts +2 -1
- package/dist/types/internal-urls/types.d.ts +26 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/resolve.d.ts +2 -1
- package/dist/types/memory-backend/types.d.ts +7 -1
- package/dist/types/mnemosyne/backend.d.ts +4 -0
- package/dist/types/mnemosyne/config.d.ts +29 -0
- package/dist/types/mnemosyne/index.d.ts +3 -0
- package/dist/types/mnemosyne/state.d.ts +72 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -3
- package/dist/types/modes/components/hook-selector.d.ts +27 -0
- package/dist/types/modes/components/index.d.ts +1 -0
- package/dist/types/modes/components/status-line/context-thresholds.d.ts +6 -0
- package/dist/types/modes/components/tiny-title-download-progress.d.ts +11 -0
- package/dist/types/modes/components/welcome.d.ts +1 -0
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +4 -1
- package/dist/types/modes/gradient-highlight.d.ts +23 -0
- package/dist/types/modes/interactive-mode.d.ts +4 -2
- package/dist/types/modes/internal-url-autocomplete.d.ts +43 -0
- package/dist/types/modes/orchestrate.d.ts +10 -0
- package/dist/types/modes/theme/defaults/index.d.ts +8406 -8406
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/modes/ultrathink.d.ts +3 -3
- package/dist/types/modes/utils/keybinding-matchers.d.ts +5 -0
- package/dist/types/sdk.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +35 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +2 -0
- package/dist/types/task/render.d.ts +5 -1
- package/dist/types/tiny/models.d.ts +185 -0
- package/dist/types/tiny/text.d.ts +4 -0
- package/dist/types/tiny/title-client.d.ts +24 -0
- package/dist/types/tiny/title-protocol.d.ts +74 -0
- package/dist/types/tiny/worker.d.ts +2 -0
- package/dist/types/tools/bash.d.ts +3 -1
- package/dist/types/tools/index.d.ts +7 -4
- package/dist/types/tools/memory-edit.d.ts +40 -0
- package/dist/types/tools/{hindsight-recall.d.ts → memory-recall.d.ts} +6 -6
- package/dist/types/tools/{hindsight-reflect.d.ts → memory-reflect.d.ts} +6 -6
- package/dist/types/tools/memory-render.d.ts +60 -0
- package/dist/types/tools/{hindsight-retain.d.ts → memory-retain.d.ts} +6 -6
- package/dist/types/tools/todo-write.d.ts +8 -0
- package/dist/types/tools/tool-result.d.ts +2 -0
- package/dist/types/utils/title-generator.d.ts +3 -0
- package/package.json +18 -14
- package/scripts/build-binary.ts +1 -0
- package/src/cli/tiny-models-cli.ts +127 -0
- package/src/cli-commands.ts +1 -0
- package/src/cli.ts +8 -8
- package/src/commands/tiny-models.ts +36 -0
- package/src/config/model-equivalence.ts +43 -2
- package/src/config/model-id-affixes.ts +64 -0
- package/src/config/model-registry.ts +166 -8
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +206 -14
- package/src/edit/hashline/diff.ts +5 -7
- package/src/eval/__tests__/llm-bridge.test.ts +297 -0
- package/src/eval/__tests__/shared-executors.test.ts +36 -0
- package/src/eval/js/shared/local-module-loader.ts +13 -1
- package/src/eval/js/shared/prelude.txt +8 -0
- package/src/eval/js/shared/rewrite-imports.ts +31 -26
- package/src/eval/js/tool-bridge.ts +4 -0
- package/src/eval/llm-bridge.ts +181 -0
- package/src/eval/py/prelude.py +52 -31
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +0 -13
- package/src/extensibility/plugins/legacy-pi-compat.ts +60 -23
- package/src/internal-urls/agent-protocol.ts +18 -1
- package/src/internal-urls/artifact-protocol.ts +19 -1
- package/src/internal-urls/docs-index.generated.ts +5 -4
- package/src/internal-urls/local-protocol.ts +14 -1
- package/src/internal-urls/memory-protocol.ts +6 -1
- package/src/internal-urls/omp-protocol.ts +5 -1
- package/src/internal-urls/router.ts +20 -1
- package/src/internal-urls/rule-protocol.ts +8 -1
- package/src/internal-urls/skill-protocol.ts +8 -1
- package/src/internal-urls/types.ts +27 -0
- package/src/lsp/render.ts +1 -1
- package/src/main.ts +4 -0
- package/src/mcp/oauth-flow.ts +2 -2
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/resolve.ts +4 -1
- package/src/memory-backend/types.ts +8 -1
- package/src/mnemosyne/backend.ts +374 -0
- package/src/mnemosyne/config.ts +160 -0
- package/src/mnemosyne/index.ts +3 -0
- package/src/mnemosyne/state.ts +548 -0
- package/src/modes/acp/acp-agent.ts +11 -6
- package/src/modes/components/agent-dashboard.ts +4 -4
- package/src/modes/components/custom-editor.ts +3 -2
- package/src/modes/components/diff.ts +2 -2
- package/src/modes/components/extensions/extension-list.ts +3 -2
- package/src/modes/components/footer.ts +5 -6
- package/src/modes/components/history-search.ts +3 -3
- package/src/modes/components/hook-selector.ts +94 -8
- package/src/modes/components/index.ts +1 -0
- package/src/modes/components/mcp-add-wizard.ts +3 -3
- package/src/modes/components/model-selector.ts +124 -26
- package/src/modes/components/oauth-selector.ts +3 -3
- package/src/modes/components/session-observer-overlay.ts +19 -13
- package/src/modes/components/session-selector.ts +3 -3
- package/src/modes/components/settings-defs.ts +7 -0
- package/src/modes/components/status-line/context-thresholds.ts +11 -0
- package/src/modes/components/status-line/presets.ts +1 -0
- package/src/modes/components/status-line/segments.ts +25 -2
- package/src/modes/components/tiny-title-download-progress.ts +90 -0
- package/src/modes/components/tips.txt +12 -0
- package/src/modes/components/tool-execution.ts +67 -3
- package/src/modes/components/tree-selector.ts +3 -3
- package/src/modes/components/user-message-selector.ts +3 -3
- package/src/modes/components/welcome.ts +55 -1
- package/src/modes/controllers/command-controller.ts +16 -1
- package/src/modes/controllers/extension-ui-controller.ts +3 -1
- package/src/modes/controllers/input-controller.ts +57 -0
- package/src/modes/gradient-highlight.ts +70 -0
- package/src/modes/interactive-mode.ts +80 -196
- package/src/modes/internal-url-autocomplete.ts +143 -0
- package/src/modes/orchestrate.ts +36 -0
- package/src/modes/prompt-action-autocomplete.ts +12 -0
- package/src/modes/theme/theme.ts +7 -0
- package/src/modes/ultrathink.ts +9 -53
- package/src/modes/utils/keybinding-matchers.ts +11 -0
- package/src/prompts/system/memory-consolidation-system.md +8 -0
- package/src/prompts/system/memory-extraction-system.md +26 -0
- package/src/prompts/{commands/orchestrate.md → system/orchestrate-notice.md} +5 -16
- package/src/prompts/system/system-prompt.md +2 -0
- package/src/prompts/system/tiny-title-system.md +8 -0
- package/src/prompts/tools/eval.md +2 -0
- package/src/prompts/tools/memory-edit.md +8 -0
- package/src/prompts/tools/task.md +4 -7
- package/src/sdk.ts +8 -6
- package/src/session/agent-session.ts +147 -44
- package/src/session/session-manager.ts +47 -0
- package/src/slash-commands/builtin-registry.ts +10 -1
- package/src/system-prompt.ts +4 -0
- package/src/task/commands.ts +1 -5
- package/src/task/executor.ts +8 -0
- package/src/task/index.ts +2 -0
- package/src/task/render.ts +69 -26
- package/src/tiny/models.ts +217 -0
- package/src/tiny/text.ts +19 -0
- package/src/tiny/title-client.ts +340 -0
- package/src/tiny/title-protocol.ts +51 -0
- package/src/tiny/worker.ts +523 -0
- package/src/tools/bash.ts +58 -16
- package/src/tools/browser/tab-worker.ts +1 -1
- package/src/tools/eval.ts +24 -48
- package/src/tools/index.ts +17 -15
- package/src/tools/memory-edit.ts +59 -0
- package/src/tools/memory-recall.ts +100 -0
- package/src/tools/memory-reflect.ts +88 -0
- package/src/tools/memory-render.ts +185 -0
- package/src/tools/memory-retain.ts +91 -0
- package/src/tools/renderers.ts +4 -2
- package/src/tools/todo-write.ts +128 -29
- package/src/tools/tool-result.ts +8 -0
- package/src/utils/title-generator.ts +115 -13
- package/dist/types/tools/calculator.d.ts +0 -77
- package/src/prompts/tools/calculator.md +0 -10
- package/src/tools/calculator.ts +0 -541
- package/src/tools/hindsight-recall.ts +0 -69
- package/src/tools/hindsight-reflect.ts +0 -58
- package/src/tools/hindsight-retain.ts +0 -57
|
@@ -42,6 +42,12 @@ import {
|
|
|
42
42
|
formatCanonicalVariantSelector,
|
|
43
43
|
type ModelEquivalenceConfig,
|
|
44
44
|
} from "./model-equivalence";
|
|
45
|
+
import {
|
|
46
|
+
getBracketStrippedModelIdCandidates,
|
|
47
|
+
getLongestModelLikeIdSegment,
|
|
48
|
+
getModelLikeIdSegments,
|
|
49
|
+
stripBracketedModelIdAffixes,
|
|
50
|
+
} from "./model-id-affixes";
|
|
45
51
|
import {
|
|
46
52
|
type ModelOverride,
|
|
47
53
|
type ModelsConfig,
|
|
@@ -192,7 +198,7 @@ function validateProviderConfiguration(
|
|
|
192
198
|
}
|
|
193
199
|
}
|
|
194
200
|
|
|
195
|
-
if (mode === "models-config" && config.discovery && !config.api) {
|
|
201
|
+
if (mode === "models-config" && config.discovery && !config.api && config.discovery.type !== "proxy") {
|
|
196
202
|
throw new Error(`Provider ${providerName}: "api" is required when discovery is enabled at provider level.`);
|
|
197
203
|
}
|
|
198
204
|
|
|
@@ -650,20 +656,53 @@ function shouldReplaceCustomReference(existing: Model<Api> | undefined, candidat
|
|
|
650
656
|
return existing.provider !== "openai" && candidate.provider === "openai";
|
|
651
657
|
}
|
|
652
658
|
|
|
659
|
+
function normalizeCustomReferenceKey(value: string): string {
|
|
660
|
+
return value.trim().toLowerCase();
|
|
661
|
+
}
|
|
662
|
+
|
|
653
663
|
function buildCustomReferenceMap(): Map<string, Model<Api>> {
|
|
654
664
|
const references = new Map<string, Model<Api>>();
|
|
655
665
|
for (const provider of getBundledProviders()) {
|
|
656
666
|
for (const model of getBundledModels(provider as Parameters<typeof getBundledModels>[0])) {
|
|
657
667
|
const candidate = model as Model<Api>;
|
|
658
|
-
|
|
659
|
-
|
|
668
|
+
const key = normalizeCustomReferenceKey(candidate.id);
|
|
669
|
+
if (shouldReplaceCustomReference(references.get(key), candidate)) {
|
|
670
|
+
references.set(key, candidate);
|
|
660
671
|
}
|
|
661
672
|
}
|
|
662
673
|
}
|
|
663
674
|
return references;
|
|
664
675
|
}
|
|
665
676
|
|
|
677
|
+
function buildCustomReferenceSuffixAliasMap(exactReferences: ReadonlyMap<string, Model<Api>>): Map<string, Model<Api>> {
|
|
678
|
+
const aliases = new Map<string, Model<Api>>();
|
|
679
|
+
for (const reference of exactReferences.values()) {
|
|
680
|
+
const slashIndex = reference.id.lastIndexOf("/");
|
|
681
|
+
if (slashIndex === -1) {
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
const suffix = reference.id.slice(slashIndex + 1);
|
|
685
|
+
const alias = getLongestModelLikeIdSegment(suffix);
|
|
686
|
+
if (!alias) {
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
if (shouldReplaceCustomReference(aliases.get(alias), reference)) {
|
|
690
|
+
aliases.set(alias, reference);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return aliases;
|
|
694
|
+
}
|
|
695
|
+
|
|
666
696
|
const customReferenceMap = buildCustomReferenceMap();
|
|
697
|
+
const customReferenceSuffixAliasMap = buildCustomReferenceSuffixAliasMap(customReferenceMap);
|
|
698
|
+
|
|
699
|
+
const CUSTOM_REFERENCE_TRAILING_MARKER_PATTERN =
|
|
700
|
+
/[-:](?:thinking|customtools|high|low|medium|minimal|xhigh|free|cloud|exacto|nitro|original|optimized|nvfp4|fp8|fp4|bf16|int8|int4|search)$/i;
|
|
701
|
+
|
|
702
|
+
function stripCustomReferenceTrailingMarker(candidate: string): string | undefined {
|
|
703
|
+
const match = CUSTOM_REFERENCE_TRAILING_MARKER_PATTERN.exec(candidate);
|
|
704
|
+
return match ? candidate.slice(0, match.index) : undefined;
|
|
705
|
+
}
|
|
667
706
|
|
|
668
707
|
function getCustomReferenceCandidateIds(modelId: string): string[] {
|
|
669
708
|
const candidates = new Set<string>();
|
|
@@ -673,23 +712,46 @@ function getCustomReferenceCandidateIds(modelId: string): string[] {
|
|
|
673
712
|
if (!candidate || candidates.has(candidate)) continue;
|
|
674
713
|
candidates.add(candidate);
|
|
675
714
|
|
|
715
|
+
for (const stripped of getBracketStrippedModelIdCandidates(candidate)) {
|
|
716
|
+
queue.push(stripped);
|
|
717
|
+
}
|
|
718
|
+
for (const segment of getModelLikeIdSegments(candidate)) {
|
|
719
|
+
queue.push(segment);
|
|
720
|
+
}
|
|
721
|
+
|
|
676
722
|
for (const suffix of [":cloud", "-cloud"] as const) {
|
|
677
723
|
if (candidate.toLowerCase().endsWith(suffix)) {
|
|
678
724
|
queue.push(candidate.slice(0, -suffix.length));
|
|
679
725
|
}
|
|
680
726
|
}
|
|
681
727
|
|
|
728
|
+
const slashIndex = candidate.lastIndexOf("/");
|
|
729
|
+
if (slashIndex !== -1) {
|
|
730
|
+
queue.push(candidate.slice(slashIndex + 1));
|
|
731
|
+
}
|
|
732
|
+
|
|
682
733
|
const colonToDash = candidate.replace(/:/g, "-");
|
|
683
734
|
if (colonToDash !== candidate) {
|
|
684
735
|
queue.push(colonToDash);
|
|
685
736
|
}
|
|
737
|
+
|
|
738
|
+
const lowercased = candidate.toLowerCase();
|
|
739
|
+
if (lowercased !== candidate) {
|
|
740
|
+
queue.push(lowercased);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const strippedMarker = stripCustomReferenceTrailingMarker(candidate);
|
|
744
|
+
if (strippedMarker) {
|
|
745
|
+
queue.push(strippedMarker);
|
|
746
|
+
}
|
|
686
747
|
}
|
|
687
748
|
return [...candidates];
|
|
688
749
|
}
|
|
689
750
|
|
|
690
751
|
function resolveCustomModelReference(modelId: string): Model<Api> | undefined {
|
|
691
752
|
for (const candidate of getCustomReferenceCandidateIds(modelId)) {
|
|
692
|
-
const
|
|
753
|
+
const key = normalizeCustomReferenceKey(candidate);
|
|
754
|
+
const reference = customReferenceMap.get(key) ?? customReferenceSuffixAliasMap.get(key);
|
|
693
755
|
if (reference) return reference;
|
|
694
756
|
}
|
|
695
757
|
return undefined;
|
|
@@ -1209,13 +1271,17 @@ export class ModelRegistry {
|
|
|
1209
1271
|
keylessProviders.add(providerName);
|
|
1210
1272
|
}
|
|
1211
1273
|
|
|
1212
|
-
if (providerConfig.discovery && providerConfig.api) {
|
|
1274
|
+
if (providerConfig.discovery && (providerConfig.api || providerConfig.discovery.type === "proxy")) {
|
|
1275
|
+
const disableStrictCompat = providerConfig.disableStrictTools ? { disableStrictTools: true } : undefined;
|
|
1213
1276
|
discoverableProviders.push({
|
|
1214
1277
|
provider: providerName,
|
|
1215
|
-
|
|
1278
|
+
// Proxy discovery derives per-model api from /v1/models's
|
|
1279
|
+
// supported_endpoint_types; the provider-level api is only a
|
|
1280
|
+
// fallback for entries that don't advertise one.
|
|
1281
|
+
api: (providerConfig.api ?? "openai-completions") as Api,
|
|
1216
1282
|
baseUrl: providerConfig.baseUrl,
|
|
1217
1283
|
headers: providerConfig.headers,
|
|
1218
|
-
compat: providerConfig.compat,
|
|
1284
|
+
compat: mergeCompat(providerConfig.compat, disableStrictCompat),
|
|
1219
1285
|
discovery: providerConfig.discovery,
|
|
1220
1286
|
optional: false,
|
|
1221
1287
|
});
|
|
@@ -1385,6 +1451,8 @@ export class ModelRegistry {
|
|
|
1385
1451
|
case "lm-studio":
|
|
1386
1452
|
case "openai-models-list":
|
|
1387
1453
|
return this.#discoverOpenAIModelsList(providerConfig);
|
|
1454
|
+
case "proxy":
|
|
1455
|
+
return this.#discoverProxyModels(providerConfig);
|
|
1388
1456
|
}
|
|
1389
1457
|
}
|
|
1390
1458
|
|
|
@@ -1711,7 +1779,7 @@ export class ModelRegistry {
|
|
|
1711
1779
|
|
|
1712
1780
|
const response = await fetch(modelsUrl, {
|
|
1713
1781
|
headers,
|
|
1714
|
-
signal: AbortSignal.timeout(
|
|
1782
|
+
signal: AbortSignal.timeout(10_000),
|
|
1715
1783
|
});
|
|
1716
1784
|
if (!response.ok) {
|
|
1717
1785
|
throw new Error(`HTTP ${response.status} from ${modelsUrl}`);
|
|
@@ -1746,6 +1814,96 @@ export class ModelRegistry {
|
|
|
1746
1814
|
return this.#applyProviderModelOverrides(providerConfig.provider, discovered);
|
|
1747
1815
|
}
|
|
1748
1816
|
|
|
1817
|
+
/**
|
|
1818
|
+
* Discover models from an Anthropic+OpenAI-compatible reseller proxy that
|
|
1819
|
+
* exposes both `/v1/messages` and `/v1/chat/completions`, advertising each
|
|
1820
|
+
* model's wire capabilities through `supported_endpoint_types` on
|
|
1821
|
+
* `GET /v1/models` (new-api / one-api-style proxies).
|
|
1822
|
+
*
|
|
1823
|
+
* Routing per model:
|
|
1824
|
+
* supported_endpoint_types: ["anthropic", ...] -> api: "anthropic-messages"
|
|
1825
|
+
* supported_endpoint_types: ["openai"] -> api: "openai-completions"
|
|
1826
|
+
* missing / neither -> provider-level api fallback
|
|
1827
|
+
*
|
|
1828
|
+
* Anthropic models share the same baseUrl; the Anthropic SDK strips a
|
|
1829
|
+
* trailing `/v1` itself before appending `/v1/messages`, so the discovery
|
|
1830
|
+
* URL (which ends in `/v1`) round-trips correctly.
|
|
1831
|
+
*/
|
|
1832
|
+
async #discoverProxyModels(providerConfig: DiscoveryProviderConfig): Promise<Model<Api>[]> {
|
|
1833
|
+
const baseUrl = this.#normalizeOpenAIModelsListBaseUrl(providerConfig.baseUrl);
|
|
1834
|
+
const modelsUrl = `${baseUrl}/models`;
|
|
1835
|
+
|
|
1836
|
+
const headers: Record<string, string> = { ...(providerConfig.headers ?? {}) };
|
|
1837
|
+
const apiKey = await this.authStorage.getApiKey(providerConfig.provider);
|
|
1838
|
+
if (apiKey && apiKey !== DEFAULT_LOCAL_TOKEN && apiKey !== kNoAuth) {
|
|
1839
|
+
headers.Authorization = `Bearer ${apiKey}`;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
const response = await fetch(modelsUrl, {
|
|
1843
|
+
headers,
|
|
1844
|
+
signal: AbortSignal.timeout(10_000),
|
|
1845
|
+
});
|
|
1846
|
+
if (!response.ok) {
|
|
1847
|
+
throw new Error(`HTTP ${response.status} from ${modelsUrl}`);
|
|
1848
|
+
}
|
|
1849
|
+
const payload = (await response.json()) as {
|
|
1850
|
+
data?: Array<{ id?: string; name?: string; supported_endpoint_types?: string[] }>;
|
|
1851
|
+
};
|
|
1852
|
+
const items = payload.data ?? [];
|
|
1853
|
+
const discovered: Model<Api>[] = [];
|
|
1854
|
+
for (const item of items) {
|
|
1855
|
+
const id = item.id;
|
|
1856
|
+
if (!id) continue;
|
|
1857
|
+
const endpoints = item.supported_endpoint_types ?? [];
|
|
1858
|
+
const api: Api | undefined = endpoints.includes("anthropic")
|
|
1859
|
+
? "anthropic-messages"
|
|
1860
|
+
: endpoints.includes("openai")
|
|
1861
|
+
? "openai-completions"
|
|
1862
|
+
: providerConfig.api;
|
|
1863
|
+
if (!api) continue;
|
|
1864
|
+
const isAnthropic = api === "anthropic-messages";
|
|
1865
|
+
const reference = resolveCustomModelReference(id);
|
|
1866
|
+
const discoveryName = typeof item.name === "string" ? item.name.trim() : "";
|
|
1867
|
+
const displayName =
|
|
1868
|
+
reference?.name ??
|
|
1869
|
+
(discoveryName && discoveryName !== id ? discoveryName : undefined) ??
|
|
1870
|
+
stripBracketedModelIdAffixes(id) ??
|
|
1871
|
+
id;
|
|
1872
|
+
discovered.push(
|
|
1873
|
+
enrichModelThinking({
|
|
1874
|
+
id,
|
|
1875
|
+
name: displayName,
|
|
1876
|
+
api,
|
|
1877
|
+
provider: providerConfig.provider,
|
|
1878
|
+
baseUrl,
|
|
1879
|
+
reasoning: reference?.reasoning ?? false,
|
|
1880
|
+
thinking: reference?.thinking,
|
|
1881
|
+
input: reference?.input ?? ["text"],
|
|
1882
|
+
// Proxy pricing is provider-specific and usually does not match
|
|
1883
|
+
// upstream bundled catalogs, so keep costs local-unknown even when
|
|
1884
|
+
// we successfully recover the upstream model identity.
|
|
1885
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1886
|
+
contextWindow: reference?.contextWindow ?? 128000,
|
|
1887
|
+
maxTokens: reference?.maxTokens ?? 8192,
|
|
1888
|
+
headers,
|
|
1889
|
+
// OpenAI-compat fields are no-ops on anthropic models; the
|
|
1890
|
+
// Anthropic SDK ignores them. Provider-level disableStrictTools
|
|
1891
|
+
// flows in via #applyProviderCompat for the third-party-Anthropic
|
|
1892
|
+
// path. Cross-wire bundled compat is intentionally not copied:
|
|
1893
|
+
// request-shaping fields are provider-wire specific.
|
|
1894
|
+
compat: isAnthropic
|
|
1895
|
+
? undefined
|
|
1896
|
+
: {
|
|
1897
|
+
supportsStore: false,
|
|
1898
|
+
supportsDeveloperRole: false,
|
|
1899
|
+
supportsReasoningEffort: false,
|
|
1900
|
+
},
|
|
1901
|
+
}),
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1904
|
+
return this.#applyProviderModelOverrides(providerConfig.provider, discovered);
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1749
1907
|
#normalizeLlamaCppBaseUrl(baseUrl?: string): string {
|
|
1750
1908
|
const defaultBaseUrl = "http://127.0.0.1:8080";
|
|
1751
1909
|
const raw = baseUrl || defaultBaseUrl;
|
|
@@ -121,7 +121,7 @@ export const ModelOverrideSchema = z.object({
|
|
|
121
121
|
export type ModelOverride = z.infer<typeof ModelOverrideSchema>;
|
|
122
122
|
|
|
123
123
|
export const ProviderDiscoverySchema = z.object({
|
|
124
|
-
type: z.enum(["ollama", "llama.cpp", "lm-studio", "openai-models-list"]),
|
|
124
|
+
type: z.enum(["ollama", "llama.cpp", "lm-studio", "openai-models-list", "proxy"]),
|
|
125
125
|
});
|
|
126
126
|
|
|
127
127
|
export const ProviderAuthSchema = z.enum(["apiKey", "none", "oauth"]);
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { THINKING_EFFORTS } from "@oh-my-pi/pi-ai";
|
|
2
2
|
import { TASK_SIMPLE_MODES } from "../task/simple-mode";
|
|
3
3
|
import { getThinkingLevelMetadata } from "../thinking";
|
|
4
|
+
import {
|
|
5
|
+
ONLINE_MEMORY_MODEL_KEY,
|
|
6
|
+
ONLINE_TINY_TITLE_MODEL_KEY,
|
|
7
|
+
TINY_MEMORY_MODEL_OPTIONS,
|
|
8
|
+
TINY_MEMORY_MODEL_VALUES,
|
|
9
|
+
TINY_TITLE_MODEL_OPTIONS,
|
|
10
|
+
TINY_TITLE_MODEL_VALUES,
|
|
11
|
+
} from "../tiny/models";
|
|
4
12
|
import { EDIT_MODES } from "../utils/edit-mode";
|
|
5
13
|
|
|
6
14
|
/** Unified settings schema - single source of truth for all settings.
|
|
@@ -81,6 +89,7 @@ export type StatusLineSegmentId =
|
|
|
81
89
|
| "hostname"
|
|
82
90
|
| "cache_read"
|
|
83
91
|
| "cache_write"
|
|
92
|
+
| "cache_hit"
|
|
84
93
|
| "session_name"
|
|
85
94
|
| "usage";
|
|
86
95
|
|
|
@@ -1291,24 +1300,193 @@ export const SETTINGS_SCHEMA = {
|
|
|
1291
1300
|
"memories.summaryInjectionTokenLimit": { type: "number", default: 5000 },
|
|
1292
1301
|
|
|
1293
1302
|
// Memory backend selector — picks between local memories pipeline,
|
|
1294
|
-
// Hindsight remote memory, or off. Legacy
|
|
1295
|
-
// the local backend; see config/settings.ts
|
|
1303
|
+
// Mnemosyne local SQLite, Hindsight remote memory, or off. Legacy
|
|
1304
|
+
// `memories.enabled` keeps gating the local backend; see config/settings.ts
|
|
1305
|
+
// migration for details.
|
|
1296
1306
|
"memory.backend": {
|
|
1297
1307
|
type: "enum",
|
|
1298
|
-
values: ["off", "local", "hindsight"] as const,
|
|
1308
|
+
values: ["off", "local", "hindsight", "mnemosyne"] as const,
|
|
1299
1309
|
default: "off",
|
|
1300
1310
|
ui: {
|
|
1301
1311
|
tab: "memory",
|
|
1302
1312
|
label: "Memory Backend",
|
|
1303
|
-
description: "Off, local
|
|
1313
|
+
description: "Off, local summary pipeline, Mnemosyne SQLite, or Hindsight remote memory",
|
|
1304
1314
|
options: [
|
|
1305
1315
|
{ value: "off", label: "Off", description: "No memory subsystem runs" },
|
|
1306
1316
|
{ value: "local", label: "Local", description: "Local rollout summarisation pipeline (memory_summary.md)" },
|
|
1307
1317
|
{ value: "hindsight", label: "Hindsight", description: "Vectorize Hindsight remote memory service" },
|
|
1318
|
+
{
|
|
1319
|
+
value: "mnemosyne",
|
|
1320
|
+
label: "Mnemosyne",
|
|
1321
|
+
description: "Local SQLite recall/retain backend with optional embeddings",
|
|
1322
|
+
},
|
|
1308
1323
|
],
|
|
1309
1324
|
},
|
|
1310
1325
|
},
|
|
1311
1326
|
|
|
1327
|
+
// Mnemosyne local SQLite memory backend.
|
|
1328
|
+
"mnemosyne.dbPath": {
|
|
1329
|
+
type: "string",
|
|
1330
|
+
default: undefined,
|
|
1331
|
+
ui: {
|
|
1332
|
+
tab: "memory",
|
|
1333
|
+
label: "Mnemosyne DB Path",
|
|
1334
|
+
description: "Optional SQLite DB path. Defaults to the agent memories directory.",
|
|
1335
|
+
condition: "mnemosyneActive",
|
|
1336
|
+
},
|
|
1337
|
+
},
|
|
1338
|
+
"mnemosyne.bank": {
|
|
1339
|
+
type: "string",
|
|
1340
|
+
default: undefined,
|
|
1341
|
+
ui: {
|
|
1342
|
+
tab: "memory",
|
|
1343
|
+
label: "Mnemosyne Bank",
|
|
1344
|
+
description: "Optional shared bank base name. Per-project modes derive project-local banks from it.",
|
|
1345
|
+
condition: "mnemosyneActive",
|
|
1346
|
+
},
|
|
1347
|
+
},
|
|
1348
|
+
"mnemosyne.scoping": {
|
|
1349
|
+
type: "enum",
|
|
1350
|
+
values: ["global", "per-project", "per-project-tagged"] as const,
|
|
1351
|
+
default: "per-project",
|
|
1352
|
+
ui: {
|
|
1353
|
+
tab: "memory",
|
|
1354
|
+
label: "Mnemosyne Scoping",
|
|
1355
|
+
description:
|
|
1356
|
+
"global = one shared bank; per-project = isolated bank per cwd; per-project-tagged = project-local writes plus global recall visibility",
|
|
1357
|
+
options: [
|
|
1358
|
+
{
|
|
1359
|
+
value: "global",
|
|
1360
|
+
label: "Global",
|
|
1361
|
+
description: "One shared Mnemosyne bank for every project",
|
|
1362
|
+
},
|
|
1363
|
+
{
|
|
1364
|
+
value: "per-project",
|
|
1365
|
+
label: "Per project",
|
|
1366
|
+
description: "Project-local Mnemosyne bank per cwd basename",
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
value: "per-project-tagged",
|
|
1370
|
+
label: "Per project (tagged)",
|
|
1371
|
+
description: "Write to a project-local bank but merge project + shared recall results",
|
|
1372
|
+
},
|
|
1373
|
+
],
|
|
1374
|
+
condition: "mnemosyneActive",
|
|
1375
|
+
},
|
|
1376
|
+
},
|
|
1377
|
+
"mnemosyne.autoRecall": {
|
|
1378
|
+
type: "boolean",
|
|
1379
|
+
default: true,
|
|
1380
|
+
ui: {
|
|
1381
|
+
tab: "memory",
|
|
1382
|
+
label: "Mnemosyne Auto Recall",
|
|
1383
|
+
description: "Recall local memories into the first turn of each session",
|
|
1384
|
+
condition: "mnemosyneActive",
|
|
1385
|
+
},
|
|
1386
|
+
},
|
|
1387
|
+
"mnemosyne.autoRetain": {
|
|
1388
|
+
type: "boolean",
|
|
1389
|
+
default: true,
|
|
1390
|
+
ui: {
|
|
1391
|
+
tab: "memory",
|
|
1392
|
+
label: "Mnemosyne Auto Retain",
|
|
1393
|
+
description: "Retain completed conversation turns into local Mnemosyne memory",
|
|
1394
|
+
condition: "mnemosyneActive",
|
|
1395
|
+
},
|
|
1396
|
+
},
|
|
1397
|
+
"mnemosyne.noEmbeddings": {
|
|
1398
|
+
type: "boolean",
|
|
1399
|
+
default: false,
|
|
1400
|
+
ui: {
|
|
1401
|
+
tab: "memory",
|
|
1402
|
+
label: "Mnemosyne Disable Embeddings",
|
|
1403
|
+
description: "Force deterministic FTS-only recall instead of vector embeddings",
|
|
1404
|
+
condition: "mnemosyneActive",
|
|
1405
|
+
},
|
|
1406
|
+
},
|
|
1407
|
+
"mnemosyne.embeddingModel": {
|
|
1408
|
+
type: "string",
|
|
1409
|
+
default: undefined,
|
|
1410
|
+
ui: {
|
|
1411
|
+
tab: "memory",
|
|
1412
|
+
label: "Mnemosyne Embedding Model",
|
|
1413
|
+
description: "Optional embedding model override passed to Mnemosyne",
|
|
1414
|
+
condition: "mnemosyneActive",
|
|
1415
|
+
},
|
|
1416
|
+
},
|
|
1417
|
+
"mnemosyne.embeddingApiUrl": {
|
|
1418
|
+
type: "string",
|
|
1419
|
+
default: undefined,
|
|
1420
|
+
ui: {
|
|
1421
|
+
tab: "memory",
|
|
1422
|
+
label: "Mnemosyne Embedding API URL",
|
|
1423
|
+
description: "Optional OpenAI-compatible embedding endpoint passed to Mnemosyne",
|
|
1424
|
+
condition: "mnemosyneActive",
|
|
1425
|
+
},
|
|
1426
|
+
},
|
|
1427
|
+
"mnemosyne.embeddingApiKey": {
|
|
1428
|
+
type: "string",
|
|
1429
|
+
default: undefined,
|
|
1430
|
+
ui: {
|
|
1431
|
+
tab: "memory",
|
|
1432
|
+
label: "Mnemosyne Embedding API Key",
|
|
1433
|
+
description: "Optional embedding API key passed to Mnemosyne",
|
|
1434
|
+
condition: "mnemosyneActive",
|
|
1435
|
+
},
|
|
1436
|
+
},
|
|
1437
|
+
"mnemosyne.llmMode": {
|
|
1438
|
+
type: "enum",
|
|
1439
|
+
values: ["none", "smol", "remote"] as const,
|
|
1440
|
+
default: "smol",
|
|
1441
|
+
ui: {
|
|
1442
|
+
tab: "memory",
|
|
1443
|
+
label: "Mnemosyne LLM Mode",
|
|
1444
|
+
description: "Use no LLM, the configured smol model, or a remote OpenAI-compatible endpoint",
|
|
1445
|
+
condition: "mnemosyneActive",
|
|
1446
|
+
options: [
|
|
1447
|
+
{ value: "none", label: "None", description: "Disable Mnemosyne LLM-backed extraction" },
|
|
1448
|
+
{ value: "smol", label: "Smol", description: "Use the configured pi-ai smol model" },
|
|
1449
|
+
{ value: "remote", label: "Remote", description: "Use the Mnemosyne remote LLM settings below" },
|
|
1450
|
+
],
|
|
1451
|
+
},
|
|
1452
|
+
},
|
|
1453
|
+
"mnemosyne.llmBaseUrl": {
|
|
1454
|
+
type: "string",
|
|
1455
|
+
default: undefined,
|
|
1456
|
+
ui: {
|
|
1457
|
+
tab: "memory",
|
|
1458
|
+
label: "Mnemosyne LLM Base URL",
|
|
1459
|
+
description: "Optional OpenAI-compatible LLM endpoint for Mnemosyne remote mode",
|
|
1460
|
+
condition: "mnemosyneActive",
|
|
1461
|
+
},
|
|
1462
|
+
},
|
|
1463
|
+
"mnemosyne.llmApiKey": {
|
|
1464
|
+
type: "string",
|
|
1465
|
+
default: undefined,
|
|
1466
|
+
ui: {
|
|
1467
|
+
tab: "memory",
|
|
1468
|
+
label: "Mnemosyne LLM API Key",
|
|
1469
|
+
description: "Optional LLM API key for Mnemosyne remote mode",
|
|
1470
|
+
condition: "mnemosyneActive",
|
|
1471
|
+
},
|
|
1472
|
+
},
|
|
1473
|
+
"mnemosyne.llmModel": {
|
|
1474
|
+
type: "string",
|
|
1475
|
+
default: undefined,
|
|
1476
|
+
ui: {
|
|
1477
|
+
tab: "memory",
|
|
1478
|
+
label: "Mnemosyne LLM Model",
|
|
1479
|
+
description: "Optional LLM model name for Mnemosyne remote mode",
|
|
1480
|
+
condition: "mnemosyneActive",
|
|
1481
|
+
},
|
|
1482
|
+
},
|
|
1483
|
+
"mnemosyne.retainEveryNTurns": { type: "number", default: 4 },
|
|
1484
|
+
"mnemosyne.recallLimit": { type: "number", default: 8 },
|
|
1485
|
+
"mnemosyne.recallContextTurns": { type: "number", default: 3 },
|
|
1486
|
+
"mnemosyne.recallMaxQueryChars": { type: "number", default: 4000 },
|
|
1487
|
+
"mnemosyne.injectionTokenLimit": { type: "number", default: 5000 },
|
|
1488
|
+
"mnemosyne.debug": { type: "boolean", default: false },
|
|
1489
|
+
|
|
1312
1490
|
// Hindsight (https://hindsight.vectorize.io)
|
|
1313
1491
|
"hindsight.apiUrl": {
|
|
1314
1492
|
type: "string",
|
|
@@ -2016,16 +2194,6 @@ export const SETTINGS_SCHEMA = {
|
|
|
2016
2194
|
},
|
|
2017
2195
|
},
|
|
2018
2196
|
|
|
2019
|
-
"calc.enabled": {
|
|
2020
|
-
type: "boolean",
|
|
2021
|
-
default: false,
|
|
2022
|
-
ui: {
|
|
2023
|
-
tab: "tools",
|
|
2024
|
-
label: "Calculator",
|
|
2025
|
-
description: "Enable the calculator tool for basic calculations",
|
|
2026
|
-
},
|
|
2027
|
-
},
|
|
2028
|
-
|
|
2029
2197
|
"tts.enabled": {
|
|
2030
2198
|
type: "boolean",
|
|
2031
2199
|
default: false,
|
|
@@ -2736,6 +2904,30 @@ export const SETTINGS_SCHEMA = {
|
|
|
2736
2904
|
],
|
|
2737
2905
|
},
|
|
2738
2906
|
},
|
|
2907
|
+
"providers.tinyModel": {
|
|
2908
|
+
type: "enum",
|
|
2909
|
+
values: TINY_TITLE_MODEL_VALUES,
|
|
2910
|
+
default: ONLINE_TINY_TITLE_MODEL_KEY,
|
|
2911
|
+
ui: {
|
|
2912
|
+
tab: "providers",
|
|
2913
|
+
label: "Tiny Model",
|
|
2914
|
+
description: "Session-title model: online pi/smol by default, or a local on-device model",
|
|
2915
|
+
options: TINY_TITLE_MODEL_OPTIONS,
|
|
2916
|
+
},
|
|
2917
|
+
},
|
|
2918
|
+
"providers.memoryModel": {
|
|
2919
|
+
type: "enum",
|
|
2920
|
+
values: TINY_MEMORY_MODEL_VALUES,
|
|
2921
|
+
default: ONLINE_MEMORY_MODEL_KEY,
|
|
2922
|
+
ui: {
|
|
2923
|
+
tab: "memory",
|
|
2924
|
+
label: "Memory Model",
|
|
2925
|
+
description:
|
|
2926
|
+
"Mnemosyne LLM for fact extraction + consolidation: online (smol/remote) by default, or a local on-device model",
|
|
2927
|
+
condition: "mnemosyneActive",
|
|
2928
|
+
options: TINY_MEMORY_MODEL_OPTIONS,
|
|
2929
|
+
},
|
|
2930
|
+
},
|
|
2739
2931
|
|
|
2740
2932
|
"providers.kimiApiFormat": {
|
|
2741
2933
|
type: "enum",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import {
|
|
13
13
|
Patch as HashlinePatch,
|
|
14
|
+
missingSnapshotTagMessage,
|
|
14
15
|
normalizeToLF,
|
|
15
16
|
type Patch,
|
|
16
17
|
type PatchSection,
|
|
@@ -40,10 +41,6 @@ async function readSectionText(absolutePath: string, sectionPath: string): Promi
|
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
function hasAnchorScoped(section: PatchSection): boolean {
|
|
44
|
-
return section.hasAnchorScopedEdit;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
44
|
function snapshotMatchesCurrent(snapshot: Snapshot, currentText: string): boolean {
|
|
48
45
|
return snapshot.text === currentText;
|
|
49
46
|
}
|
|
@@ -54,9 +51,10 @@ function validateSectionHash(
|
|
|
54
51
|
snapshots: SnapshotStore,
|
|
55
52
|
): string | null {
|
|
56
53
|
if (section.fileHash === undefined) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
// The snapshot tag is mandatory on every section — head/tail inserts
|
|
55
|
+
// included — to keep this preview path in lockstep with the apply path
|
|
56
|
+
// (`Patcher.prepare`), which rejects tagless sections unconditionally.
|
|
57
|
+
return missingSnapshotTagMessage(section.path);
|
|
60
58
|
}
|
|
61
59
|
const snapshot = snapshots.byHash(absolutePath, section.fileHash);
|
|
62
60
|
if (snapshot && snapshotMatchesCurrent(snapshot, text)) return null;
|