@oh-my-pi/pi-coding-agent 15.7.1 → 15.7.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 +95 -6
- package/dist/types/auto-thinking/classifier.d.ts +35 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/extension-flags.d.ts +36 -0
- package/dist/types/config/config-file.d.ts +4 -0
- package/dist/types/config/file-lock.d.ts +23 -0
- package/dist/types/config/keybindings.d.ts +2 -1
- package/dist/types/config/model-registry.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +112 -69
- package/dist/types/edit/hashline/diff.d.ts +9 -3
- package/dist/types/eval/__tests__/agent-bridge.test.d.ts +1 -0
- package/dist/types/eval/__tests__/budget-bridge.test.d.ts +1 -0
- package/dist/types/eval/__tests__/idle-timeout.test.d.ts +1 -0
- package/dist/types/eval/agent-bridge.d.ts +25 -0
- package/dist/types/eval/backend.d.ts +17 -2
- package/dist/types/eval/budget-bridge.d.ts +29 -0
- package/dist/types/eval/idle-timeout.d.ts +28 -0
- package/dist/types/eval/js/executor.d.ts +8 -0
- package/dist/types/eval/js/tool-bridge.d.ts +2 -1
- package/dist/types/eval/py/executor.d.ts +13 -0
- package/dist/types/exec/bash-executor.d.ts +1 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/runner.d.ts +7 -0
- package/dist/types/extensibility/plugins/git-url.d.ts +11 -1
- package/dist/types/extensibility/plugins/manager.d.ts +12 -1
- package/dist/types/extensibility/shared-events.d.ts +2 -2
- package/dist/types/memory-backend/index.d.ts +1 -1
- package/dist/types/memory-backend/resolve.d.ts +1 -1
- package/dist/types/memory-backend/types.d.ts +3 -3
- package/dist/types/mnemopi/backend.d.ts +4 -0
- package/dist/types/mnemopi/config.d.ts +29 -0
- package/dist/types/mnemopi/state.d.ts +72 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -2
- package/dist/types/modes/components/model-selector.d.ts +3 -2
- package/dist/types/modes/components/omfg-panel.d.ts +19 -0
- package/dist/types/modes/controllers/command-controller.d.ts +7 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/controllers/omfg-controller.d.ts +10 -0
- package/dist/types/modes/controllers/omfg-rule.d.ts +26 -0
- package/dist/types/modes/gradient-highlight.d.ts +5 -1
- package/dist/types/modes/interactive-mode.d.ts +7 -3
- package/dist/types/modes/magic-keywords.d.ts +14 -0
- package/dist/types/modes/markdown-prose.d.ts +27 -0
- package/dist/types/modes/orchestrate.d.ts +7 -2
- package/dist/types/modes/shared.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/modes/turn-budget.d.ts +18 -0
- package/dist/types/modes/types.d.ts +7 -3
- package/dist/types/modes/ultrathink.d.ts +7 -2
- package/dist/types/modes/workflow.d.ts +15 -0
- package/dist/types/sdk.d.ts +15 -4
- package/dist/types/session/agent-session.d.ts +59 -23
- package/dist/types/session/session-manager.d.ts +18 -0
- package/dist/types/session/session-storage.d.ts +6 -0
- package/dist/types/session/shake-types.d.ts +24 -0
- package/dist/types/task/executor.d.ts +2 -2
- package/dist/types/thinking.d.ts +39 -1
- package/dist/types/tiny/device.d.ts +3 -3
- package/dist/types/tiny/models.d.ts +34 -1
- package/dist/types/tiny/title-protocol.d.ts +4 -0
- package/dist/types/tools/index.d.ts +19 -3
- package/dist/types/tools/memory-edit.d.ts +1 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/package.json +10 -10
- package/src/auto-thinking/classifier.ts +180 -0
- package/src/autoresearch/tools/run-experiment.ts +45 -113
- package/src/cli/args.ts +39 -16
- package/src/cli/extension-flags.ts +48 -0
- package/src/cli/plugin-cli.ts +11 -2
- package/src/config/config-file.ts +98 -13
- package/src/config/file-lock.ts +60 -17
- package/src/config/keybindings.ts +78 -27
- package/src/config/model-registry.ts +7 -1
- package/src/config/settings-schema.ts +118 -71
- package/src/config/settings.ts +12 -0
- package/src/edit/hashline/diff.ts +87 -22
- package/src/edit/renderer.ts +16 -12
- package/src/edit/streaming.ts +17 -6
- package/src/eval/__tests__/agent-bridge.test.ts +433 -0
- package/src/eval/__tests__/budget-bridge.test.ts +69 -0
- package/src/eval/__tests__/idle-timeout.test.ts +66 -0
- package/src/eval/__tests__/shared-executors.test.ts +53 -0
- package/src/eval/agent-bridge.ts +295 -0
- package/src/eval/backend.ts +17 -2
- package/src/eval/budget-bridge.ts +48 -0
- package/src/eval/idle-timeout.ts +80 -0
- package/src/eval/js/executor.ts +35 -7
- package/src/eval/js/index.ts +2 -1
- package/src/eval/js/shared/local-module-loader.ts +75 -10
- package/src/eval/js/shared/prelude.txt +85 -1
- package/src/eval/js/tool-bridge.ts +9 -0
- package/src/eval/py/executor.ts +41 -14
- package/src/eval/py/index.ts +2 -1
- package/src/eval/py/prelude.py +132 -1
- package/src/exec/bash-executor.ts +2 -3
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/runner.ts +12 -2
- package/src/extensibility/plugins/git-url.ts +90 -4
- package/src/extensibility/plugins/manager.ts +103 -7
- package/src/extensibility/shared-events.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +88 -88
- package/src/main.ts +50 -56
- package/src/memory-backend/index.ts +1 -1
- package/src/memory-backend/resolve.ts +3 -3
- package/src/memory-backend/types.ts +3 -3
- package/src/{mnemosyne → mnemopi}/backend.ts +70 -70
- package/src/{mnemosyne → mnemopi}/config.ts +36 -36
- package/src/{mnemosyne → mnemopi}/state.ts +67 -67
- package/src/modes/acp/acp-agent.ts +13 -3
- package/src/modes/components/agent-dashboard.ts +6 -6
- package/src/modes/components/custom-editor.ts +4 -11
- package/src/modes/components/extensions/state-manager.ts +3 -4
- package/src/modes/components/footer.ts +18 -12
- package/src/modes/components/hook-selector.ts +86 -20
- package/src/modes/components/model-selector.ts +20 -11
- package/src/modes/components/oauth-selector.ts +93 -21
- package/src/modes/components/omfg-panel.ts +141 -0
- package/src/modes/components/settings-defs.ts +9 -2
- package/src/modes/components/settings-selector.ts +4 -1
- package/src/modes/components/status-line/segments.ts +13 -5
- package/src/modes/components/tips.txt +2 -1
- package/src/modes/components/tool-execution.ts +38 -19
- package/src/modes/components/tree-selector.ts +4 -3
- package/src/modes/components/user-message-selector.ts +94 -19
- package/src/modes/components/user-message.ts +8 -1
- package/src/modes/controllers/command-controller.ts +57 -0
- package/src/modes/controllers/event-controller.ts +65 -3
- package/src/modes/controllers/input-controller.ts +14 -11
- package/src/modes/controllers/omfg-controller.ts +283 -0
- package/src/modes/controllers/omfg-rule.ts +647 -0
- package/src/modes/controllers/selector-controller.ts +21 -6
- package/src/modes/gradient-highlight.ts +23 -6
- package/src/modes/interactive-mode.ts +41 -7
- package/src/modes/magic-keywords.ts +20 -0
- package/src/modes/markdown-prose.ts +247 -0
- package/src/modes/orchestrate.ts +17 -11
- package/src/modes/shared.ts +3 -11
- package/src/modes/theme/theme.ts +6 -0
- package/src/modes/turn-budget.ts +31 -0
- package/src/modes/types.ts +7 -1
- package/src/modes/ultrathink.ts +16 -10
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/modes/workflow.ts +42 -0
- package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
- package/src/prompts/system/auto-thinking-difficulty.md +12 -0
- package/src/prompts/system/omfg-user.md +51 -0
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/prompts/system/workflow-notice.md +70 -0
- package/src/prompts/tools/eval.md +13 -1
- package/src/prompts/tools/memory-edit.md +1 -1
- package/src/sdk.ts +86 -38
- package/src/session/agent-session.ts +558 -80
- package/src/session/session-manager.ts +32 -0
- package/src/session/session-storage.ts +68 -8
- package/src/session/shake-types.ts +44 -0
- package/src/slash-commands/builtin-registry.ts +41 -16
- package/src/task/executor.ts +3 -3
- package/src/task/index.ts +6 -6
- package/src/thinking.ts +73 -1
- package/src/tiny/device.ts +4 -10
- package/src/tiny/models.ts +54 -2
- package/src/tiny/title-protocol.ts +11 -1
- package/src/tiny/worker.ts +19 -7
- package/src/tools/eval.ts +202 -26
- package/src/tools/grouped-file-output.ts +9 -2
- package/src/tools/index.ts +17 -5
- package/src/tools/memory-edit.ts +4 -4
- package/src/tools/memory-recall.ts +5 -5
- package/src/tools/memory-reflect.ts +5 -5
- package/src/tools/memory-retain.ts +4 -4
- package/src/tools/render-utils.ts +2 -1
- package/src/tools/search.ts +480 -76
- package/dist/types/mnemosyne/backend.d.ts +0 -4
- package/dist/types/mnemosyne/config.d.ts +0 -29
- package/dist/types/mnemosyne/state.d.ts +0 -72
- /package/dist/types/{mnemosyne → mnemopi}/index.d.ts +0 -0
- /package/src/{mnemosyne → mnemopi}/index.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { THINKING_EFFORTS } from "@oh-my-pi/pi-ai";
|
|
2
2
|
import { TASK_SIMPLE_MODES } from "../task/simple-mode";
|
|
3
|
-
import { getThinkingLevelMetadata } from "../thinking";
|
|
3
|
+
import { AUTO_THINKING, getConfiguredThinkingLevelMetadata, getThinkingLevelMetadata } from "../thinking";
|
|
4
4
|
import {
|
|
5
5
|
TINY_MODEL_DEVICE_DEFAULT,
|
|
6
6
|
TINY_MODEL_DEVICE_SETTING_OPTIONS,
|
|
@@ -12,8 +12,14 @@ import {
|
|
|
12
12
|
TINY_MODEL_DTYPE_SETTING_VALUES,
|
|
13
13
|
} from "../tiny/dtype";
|
|
14
14
|
import {
|
|
15
|
+
AUTO_THINKING_MODEL_OPTIONS,
|
|
16
|
+
AUTO_THINKING_MODEL_VALUES,
|
|
17
|
+
DEFAULT_SHAKE_SUMMARY_MODEL_KEY,
|
|
18
|
+
ONLINE_AUTO_THINKING_MODEL_KEY,
|
|
15
19
|
ONLINE_MEMORY_MODEL_KEY,
|
|
16
20
|
ONLINE_TINY_TITLE_MODEL_KEY,
|
|
21
|
+
SHAKE_SUMMARY_MODEL_OPTIONS,
|
|
22
|
+
SHAKE_SUMMARY_MODEL_VALUES,
|
|
17
23
|
TINY_MEMORY_MODEL_OPTIONS,
|
|
18
24
|
TINY_MEMORY_MODEL_VALUES,
|
|
19
25
|
TINY_TITLE_MODEL_OPTIONS,
|
|
@@ -671,13 +677,16 @@ export const SETTINGS_SCHEMA = {
|
|
|
671
677
|
// Reasoning and prompts
|
|
672
678
|
defaultThinkingLevel: {
|
|
673
679
|
type: "enum",
|
|
674
|
-
values: THINKING_EFFORTS,
|
|
680
|
+
values: [...THINKING_EFFORTS, AUTO_THINKING],
|
|
675
681
|
default: "high",
|
|
676
682
|
ui: {
|
|
677
683
|
tab: "model",
|
|
678
684
|
label: "Thinking Level",
|
|
679
685
|
description: "Reasoning depth for thinking-capable models",
|
|
680
|
-
options: [
|
|
686
|
+
options: [
|
|
687
|
+
getConfiguredThinkingLevelMetadata(AUTO_THINKING),
|
|
688
|
+
...THINKING_EFFORTS.map(getThinkingLevelMetadata),
|
|
689
|
+
],
|
|
681
690
|
},
|
|
682
691
|
},
|
|
683
692
|
|
|
@@ -1130,12 +1139,13 @@ export const SETTINGS_SCHEMA = {
|
|
|
1130
1139
|
|
|
1131
1140
|
"compaction.strategy": {
|
|
1132
1141
|
type: "enum",
|
|
1133
|
-
values: ["context-full", "handoff", "off"] as const,
|
|
1142
|
+
values: ["context-full", "handoff", "shake", "shake-summary", "off"] as const,
|
|
1134
1143
|
default: "context-full",
|
|
1135
1144
|
ui: {
|
|
1136
1145
|
tab: "context",
|
|
1137
1146
|
label: "Compaction Strategy",
|
|
1138
|
-
description:
|
|
1147
|
+
description:
|
|
1148
|
+
"Choose in-place context-full maintenance, auto-handoff, surgical shake (drop heavy content), shake with local-model summaries, or disable auto maintenance (off)",
|
|
1139
1149
|
options: [
|
|
1140
1150
|
{
|
|
1141
1151
|
value: "context-full",
|
|
@@ -1143,6 +1153,16 @@ export const SETTINGS_SCHEMA = {
|
|
|
1143
1153
|
description: "Summarize in-place and keep the current session",
|
|
1144
1154
|
},
|
|
1145
1155
|
{ value: "handoff", label: "Handoff", description: "Generate handoff and continue in a new session" },
|
|
1156
|
+
{
|
|
1157
|
+
value: "shake",
|
|
1158
|
+
label: "Shake",
|
|
1159
|
+
description: "Drop heavy content (tool results + large blocks) in place; recover via artifact",
|
|
1160
|
+
},
|
|
1161
|
+
{
|
|
1162
|
+
value: "shake-summary",
|
|
1163
|
+
label: "Shake (summary)",
|
|
1164
|
+
description: "Shake, but compress heavy regions with a local on-device model instead of dropping",
|
|
1165
|
+
},
|
|
1146
1166
|
{
|
|
1147
1167
|
value: "off",
|
|
1148
1168
|
label: "Off",
|
|
@@ -1321,70 +1341,70 @@ export const SETTINGS_SCHEMA = {
|
|
|
1321
1341
|
"memories.summaryInjectionTokenLimit": { type: "number", default: 5000 },
|
|
1322
1342
|
|
|
1323
1343
|
// Memory backend selector — picks between local memories pipeline,
|
|
1324
|
-
//
|
|
1344
|
+
// Mnemopi local SQLite, Hindsight remote memory, or off. Legacy
|
|
1325
1345
|
// `memories.enabled` keeps gating the local backend; see config/settings.ts
|
|
1326
1346
|
// migration for details.
|
|
1327
1347
|
"memory.backend": {
|
|
1328
1348
|
type: "enum",
|
|
1329
|
-
values: ["off", "local", "hindsight", "
|
|
1349
|
+
values: ["off", "local", "hindsight", "mnemopi"] as const,
|
|
1330
1350
|
default: "off",
|
|
1331
1351
|
ui: {
|
|
1332
1352
|
tab: "memory",
|
|
1333
1353
|
label: "Memory Backend",
|
|
1334
|
-
description: "Off, local summary pipeline,
|
|
1354
|
+
description: "Off, local summary pipeline, Mnemopi SQLite, or Hindsight remote memory",
|
|
1335
1355
|
options: [
|
|
1336
1356
|
{ value: "off", label: "Off", description: "No memory subsystem runs" },
|
|
1337
1357
|
{ value: "local", label: "Local", description: "Local rollout summarisation pipeline (memory_summary.md)" },
|
|
1338
1358
|
{ value: "hindsight", label: "Hindsight", description: "Vectorize Hindsight remote memory service" },
|
|
1339
1359
|
{
|
|
1340
|
-
value: "
|
|
1341
|
-
label: "
|
|
1360
|
+
value: "mnemopi",
|
|
1361
|
+
label: "Mnemopi",
|
|
1342
1362
|
description: "Local SQLite recall/retain backend with optional embeddings",
|
|
1343
1363
|
},
|
|
1344
1364
|
],
|
|
1345
1365
|
},
|
|
1346
1366
|
},
|
|
1347
1367
|
|
|
1348
|
-
//
|
|
1349
|
-
"
|
|
1368
|
+
// Mnemopi local SQLite memory backend.
|
|
1369
|
+
"mnemopi.dbPath": {
|
|
1350
1370
|
type: "string",
|
|
1351
1371
|
default: undefined,
|
|
1352
1372
|
ui: {
|
|
1353
1373
|
tab: "memory",
|
|
1354
|
-
label: "
|
|
1374
|
+
label: "Mnemopi DB Path",
|
|
1355
1375
|
description: "Optional SQLite DB path. Defaults to the agent memories directory.",
|
|
1356
|
-
condition: "
|
|
1376
|
+
condition: "mnemopiActive",
|
|
1357
1377
|
},
|
|
1358
1378
|
},
|
|
1359
|
-
"
|
|
1379
|
+
"mnemopi.bank": {
|
|
1360
1380
|
type: "string",
|
|
1361
1381
|
default: undefined,
|
|
1362
1382
|
ui: {
|
|
1363
1383
|
tab: "memory",
|
|
1364
|
-
label: "
|
|
1384
|
+
label: "Mnemopi Bank",
|
|
1365
1385
|
description: "Optional shared bank base name. Per-project modes derive project-local banks from it.",
|
|
1366
|
-
condition: "
|
|
1386
|
+
condition: "mnemopiActive",
|
|
1367
1387
|
},
|
|
1368
1388
|
},
|
|
1369
|
-
"
|
|
1389
|
+
"mnemopi.scoping": {
|
|
1370
1390
|
type: "enum",
|
|
1371
1391
|
values: ["global", "per-project", "per-project-tagged"] as const,
|
|
1372
1392
|
default: "per-project",
|
|
1373
1393
|
ui: {
|
|
1374
1394
|
tab: "memory",
|
|
1375
|
-
label: "
|
|
1395
|
+
label: "Mnemopi Scoping",
|
|
1376
1396
|
description:
|
|
1377
1397
|
"global = one shared bank; per-project = isolated bank per cwd; per-project-tagged = project-local writes plus global recall visibility",
|
|
1378
1398
|
options: [
|
|
1379
1399
|
{
|
|
1380
1400
|
value: "global",
|
|
1381
1401
|
label: "Global",
|
|
1382
|
-
description: "One shared
|
|
1402
|
+
description: "One shared Mnemopi bank for every project",
|
|
1383
1403
|
},
|
|
1384
1404
|
{
|
|
1385
1405
|
value: "per-project",
|
|
1386
1406
|
label: "Per project",
|
|
1387
|
-
description: "Project-local
|
|
1407
|
+
description: "Project-local Mnemopi bank per cwd basename",
|
|
1388
1408
|
},
|
|
1389
1409
|
{
|
|
1390
1410
|
value: "per-project-tagged",
|
|
@@ -1392,121 +1412,121 @@ export const SETTINGS_SCHEMA = {
|
|
|
1392
1412
|
description: "Write to a project-local bank but merge project + shared recall results",
|
|
1393
1413
|
},
|
|
1394
1414
|
],
|
|
1395
|
-
condition: "
|
|
1415
|
+
condition: "mnemopiActive",
|
|
1396
1416
|
},
|
|
1397
1417
|
},
|
|
1398
|
-
"
|
|
1418
|
+
"mnemopi.autoRecall": {
|
|
1399
1419
|
type: "boolean",
|
|
1400
1420
|
default: true,
|
|
1401
1421
|
ui: {
|
|
1402
1422
|
tab: "memory",
|
|
1403
|
-
label: "
|
|
1423
|
+
label: "Mnemopi Auto Recall",
|
|
1404
1424
|
description: "Recall local memories into the first turn of each session",
|
|
1405
|
-
condition: "
|
|
1425
|
+
condition: "mnemopiActive",
|
|
1406
1426
|
},
|
|
1407
1427
|
},
|
|
1408
|
-
"
|
|
1428
|
+
"mnemopi.autoRetain": {
|
|
1409
1429
|
type: "boolean",
|
|
1410
1430
|
default: true,
|
|
1411
1431
|
ui: {
|
|
1412
1432
|
tab: "memory",
|
|
1413
|
-
label: "
|
|
1414
|
-
description: "Retain completed conversation turns into local
|
|
1415
|
-
condition: "
|
|
1433
|
+
label: "Mnemopi Auto Retain",
|
|
1434
|
+
description: "Retain completed conversation turns into local Mnemopi memory",
|
|
1435
|
+
condition: "mnemopiActive",
|
|
1416
1436
|
},
|
|
1417
1437
|
},
|
|
1418
|
-
"
|
|
1438
|
+
"mnemopi.noEmbeddings": {
|
|
1419
1439
|
type: "boolean",
|
|
1420
1440
|
default: false,
|
|
1421
1441
|
ui: {
|
|
1422
1442
|
tab: "memory",
|
|
1423
|
-
label: "
|
|
1443
|
+
label: "Mnemopi Disable Embeddings",
|
|
1424
1444
|
description: "Force deterministic FTS-only recall instead of vector embeddings",
|
|
1425
|
-
condition: "
|
|
1445
|
+
condition: "mnemopiActive",
|
|
1426
1446
|
},
|
|
1427
1447
|
},
|
|
1428
|
-
"
|
|
1448
|
+
"mnemopi.embeddingModel": {
|
|
1429
1449
|
type: "string",
|
|
1430
1450
|
default: undefined,
|
|
1431
1451
|
ui: {
|
|
1432
1452
|
tab: "memory",
|
|
1433
|
-
label: "
|
|
1434
|
-
description: "Optional embedding model override passed to
|
|
1435
|
-
condition: "
|
|
1453
|
+
label: "Mnemopi Embedding Model",
|
|
1454
|
+
description: "Optional embedding model override passed to Mnemopi",
|
|
1455
|
+
condition: "mnemopiActive",
|
|
1436
1456
|
},
|
|
1437
1457
|
},
|
|
1438
|
-
"
|
|
1458
|
+
"mnemopi.embeddingApiUrl": {
|
|
1439
1459
|
type: "string",
|
|
1440
1460
|
default: undefined,
|
|
1441
1461
|
ui: {
|
|
1442
1462
|
tab: "memory",
|
|
1443
|
-
label: "
|
|
1444
|
-
description: "Optional OpenAI-compatible embedding endpoint passed to
|
|
1445
|
-
condition: "
|
|
1463
|
+
label: "Mnemopi Embedding API URL",
|
|
1464
|
+
description: "Optional OpenAI-compatible embedding endpoint passed to Mnemopi",
|
|
1465
|
+
condition: "mnemopiActive",
|
|
1446
1466
|
},
|
|
1447
1467
|
},
|
|
1448
|
-
"
|
|
1468
|
+
"mnemopi.embeddingApiKey": {
|
|
1449
1469
|
type: "string",
|
|
1450
1470
|
default: undefined,
|
|
1451
1471
|
ui: {
|
|
1452
1472
|
tab: "memory",
|
|
1453
|
-
label: "
|
|
1454
|
-
description: "Optional embedding API key passed to
|
|
1455
|
-
condition: "
|
|
1473
|
+
label: "Mnemopi Embedding API Key",
|
|
1474
|
+
description: "Optional embedding API key passed to Mnemopi",
|
|
1475
|
+
condition: "mnemopiActive",
|
|
1456
1476
|
},
|
|
1457
1477
|
},
|
|
1458
|
-
"
|
|
1478
|
+
"mnemopi.llmMode": {
|
|
1459
1479
|
type: "enum",
|
|
1460
1480
|
values: ["none", "smol", "remote"] as const,
|
|
1461
1481
|
default: "smol",
|
|
1462
1482
|
ui: {
|
|
1463
1483
|
tab: "memory",
|
|
1464
|
-
label: "
|
|
1484
|
+
label: "Mnemopi LLM Mode",
|
|
1465
1485
|
description: "Use no LLM, the configured smol model, or a remote OpenAI-compatible endpoint",
|
|
1466
|
-
condition: "
|
|
1486
|
+
condition: "mnemopiActive",
|
|
1467
1487
|
options: [
|
|
1468
|
-
{ value: "none", label: "None", description: "Disable
|
|
1488
|
+
{ value: "none", label: "None", description: "Disable Mnemopi LLM-backed extraction" },
|
|
1469
1489
|
{ value: "smol", label: "Smol", description: "Use the configured pi-ai smol model" },
|
|
1470
|
-
{ value: "remote", label: "Remote", description: "Use the
|
|
1490
|
+
{ value: "remote", label: "Remote", description: "Use the Mnemopi remote LLM settings below" },
|
|
1471
1491
|
],
|
|
1472
1492
|
},
|
|
1473
1493
|
},
|
|
1474
|
-
"
|
|
1494
|
+
"mnemopi.llmBaseUrl": {
|
|
1475
1495
|
type: "string",
|
|
1476
1496
|
default: undefined,
|
|
1477
1497
|
ui: {
|
|
1478
1498
|
tab: "memory",
|
|
1479
|
-
label: "
|
|
1480
|
-
description: "Optional OpenAI-compatible LLM endpoint for
|
|
1481
|
-
condition: "
|
|
1499
|
+
label: "Mnemopi LLM Base URL",
|
|
1500
|
+
description: "Optional OpenAI-compatible LLM endpoint for Mnemopi remote mode",
|
|
1501
|
+
condition: "mnemopiActive",
|
|
1482
1502
|
},
|
|
1483
1503
|
},
|
|
1484
|
-
"
|
|
1504
|
+
"mnemopi.llmApiKey": {
|
|
1485
1505
|
type: "string",
|
|
1486
1506
|
default: undefined,
|
|
1487
1507
|
ui: {
|
|
1488
1508
|
tab: "memory",
|
|
1489
|
-
label: "
|
|
1490
|
-
description: "Optional LLM API key for
|
|
1491
|
-
condition: "
|
|
1509
|
+
label: "Mnemopi LLM API Key",
|
|
1510
|
+
description: "Optional LLM API key for Mnemopi remote mode",
|
|
1511
|
+
condition: "mnemopiActive",
|
|
1492
1512
|
},
|
|
1493
1513
|
},
|
|
1494
|
-
"
|
|
1514
|
+
"mnemopi.llmModel": {
|
|
1495
1515
|
type: "string",
|
|
1496
1516
|
default: undefined,
|
|
1497
1517
|
ui: {
|
|
1498
1518
|
tab: "memory",
|
|
1499
|
-
label: "
|
|
1500
|
-
description: "Optional LLM model name for
|
|
1501
|
-
condition: "
|
|
1519
|
+
label: "Mnemopi LLM Model",
|
|
1520
|
+
description: "Optional LLM model name for Mnemopi remote mode",
|
|
1521
|
+
condition: "mnemopiActive",
|
|
1502
1522
|
},
|
|
1503
1523
|
},
|
|
1504
|
-
"
|
|
1505
|
-
"
|
|
1506
|
-
"
|
|
1507
|
-
"
|
|
1508
|
-
"
|
|
1509
|
-
"
|
|
1524
|
+
"mnemopi.retainEveryNTurns": { type: "number", default: 4 },
|
|
1525
|
+
"mnemopi.recallLimit": { type: "number", default: 8 },
|
|
1526
|
+
"mnemopi.recallContextTurns": { type: "number", default: 3 },
|
|
1527
|
+
"mnemopi.recallMaxQueryChars": { type: "number", default: 4000 },
|
|
1528
|
+
"mnemopi.injectionTokenLimit": { type: "number", default: 5000 },
|
|
1529
|
+
"mnemopi.debug": { type: "boolean", default: false },
|
|
1510
1530
|
|
|
1511
1531
|
// Hindsight (https://hindsight.vectorize.io)
|
|
1512
1532
|
"hindsight.apiUrl": {
|
|
@@ -2954,7 +2974,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
2954
2974
|
tab: "providers",
|
|
2955
2975
|
label: "Tiny Model Device",
|
|
2956
2976
|
description:
|
|
2957
|
-
"ONNX execution provider for local tiny models (titles + memory). Default
|
|
2977
|
+
"ONNX execution provider for local tiny models (titles + memory). Default uses CPU-only inference. The PI_TINY_DEVICE env var overrides this.",
|
|
2958
2978
|
options: TINY_MODEL_DEVICE_SETTING_OPTIONS,
|
|
2959
2979
|
},
|
|
2960
2980
|
},
|
|
@@ -2978,12 +2998,39 @@ export const SETTINGS_SCHEMA = {
|
|
|
2978
2998
|
tab: "memory",
|
|
2979
2999
|
label: "Memory Model",
|
|
2980
3000
|
description:
|
|
2981
|
-
"
|
|
2982
|
-
condition: "
|
|
3001
|
+
"Mnemopi LLM for fact extraction + consolidation: online (smol/remote) by default, or a local on-device model",
|
|
3002
|
+
condition: "mnemopiActive",
|
|
2983
3003
|
options: TINY_MEMORY_MODEL_OPTIONS,
|
|
2984
3004
|
},
|
|
2985
3005
|
},
|
|
2986
3006
|
|
|
3007
|
+
"providers.autoThinkingModel": {
|
|
3008
|
+
type: "enum",
|
|
3009
|
+
values: AUTO_THINKING_MODEL_VALUES,
|
|
3010
|
+
default: ONLINE_AUTO_THINKING_MODEL_KEY,
|
|
3011
|
+
ui: {
|
|
3012
|
+
tab: "model",
|
|
3013
|
+
label: "Auto Thinking Model",
|
|
3014
|
+
description:
|
|
3015
|
+
"Difficulty classifier for the `auto` thinking level: online smol by default, or a local on-device model",
|
|
3016
|
+
condition: "autoThinkingActive",
|
|
3017
|
+
options: AUTO_THINKING_MODEL_OPTIONS,
|
|
3018
|
+
},
|
|
3019
|
+
},
|
|
3020
|
+
|
|
3021
|
+
"providers.shakeSummaryModel": {
|
|
3022
|
+
type: "enum",
|
|
3023
|
+
values: SHAKE_SUMMARY_MODEL_VALUES,
|
|
3024
|
+
default: DEFAULT_SHAKE_SUMMARY_MODEL_KEY,
|
|
3025
|
+
ui: {
|
|
3026
|
+
tab: "context",
|
|
3027
|
+
label: "Shake Summary Model",
|
|
3028
|
+
description:
|
|
3029
|
+
"Local on-device model used by /shake summary and the shake-summary compaction strategy to compress heavy regions. Runs entirely on-device; downloads on first use. Falls back to plain elide when unavailable.",
|
|
3030
|
+
options: SHAKE_SUMMARY_MODEL_OPTIONS,
|
|
3031
|
+
},
|
|
3032
|
+
},
|
|
3033
|
+
|
|
2987
3034
|
"providers.kimiApiFormat": {
|
|
2988
3035
|
type: "enum",
|
|
2989
3036
|
values: ["openai", "anthropic"] as const,
|
|
@@ -3272,7 +3319,7 @@ export type TreeFilterMode = SettingValue<"treeFilterMode">;
|
|
|
3272
3319
|
|
|
3273
3320
|
export interface CompactionSettings {
|
|
3274
3321
|
enabled: boolean;
|
|
3275
|
-
strategy: "context-full" | "handoff" | "off";
|
|
3322
|
+
strategy: "context-full" | "handoff" | "shake" | "shake-summary" | "off";
|
|
3276
3323
|
thresholdPercent: number;
|
|
3277
3324
|
thresholdTokens: number;
|
|
3278
3325
|
reserveTokens: number;
|
package/src/config/settings.ts
CHANGED
|
@@ -692,6 +692,18 @@ export class Settings {
|
|
|
692
692
|
raw.memory = memoryRoot;
|
|
693
693
|
}
|
|
694
694
|
|
|
695
|
+
// Rename the legacy local `mnemosyne` memory backend to `mnemopi`.
|
|
696
|
+
// - `memory.backend: "mnemosyne"` now selects the renamed backend.
|
|
697
|
+
// - the top-level `mnemosyne` settings object becomes `mnemopi`.
|
|
698
|
+
// Idempotent: skips the object move once `mnemopi` is materialised.
|
|
699
|
+
if (memoryBackendObj && memoryBackendObj.backend === "mnemosyne") {
|
|
700
|
+
memoryBackendObj.backend = "mnemopi";
|
|
701
|
+
}
|
|
702
|
+
if ("mnemosyne" in raw && !("mnemopi" in raw)) {
|
|
703
|
+
raw.mnemopi = raw.mnemosyne;
|
|
704
|
+
delete raw.mnemosyne;
|
|
705
|
+
}
|
|
706
|
+
|
|
695
707
|
// hindsight: dynamicBankId/agentName -> scoping enum + bankId
|
|
696
708
|
// - dynamicBankId=true → scoping="per-project" (closest semantic match;
|
|
697
709
|
// the legacy `agent::project::channel::user` tuple was per-project in
|
|
@@ -5,17 +5,25 @@
|
|
|
5
5
|
* pair to {@link generateDiffString} so the renderer can show the diff
|
|
6
6
|
* while the tool call is still streaming.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* and
|
|
8
|
+
* Uses the same snapshot-tag semantics as the apply path: a live content-hash
|
|
9
|
+
* match is accepted even when the tag was minted by a source that did not keep
|
|
10
|
+
* history, and stale tags recover through the session snapshot store when possible.
|
|
11
11
|
*/
|
|
12
12
|
import {
|
|
13
|
+
type ApplyResult,
|
|
14
|
+
applyEdits,
|
|
15
|
+
computeFileHash,
|
|
16
|
+
type Edit,
|
|
13
17
|
Patch as HashlinePatch,
|
|
18
|
+
hasBlockEdit,
|
|
19
|
+
MismatchError,
|
|
14
20
|
missingSnapshotTagMessage,
|
|
15
21
|
normalizeToLF,
|
|
16
22
|
type Patch,
|
|
17
23
|
type PatchSection,
|
|
18
|
-
|
|
24
|
+
parsePatchStreaming,
|
|
25
|
+
Recovery,
|
|
26
|
+
resolveBlockEdits,
|
|
19
27
|
type SnapshotStore,
|
|
20
28
|
stripBom,
|
|
21
29
|
} from "@oh-my-pi/hashline";
|
|
@@ -31,6 +39,12 @@ export interface HashlineDiffOptions {
|
|
|
31
39
|
* preview path only.
|
|
32
40
|
*/
|
|
33
41
|
streaming?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Skip snapshot-tag validation. Streaming previews use this so transient
|
|
44
|
+
* stale/missing tags do not flash re-read errors while the model is still
|
|
45
|
+
* authoring input; the final apply path still validates through Patcher.
|
|
46
|
+
*/
|
|
47
|
+
skipHashValidation?: boolean;
|
|
34
48
|
}
|
|
35
49
|
|
|
36
50
|
async function readSectionText(absolutePath: string, sectionPath: string): Promise<string> {
|
|
@@ -42,24 +56,79 @@ async function readSectionText(absolutePath: string, sectionPath: string): Promi
|
|
|
42
56
|
}
|
|
43
57
|
}
|
|
44
58
|
|
|
45
|
-
function
|
|
46
|
-
return
|
|
59
|
+
function hasAnchorScopedEdit(edits: readonly Edit[]): boolean {
|
|
60
|
+
return edits.some(edit => {
|
|
61
|
+
if (edit.kind === "delete") return true;
|
|
62
|
+
if (edit.kind === "block") return true;
|
|
63
|
+
return edit.cursor.kind === "before_anchor" || edit.cursor.kind === "after_anchor";
|
|
64
|
+
});
|
|
47
65
|
}
|
|
48
|
-
|
|
66
|
+
|
|
67
|
+
function createMismatchError(
|
|
49
68
|
section: PatchSection,
|
|
50
69
|
absolutePath: string,
|
|
51
|
-
|
|
70
|
+
normalized: string,
|
|
52
71
|
snapshots: SnapshotStore,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
expected: string,
|
|
73
|
+
): MismatchError {
|
|
74
|
+
return new MismatchError({
|
|
75
|
+
path: section.path,
|
|
76
|
+
expectedFileHash: expected,
|
|
77
|
+
actualFileHash: computeFileHash(normalized),
|
|
78
|
+
fileLines: normalized.split("\n"),
|
|
79
|
+
anchorLines: section.collectAnchorLines(),
|
|
80
|
+
hashRecognized: snapshots.byHash(absolutePath, expected) !== null,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function parsePreviewEdits(section: PatchSection, streaming: boolean | undefined): readonly Edit[] {
|
|
85
|
+
return streaming ? parsePatchStreaming(section.diff).edits : section.edits;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function resolvePreviewEdits(args: {
|
|
89
|
+
section: PatchSection;
|
|
90
|
+
absolutePath: string;
|
|
91
|
+
normalized: string;
|
|
92
|
+
snapshots: SnapshotStore;
|
|
93
|
+
expected: string | undefined;
|
|
94
|
+
liveMatches: boolean;
|
|
95
|
+
edits: readonly Edit[];
|
|
96
|
+
}): readonly Edit[] {
|
|
97
|
+
const { section, absolutePath, normalized, snapshots, expected, liveMatches, edits } = args;
|
|
98
|
+
if (!hasBlockEdit(edits)) return edits;
|
|
99
|
+
const baseText = expected === undefined || liveMatches ? normalized : snapshots.byHash(absolutePath, expected)?.text;
|
|
100
|
+
if (baseText === undefined) {
|
|
101
|
+
throw createMismatchError(section, absolutePath, normalized, snapshots, expected ?? "");
|
|
59
102
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
103
|
+
return resolveBlockEdits(edits, baseText, section.path, nativeBlockResolver, { onUnresolved: "throw" });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function applyPreviewEdits(args: {
|
|
107
|
+
section: PatchSection;
|
|
108
|
+
absolutePath: string;
|
|
109
|
+
normalized: string;
|
|
110
|
+
snapshots: SnapshotStore;
|
|
111
|
+
options: HashlineDiffOptions;
|
|
112
|
+
}): ApplyResult {
|
|
113
|
+
const { section, absolutePath, normalized, snapshots, options } = args;
|
|
114
|
+
const expected = section.fileHash;
|
|
115
|
+
if (!options.skipHashValidation && expected === undefined) {
|
|
116
|
+
throw new Error(missingSnapshotTagMessage(section.path));
|
|
117
|
+
}
|
|
118
|
+
const liveMatches = expected !== undefined && computeFileHash(normalized) === expected;
|
|
119
|
+
const edits = parsePreviewEdits(section, options.streaming);
|
|
120
|
+
const resolved = resolvePreviewEdits({ section, absolutePath, normalized, snapshots, expected, liveMatches, edits });
|
|
121
|
+
if (options.skipHashValidation || expected === undefined || liveMatches) return applyEdits(normalized, resolved);
|
|
122
|
+
if (!hasAnchorScopedEdit(resolved)) return applyEdits(normalized, resolved);
|
|
123
|
+
|
|
124
|
+
const recovered = new Recovery(snapshots).tryRecover({
|
|
125
|
+
path: absolutePath,
|
|
126
|
+
currentText: normalized,
|
|
127
|
+
fileHash: expected,
|
|
128
|
+
edits: resolved,
|
|
129
|
+
});
|
|
130
|
+
if (recovered) return recovered;
|
|
131
|
+
throw createMismatchError(section, absolutePath, normalized, snapshots, expected);
|
|
63
132
|
}
|
|
64
133
|
|
|
65
134
|
export async function computeHashlineSectionDiff(
|
|
@@ -73,11 +142,7 @@ export async function computeHashlineSectionDiff(
|
|
|
73
142
|
const rawContent = await readSectionText(absolutePath, section.path);
|
|
74
143
|
const { text: content } = stripBom(rawContent);
|
|
75
144
|
const normalized = normalizeToLF(content);
|
|
76
|
-
const
|
|
77
|
-
if (hashError) return { error: hashError };
|
|
78
|
-
const result = options.streaming
|
|
79
|
-
? section.applyPartialTo(normalized, nativeBlockResolver)
|
|
80
|
-
: section.applyTo(normalized, nativeBlockResolver);
|
|
145
|
+
const result = applyPreviewEdits({ section, absolutePath, normalized, snapshots, options });
|
|
81
146
|
if (normalized === result.text) return { error: `No changes would be made to ${section.path}.` };
|
|
82
147
|
return generateDiffString(normalized, result.text);
|
|
83
148
|
} catch (err) {
|
package/src/edit/renderer.ts
CHANGED
|
@@ -235,23 +235,27 @@ function renderPlainTextPreview(text: string, uiTheme: Theme, filePath?: string)
|
|
|
235
235
|
|
|
236
236
|
function formatStreamingDiff(diff: string, rawPath: string, uiTheme: Theme, label = "streaming"): string {
|
|
237
237
|
if (!diff) return "";
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
238
|
+
// "Cursor" tail window: pin the last EDIT_STREAMING_PREVIEW_LINES rows to the
|
|
239
|
+
// bottom of the diff so freshly streamed changes stay on screen, and accept
|
|
240
|
+
// the trailing rows "from the back" once the diff outgrows the window. The
|
|
241
|
+
// whole-file diff is recomputed on every streamed chunk and its Myers
|
|
242
|
+
// alignment is not monotonic in payload length, so a hunk-aware window that
|
|
243
|
+
// kept whole change segments gained and lost rows tick to tick — the box
|
|
244
|
+
// stuttered, and the earlier high-water fix traded that for a half-empty
|
|
245
|
+
// rectangle. A strict fixed-height window keeps the box steady and always
|
|
246
|
+
// full of real diff context instead of blank padding.
|
|
247
|
+
const allLines = diff.replace(/\n+$/u, "").split("\n");
|
|
248
|
+
const hiddenLines = Math.max(0, allLines.length - EDIT_STREAMING_PREVIEW_LINES);
|
|
249
|
+
const visible = hiddenLines > 0 ? allLines.slice(hiddenLines) : allLines;
|
|
247
250
|
let text = "\n\n";
|
|
248
|
-
if (
|
|
251
|
+
if (hiddenLines > 0) {
|
|
252
|
+
const hiddenHunks = getDiffStats(allLines.slice(0, hiddenLines).join("\n")).hunks;
|
|
249
253
|
const remainder: string[] = [];
|
|
250
254
|
if (hiddenHunks > 0) remainder.push(`${hiddenHunks} more hunks`);
|
|
251
|
-
|
|
255
|
+
remainder.push(`${hiddenLines} more lines`);
|
|
252
256
|
text += `${uiTheme.fg("dim", `… (${remainder.join(", ")} above)`)}\n`;
|
|
253
257
|
}
|
|
254
|
-
text += renderDiffColored(
|
|
258
|
+
text += renderDiffColored(visible.join("\n"), { filePath: rawPath });
|
|
255
259
|
text += uiTheme.fg("dim", `\n(${label})`);
|
|
256
260
|
return text;
|
|
257
261
|
}
|
package/src/edit/streaming.ts
CHANGED
|
@@ -314,8 +314,14 @@ const hashlineStrategy: EditStreamingStrategy<HashlineArgs> = {
|
|
|
314
314
|
},
|
|
315
315
|
async computeDiffPreview(args, ctx) {
|
|
316
316
|
if (typeof args.input !== "string" || args.input.length === 0) return null;
|
|
317
|
-
|
|
318
|
-
|
|
317
|
+
// Unlike apply_patch, hashline previews flow through `applyPartialTo`,
|
|
318
|
+
// whose streaming-tolerant parser (`parsePatchStreaming` → `endStreaming`)
|
|
319
|
+
// drops a payload-less trailing op and projects a partially-typed payload
|
|
320
|
+
// line onto the file as it grows. Trimming the trailing partial line here
|
|
321
|
+
// would instead strip the sole payload of a single-op `replace`/`insert`
|
|
322
|
+
// for almost the entire stream, collapsing the preview to "No changes" and
|
|
323
|
+
// rendering a blank box. Feed the raw in-flight text straight through.
|
|
324
|
+
const input = args.input;
|
|
319
325
|
ctx.signal.throwIfAborted();
|
|
320
326
|
|
|
321
327
|
let sections: readonly HashlineInputSection[];
|
|
@@ -347,12 +353,17 @@ const hashlineStrategy: EditStreamingStrategy<HashlineArgs> = {
|
|
|
347
353
|
const section = sectionsToProcess[i];
|
|
348
354
|
const result = await computeHashlineSectionDiff(section, ctx.cwd, ctx.snapshots, {
|
|
349
355
|
streaming: ctx.isStreaming,
|
|
356
|
+
skipHashValidation: ctx.isStreaming === true,
|
|
350
357
|
});
|
|
351
358
|
ctx.signal.throwIfAborted();
|
|
352
|
-
//
|
|
353
|
-
//
|
|
354
|
-
//
|
|
355
|
-
|
|
359
|
+
// Ignore parse/apply errors from the trailing (actively-typed)
|
|
360
|
+
// section while streaming: a mid-typed op may transiently resolve to
|
|
361
|
+
// "No changes" or an out-of-bounds anchor, and surfacing that would
|
|
362
|
+
// wipe the already-stable previews (or, for a lone section, the prior
|
|
363
|
+
// good frame). Returning no entry preserves the last preview. Earlier
|
|
364
|
+
// sections, and every section once args are complete, stay rendered so
|
|
365
|
+
// real errors still reach the model.
|
|
366
|
+
if ((ctx.isStreaming || sectionsToProcess.length > 1) && i === trailingProcessedIndex && "error" in result) {
|
|
356
367
|
continue;
|
|
357
368
|
}
|
|
358
369
|
previews.push(toPerFilePreview(section.path, result));
|